@api-client/core 0.19.11 → 0.19.12

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 (47) hide show
  1. package/build/src/browser.d.ts +3 -1
  2. package/build/src/browser.d.ts.map +1 -1
  3. package/build/src/browser.js +2 -0
  4. package/build/src/browser.js.map +1 -1
  5. package/build/src/index.d.ts +3 -1
  6. package/build/src/index.d.ts.map +1 -1
  7. package/build/src/index.js +2 -0
  8. package/build/src/index.js.map +1 -1
  9. package/build/src/modeling/ApiValidation.d.ts +26 -0
  10. package/build/src/modeling/ApiValidation.d.ts.map +1 -0
  11. package/build/src/modeling/ApiValidation.js +73 -0
  12. package/build/src/modeling/ApiValidation.js.map +1 -0
  13. package/build/src/modeling/DomainValidation.d.ts +10 -4
  14. package/build/src/modeling/DomainValidation.d.ts.map +1 -1
  15. package/build/src/modeling/DomainValidation.js +55 -72
  16. package/build/src/modeling/DomainValidation.js.map +1 -1
  17. package/build/src/modeling/validation/api_model_rules.d.ts +1 -2
  18. package/build/src/modeling/validation/api_model_rules.d.ts.map +1 -1
  19. package/build/src/modeling/validation/api_model_rules.js +0 -26
  20. package/build/src/modeling/validation/api_model_rules.js.map +1 -1
  21. package/build/src/modeling/validation/association_validation.d.ts +4 -4
  22. package/build/src/modeling/validation/association_validation.d.ts.map +1 -1
  23. package/build/src/modeling/validation/association_validation.js.map +1 -1
  24. package/build/src/modeling/validation/entity_validation.d.ts +6 -6
  25. package/build/src/modeling/validation/entity_validation.d.ts.map +1 -1
  26. package/build/src/modeling/validation/entity_validation.js.map +1 -1
  27. package/build/src/modeling/validation/property_validation.d.ts +3 -3
  28. package/build/src/modeling/validation/property_validation.d.ts.map +1 -1
  29. package/build/src/modeling/validation/property_validation.js.map +1 -1
  30. package/build/src/modeling/validation/rules.d.ts +2 -2
  31. package/build/src/modeling/validation/rules.d.ts.map +1 -1
  32. package/build/src/modeling/validation/rules.js.map +1 -1
  33. package/build/src/modeling/validation/semantic_validation.d.ts +2 -2
  34. package/build/src/modeling/validation/semantic_validation.d.ts.map +1 -1
  35. package/build/src/modeling/validation/semantic_validation.js.map +1 -1
  36. package/build/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +1 -1
  38. package/src/modeling/ApiValidation.ts +86 -0
  39. package/src/modeling/DomainValidation.ts +57 -74
  40. package/src/modeling/validation/api_model_rules.ts +1 -31
  41. package/src/modeling/validation/association_validation.ts +6 -6
  42. package/src/modeling/validation/entity_validation.ts +11 -11
  43. package/src/modeling/validation/property_validation.ts +4 -4
  44. package/src/modeling/validation/rules.ts +6 -3
  45. package/src/modeling/validation/semantic_validation.ts +11 -11
  46. package/tests/unit/modeling/domain_validation.spec.ts +7 -13
  47. package/tests/unit/modeling/validation/api_model_rules.spec.ts +11 -9
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.19.11",
4
+ "version": "0.19.12",
5
5
  "license": "UNLICENSED",
6
6
  "exports": {
7
7
  "./browser.js": {
@@ -0,0 +1,86 @@
1
+ import { ApiModel } from './ApiModel.js'
2
+ import { ApiModelValidationItem } from './types.js'
3
+ import { ApiModelKind } from '../models/kinds.js'
4
+ import {
5
+ validateApiModelInfo,
6
+ validateApiModelDependency,
7
+ validateApiModelSecurity,
8
+ validateApiModelMetadata,
9
+ validateExposedEntity,
10
+ } from './validation/api_model_rules.js'
11
+
12
+ /**
13
+ * ApiValidation performs comprehensive validation on an API model.
14
+ *
15
+ * This class orchestrates validation across all API model elements including
16
+ * info, security, exposures, and actions. It ensures that the API model is
17
+ * well-formed and follows established conventions before it can be published.
18
+ */
19
+ export class ApiValidation {
20
+ report: ApiModelValidationItem[] = []
21
+ #infoCount = 0
22
+ #warningCount = 0
23
+ #errorCount = 0
24
+ #counted = false
25
+
26
+ get infoCount(): number {
27
+ if (!this.#counted) {
28
+ this.computeIssueCounters()
29
+ }
30
+ return this.#infoCount
31
+ }
32
+
33
+ get warningCount(): number {
34
+ if (!this.#counted) {
35
+ this.computeIssueCounters()
36
+ }
37
+ return this.#warningCount
38
+ }
39
+
40
+ get errorCount(): number {
41
+ if (!this.#counted) {
42
+ this.computeIssueCounters()
43
+ }
44
+ return this.#errorCount
45
+ }
46
+
47
+ constructor(protected model: ApiModel) {}
48
+
49
+ /**
50
+ * Performs comprehensive validation on the entire API model.
51
+ *
52
+ * @returns A comprehensive validation report with all issues found
53
+ */
54
+ validate(): ApiModelValidationItem[] {
55
+ this.#counted = false
56
+ this.report = []
57
+
58
+ this.report.push(...validateApiModelInfo(this.model))
59
+ this.report.push(...validateApiModelDependency(this.model))
60
+ this.report.push(...validateApiModelSecurity(this.model))
61
+ this.report.push(...validateApiModelMetadata(this.model))
62
+
63
+ if (!this.model.exposes || this.model.exposes.size === 0) {
64
+ this.report.push({
65
+ code: 'API_NO_EXPOSURES',
66
+ message: 'Your API currently has no exposed data for external clients to request.',
67
+ suggestion: 'Expose a data model so apps can communicate with it.',
68
+ severity: 'warning',
69
+ context: { apiModelKey: this.model.key, kind: ApiModelKind, key: this.model.key, property: 'exposes' },
70
+ })
71
+ } else {
72
+ for (const exposure of this.model.exposes.values()) {
73
+ this.report.push(...validateExposedEntity(exposure, this.model))
74
+ }
75
+ }
76
+
77
+ return this.report
78
+ }
79
+
80
+ computeIssueCounters(): void {
81
+ this.#infoCount = this.report.filter((validation) => validation.severity === 'info').length
82
+ this.#warningCount = this.report.filter((validation) => validation.severity === 'warning').length
83
+ this.#errorCount = this.report.filter((validation) => validation.severity === 'error').length
84
+ this.#counted = true
85
+ }
86
+ }
@@ -1,9 +1,8 @@
1
- import { DataDomainKind } from '../models/kinds.js'
2
1
  import { DataDomain } from './DataDomain.js'
3
- import type { DomainImpactReport } from './types.js'
4
2
  import { AssociationValidation } from './validation/association_validation.js'
5
3
  import { EntityValidation } from './validation/entity_validation.js'
6
4
  import { PropertyValidation } from './validation/property_validation.js'
5
+ import { DomainValidationSchema } from './validation/rules.js'
7
6
  import { SemanticValidation } from './validation/semantic_validation.js'
8
7
 
9
8
  /**
@@ -76,12 +75,35 @@ import { SemanticValidation } from './validation/semantic_validation.js'
76
75
  * @see {@link SemanticValidation} for detailed semantic validation rules
77
76
  */
78
77
  export class DomainValidation {
79
- private root: DataDomain
78
+ report: DomainValidationSchema[] = []
79
+ #infoCount = 0
80
+ #warningCount = 0
81
+ #errorCount = 0
82
+ #counted = false
80
83
 
81
- constructor(root: DataDomain) {
82
- this.root = root
84
+ get infoCount(): number {
85
+ if (!this.#counted) {
86
+ this.computeIssueCounters()
87
+ }
88
+ return this.#infoCount
89
+ }
90
+
91
+ get warningCount(): number {
92
+ if (!this.#counted) {
93
+ this.computeIssueCounters()
94
+ }
95
+ return this.#warningCount
96
+ }
97
+
98
+ get errorCount(): number {
99
+ if (!this.#counted) {
100
+ this.computeIssueCounters()
101
+ }
102
+ return this.#errorCount
83
103
  }
84
104
 
105
+ constructor(protected domain: DataDomain) {}
106
+
85
107
  /**
86
108
  * Performs comprehensive validation on the entire data domain.
87
109
  *
@@ -91,93 +113,54 @@ export class DomainValidation {
91
113
  *
92
114
  * @returns A comprehensive validation report with all issues found
93
115
  */
94
- validate(): DomainImpactReport {
95
- const result: DomainImpactReport = {
96
- key: '',
97
- kind: DataDomainKind,
98
- impact: [],
99
- canProceed: true,
100
- }
101
- const entityValidator = new EntityValidation(this.root)
102
- const propertyValidator = new PropertyValidation(this.root)
103
- const associationValidator = new AssociationValidation(this.root)
104
- const semanticValidator = new SemanticValidation(this.root)
116
+ validate(): DomainValidationSchema[] {
117
+ this.#counted = false
118
+ this.report = []
119
+ const entityValidator = new EntityValidation(this.domain)
120
+ const propertyValidator = new PropertyValidation(this.domain)
121
+ const associationValidator = new AssociationValidation(this.domain)
122
+ const semanticValidator = new SemanticValidation(this.domain)
105
123
 
106
124
  let hasEntities = false
107
- // Validate entities, properties, and associations
108
- for (const entity of this.root.listEntities()) {
109
- if (entity.domain.key !== this.root.key) {
125
+ for (const entity of this.domain.listEntities()) {
126
+ if (entity.domain.key !== this.domain.key) {
110
127
  // we don't need to validate foreign entities
111
128
  continue
112
129
  }
113
130
  hasEntities = true
114
- const report = entityValidator.validate(entity)
115
- for (const item of report) {
116
- const blocking = item.severity === 'error'
117
- result.canProceed = result.canProceed && !blocking
118
- result.impact.push({
119
- key: item.key,
120
- kind: item.kind,
121
- type: 'publish',
122
- impact: item.message,
123
- resolution: item.help,
124
- severity: item.severity,
125
- parent: item.parent,
126
- })
127
- }
131
+ const entities = entityValidator.validate(entity)
132
+ this.report.push(...entities)
128
133
  for (const property of entity.properties) {
129
- const report = propertyValidator.validate(property)
130
- for (const item of report) {
131
- const blocking = item.severity === 'error'
132
- result.canProceed = result.canProceed && !blocking
133
- result.impact.push({
134
- key: item.key,
135
- kind: item.kind,
136
- type: 'publish',
137
- impact: item.message,
138
- resolution: item.help,
139
- severity: item.severity,
140
- parent: item.parent,
141
- })
134
+ if (property.domain.key !== this.domain.key) {
135
+ // we don't need to validate foreign properties
136
+ continue
142
137
  }
138
+ const properties = propertyValidator.validate(property)
139
+ this.report.push(...properties)
143
140
  }
144
141
  for (const association of entity.associations) {
145
- const report = associationValidator.validate(association)
146
- for (const item of report) {
147
- const blocking = item.severity === 'error'
148
- result.canProceed = result.canProceed && !blocking
149
- result.impact.push({
150
- key: item.key,
151
- kind: item.kind,
152
- type: 'publish',
153
- impact: item.message,
154
- resolution: item.help,
155
- severity: item.severity,
156
- parent: item.parent,
157
- })
142
+ if (association.domain.key !== this.domain.key) {
143
+ // we don't need to validate foreign properties
144
+ continue
158
145
  }
146
+ const associations = associationValidator.validate(association)
147
+ this.report.push(...associations)
159
148
  }
160
149
  }
161
150
  if (!hasEntities) {
162
151
  // no entities, no need to validate anything else
163
- return result
152
+ return this.report
164
153
  }
165
154
  // Validate semantics
166
155
  const semanticReport = semanticValidator.validate()
167
- for (const item of semanticReport) {
168
- const blocking = item.severity === 'error'
169
- result.canProceed = result.canProceed && !blocking
170
- result.impact.push({
171
- key: item.key,
172
- kind: item.kind,
173
- type: 'publish',
174
- impact: item.message,
175
- resolution: item.help,
176
- severity: item.severity,
177
- parent: item.parent,
178
- })
179
- }
156
+ this.report.push(...semanticReport)
157
+ return this.report
158
+ }
180
159
 
181
- return result
160
+ computeIssueCounters(): void {
161
+ this.#infoCount = this.report.filter((validation) => validation.severity === 'info').length
162
+ this.#warningCount = this.report.filter((validation) => validation.severity === 'warning').length
163
+ this.#errorCount = this.report.filter((validation) => validation.severity === 'error').length
164
+ this.#counted = true
182
165
  }
183
166
  }
@@ -6,7 +6,7 @@ import { DeleteAction } from '../actions/DeleteAction.js'
6
6
  import { UpdateAction } from '../actions/UpdateAction.js'
7
7
  import { SearchAction } from '../actions/SearchAction.js'
8
8
  import type { RolesBasedAccessControl, UsernamePasswordConfiguration } from '../types.js'
9
- import type { ApiModelValidationItem, ApiModelValidationResult, ApiModelValidationContext } from '../types.js'
9
+ import type { ApiModelValidationItem, ApiModelValidationContext } from '../types.js'
10
10
  import { ApiModelKind, ExposedEntityKind } from '../../models/kinds.js'
11
11
  import { SemanticType } from '../Semantics.js'
12
12
 
@@ -608,33 +608,3 @@ export function validateExposedEntity(entity: ExposedEntity, apiModel: ApiModel)
608
608
 
609
609
  return issues
610
610
  }
611
-
612
- export function validateApiModel(model: ApiModel): ApiModelValidationResult {
613
- const issues: ApiModelValidationItem[] = []
614
-
615
- issues.push(...validateApiModelInfo(model))
616
- issues.push(...validateApiModelDependency(model))
617
- issues.push(...validateApiModelSecurity(model))
618
- issues.push(...validateApiModelMetadata(model))
619
-
620
- if (!model.exposes || model.exposes.size === 0) {
621
- issues.push({
622
- code: createCode('API', 'NO_EXPOSURES'),
623
- message: 'Your API currently has no exposed data for external clients to request.',
624
- suggestion: 'Expose a data model so apps can communicate with it.',
625
- severity: 'warning',
626
- context: { apiModelKey: model.key, kind: ApiModelKind, key: model.key, property: 'exposes' },
627
- })
628
- } else {
629
- for (const exposure of model.exposes.values()) {
630
- issues.push(...validateExposedEntity(exposure, model))
631
- }
632
- }
633
-
634
- const hasErrors = issues.some((i) => i.severity === 'error')
635
-
636
- return {
637
- isValid: !hasErrors,
638
- issues,
639
- }
640
- }
@@ -2,7 +2,7 @@ import { DomainAssociationKind } from '../../models/kinds.js'
2
2
  import type { DataDomain } from '../DataDomain.js'
3
3
  import type { DomainAssociation } from '../DomainAssociation.js'
4
4
  import type { DomainEntity } from '../DomainEntity.js'
5
- import { type DomainValidation, validatePropertyName } from './rules.js'
5
+ import { type DomainValidationSchema, validatePropertyName } from './rules.js'
6
6
 
7
7
  /**
8
8
  * AssociationValidation is a class that performs validation on associations in a data domain.
@@ -16,8 +16,8 @@ export class AssociationValidation {
16
16
  * @param target The target association to validate. Can be a string with
17
17
  * the association key or a DomainAssociation object.
18
18
  */
19
- validate(target: string | DomainAssociation): DomainValidation[] {
20
- const results: DomainValidation[] = []
19
+ validate(target: string | DomainAssociation): DomainValidationSchema[] {
20
+ const results: DomainValidationSchema[] = []
21
21
  let association: DomainAssociation | undefined
22
22
  if (typeof target === 'string') {
23
23
  association = this.domain.findAssociation(target)
@@ -58,7 +58,7 @@ export class AssociationValidation {
58
58
  * - (recommendation) Column names should be in lower case.
59
59
  * @param association The association to validate
60
60
  */
61
- validateName(association: DomainAssociation): DomainValidation[] {
61
+ validateName(association: DomainAssociation): DomainValidationSchema[] {
62
62
  return validatePropertyName(association)
63
63
  }
64
64
 
@@ -66,8 +66,8 @@ export class AssociationValidation {
66
66
  * Validates the association targets.
67
67
  * @param association The association to validate
68
68
  */
69
- validateTargets(association: DomainAssociation): DomainValidation[] {
70
- const results: DomainValidation[] = []
69
+ validateTargets(association: DomainAssociation): DomainValidationSchema[] {
70
+ const results: DomainValidationSchema[] = []
71
71
  const label = association.info.getLabel()
72
72
  const parentEntity = association.getParentInstance() as DomainEntity
73
73
  if (!association.targets.length) {
@@ -2,7 +2,7 @@ import { DomainEntityKind } from '../../models/kinds.js'
2
2
  import type { DataDomain } from '../DataDomain.js'
3
3
  import type { DomainEntity } from '../DomainEntity.js'
4
4
  import { ReservedKeywords } from './postgresql.js'
5
- import type { DomainValidation } from './rules.js'
5
+ import type { DomainValidationSchema } from './rules.js'
6
6
 
7
7
  /**
8
8
  * EntityValidation is a class that performs validation on entities in a data domain.
@@ -20,8 +20,8 @@ export class EntityValidation {
20
20
  * @param target The target entity to validate. Can be a string with
21
21
  * the entity key or a DomainEntity object.
22
22
  */
23
- validate(target: string | DomainEntity): DomainValidation[] {
24
- const results: DomainValidation[] = []
23
+ validate(target: string | DomainEntity): DomainValidationSchema[] {
24
+ const results: DomainValidationSchema[] = []
25
25
  let entity: DomainEntity | undefined
26
26
  if (typeof target === 'string') {
27
27
  entity = this.domain.findEntity(target)
@@ -57,8 +57,8 @@ export class EntityValidation {
57
57
  * Validates the entity primary key.
58
58
  * @param entity The entity to validate
59
59
  */
60
- validatePrimaryKey(entity: DomainEntity): DomainValidation[] {
61
- const results: DomainValidation[] = []
60
+ validatePrimaryKey(entity: DomainEntity): DomainValidationSchema[] {
61
+ const results: DomainValidationSchema[] = []
62
62
  const primary = entity.primaryKey()
63
63
  if (!primary) {
64
64
  const message = `The "${entity.info.getLabel()}" entity has no identifier.`
@@ -124,8 +124,8 @@ export class EntityValidation {
124
124
  * Checks if the entity has the minimum required properties.
125
125
  * @param entity The entity to validate
126
126
  */
127
- minimumRequiredProperties(entity: DomainEntity): DomainValidation[] {
128
- const results: DomainValidation[] = []
127
+ minimumRequiredProperties(entity: DomainEntity): DomainValidationSchema[] {
128
+ const results: DomainValidationSchema[] = []
129
129
 
130
130
  // Check if entity has properties or associations through entire inheritance chain
131
131
  const hasProperties = this.hasPropertiesInherited(entity)
@@ -161,8 +161,8 @@ export class EntityValidation {
161
161
  * - Should not be a reserved word (for example: "IN", "SELECT", "FROM", etc.).
162
162
  * @param entity The entity to validate
163
163
  */
164
- validateName(entity: DomainEntity): DomainValidation[] {
165
- const results: DomainValidation[] = []
164
+ validateName(entity: DomainEntity): DomainValidationSchema[] {
165
+ const results: DomainValidationSchema[] = []
166
166
  const label = entity.info.getLabel()
167
167
  if (!entity.info.name) {
168
168
  const message = `The "${label}" entity has no name.`
@@ -252,8 +252,8 @@ export class EntityValidation {
252
252
  * Checks if the entity name is unique in the data domain.
253
253
  * @param entity The entity to validate
254
254
  */
255
- uniqueName(entity: DomainEntity): DomainValidation[] {
256
- const results: DomainValidation[] = []
255
+ uniqueName(entity: DomainEntity): DomainValidationSchema[] {
256
+ const results: DomainValidationSchema[] = []
257
257
  const name = entity.info.name?.toLowerCase()
258
258
  if (!name) {
259
259
  return results
@@ -1,7 +1,7 @@
1
1
  import { DomainPropertyKind } from '../../models/kinds.js'
2
2
  import type { DataDomain } from '../DataDomain.js'
3
3
  import type { DomainProperty } from '../DomainProperty.js'
4
- import { type DomainValidation, validatePropertyName } from './rules.js'
4
+ import { type DomainValidationSchema, validatePropertyName } from './rules.js'
5
5
 
6
6
  export class PropertyValidation {
7
7
  constructor(protected domain: DataDomain) {}
@@ -12,8 +12,8 @@ export class PropertyValidation {
12
12
  * @param target The target property to validate. Can be a string with
13
13
  * the property key or a DomainProperty object.
14
14
  */
15
- validate(target: string | DomainProperty): DomainValidation[] {
16
- const results: DomainValidation[] = []
15
+ validate(target: string | DomainProperty): DomainValidationSchema[] {
16
+ const results: DomainValidationSchema[] = []
17
17
  let property: DomainProperty | undefined
18
18
  if (typeof target === 'string') {
19
19
  property = this.domain.findProperty(target)
@@ -52,7 +52,7 @@ export class PropertyValidation {
52
52
  * - (recommendation) Column names should be in lower case.
53
53
  * @param property The property to validate
54
54
  */
55
- validateName(property: DomainProperty): DomainValidation[] {
55
+ validateName(property: DomainProperty): DomainValidationSchema[] {
56
56
  return validatePropertyName(property)
57
57
  }
58
58
  }
@@ -12,7 +12,10 @@ import { DomainPropertyKind } from '../../models/kinds.js'
12
12
  * - `type` -> unused
13
13
  * - `relationship` -> unused
14
14
  */
15
- export interface DomainValidation extends Omit<DomainImpactItem, 'type' | 'impact' | 'relationship' | 'resolution'> {
15
+ export interface DomainValidationSchema extends Omit<
16
+ DomainImpactItem,
17
+ 'type' | 'impact' | 'relationship' | 'resolution'
18
+ > {
16
19
  /**
17
20
  * The field that did not pass validation.
18
21
  */
@@ -55,8 +58,8 @@ export interface DomainValidation extends Omit<DomainImpactItem, 'type' | 'impac
55
58
  *
56
59
  * @param property The property to validate
57
60
  */
58
- export function validatePropertyName(property: DomainProperty | DomainAssociation): DomainValidation[] {
59
- const results: DomainValidation[] = []
61
+ export function validatePropertyName(property: DomainProperty | DomainAssociation): DomainValidationSchema[] {
62
+ const results: DomainValidationSchema[] = []
60
63
  const label = property.info.getLabel()
61
64
  const parentEntity = property.getParentInstance() as DomainEntity
62
65
  const type = property.kind === DomainPropertyKind ? 'property' : 'association'
@@ -1,7 +1,7 @@
1
1
  import { DomainEntityKind } from '../../models/kinds.js'
2
2
  import type { DataDomain } from '../DataDomain.js'
3
3
  import { DataSemantics, isPropertySemantic, SemanticType } from '../Semantics.js'
4
- import type { DomainValidation } from './rules.js'
4
+ import type { DomainValidationSchema } from './rules.js'
5
5
 
6
6
  /**
7
7
  * SemanticValidation is a class that performs validation on semantics in a data domain.
@@ -14,8 +14,8 @@ export class SemanticValidation {
14
14
  * Performs all the semantic validation rules on the domain.
15
15
  * @returns The list of validation messages.
16
16
  */
17
- validate(): DomainValidation[] {
18
- const results: DomainValidation[] = []
17
+ validate(): DomainValidationSchema[] {
18
+ const results: DomainValidationSchema[] = []
19
19
 
20
20
  // Check for User entity semantic
21
21
  const hasUserEntity = this.validateUserEntity()
@@ -40,8 +40,8 @@ export class SemanticValidation {
40
40
  * Validates if there is at least one entity with the User semantic.
41
41
  * This is a recommended semantic for authentication purposes.
42
42
  */
43
- private validateUserEntity(): DomainValidation[] {
44
- const results: DomainValidation[] = []
43
+ private validateUserEntity(): DomainValidationSchema[] {
44
+ const results: DomainValidationSchema[] = []
45
45
  let hasUserEntity = false
46
46
 
47
47
  for (const entity of this.domain.listEntities()) {
@@ -70,8 +70,8 @@ export class SemanticValidation {
70
70
  * Validates if entities have the recommended timestamp semantics.
71
71
  * This includes CreatedTimestamp and UpdatedTimestamp.
72
72
  */
73
- private validateTimestampSemantics(): DomainValidation[] {
74
- const results: DomainValidation[] = []
73
+ private validateTimestampSemantics(): DomainValidationSchema[] {
74
+ const results: DomainValidationSchema[] = []
75
75
 
76
76
  for (const entity of this.domain.listEntities()) {
77
77
  let hasCreatedTimestamp = false
@@ -118,8 +118,8 @@ export class SemanticValidation {
118
118
  * Validates if entities have the recommended soft delete semantics.
119
119
  * This includes either DeletedTimestamp or DeletedFlag.
120
120
  */
121
- private validateSoftDeleteSemantics(): DomainValidation[] {
122
- const results: DomainValidation[] = []
121
+ private validateSoftDeleteSemantics(): DomainValidationSchema[] {
122
+ const results: DomainValidationSchema[] = []
123
123
 
124
124
  for (const entity of this.domain.listEntities()) {
125
125
  let hasSoftDelete = false
@@ -150,8 +150,8 @@ export class SemanticValidation {
150
150
  /**
151
151
  * Validates if property semantics are applied to properties with compatible data types.
152
152
  */
153
- private validatePropertySemanticsDataTypes(): DomainValidation[] {
154
- const results: DomainValidation[] = []
153
+ private validatePropertySemanticsDataTypes(): DomainValidationSchema[] {
154
+ const results: DomainValidationSchema[] = []
155
155
 
156
156
  for (const entity of this.domain.listEntities()) {
157
157
  for (const property of entity.listProperties()) {
@@ -1,6 +1,6 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { DomainValidation } from '../../../src/modeling/DomainValidation.js'
3
- import { DataDomain, DataDomainKind } from '../../../src/index.js'
3
+ import { DataDomain } from '../../../src/index.js'
4
4
  import { SemanticType } from '../../../src/modeling/Semantics.js'
5
5
 
6
6
  test.group('DomainImpactAnalysis.validate()', (group) => {
@@ -14,12 +14,7 @@ test.group('DomainImpactAnalysis.validate()', (group) => {
14
14
 
15
15
  test('validate() should return an empty report when the domain is empty', ({ assert }) => {
16
16
  const report = analysis.validate()
17
- assert.deepEqual(report, {
18
- key: '',
19
- kind: DataDomainKind,
20
- impact: [],
21
- canProceed: true,
22
- })
17
+ assert.deepEqual(report, [])
23
18
  })
24
19
 
25
20
  test('validate() should return validation errors for entities', ({ assert }) => {
@@ -27,7 +22,7 @@ test.group('DomainImpactAnalysis.validate()', (group) => {
27
22
  model.addEntity({ key: 'entity', info: { name: 'Invalid-Name' } }) // Invalid name
28
23
 
29
24
  const report = analysis.validate()
30
- assert.lengthOf(report.impact, 8)
25
+ assert.lengthOf(report, 8)
31
26
  // we test specific rules in the validation tests
32
27
  })
33
28
 
@@ -37,7 +32,7 @@ test.group('DomainImpactAnalysis.validate()', (group) => {
37
32
  entity.addProperty({ key: 'invalid-property', type: 'string', info: { name: 'invalid-property' } })
38
33
 
39
34
  const report = analysis.validate()
40
- assert.lengthOf(report.impact, 6)
35
+ assert.lengthOf(report, 6)
41
36
  // we test specific rules in the validation tests
42
37
  })
43
38
 
@@ -48,7 +43,7 @@ test.group('DomainImpactAnalysis.validate()', (group) => {
48
43
  entity1.addAssociation({ targets: [{ key: entity2.key }], info: { name: 'Invalid-Name' } })
49
44
 
50
45
  const report = analysis.validate()
51
- assert.lengthOf(report.impact, 12)
46
+ assert.lengthOf(report, 12)
52
47
  // we test specific rules in the validation tests
53
48
  })
54
49
 
@@ -60,7 +55,7 @@ test.group('DomainImpactAnalysis.validate()', (group) => {
60
55
  entity1.addAssociation({ targets: [{ key: entity2.key }], info: { name: 'Invalid-Name' } })
61
56
 
62
57
  const report = analysis.validate()
63
- assert.lengthOf(report.impact, 16)
58
+ assert.lengthOf(report, 16)
64
59
  // we test specific rules in the validation tests
65
60
  })
66
61
 
@@ -88,7 +83,6 @@ test.group('DomainImpactAnalysis.validate()', (group) => {
88
83
  p5e1.addSemantic({ id: SemanticType.DeletedFlag })
89
84
 
90
85
  const report = analysis.validate()
91
- assert.lengthOf(report.impact, 0)
92
- assert.equal(report.canProceed, true)
86
+ assert.lengthOf(report, 0)
93
87
  })
94
88
  })
@@ -9,8 +9,8 @@ import {
9
9
  validateApiModelMetadata,
10
10
  validateExposedEntity,
11
11
  validateAction,
12
- validateApiModel,
13
12
  } from '../../../../src/modeling/validation/api_model_rules.js'
13
+ import { ApiValidation } from '../../../../src/modeling/ApiValidation.js'
14
14
  import { ExposedEntity } from '../../../../src/modeling/ExposedEntity.js'
15
15
  import { ListAction } from '../../../../src/modeling/actions/ListAction.js'
16
16
  import { DeleteAction } from '../../../../src/modeling/actions/DeleteAction.js'
@@ -305,9 +305,10 @@ test.group('ApiModel Validation', () => {
305
305
  },
306
306
  domain
307
307
  )
308
- const result = validateApiModel(model)
309
- assert.isTrue(result.isValid)
310
- assert.isEmpty(result.issues.filter((i) => i.severity === 'error'))
308
+ const validator = new ApiValidation(model)
309
+ const report = validator.validate()
310
+ assert.equal(validator.errorCount, 0)
311
+ assert.isEmpty(report.filter((i) => i.severity === 'error'))
311
312
  })
312
313
 
313
314
  test('validateApiModel - fails on multiple errors', ({ assert }) => {
@@ -315,10 +316,11 @@ test.group('ApiModel Validation', () => {
315
316
  info: { name: '' },
316
317
  })
317
318
  // Now it's missing name, missing domain, missing security context, missing contact.
318
- const result = validateApiModel(model)
319
- assert.isFalse(result.isValid)
320
- assert.isTrue(result.issues.some((i) => i.code === 'API_MISSING_NAME'))
321
- assert.isTrue(result.issues.some((i) => i.code === 'API_MISSING_DOMAIN'))
322
- assert.isTrue(result.issues.some((i) => i.code === 'API_MISSING_AUTHENTICATION'))
319
+ const validator = new ApiValidation(model)
320
+ const report = validator.validate()
321
+ assert.isAbove(validator.errorCount, 0)
322
+ assert.isTrue(report.some((i) => i.code === 'API_MISSING_NAME'))
323
+ assert.isTrue(report.some((i) => i.code === 'API_MISSING_DOMAIN'))
324
+ assert.isTrue(report.some((i) => i.code === 'API_MISSING_AUTHENTICATION'))
323
325
  })
324
326
  })