@api-client/core 0.12.0 → 0.12.2
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/bin/plugins/sinon/assert.ts +29 -0
- package/bin/test.ts +2 -0
- package/build/src/amf/AmfShapeGenerator.js +3 -3
- package/build/src/amf/AmfShapeGenerator.js.map +1 -1
- package/build/src/amf/DataValueGenerator.d.ts.map +1 -1
- package/build/src/amf/DataValueGenerator.js +3 -2
- package/build/src/amf/DataValueGenerator.js.map +1 -1
- package/build/src/amf/models/AmfDataNode.d.ts.map +1 -1
- package/build/src/amf/models/AmfDataNode.js +2 -2
- package/build/src/amf/models/AmfDataNode.js.map +1 -1
- package/build/src/browser.d.ts +4 -0
- package/build/src/browser.d.ts.map +1 -1
- package/build/src/browser.js +3 -0
- package/build/src/browser.js.map +1 -1
- package/build/src/index.d.ts +4 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +3 -0
- package/build/src/index.js.map +1 -1
- package/build/src/lib/uuid.d.ts +1 -1
- package/build/src/lib/uuid.js +1 -1
- package/build/src/lib/uuid.js.map +1 -1
- package/build/src/mocking/lib/History.js +8 -8
- package/build/src/mocking/lib/History.js.map +1 -1
- package/build/src/mocking/lib/HostRules.js +1 -1
- package/build/src/mocking/lib/HostRules.js.map +1 -1
- package/build/src/mocking/lib/User.js +2 -2
- package/build/src/mocking/lib/User.js.map +1 -1
- package/build/src/modeling/DataDomain.d.ts +4 -0
- package/build/src/modeling/DataDomain.d.ts.map +1 -1
- package/build/src/modeling/DataDomain.js +13 -3
- package/build/src/modeling/DataDomain.js.map +1 -1
- package/build/src/modeling/DomainAssociation.js +1 -1
- package/build/src/modeling/DomainAssociation.js.map +1 -1
- package/build/src/modeling/DomainEntity.d.ts +46 -0
- package/build/src/modeling/DomainEntity.d.ts.map +1 -1
- package/build/src/modeling/DomainEntity.js +71 -0
- package/build/src/modeling/DomainEntity.js.map +1 -1
- package/build/src/modeling/DomainFile.js +2 -2
- package/build/src/modeling/DomainFile.js.map +1 -1
- package/build/src/modeling/DomainImpactAnalysis.d.ts +31 -8
- package/build/src/modeling/DomainImpactAnalysis.d.ts.map +1 -1
- package/build/src/modeling/DomainImpactAnalysis.js +118 -46
- package/build/src/modeling/DomainImpactAnalysis.js.map +1 -1
- package/build/src/modeling/DomainProperty.js +1 -1
- package/build/src/modeling/DomainProperty.js.map +1 -1
- package/build/src/modeling/legacy/DataAssociation.js +3 -3
- package/build/src/modeling/legacy/DataAssociation.js.map +1 -1
- package/build/src/modeling/legacy/DataEntity.js +3 -3
- package/build/src/modeling/legacy/DataEntity.js.map +1 -1
- package/build/src/modeling/legacy/DataEntityBuilder.js +2 -2
- package/build/src/modeling/legacy/DataEntityBuilder.js.map +1 -1
- package/build/src/modeling/legacy/DataModel.js +3 -3
- package/build/src/modeling/legacy/DataModel.js.map +1 -1
- package/build/src/modeling/legacy/DataNamespace.js +3 -3
- package/build/src/modeling/legacy/DataNamespace.js.map +1 -1
- package/build/src/modeling/legacy/DataProperty.js +3 -3
- package/build/src/modeling/legacy/DataProperty.js.map +1 -1
- package/build/src/modeling/validation/association_validation.d.ts +38 -0
- package/build/src/modeling/validation/association_validation.d.ts.map +1 -0
- package/build/src/modeling/validation/association_validation.js +108 -0
- package/build/src/modeling/validation/association_validation.js.map +1 -0
- package/build/src/modeling/validation/entity_validation.d.ts +52 -0
- package/build/src/modeling/validation/entity_validation.d.ts.map +1 -0
- package/build/src/modeling/validation/entity_validation.js +241 -0
- package/build/src/modeling/validation/entity_validation.js.map +1 -0
- package/build/src/modeling/validation/postgresql.d.ts +2 -0
- package/build/src/modeling/validation/postgresql.d.ts.map +1 -0
- package/build/src/modeling/validation/postgresql.js +58 -0
- package/build/src/modeling/validation/postgresql.js.map +1 -0
- package/build/src/modeling/validation/property_validation.d.ts +29 -0
- package/build/src/modeling/validation/property_validation.d.ts.map +1 -0
- package/build/src/modeling/validation/property_validation.js +58 -0
- package/build/src/modeling/validation/property_validation.js.map +1 -0
- package/build/src/modeling/validation/rules.d.ts +55 -0
- package/build/src/modeling/validation/rules.d.ts.map +1 -0
- package/build/src/modeling/validation/rules.js +110 -0
- package/build/src/modeling/validation/rules.js.map +1 -0
- package/build/src/models/AuthorizationData.js +3 -3
- package/build/src/models/AuthorizationData.js.map +1 -1
- package/build/src/models/CertificateFile.js +2 -2
- package/build/src/models/CertificateFile.js.map +1 -1
- package/build/src/models/ClientCertificate.js +5 -5
- package/build/src/models/ClientCertificate.js.map +1 -1
- package/build/src/models/Environment.js +6 -6
- package/build/src/models/Environment.js.map +1 -1
- package/build/src/models/Folder.js +2 -2
- package/build/src/models/Folder.js.map +1 -1
- package/build/src/models/HostRule.js +4 -4
- package/build/src/models/HostRule.js.map +1 -1
- package/build/src/models/HttpProject.js +12 -12
- package/build/src/models/HttpProject.js.map +1 -1
- package/build/src/models/Project.d.ts.map +1 -1
- package/build/src/models/Project.js +2 -2
- package/build/src/models/Project.js.map +1 -1
- package/build/src/models/ProjectFolder.d.ts.map +1 -1
- package/build/src/models/ProjectFolder.js +6 -6
- package/build/src/models/ProjectFolder.js.map +1 -1
- package/build/src/models/ProjectRequest.d.ts.map +1 -1
- package/build/src/models/ProjectRequest.js +8 -8
- package/build/src/models/ProjectRequest.js.map +1 -1
- package/build/src/models/ProjectSchema.js +6 -6
- package/build/src/models/ProjectSchema.js.map +1 -1
- package/build/src/models/store/DataFile.js +2 -2
- package/build/src/models/store/DataFile.js.map +1 -1
- package/build/src/models/store/File.d.ts.map +1 -1
- package/build/src/models/store/File.js +3 -3
- package/build/src/models/store/File.js.map +1 -1
- package/build/src/models/store/Organization.js +3 -3
- package/build/src/models/store/Organization.js.map +1 -1
- package/build/src/models/store/Permission.js +7 -7
- package/build/src/models/store/Permission.js.map +1 -1
- package/build/src/models/store/UserIdentity.js +3 -3
- package/build/src/models/store/UserIdentity.js.map +1 -1
- package/build/src/models/transformers/ArcDexieTransformer.js +4 -4
- package/build/src/models/transformers/ArcDexieTransformer.js.map +1 -1
- package/build/src/models/transformers/ArcLegacyTransformer.js +3 -3
- package/build/src/models/transformers/ArcLegacyTransformer.js.map +1 -1
- package/build/src/models/transformers/ArcPouchTransformer.js +2 -2
- package/build/src/models/transformers/ArcPouchTransformer.js.map +1 -1
- package/build/src/models/transformers/PostmanV21Transformer.js +2 -2
- package/build/src/models/transformers/PostmanV21Transformer.js.map +1 -1
- package/build/src/models/transformers/PostmanV2Transformer.js +2 -2
- package/build/src/models/transformers/PostmanV2Transformer.js.map +1 -1
- package/build/src/patch/PatchClient.js +2 -2
- package/build/src/patch/PatchClient.js.map +1 -1
- package/build/src/runtime/store/FilesSdk.js +3 -3
- package/build/src/runtime/store/FilesSdk.js.map +1 -1
- package/data/models/example-generator-api.json +20 -20
- package/package.json +1 -1
- package/src/amf/AmfShapeGenerator.ts +3 -3
- package/src/amf/DataValueGenerator.ts +3 -2
- package/src/amf/models/AmfDataNode.ts +2 -2
- package/src/lib/uuid.ts +1 -1
- package/src/mocking/lib/History.ts +8 -8
- package/src/mocking/lib/HostRules.ts +1 -1
- package/src/mocking/lib/User.ts +2 -2
- package/src/modeling/DataDomain.ts +14 -3
- package/src/modeling/DomainAssociation.ts +1 -1
- package/src/modeling/DomainEntity.ts +75 -0
- package/src/modeling/DomainFile.ts +2 -2
- package/src/modeling/DomainImpactAnalysis.ts +144 -54
- package/src/modeling/DomainProperty.ts +1 -1
- package/src/modeling/legacy/DataAssociation.ts +3 -3
- package/src/modeling/legacy/DataEntity.ts +3 -3
- package/src/modeling/legacy/DataEntityBuilder.ts +2 -2
- package/src/modeling/legacy/DataModel.ts +3 -3
- package/src/modeling/legacy/DataNamespace.ts +3 -3
- package/src/modeling/legacy/DataProperty.ts +3 -3
- package/src/modeling/validation/association_validation.ts +109 -0
- package/src/modeling/validation/entity_validation.ts +246 -0
- package/src/modeling/validation/postgresql.ts +57 -0
- package/src/modeling/validation/property_validation.ts +58 -0
- package/src/modeling/validation/rules.ts +152 -0
- package/src/models/AuthorizationData.ts +3 -3
- package/src/models/CertificateFile.ts +2 -2
- package/src/models/ClientCertificate.ts +5 -5
- package/src/models/Environment.ts +6 -6
- package/src/models/Folder.ts +2 -2
- package/src/models/HostRule.ts +4 -4
- package/src/models/HttpProject.ts +12 -12
- package/src/models/Project.ts +2 -2
- package/src/models/ProjectFolder.ts +6 -6
- package/src/models/ProjectRequest.ts +8 -8
- package/src/models/ProjectSchema.ts +6 -6
- package/src/models/store/DataFile.ts +2 -2
- package/src/models/store/File.ts +3 -3
- package/src/models/store/Organization.ts +3 -3
- package/src/models/store/Permission.ts +7 -7
- package/src/models/store/UserIdentity.ts +3 -3
- package/src/models/transformers/ArcDexieTransformer.ts +4 -4
- package/src/models/transformers/ArcLegacyTransformer.ts +3 -3
- package/src/models/transformers/ArcPouchTransformer.ts +2 -2
- package/src/models/transformers/PostmanV21Transformer.ts +2 -2
- package/src/models/transformers/PostmanV2Transformer.ts +2 -2
- package/src/patch/PatchClient.ts +2 -2
- package/src/runtime/store/FilesSdk.ts +3 -3
- package/tests/unit/modeling/data_domain_associations.spec.ts +1 -1
- package/tests/unit/modeling/data_domain_property.spec.ts +1 -1
- package/tests/unit/modeling/domain.property.spec.ts +7 -7
- package/tests/unit/modeling/domain_asociation.spec.ts +3 -3
- package/tests/unit/modeling/domain_entity_associations.spec.ts +1 -1
- package/tests/unit/modeling/domain_entity_properties.spec.ts +2 -2
- package/tests/unit/modeling/domain_impact_analysis.spec.ts +138 -29
- package/tests/unit/modeling/validation/association_validation.spec.ts +140 -0
- package/tests/unit/modeling/validation/entity_validation.spec.ts +192 -0
- package/tests/unit/modeling/validation/property_validation.spec.ts +125 -0
- package/tests/unit/runtime/proxy/HttpProjectProxy.spec.ts +8 -8
|
@@ -7,6 +7,9 @@ import {
|
|
|
7
7
|
DataDomainKind,
|
|
8
8
|
} from '../models/kinds.js'
|
|
9
9
|
import type { DataDomain } from './DataDomain.js'
|
|
10
|
+
import { AssociationValidation } from './validation/association_validation.js'
|
|
11
|
+
import { EntityValidation } from './validation/entity_validation.js'
|
|
12
|
+
import { PropertyValidation } from './validation/property_validation.js'
|
|
10
13
|
|
|
11
14
|
export type DomainImpactKinds =
|
|
12
15
|
| typeof DomainNamespaceKind
|
|
@@ -55,14 +58,26 @@ export interface DomainImpactItem {
|
|
|
55
58
|
*
|
|
56
59
|
* - `delete` - The data object would be deleted.
|
|
57
60
|
*/
|
|
58
|
-
type: 'delete'
|
|
61
|
+
type: 'delete' | 'publish'
|
|
59
62
|
/**
|
|
60
63
|
* The impact description.
|
|
64
|
+
* Explains what will happen to the impacted data object.
|
|
65
|
+
* This is a human-readable description of the impact.
|
|
66
|
+
* It should be clear and concise.
|
|
61
67
|
*/
|
|
62
68
|
impact: string
|
|
69
|
+
/**
|
|
70
|
+
* The severity of the impact.
|
|
71
|
+
*
|
|
72
|
+
* - `info` - The impact is informational.
|
|
73
|
+
* - `warning` - The impact can potentially cause problems but is not a blocker.
|
|
74
|
+
* - `error` - The impact is a blocker and needs to be resolved before proceeding.
|
|
75
|
+
*/
|
|
76
|
+
severity: 'info' | 'warning' | 'error'
|
|
63
77
|
/**
|
|
64
78
|
* Whether the impact is blocking the operation.
|
|
65
79
|
* If true, the operation cannot proceed.
|
|
80
|
+
* @deprecated Use `severity` instead.
|
|
66
81
|
*/
|
|
67
82
|
blocking: boolean
|
|
68
83
|
/**
|
|
@@ -73,6 +88,11 @@ export interface DomainImpactItem {
|
|
|
73
88
|
* The resolution of the conflict if the change will be forced.
|
|
74
89
|
*/
|
|
75
90
|
resolution?: string
|
|
91
|
+
/**
|
|
92
|
+
* The optional parent of the impacted data object.
|
|
93
|
+
* For example, if the impacted item is a property, this will be the entity it belongs to.
|
|
94
|
+
*/
|
|
95
|
+
parent?: string
|
|
76
96
|
}
|
|
77
97
|
|
|
78
98
|
/**
|
|
@@ -317,7 +337,7 @@ export class DomainImpactAnalysis {
|
|
|
317
337
|
impact: [],
|
|
318
338
|
canProceed: true,
|
|
319
339
|
}
|
|
320
|
-
this.
|
|
340
|
+
this.createDeleteImpact(key, kind, key)
|
|
321
341
|
return this.report
|
|
322
342
|
}
|
|
323
343
|
|
|
@@ -333,83 +353,156 @@ export class DomainImpactAnalysis {
|
|
|
333
353
|
impact: [],
|
|
334
354
|
canProceed: true,
|
|
335
355
|
}
|
|
336
|
-
this.
|
|
356
|
+
this.createRemoveForeignNamespaceImpact(key)
|
|
357
|
+
return this.report
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Analyzes the data domain for publishing. Essentially, it performs a validation of the data domain
|
|
362
|
+
* and returns a report of the impact.
|
|
363
|
+
* @returns The publish impact analysis report.
|
|
364
|
+
*/
|
|
365
|
+
publishAnalysis(): DomainImpactReport {
|
|
366
|
+
this.report = {
|
|
367
|
+
key: '',
|
|
368
|
+
kind: DataDomainKind,
|
|
369
|
+
impact: [],
|
|
370
|
+
canProceed: true,
|
|
371
|
+
}
|
|
372
|
+
const entityValidator = new EntityValidation(this.root)
|
|
373
|
+
const propertyValidator = new PropertyValidation(this.root)
|
|
374
|
+
const associationValidator = new AssociationValidation(this.root)
|
|
375
|
+
for (const entity of this.root.listEntities()) {
|
|
376
|
+
if (entity.domain.key !== this.root.key) {
|
|
377
|
+
// we don't need to validate foreign entities
|
|
378
|
+
continue
|
|
379
|
+
}
|
|
380
|
+
const report = entityValidator.validate(entity)
|
|
381
|
+
for (const item of report) {
|
|
382
|
+
const blocking = item.severity === 'error'
|
|
383
|
+
this.report.canProceed = this.report.canProceed && !blocking
|
|
384
|
+
this.report.impact.push({
|
|
385
|
+
key: item.key,
|
|
386
|
+
kind: item.kind,
|
|
387
|
+
type: 'publish',
|
|
388
|
+
impact: item.message,
|
|
389
|
+
blocking,
|
|
390
|
+
resolution: item.help,
|
|
391
|
+
severity: item.severity,
|
|
392
|
+
parent: item.parent,
|
|
393
|
+
})
|
|
394
|
+
}
|
|
395
|
+
for (const property of entity.properties) {
|
|
396
|
+
const report = propertyValidator.validate(property)
|
|
397
|
+
for (const item of report) {
|
|
398
|
+
const blocking = item.severity === 'error'
|
|
399
|
+
this.report.canProceed = this.report.canProceed && !blocking
|
|
400
|
+
this.report.impact.push({
|
|
401
|
+
key: item.key,
|
|
402
|
+
kind: item.kind,
|
|
403
|
+
type: 'publish',
|
|
404
|
+
impact: item.message,
|
|
405
|
+
blocking,
|
|
406
|
+
resolution: item.help,
|
|
407
|
+
severity: item.severity,
|
|
408
|
+
parent: item.parent,
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
for (const association of entity.associations) {
|
|
413
|
+
const report = associationValidator.validate(association)
|
|
414
|
+
for (const item of report) {
|
|
415
|
+
const blocking = item.severity === 'error'
|
|
416
|
+
this.report.canProceed = this.report.canProceed && !blocking
|
|
417
|
+
this.report.impact.push({
|
|
418
|
+
key: item.key,
|
|
419
|
+
kind: item.kind,
|
|
420
|
+
type: 'publish',
|
|
421
|
+
impact: item.message,
|
|
422
|
+
blocking,
|
|
423
|
+
resolution: item.help,
|
|
424
|
+
severity: item.severity,
|
|
425
|
+
parent: item.parent,
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
337
430
|
return this.report
|
|
338
431
|
}
|
|
339
432
|
|
|
340
|
-
protected createDeleteImpact(key: string, kind: DomainImpactKinds, rootKey: string):
|
|
433
|
+
protected createDeleteImpact(key: string, kind: DomainImpactKinds, rootKey: string): void {
|
|
341
434
|
switch (kind) {
|
|
342
435
|
case DomainNamespaceKind:
|
|
343
|
-
|
|
436
|
+
this.deleteNamespaceAnalysis(key, rootKey)
|
|
437
|
+
break
|
|
344
438
|
case DomainModelKind:
|
|
345
|
-
|
|
439
|
+
this.deleteDataModelAnalysis(key, rootKey)
|
|
440
|
+
break
|
|
346
441
|
case DomainEntityKind:
|
|
347
|
-
|
|
442
|
+
this.deleteEntityAnalysis(key, rootKey)
|
|
443
|
+
break
|
|
348
444
|
case DomainPropertyKind:
|
|
349
|
-
|
|
445
|
+
this.deletePropertyAnalysis(key)
|
|
446
|
+
break
|
|
350
447
|
case DomainAssociationKind:
|
|
351
|
-
|
|
448
|
+
this.deleteAssociationAnalysis(key)
|
|
449
|
+
break
|
|
352
450
|
default:
|
|
353
|
-
|
|
451
|
+
// ignore unknown kinds
|
|
354
452
|
}
|
|
355
453
|
}
|
|
356
454
|
|
|
357
|
-
protected deleteNamespaceAnalysis(key: string, rootKey: string):
|
|
358
|
-
const result: DomainImpactItem[] = []
|
|
455
|
+
protected deleteNamespaceAnalysis(key: string, rootKey: string): void {
|
|
359
456
|
const ns = this.root.findNamespace(key)
|
|
360
457
|
if (!ns) {
|
|
361
|
-
return
|
|
458
|
+
return
|
|
362
459
|
}
|
|
363
|
-
|
|
460
|
+
this.report.impact.push({
|
|
364
461
|
key: ns.key,
|
|
365
462
|
kind: ns.kind,
|
|
366
463
|
type: 'delete',
|
|
367
464
|
impact: `The ${ns.info.getLabel()} ${this.kindToLabel(DomainNamespaceKind)} will be deleted.`,
|
|
368
465
|
blocking: false,
|
|
466
|
+
severity: 'info',
|
|
369
467
|
})
|
|
370
468
|
for (const child of ns.listNamespaces()) {
|
|
371
|
-
|
|
372
|
-
result.push(...items)
|
|
469
|
+
this.deleteNamespaceAnalysis(child.key, rootKey)
|
|
373
470
|
}
|
|
374
471
|
for (const child of ns.listModels()) {
|
|
375
|
-
|
|
376
|
-
result.push(...items)
|
|
472
|
+
this.deleteDataModelAnalysis(child.key, rootKey)
|
|
377
473
|
}
|
|
378
|
-
return result
|
|
379
474
|
}
|
|
380
475
|
|
|
381
|
-
protected deleteDataModelAnalysis(key: string, rootKey: string):
|
|
382
|
-
const result: DomainImpactItem[] = []
|
|
476
|
+
protected deleteDataModelAnalysis(key: string, rootKey: string): void {
|
|
383
477
|
const model = this.root.findModel(key)
|
|
384
478
|
if (!model) {
|
|
385
|
-
return
|
|
479
|
+
return
|
|
386
480
|
}
|
|
387
|
-
|
|
481
|
+
this.report.impact.push({
|
|
388
482
|
key: model.key,
|
|
389
483
|
kind: model.kind,
|
|
390
484
|
type: 'delete',
|
|
391
485
|
impact: `The ${model.info.getLabel()} ${this.kindToLabel(DomainModelKind)} will be deleted.`,
|
|
392
486
|
blocking: false,
|
|
487
|
+
severity: 'info',
|
|
393
488
|
})
|
|
394
489
|
for (const child of model.listEntities()) {
|
|
395
|
-
|
|
396
|
-
result.push(...items)
|
|
490
|
+
this.deleteEntityAnalysis(child.key, rootKey)
|
|
397
491
|
}
|
|
398
|
-
return result
|
|
399
492
|
}
|
|
400
493
|
|
|
401
|
-
protected deleteEntityAnalysis(key: string, rootKey: string):
|
|
402
|
-
const result: DomainImpactItem[] = []
|
|
494
|
+
protected deleteEntityAnalysis(key: string, rootKey: string): void {
|
|
403
495
|
const entity = this.root.findEntity(key)
|
|
404
496
|
if (!entity) {
|
|
405
|
-
return
|
|
497
|
+
return
|
|
406
498
|
}
|
|
407
|
-
|
|
499
|
+
this.report.impact.push({
|
|
408
500
|
key: entity.key,
|
|
409
501
|
kind: entity.kind,
|
|
410
502
|
type: 'delete',
|
|
411
503
|
impact: `The ${entity.info.getLabel()} ${this.kindToLabel(DomainEntityKind)} will be deleted.`,
|
|
412
504
|
blocking: false,
|
|
505
|
+
severity: 'info',
|
|
413
506
|
})
|
|
414
507
|
|
|
415
508
|
// We need to know whether the entity is a parent of another entity
|
|
@@ -428,14 +521,15 @@ export class DomainImpactAnalysis {
|
|
|
428
521
|
}
|
|
429
522
|
const pLabel = entity.info.getLabel()
|
|
430
523
|
const cLabel = childEntity.info.getLabel()
|
|
431
|
-
|
|
524
|
+
this.report.impact.push({
|
|
432
525
|
key: childEntity.key,
|
|
433
526
|
kind: childEntity.kind,
|
|
434
527
|
type: 'delete',
|
|
435
528
|
impact: `The "${cLabel}" ${this.kindToLabel(DomainEntityKind)} will become an orphan because it is a child of the "${pLabel}" entity.`,
|
|
436
529
|
resolution: `The "${pLabel}" entity will be removed as the parent of the "${cLabel}" entity.`,
|
|
437
|
-
blocking:
|
|
530
|
+
blocking: false,
|
|
438
531
|
relationship: 'child',
|
|
532
|
+
severity: 'error',
|
|
439
533
|
})
|
|
440
534
|
this.report.canProceed = false
|
|
441
535
|
}
|
|
@@ -460,57 +554,53 @@ export class DomainImpactAnalysis {
|
|
|
460
554
|
|
|
461
555
|
const aLabel = association.info.getLabel()
|
|
462
556
|
const eLabel = entity.info.getLabel()
|
|
463
|
-
|
|
557
|
+
this.report.impact.push({
|
|
464
558
|
key: association.key,
|
|
465
559
|
kind: association.kind,
|
|
466
560
|
type: 'delete',
|
|
467
561
|
impact: `The ${aLabel} ${this.kindToLabel(DomainAssociationKind)} will be broken because it has a target to ${eLabel}.`,
|
|
468
562
|
resolution: `The ${aLabel} ${this.kindToLabel(DomainAssociationKind)} will be removed from ${eLabel}.`,
|
|
469
563
|
blocking: true,
|
|
564
|
+
severity: 'error',
|
|
470
565
|
})
|
|
471
566
|
this.report.canProceed = false
|
|
472
567
|
}
|
|
473
568
|
for (const child of entity.listProperties()) {
|
|
474
|
-
|
|
475
|
-
result.push(...items)
|
|
569
|
+
this.deletePropertyAnalysis(child.key)
|
|
476
570
|
}
|
|
477
571
|
for (const child of entity.listAssociations()) {
|
|
478
|
-
|
|
479
|
-
result.push(...items)
|
|
572
|
+
this.deleteAssociationAnalysis(child.key)
|
|
480
573
|
}
|
|
481
|
-
return result
|
|
482
574
|
}
|
|
483
575
|
|
|
484
|
-
protected deletePropertyAnalysis(key: string):
|
|
485
|
-
const result: DomainImpactItem[] = []
|
|
576
|
+
protected deletePropertyAnalysis(key: string): void {
|
|
486
577
|
const property = this.root.findProperty(key)
|
|
487
578
|
if (!property) {
|
|
488
|
-
return
|
|
579
|
+
return
|
|
489
580
|
}
|
|
490
|
-
|
|
581
|
+
this.report.impact.push({
|
|
491
582
|
key: property.key,
|
|
492
583
|
kind: property.kind,
|
|
493
584
|
type: 'delete',
|
|
494
585
|
impact: `The ${property.info.getLabel()} ${this.kindToLabel(DomainPropertyKind)} will be deleted.`,
|
|
495
586
|
blocking: false,
|
|
587
|
+
severity: 'info',
|
|
496
588
|
})
|
|
497
|
-
return result
|
|
498
589
|
}
|
|
499
590
|
|
|
500
|
-
protected deleteAssociationAnalysis(key: string):
|
|
501
|
-
const result: DomainImpactItem[] = []
|
|
591
|
+
protected deleteAssociationAnalysis(key: string): void {
|
|
502
592
|
const association = this.root.findAssociation(key)
|
|
503
593
|
if (!association) {
|
|
504
|
-
return
|
|
594
|
+
return
|
|
505
595
|
}
|
|
506
|
-
|
|
596
|
+
this.report.impact.push({
|
|
507
597
|
key: association.key,
|
|
508
598
|
kind: association.kind,
|
|
509
599
|
type: 'delete',
|
|
510
600
|
impact: `The ${association.info.getLabel()} ${this.kindToLabel(DomainAssociationKind)} will be deleted.`,
|
|
511
601
|
blocking: false,
|
|
602
|
+
severity: 'info',
|
|
512
603
|
})
|
|
513
|
-
return result
|
|
514
604
|
}
|
|
515
605
|
|
|
516
606
|
protected kindToLabel(kind: DomainImpactKinds): string {
|
|
@@ -530,11 +620,10 @@ export class DomainImpactAnalysis {
|
|
|
530
620
|
}
|
|
531
621
|
}
|
|
532
622
|
|
|
533
|
-
protected createRemoveForeignNamespaceImpact(key: string):
|
|
534
|
-
const result: DomainImpactItem[] = []
|
|
623
|
+
protected createRemoveForeignNamespaceImpact(key: string): void {
|
|
535
624
|
const foreignNamespace = this.root.dependencies.get(key)
|
|
536
625
|
if (!foreignNamespace) {
|
|
537
|
-
return
|
|
626
|
+
return
|
|
538
627
|
}
|
|
539
628
|
// Check for parent relationships to foreign entities
|
|
540
629
|
for (const entity of this.root.listEntities()) {
|
|
@@ -551,7 +640,7 @@ export class DomainImpactAnalysis {
|
|
|
551
640
|
}
|
|
552
641
|
const eLabel = entity.info.getLabel()
|
|
553
642
|
const pLabel = parentEntity.info.getLabel()
|
|
554
|
-
|
|
643
|
+
this.report.impact.push({
|
|
555
644
|
key: entity.key,
|
|
556
645
|
kind: entity.kind,
|
|
557
646
|
type: 'delete',
|
|
@@ -559,6 +648,7 @@ export class DomainImpactAnalysis {
|
|
|
559
648
|
resolution: `The "${pLabel}" entity will be removed as the parent of the "${eLabel}" entity.`,
|
|
560
649
|
blocking: true,
|
|
561
650
|
relationship: 'child',
|
|
651
|
+
severity: 'error',
|
|
562
652
|
})
|
|
563
653
|
this.report.canProceed = false
|
|
564
654
|
} else if (edge.type === 'association') {
|
|
@@ -576,13 +666,14 @@ export class DomainImpactAnalysis {
|
|
|
576
666
|
const aLabel = association.info.getLabel()
|
|
577
667
|
const eLabel = entity.info.getLabel()
|
|
578
668
|
const tLabel = targetEntity.info.getLabel()
|
|
579
|
-
|
|
669
|
+
this.report.impact.push({
|
|
580
670
|
key: association.key,
|
|
581
671
|
kind: association.kind,
|
|
582
672
|
type: 'delete',
|
|
583
673
|
impact: `The "${aLabel}" ${this.kindToLabel(DomainAssociationKind)} from "${eLabel}" will be broken because it targets "${tLabel}" in the foreign namespace "${foreignNamespace.key}".`,
|
|
584
674
|
resolution: `The "${aLabel}" ${this.kindToLabel(DomainAssociationKind)} will be removed from "${eLabel}".`,
|
|
585
675
|
blocking: true,
|
|
676
|
+
severity: 'error',
|
|
586
677
|
})
|
|
587
678
|
this.report.canProceed = false
|
|
588
679
|
}
|
|
@@ -590,6 +681,5 @@ export class DomainImpactAnalysis {
|
|
|
590
681
|
}
|
|
591
682
|
}
|
|
592
683
|
}
|
|
593
|
-
return result
|
|
594
684
|
}
|
|
595
685
|
}
|
|
@@ -242,7 +242,7 @@ export class DomainProperty extends DomainElement {
|
|
|
242
242
|
throw new Error(`Invalid data property type ${type}`)
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
|
-
const info = Thing.fromJSON(input.info, { name: '
|
|
245
|
+
const info = Thing.fromJSON(input.info, { name: 'new_property' }).toJSON()
|
|
246
246
|
const result: DomainPropertySchema = {
|
|
247
247
|
kind: DomainPropertyKind,
|
|
248
248
|
key,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Json } from '@api-client/json'
|
|
2
2
|
import { AmfShapeGenerator } from '../../amf/AmfShapeGenerator.js'
|
|
3
3
|
import { IApiAssociationShape, IApiPropertyShape } from '../../amf/definitions/Shapes.js'
|
|
4
|
-
import
|
|
4
|
+
import { nanoid } from 'nanoid'
|
|
5
5
|
import { IThing, Thing } from '../../models/Thing.js'
|
|
6
6
|
import { DataEntity, IDataEntity } from './DataEntity.js'
|
|
7
7
|
import { DataNamespace } from './DataNamespace.js'
|
|
@@ -230,7 +230,7 @@ export class DataAssociation {
|
|
|
230
230
|
} else {
|
|
231
231
|
init = {
|
|
232
232
|
kind: DataAssociationKind,
|
|
233
|
-
key:
|
|
233
|
+
key: nanoid(),
|
|
234
234
|
info: Thing.fromName('Unnamed association').toJSON(),
|
|
235
235
|
}
|
|
236
236
|
}
|
|
@@ -244,7 +244,7 @@ export class DataAssociation {
|
|
|
244
244
|
*/
|
|
245
245
|
new(init: IDataAssociation): this {
|
|
246
246
|
DataAssociation.validate(init)
|
|
247
|
-
const { info, key =
|
|
247
|
+
const { info, key = nanoid(), kind = DataAssociationKind, schema, multiple, required, targets, bindings } = init
|
|
248
248
|
this.kind = kind
|
|
249
249
|
this.key = key
|
|
250
250
|
if (info) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IThing, Thing } from '../../models/Thing.js'
|
|
2
|
-
import
|
|
2
|
+
import { nanoid } from 'nanoid'
|
|
3
3
|
import { DataNamespace } from './DataNamespace.js'
|
|
4
4
|
import { DataProperty } from './DataProperty.js'
|
|
5
5
|
import { type DataPropertyType } from '../DataFormat.js'
|
|
@@ -185,7 +185,7 @@ export class DataEntity {
|
|
|
185
185
|
} else {
|
|
186
186
|
init = {
|
|
187
187
|
kind: DataEntityKind,
|
|
188
|
-
key:
|
|
188
|
+
key: nanoid(),
|
|
189
189
|
info: Thing.fromName('').toJSON(),
|
|
190
190
|
}
|
|
191
191
|
}
|
|
@@ -196,7 +196,7 @@ export class DataEntity {
|
|
|
196
196
|
DataEntity.validate(init)
|
|
197
197
|
const {
|
|
198
198
|
info,
|
|
199
|
-
key =
|
|
199
|
+
key = nanoid(),
|
|
200
200
|
kind = DataEntityKind,
|
|
201
201
|
tags,
|
|
202
202
|
taxonomy,
|
|
@@ -2,7 +2,7 @@ import { DataEntity } from './DataEntity.js'
|
|
|
2
2
|
import { DataNamespace } from './DataNamespace.js'
|
|
3
3
|
import { type DataPropertyType } from '../DataFormat.js'
|
|
4
4
|
import { type IThing, Thing } from '../../models/Thing.js'
|
|
5
|
-
import
|
|
5
|
+
import { nanoid } from 'nanoid'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* A fluent builder for constructing `DataEntity` instances.
|
|
@@ -228,7 +228,7 @@ export class DataEntityBuilder {
|
|
|
228
228
|
*/
|
|
229
229
|
build(): DataEntity {
|
|
230
230
|
if (!this.entity.key) {
|
|
231
|
-
this.entity.key =
|
|
231
|
+
this.entity.key = nanoid()
|
|
232
232
|
}
|
|
233
233
|
this.root.definitions.entities.push(this.entity)
|
|
234
234
|
return this.entity
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IThing, Thing } from '../../models/Thing.js'
|
|
2
|
-
import
|
|
2
|
+
import { nanoid } from 'nanoid'
|
|
3
3
|
import { DataEntity, IDataEntity } from './DataEntity.js'
|
|
4
4
|
import type { DataItemAdaptingOptions, DataNamespace } from './DataNamespace.js'
|
|
5
5
|
import { FileBreadcrumb } from '../../models/store/File.js'
|
|
@@ -73,7 +73,7 @@ export class DataModel {
|
|
|
73
73
|
} else {
|
|
74
74
|
init = {
|
|
75
75
|
kind: DataModelKind,
|
|
76
|
-
key:
|
|
76
|
+
key: nanoid(),
|
|
77
77
|
info: Thing.fromName('').toJSON(),
|
|
78
78
|
entities: [],
|
|
79
79
|
}
|
|
@@ -85,7 +85,7 @@ export class DataModel {
|
|
|
85
85
|
if (!DataModel.isDataModel(init)) {
|
|
86
86
|
throw new Error(`Not a data model.`)
|
|
87
87
|
}
|
|
88
|
-
const { info, key =
|
|
88
|
+
const { info, key = nanoid(), kind = DataModelKind, entities } = init
|
|
89
89
|
this.kind = kind
|
|
90
90
|
this.key = key
|
|
91
91
|
if (info) {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
DataPropertyKind,
|
|
12
12
|
DataAssociationKind,
|
|
13
13
|
} from '../../models/kinds.js'
|
|
14
|
-
import
|
|
14
|
+
import { nanoid } from 'nanoid'
|
|
15
15
|
import type { DataDomainRemoveOptions } from '../types.js'
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -288,7 +288,7 @@ export class DataNamespace {
|
|
|
288
288
|
} else {
|
|
289
289
|
init = {
|
|
290
290
|
kind: DataNamespaceKind,
|
|
291
|
-
key:
|
|
291
|
+
key: nanoid(),
|
|
292
292
|
definitions: {},
|
|
293
293
|
items: [],
|
|
294
294
|
info: Thing.fromName('').toJSON(),
|
|
@@ -301,7 +301,7 @@ export class DataNamespace {
|
|
|
301
301
|
if (!init || !init.definitions || !init.items) {
|
|
302
302
|
throw new Error(`Not a data namespace.`)
|
|
303
303
|
}
|
|
304
|
-
const { key =
|
|
304
|
+
const { key = nanoid(), definitions = {}, items, info } = init
|
|
305
305
|
this.key = key
|
|
306
306
|
if (info) {
|
|
307
307
|
this.info = new Thing(info)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Json } from '@api-client/json'
|
|
2
2
|
import { IThing, Thing } from '../../models/Thing.js'
|
|
3
|
-
import
|
|
3
|
+
import { nanoid } from 'nanoid'
|
|
4
4
|
import { DataNamespace } from './DataNamespace.js'
|
|
5
5
|
import { IApiPropertyShape } from '../../amf/definitions/Shapes.js'
|
|
6
6
|
import { AmfShapeGenerator } from '../../amf/AmfShapeGenerator.js'
|
|
@@ -304,7 +304,7 @@ export class DataProperty {
|
|
|
304
304
|
} else {
|
|
305
305
|
init = {
|
|
306
306
|
kind: DataPropertyKind,
|
|
307
|
-
key:
|
|
307
|
+
key: nanoid(),
|
|
308
308
|
info: Thing.fromName('').toJSON(),
|
|
309
309
|
type: 'string',
|
|
310
310
|
}
|
|
@@ -318,7 +318,7 @@ export class DataProperty {
|
|
|
318
318
|
}
|
|
319
319
|
const {
|
|
320
320
|
info,
|
|
321
|
-
key =
|
|
321
|
+
key = nanoid(),
|
|
322
322
|
kind = DataPropertyKind,
|
|
323
323
|
multiple,
|
|
324
324
|
required,
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { DomainAssociationKind } from '../../models/kinds.js'
|
|
2
|
+
import type { DataDomain } from '../DataDomain.js'
|
|
3
|
+
import type { DomainAssociation } from '../DomainAssociation.js'
|
|
4
|
+
import type { DomainEntity } from '../DomainEntity.js'
|
|
5
|
+
import { type DomainValidation, validatePropertyName } from './rules.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* AssociationValidation is a class that performs validation on associations in a data domain.
|
|
9
|
+
* Note that an association in most cases is a property of an entity.
|
|
10
|
+
*/
|
|
11
|
+
export class AssociationValidation {
|
|
12
|
+
constructor(protected domain: DataDomain) {}
|
|
13
|
+
/**
|
|
14
|
+
* Performs all the validation rules on the association.
|
|
15
|
+
* If you are interested in a specific rule, use the specific method.
|
|
16
|
+
* @param target The target association to validate. Can be a string with
|
|
17
|
+
* the association key or a DomainAssociation object.
|
|
18
|
+
*/
|
|
19
|
+
validate(target: string | DomainAssociation): DomainValidation[] {
|
|
20
|
+
const results: DomainValidation[] = []
|
|
21
|
+
let association: DomainAssociation | undefined
|
|
22
|
+
if (typeof target === 'string') {
|
|
23
|
+
association = this.domain.findAssociation(target)
|
|
24
|
+
} else {
|
|
25
|
+
association = target
|
|
26
|
+
}
|
|
27
|
+
if (!association) {
|
|
28
|
+
const message = `The "${target}" association does not exist.`
|
|
29
|
+
const help = `The association must be defined in the domain.`
|
|
30
|
+
results.push({
|
|
31
|
+
field: '*',
|
|
32
|
+
rule: 'exists',
|
|
33
|
+
message,
|
|
34
|
+
help,
|
|
35
|
+
key: target as string,
|
|
36
|
+
kind: DomainAssociationKind,
|
|
37
|
+
severity: 'error',
|
|
38
|
+
})
|
|
39
|
+
return results
|
|
40
|
+
}
|
|
41
|
+
const name = this.validateName(association)
|
|
42
|
+
results.push(...name)
|
|
43
|
+
const targets = this.validateTargets(association)
|
|
44
|
+
results.push(...targets)
|
|
45
|
+
return results
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validates the association name.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* - A association must have a name defined.
|
|
53
|
+
* - The name has to follow the same rules as the names in a PostgreSQL database.
|
|
54
|
+
* - Column names can only contain letters (a-z, A-Z), numbers (0-9), and underscores (_).
|
|
55
|
+
* - The name must start with a letter (a-z, A-Z) or an underscore (_).
|
|
56
|
+
* - PostgreSQL limits column names to a maximum of 59 characters.
|
|
57
|
+
* - (our rule) Column names are case insensitive.
|
|
58
|
+
* - (recommendation) Column names should be in lower case.
|
|
59
|
+
* @param association The association to validate
|
|
60
|
+
*/
|
|
61
|
+
validateName(association: DomainAssociation): DomainValidation[] {
|
|
62
|
+
return validatePropertyName(association)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validates the association targets.
|
|
67
|
+
* @param association The association to validate
|
|
68
|
+
*/
|
|
69
|
+
validateTargets(association: DomainAssociation): DomainValidation[] {
|
|
70
|
+
const results: DomainValidation[] = []
|
|
71
|
+
const label = association.info.getLabel()
|
|
72
|
+
const parentEntity = association.getParentInstance() as DomainEntity
|
|
73
|
+
if (!association.targets.length) {
|
|
74
|
+
const message = `The "${label}" association has no target.`
|
|
75
|
+
const help = `An association must have at least one target.`
|
|
76
|
+
results.push({
|
|
77
|
+
field: 'targets',
|
|
78
|
+
rule: 'required',
|
|
79
|
+
message,
|
|
80
|
+
help,
|
|
81
|
+
severity: 'error',
|
|
82
|
+
key: association.key,
|
|
83
|
+
kind: association.kind,
|
|
84
|
+
parent: parentEntity.key,
|
|
85
|
+
})
|
|
86
|
+
return results
|
|
87
|
+
}
|
|
88
|
+
for (const target of association.targets) {
|
|
89
|
+
const entity = target.domain
|
|
90
|
+
? this.domain.findForeignEntity(target.key, target.domain)
|
|
91
|
+
: this.domain.findEntity(target.key)
|
|
92
|
+
if (!entity) {
|
|
93
|
+
const message = `The "${label}" association has an invalid target "${target.key}".`
|
|
94
|
+
const help = `The target must be defined in the domain.`
|
|
95
|
+
results.push({
|
|
96
|
+
field: 'targets',
|
|
97
|
+
rule: 'exists',
|
|
98
|
+
message,
|
|
99
|
+
help,
|
|
100
|
+
severity: 'error',
|
|
101
|
+
key: association.key,
|
|
102
|
+
kind: association.kind,
|
|
103
|
+
parent: parentEntity.key,
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return results
|
|
108
|
+
}
|
|
109
|
+
}
|