@api-client/core 0.11.6 → 0.11.8

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 (58) hide show
  1. package/build/src/amf/definitions/Shapes.d.ts +1 -1
  2. package/build/src/amf/definitions/Shapes.js.map +1 -1
  3. package/build/src/browser.d.ts +2 -0
  4. package/build/src/browser.d.ts.map +1 -1
  5. package/build/src/browser.js +2 -0
  6. package/build/src/browser.js.map +1 -1
  7. package/build/src/index.d.ts +2 -0
  8. package/build/src/index.d.ts.map +1 -1
  9. package/build/src/index.js +2 -0
  10. package/build/src/index.js.map +1 -1
  11. package/build/src/modeling/DataAssociation.d.ts +10 -2
  12. package/build/src/modeling/DataAssociation.d.ts.map +1 -1
  13. package/build/src/modeling/DataAssociation.js +32 -2
  14. package/build/src/modeling/DataAssociation.js.map +1 -1
  15. package/build/src/modeling/DataEntity.d.ts +26 -1
  16. package/build/src/modeling/DataEntity.d.ts.map +1 -1
  17. package/build/src/modeling/DataEntity.js +73 -8
  18. package/build/src/modeling/DataEntity.js.map +1 -1
  19. package/build/src/modeling/DataModel.d.ts +10 -1
  20. package/build/src/modeling/DataModel.d.ts.map +1 -1
  21. package/build/src/modeling/DataModel.js +22 -2
  22. package/build/src/modeling/DataModel.js.map +1 -1
  23. package/build/src/modeling/DataNamespace.d.ts +60 -55
  24. package/build/src/modeling/DataNamespace.d.ts.map +1 -1
  25. package/build/src/modeling/DataNamespace.js +133 -116
  26. package/build/src/modeling/DataNamespace.js.map +1 -1
  27. package/build/src/modeling/DataProperty.d.ts +16 -3
  28. package/build/src/modeling/DataProperty.d.ts.map +1 -1
  29. package/build/src/modeling/DataProperty.js +28 -2
  30. package/build/src/modeling/DataProperty.js.map +1 -1
  31. package/build/src/modeling/ImpactAnalysis.d.ts +290 -0
  32. package/build/src/modeling/ImpactAnalysis.d.ts.map +1 -0
  33. package/build/src/modeling/ImpactAnalysis.js +437 -0
  34. package/build/src/modeling/ImpactAnalysis.js.map +1 -0
  35. package/build/src/modeling/types.d.ts +14 -0
  36. package/build/src/modeling/types.d.ts.map +1 -0
  37. package/build/src/modeling/types.js +2 -0
  38. package/build/src/modeling/types.js.map +1 -0
  39. package/data/models/example-generator-api.json +9 -9
  40. package/package.json +9 -19
  41. package/src/amf/definitions/Shapes.ts +1 -1
  42. package/src/modeling/DataAssociation.ts +36 -2
  43. package/src/modeling/DataEntity.ts +88 -12
  44. package/src/modeling/DataModel.ts +24 -2
  45. package/src/modeling/DataNamespace.ts +150 -137
  46. package/src/modeling/DataProperty.ts +32 -3
  47. package/src/modeling/ImpactAnalysis.ts +519 -0
  48. package/src/modeling/types.ts +13 -0
  49. package/tests/servers/ExpressServer.ts +1 -0
  50. package/tests/servers/express-routes/BaseApi.ts +1 -1
  51. package/tests/servers/express-routes/TestsApi.ts +1 -1
  52. package/tests/unit/modeling/data_association.spec.ts +73 -0
  53. package/tests/unit/modeling/data_entity.spec.ts +111 -1
  54. package/tests/unit/modeling/data_model.spec.ts +54 -0
  55. package/tests/unit/modeling/data_namespace.spec.ts +46 -1
  56. package/tests/unit/modeling/data_property.spec.ts +73 -0
  57. package/tests/unit/modeling/impact_analysis.spec.ts +373 -0
  58. package/tsconfig.browser.json +2 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@api-client/core",
3
3
  "description": "The API Client's core client library. Works in NodeJS and in a ES enabled browser.",
4
- "version": "0.11.6",
4
+ "version": "0.11.8",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {
7
7
  "./browser.js": {
@@ -31,9 +31,9 @@
31
31
  "#proxy/*": "./src/proxy/*",
32
32
  "#ui/*": "./src/ui/*"
33
33
  },
34
- "main": "./build/index.js",
35
- "browser": "./build/browser.js",
36
- "module": "./build/index.js",
34
+ "main": "./build/src/index.js",
35
+ "browser": "./build/src/browser.js",
36
+ "module": "./build/src/index.js",
37
37
  "type": "module",
38
38
  "author": {
39
39
  "name": "Pawel Uchida-Psztyc"
@@ -49,8 +49,6 @@
49
49
  "url": "https://github.com/api-client/core/issues"
50
50
  },
51
51
  "dependencies": {
52
- "@adonisjs/transmit-client": "^1.0.0",
53
- "@api-client/graph": "^0.2.0",
54
52
  "@api-client/json": "^0.2.0",
55
53
  "@esm-bundle/chai": "^4.3.4-fix.0",
56
54
  "@material/web": "^2.2.0",
@@ -60,12 +58,6 @@
60
58
  "@xmldom/xmldom": "^0.9.7",
61
59
  "amf-json-ld-lib": "^0.0.15",
62
60
  "console-table-printer": "^2.11.2",
63
- "dompurify": "^3.1.5",
64
- "idb-keyval": "^6.2.1",
65
- "lit": "^3.1.4",
66
- "marked": "^15.0.7",
67
- "monaco-editor": "^0.52.2",
68
- "prismjs": "^1.29.0",
69
61
  "ws": "^8.12.0",
70
62
  "xpath": "^0.0.34"
71
63
  },
@@ -78,21 +70,16 @@
78
70
  "@japa/browser-client": "^2.1.1",
79
71
  "@japa/expect-type": "^2.0.3",
80
72
  "@japa/runner": "^4.2.0",
81
- "@open-wc/semantic-dom-diff": "^0.20.1",
82
- "@open-wc/testing": "^4.0.0",
83
73
  "@rollup/plugin-typescript": "^12.1.2",
84
74
  "@types/cors": "^2.8.12",
85
- "@types/dompurify": "^3.0.5",
86
75
  "@types/express-ntlm": "^2.3.3",
87
76
  "@types/jsdom": "^21.1.7",
88
77
  "@types/mocha": "^10.0.10",
89
78
  "@types/node": "^22.13.4",
90
- "@types/prismjs": "^1.26.4",
91
79
  "@types/sinon": "^17.0.1",
92
80
  "@web/dev-server": "^0.4.6",
93
81
  "@web/dev-server-rollup": "^0.6.4",
94
82
  "@web/test-runner": "^0.20.0",
95
- "@web/test-runner-commands": "^0.9.0",
96
83
  "@web/test-runner-playwright": "^0.11.0",
97
84
  "amf-client-js": "^5.7.0",
98
85
  "c8": "^10.1.3",
@@ -101,7 +88,7 @@
101
88
  "eslint-config-prettier": "^10.0.1",
102
89
  "eslint-plugin-no-only-tests": "^3.3.0",
103
90
  "eslint-plugin-prettier": "^5.2.3",
104
- "express": "^4.17.1",
91
+ "express": "^5.1.0",
105
92
  "express-ntlm": "^2.6.1",
106
93
  "get-port": "^7.0.0",
107
94
  "globals": "^16.0.0",
@@ -113,7 +100,6 @@
113
100
  "playwright": "^1.50.1",
114
101
  "prettier": "^3.5.1",
115
102
  "sinon": "^20.0.0",
116
- "ssl-root-cas": "^1.3.1",
117
103
  "ts-lit-plugin": "^2.0.2",
118
104
  "ts-node-maintained": "^10.9.5",
119
105
  "typescript": "^5.5.2",
@@ -133,6 +119,7 @@
133
119
  "test:browser": "node --import ts-node-maintained/register/esm --enable-source-maps bin/test-web.ts --playwright --browsers chromium",
134
120
  "test:browser:watch": "node --import ts-node-maintained/register/esm --enable-source-maps bin/test-web.ts --watch --playwright --browsers chromium",
135
121
  "test": "wireit",
122
+ "test:coverage": "wireit",
136
123
  "test:node": "node --import ts-node-maintained/register/esm --enable-source-maps bin/test.ts",
137
124
  "test:node:coverage": "c8 --reporter lcov --reporter text node --import ts-node-maintained/register/esm --enable-source-maps bin/test.ts",
138
125
  "test:node:watch": "node --import ts-node-maintained/register/esm --enable-source-maps bin/test.ts --watch",
@@ -143,6 +130,9 @@
143
130
  },
144
131
  "wireit": {
145
132
  "test": {
133
+ "command": "npm run test:node && npm run test:browser"
134
+ },
135
+ "test:coverage": {
146
136
  "command": "npm run test:node:coverage && npm run test:browser"
147
137
  },
148
138
  "tsc:watch": {
@@ -68,7 +68,7 @@ export interface IApiAssociationShape {
68
68
  * - anyOf - To validate against `anyOf`, the given data must be valid against
69
69
  * any (one or more) of the given sub-schemas. When generation a schema, it takes first union schema.
70
70
  * - oneOf - To validate against `oneOf`, the given data must be valid against
71
- * exactly one of the given sub-schemas. It behaves the same as `oneOf` when generating a schema
71
+ * exactly one of the given sub-schemas. It behaves the same as `anyOf` when generating a schema
72
72
  * - not - The `not` keyword declares that an instance validates if it doesn’t
73
73
  * validate against the given sub-schema. It has no use when generating a schema.
74
74
  *
@@ -402,6 +402,19 @@ export class DataAssociation {
402
402
  namespace = typed.root.key
403
403
  }
404
404
  }
405
+ if (this.targets.some((i) => i.key === key)) {
406
+ const message = `Target ${key} already exists.`
407
+ throw new ValidationError(
408
+ [
409
+ {
410
+ field: 'targets',
411
+ message,
412
+ rule: 'unique',
413
+ },
414
+ ],
415
+ { message }
416
+ )
417
+ }
405
418
  if (namespace && namespace !== this.root.key) {
406
419
  const foreignNamespace = this.root.foreign.find((ns) => ns.key === namespace)
407
420
  if (!foreignNamespace) {
@@ -480,9 +493,9 @@ export class DataAssociation {
480
493
  }
481
494
 
482
495
  /**
483
- * Checks whether the passed value is one of the supported data proprty attributes.
496
+ * Checks whether the passed value is one of the supported data property attributes.
484
497
  * @param value The value to test
485
- * @returns True when the passed value is one of the supported data proprty attributes.
498
+ * @returns True when the passed value is one of the supported data property attributes.
486
499
  */
487
500
  static isValidAttribute(value: unknown): value is DataAttributeAttribute {
488
501
  if (typeof value !== 'string') {
@@ -513,4 +526,25 @@ export class DataAssociation {
513
526
  const item = this.bindings.find((i) => i.type === type) as AssociationBinding
514
527
  return item?.schema
515
528
  }
529
+
530
+ /**
531
+ * Checks whether the association is a child of the given namespace, data model, or an entity.
532
+ * The relationship doesn't have to be direct, as long as the association is in the hierarchy it will return true.
533
+ *
534
+ * @param key The key of the parent to check.
535
+ * @returns True if this data association is a child of the given namespace, data model, or an entity
536
+ */
537
+ isChildOf(key: string): boolean {
538
+ if (this.key === key) {
539
+ return false
540
+ }
541
+ const parent = this.getParentInstance()
542
+ if (!parent) {
543
+ return false
544
+ }
545
+ if (parent.key === key) {
546
+ return true
547
+ }
548
+ return parent.isChildOf(key)
549
+ }
516
550
  }
@@ -16,9 +16,16 @@ import { RemoveAssociationException } from '../exceptions/remove_association_exc
16
16
  import { ValidationError, type FieldValidationMessage } from '../exceptions/validation_error.js'
17
17
  import { RemoveEntityException } from '../exceptions/remove_entity_exception.js'
18
18
  import { ForeignAssociationException } from '../exceptions/foreign_association_exception.js'
19
+ import type { DataDomainRemoveOptions } from './types.js'
19
20
 
20
21
  interface OrderedItem {
22
+ /**
23
+ * The type of the ordered item.
24
+ */
21
25
  type: 'property' | 'association'
26
+ /**
27
+ * The key of the ordered item.
28
+ */
22
29
  key: string
23
30
  }
24
31
 
@@ -556,6 +563,7 @@ export class DataEntity {
556
563
 
557
564
  /**
558
565
  * Computes a list of entities that are associated with the current entity.
566
+ * This is the association-out (out-edge) direction.
559
567
  */
560
568
  getComputedAssociations(): DataEntity[] {
561
569
  const { associations } = this
@@ -577,23 +585,43 @@ export class DataEntity {
577
585
  /**
578
586
  * Removes self from the namespace with all properties and attributes.
579
587
  */
580
- remove(): void {
588
+ remove(opts: DataDomainRemoveOptions = {}): void {
581
589
  const { key, properties, associations, root } = this
582
590
  // check if some entity has reference to this entity as a target
583
- const associationsToEntity = this.root.definitions.associations.filter((a) =>
584
- a.targets.some((t) => t.key === this.key)
585
- )
586
- if (associationsToEntity.length > 0) {
587
- const entitiesNames = associationsToEntity.reduce<string[]>((acc, association) => {
591
+ const toEdges = this.root.definitions.associations.filter((a) => a.targets.some((t) => t.key === this.key))
592
+ if (toEdges.length > 0) {
593
+ const result = toEdges.reduce<{ entity: DataEntity; association: DataAssociation }[]>((acc, association) => {
588
594
  const entity = root.definitions.entities.find((e) => e.associations.some((a) => a.key === association.key))
589
595
  if (entity) {
590
- acc.push(entity.info.name as string)
596
+ acc.push({ entity, association })
591
597
  }
592
598
  return acc
593
599
  }, [])
594
- throw new RemoveEntityException(
595
- `Cannot remove entity ${this.info.name} because it is used as a target in associations in entities: ${entitiesNames.join(', ')}.`
596
- )
600
+ if (opts.force) {
601
+ // remove the association from the entity
602
+ result.forEach(({ entity: item, association }) => {
603
+ item.removeAssociation(association.key)
604
+ })
605
+ } else {
606
+ const entitiesNames = result.map(({ entity }) => entity.info.renderLabel || entity.key)
607
+ throw new RemoveEntityException(
608
+ `Cannot remove entity ${this.info.renderLabel} because it is used as a target in associations in entities: ${entitiesNames.join(', ')}.`
609
+ )
610
+ }
611
+ }
612
+
613
+ const children = this.getComputedChildren()
614
+ if (children.length > 0) {
615
+ if (opts.force) {
616
+ children.forEach((child) => {
617
+ child.parents = child.parents.filter((i) => i !== this.key)
618
+ })
619
+ } else {
620
+ const childrenNames = children.map((i) => i.info.renderLabel || i.key)
621
+ throw new RemoveEntityException(
622
+ `Cannot remove entity ${this.info.renderLabel} because it is a parent for the following entities: ${childrenNames.join(', ')}.`
623
+ )
624
+ }
597
625
  }
598
626
 
599
627
  // remove own stuff
@@ -615,7 +643,7 @@ export class DataEntity {
615
643
  /**
616
644
  * @deprecated Use the `getParentInstance()` method instead.
617
645
  */
618
- // This method name colides with the `getParents()` method.
646
+ // This method name collides with the `getParents()` method.
619
647
  getParent(): DataModel | undefined {
620
648
  return this.getParentInstance()
621
649
  }
@@ -685,7 +713,7 @@ export class DataEntity {
685
713
  {
686
714
  field: 'parents',
687
715
  message,
688
- rule: 'exists',
716
+ rule: 'unique',
689
717
  },
690
718
  ],
691
719
  { message }
@@ -695,6 +723,33 @@ export class DataEntity {
695
723
  return this
696
724
  }
697
725
 
726
+ /**
727
+ * Removes a parent reference from this entity.
728
+ * It keeps the parent as is.
729
+ *
730
+ * @param key The key of the parent entity to remove.
731
+ * @throws ValidationError when the parent is not found.
732
+ * @returns Self for chaining.
733
+ */
734
+ removeParent(key: string): this {
735
+ const index = this.parents.findIndex((i) => i === key)
736
+ if (index < 0) {
737
+ const message = `Parent ${key} not found.`
738
+ throw new ValidationError(
739
+ [
740
+ {
741
+ field: 'parents',
742
+ message,
743
+ rule: 'not-found',
744
+ },
745
+ ],
746
+ { message }
747
+ )
748
+ }
749
+ this.parents.splice(index, 1)
750
+ return this
751
+ }
752
+
698
753
  /**
699
754
  * Checks if the entity has a circular parent relationship when attempting to add a new parent.
700
755
  * @param key The key of the parent being added.
@@ -935,4 +990,25 @@ export class DataEntity {
935
990
  }
936
991
  return false
937
992
  }
993
+
994
+ /**
995
+ * Checks whether the entity is a child of the given namespace or data model.
996
+ * The relationship doesn't have to be direct, as long as the entity is in the hierarchy it will return true.
997
+ *
998
+ * @param key The key of the parent to check.
999
+ * @returns True if this entity is a child of the given namespace or data model.
1000
+ */
1001
+ isChildOf(key: string): boolean {
1002
+ if (this.key === key) {
1003
+ return false
1004
+ }
1005
+ const parent = this.getParentInstance()
1006
+ if (!parent) {
1007
+ return false
1008
+ }
1009
+ if (parent.key === key) {
1010
+ return true
1011
+ }
1012
+ return parent.isChildOf(key)
1013
+ }
938
1014
  }
@@ -4,6 +4,7 @@ import { DataEntity, IDataEntity } from './DataEntity.js'
4
4
  import type { DataItemAdaptingOptions, DataNamespace } from './DataNamespace.js'
5
5
  import { FileBreadcrumb } from '../models/store/File.js'
6
6
  import { DataModelKind } from '../models/kinds.js'
7
+ import type { DataDomainRemoveOptions } from './types.js'
7
8
 
8
9
  /**
9
10
  * Data model creates a logical structure around data entities.
@@ -129,10 +130,10 @@ export class DataModel {
129
130
  /**
130
131
  * Removes self from the namespace with all entities.
131
132
  */
132
- remove(): void {
133
+ remove(opts?: DataDomainRemoveOptions): void {
133
134
  const { key, entities, root } = this
134
135
  // remove children
135
- entities.forEach((e) => e.remove())
136
+ entities.forEach((e) => e.remove(opts))
136
137
 
137
138
  // remove self from the parent
138
139
  const parent = this.getParentInstance()
@@ -249,4 +250,25 @@ export class DataModel {
249
250
  })
250
251
  return result.reverse()
251
252
  }
253
+
254
+ /**
255
+ * Checks whether the data model is a child of the given namespace.
256
+ * The relationship doesn't have to be direct, as long as the data model is in the hierarchy it will return true.
257
+ *
258
+ * @param key The key of the parent namespace to check.
259
+ * @returns True if this data model is a child of the given namespace.
260
+ */
261
+ isChildOf(key: string): boolean {
262
+ if (this.key === key) {
263
+ return false
264
+ }
265
+ const parent = this.getParentInstance()
266
+ if (!parent) {
267
+ return false
268
+ }
269
+ if (parent.key === key) {
270
+ return true
271
+ }
272
+ return parent.isChildOf(key)
273
+ }
252
274
  }