@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.
- package/build/src/amf/definitions/Shapes.d.ts +1 -1
- package/build/src/amf/definitions/Shapes.js.map +1 -1
- package/build/src/browser.d.ts +2 -0
- package/build/src/browser.d.ts.map +1 -1
- package/build/src/browser.js +2 -0
- package/build/src/browser.js.map +1 -1
- package/build/src/index.d.ts +2 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +2 -0
- package/build/src/index.js.map +1 -1
- package/build/src/modeling/DataAssociation.d.ts +10 -2
- package/build/src/modeling/DataAssociation.d.ts.map +1 -1
- package/build/src/modeling/DataAssociation.js +32 -2
- package/build/src/modeling/DataAssociation.js.map +1 -1
- package/build/src/modeling/DataEntity.d.ts +26 -1
- package/build/src/modeling/DataEntity.d.ts.map +1 -1
- package/build/src/modeling/DataEntity.js +73 -8
- package/build/src/modeling/DataEntity.js.map +1 -1
- package/build/src/modeling/DataModel.d.ts +10 -1
- package/build/src/modeling/DataModel.d.ts.map +1 -1
- package/build/src/modeling/DataModel.js +22 -2
- package/build/src/modeling/DataModel.js.map +1 -1
- package/build/src/modeling/DataNamespace.d.ts +60 -55
- package/build/src/modeling/DataNamespace.d.ts.map +1 -1
- package/build/src/modeling/DataNamespace.js +133 -116
- package/build/src/modeling/DataNamespace.js.map +1 -1
- package/build/src/modeling/DataProperty.d.ts +16 -3
- package/build/src/modeling/DataProperty.d.ts.map +1 -1
- package/build/src/modeling/DataProperty.js +28 -2
- package/build/src/modeling/DataProperty.js.map +1 -1
- package/build/src/modeling/ImpactAnalysis.d.ts +290 -0
- package/build/src/modeling/ImpactAnalysis.d.ts.map +1 -0
- package/build/src/modeling/ImpactAnalysis.js +437 -0
- package/build/src/modeling/ImpactAnalysis.js.map +1 -0
- package/build/src/modeling/types.d.ts +14 -0
- package/build/src/modeling/types.d.ts.map +1 -0
- package/build/src/modeling/types.js +2 -0
- package/build/src/modeling/types.js.map +1 -0
- package/data/models/example-generator-api.json +9 -9
- package/package.json +9 -19
- package/src/amf/definitions/Shapes.ts +1 -1
- package/src/modeling/DataAssociation.ts +36 -2
- package/src/modeling/DataEntity.ts +88 -12
- package/src/modeling/DataModel.ts +24 -2
- package/src/modeling/DataNamespace.ts +150 -137
- package/src/modeling/DataProperty.ts +32 -3
- package/src/modeling/ImpactAnalysis.ts +519 -0
- package/src/modeling/types.ts +13 -0
- package/tests/servers/ExpressServer.ts +1 -0
- package/tests/servers/express-routes/BaseApi.ts +1 -1
- package/tests/servers/express-routes/TestsApi.ts +1 -1
- package/tests/unit/modeling/data_association.spec.ts +73 -0
- package/tests/unit/modeling/data_entity.spec.ts +111 -1
- package/tests/unit/modeling/data_model.spec.ts +54 -0
- package/tests/unit/modeling/data_namespace.spec.ts +46 -1
- package/tests/unit/modeling/data_property.spec.ts +73 -0
- package/tests/unit/modeling/impact_analysis.spec.ts +373 -0
- 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.
|
|
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": "^
|
|
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 `
|
|
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
|
|
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
|
|
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
|
|
584
|
-
|
|
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
|
|
596
|
+
acc.push({ entity, association })
|
|
591
597
|
}
|
|
592
598
|
return acc
|
|
593
599
|
}, [])
|
|
594
|
-
|
|
595
|
-
|
|
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
|
|
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: '
|
|
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
|
}
|