@api-client/core 0.18.13 → 0.18.14

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.
@@ -1,8 +1,86 @@
1
1
  import { DataDomain } from './DataDomain.js';
2
2
  import { DomainImpactReport } from './types.js';
3
+ /**
4
+ * DomainValidation performs comprehensive validation on a data domain and its components.
5
+ *
6
+ * This class orchestrates validation across all domain elements including entities, properties,
7
+ * associations, and semantics. It ensures that the data domain is well-formed and follows
8
+ * established conventions before it can be published or used in API generation.
9
+ *
10
+ * ## Validation Scope
11
+ *
12
+ * The validation process covers:
13
+ * - **Entities**: Structure, naming, primary keys, and inheritance
14
+ * - **Properties**: Naming conventions, data types, and constraints
15
+ * - **Associations**: Relationships, targets, and naming
16
+ * - **Semantics**: Recommended patterns and best practices
17
+ *
18
+ * ## Validation Severity Levels
19
+ *
20
+ * - **Error**: Blocking issues that prevent domain publication
21
+ * - **Warning**: Issues that may cause problems but don't block publication
22
+ * - **Info**: Recommendations for best practices
23
+ *
24
+ * ## Usage
25
+ *
26
+ * ```typescript
27
+ * const domain = new DataDomain()
28
+ * // ... add entities, properties, associations
29
+ *
30
+ * const validator = new DomainValidation(domain)
31
+ * const report = validator.validate()
32
+ *
33
+ * if (report.canProceed) {
34
+ * // Domain is valid and can be published
35
+ * } else {
36
+ * // Handle validation errors
37
+ * console.log(report.impact)
38
+ * }
39
+ * ```
40
+ *
41
+ * ## Validation Rules
42
+ *
43
+ * ### Entity Validation Rules
44
+ * - **Primary Key**: Each entity must have a primary key (can be inherited)
45
+ * - **Minimum Properties**: Entities should have properties or associations (can be inherited)
46
+ * - **Naming**: Entity names must follow PostgreSQL naming conventions
47
+ * - **Uniqueness**: Entity names must be unique within the domain
48
+ *
49
+ * ### Property Validation Rules
50
+ * - **Naming**: Properties must follow PostgreSQL column naming conventions
51
+ * - **Length**: Names must be 2-59 characters long
52
+ * - **Format**: Names must start with letter/underscore, contain only alphanumeric/underscore
53
+ * - **Reserved Words**: Names cannot be PostgreSQL reserved keywords
54
+ * - **Case**: Snake case is recommended (lowercase with underscores)
55
+ *
56
+ * ### Association Validation Rules
57
+ * - **Targets**: Associations must have at least one target entity
58
+ * - **Target Existence**: Target entities must exist in the domain
59
+ * - **Naming**: Same rules as properties
60
+ *
61
+ * ### Semantic Validation Rules
62
+ * - **User Entity**: Recommended to have at least one entity with User semantic
63
+ * - **Timestamps**: Recommended to have CreatedTimestamp and UpdatedTimestamp properties
64
+ * - **Soft Delete**: Recommended to have soft delete capability for entities
65
+ * - **Data Types**: Semantic-specific data type validation
66
+ *
67
+ * @see {@link EntityValidation} for detailed entity validation rules
68
+ * @see {@link PropertyValidation} for detailed property validation rules
69
+ * @see {@link AssociationValidation} for detailed association validation rules
70
+ * @see {@link SemanticValidation} for detailed semantic validation rules
71
+ */
3
72
  export declare class DomainValidation {
4
73
  private root;
5
74
  constructor(root: DataDomain);
75
+ /**
76
+ * Performs comprehensive validation on the entire data domain.
77
+ *
78
+ * This method validates all entities, properties, associations, and semantics
79
+ * in the domain. It returns a detailed report of all validation issues found,
80
+ * categorized by severity level.
81
+ *
82
+ * @returns A comprehensive validation report with all issues found
83
+ */
6
84
  validate(): DomainImpactReport;
7
85
  }
8
86
  //# sourceMappingURL=DomainValidation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DomainValidation.d.ts","sourceRoot":"","sources":["../../../src/modeling/DomainValidation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAM/C,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,IAAI,CAAY;gBAEZ,IAAI,EAAE,UAAU;IAI5B,QAAQ,IAAI,kBAAkB;CAyF/B"}
1
+ {"version":3,"file":"DomainValidation.d.ts","sourceRoot":"","sources":["../../../src/modeling/DomainValidation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAM/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,IAAI,CAAY;gBAEZ,IAAI,EAAE,UAAU;IAI5B;;;;;;;;OAQG;IACH,QAAQ,IAAI,kBAAkB;CAyF/B"}
@@ -3,11 +3,89 @@ import { AssociationValidation } from './validation/association_validation.js';
3
3
  import { EntityValidation } from './validation/entity_validation.js';
4
4
  import { PropertyValidation } from './validation/property_validation.js';
5
5
  import { SemanticValidation } from './validation/semantic_validation.js';
6
+ /**
7
+ * DomainValidation performs comprehensive validation on a data domain and its components.
8
+ *
9
+ * This class orchestrates validation across all domain elements including entities, properties,
10
+ * associations, and semantics. It ensures that the data domain is well-formed and follows
11
+ * established conventions before it can be published or used in API generation.
12
+ *
13
+ * ## Validation Scope
14
+ *
15
+ * The validation process covers:
16
+ * - **Entities**: Structure, naming, primary keys, and inheritance
17
+ * - **Properties**: Naming conventions, data types, and constraints
18
+ * - **Associations**: Relationships, targets, and naming
19
+ * - **Semantics**: Recommended patterns and best practices
20
+ *
21
+ * ## Validation Severity Levels
22
+ *
23
+ * - **Error**: Blocking issues that prevent domain publication
24
+ * - **Warning**: Issues that may cause problems but don't block publication
25
+ * - **Info**: Recommendations for best practices
26
+ *
27
+ * ## Usage
28
+ *
29
+ * ```typescript
30
+ * const domain = new DataDomain()
31
+ * // ... add entities, properties, associations
32
+ *
33
+ * const validator = new DomainValidation(domain)
34
+ * const report = validator.validate()
35
+ *
36
+ * if (report.canProceed) {
37
+ * // Domain is valid and can be published
38
+ * } else {
39
+ * // Handle validation errors
40
+ * console.log(report.impact)
41
+ * }
42
+ * ```
43
+ *
44
+ * ## Validation Rules
45
+ *
46
+ * ### Entity Validation Rules
47
+ * - **Primary Key**: Each entity must have a primary key (can be inherited)
48
+ * - **Minimum Properties**: Entities should have properties or associations (can be inherited)
49
+ * - **Naming**: Entity names must follow PostgreSQL naming conventions
50
+ * - **Uniqueness**: Entity names must be unique within the domain
51
+ *
52
+ * ### Property Validation Rules
53
+ * - **Naming**: Properties must follow PostgreSQL column naming conventions
54
+ * - **Length**: Names must be 2-59 characters long
55
+ * - **Format**: Names must start with letter/underscore, contain only alphanumeric/underscore
56
+ * - **Reserved Words**: Names cannot be PostgreSQL reserved keywords
57
+ * - **Case**: Snake case is recommended (lowercase with underscores)
58
+ *
59
+ * ### Association Validation Rules
60
+ * - **Targets**: Associations must have at least one target entity
61
+ * - **Target Existence**: Target entities must exist in the domain
62
+ * - **Naming**: Same rules as properties
63
+ *
64
+ * ### Semantic Validation Rules
65
+ * - **User Entity**: Recommended to have at least one entity with User semantic
66
+ * - **Timestamps**: Recommended to have CreatedTimestamp and UpdatedTimestamp properties
67
+ * - **Soft Delete**: Recommended to have soft delete capability for entities
68
+ * - **Data Types**: Semantic-specific data type validation
69
+ *
70
+ * @see {@link EntityValidation} for detailed entity validation rules
71
+ * @see {@link PropertyValidation} for detailed property validation rules
72
+ * @see {@link AssociationValidation} for detailed association validation rules
73
+ * @see {@link SemanticValidation} for detailed semantic validation rules
74
+ */
6
75
  export class DomainValidation {
7
76
  root;
8
77
  constructor(root) {
9
78
  this.root = root;
10
79
  }
80
+ /**
81
+ * Performs comprehensive validation on the entire data domain.
82
+ *
83
+ * This method validates all entities, properties, associations, and semantics
84
+ * in the domain. It returns a detailed report of all validation issues found,
85
+ * categorized by severity level.
86
+ *
87
+ * @returns A comprehensive validation report with all issues found
88
+ */
11
89
  validate() {
12
90
  const result = {
13
91
  key: '',
@@ -1 +1 @@
1
- {"version":3,"file":"DomainValidation.js","sourceRoot":"","sources":["../../../src/modeling/DomainValidation.ts"],"names":[],"mappings":"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","sourcesContent":["import { DataDomainKind } from '../models/kinds.js'\nimport { DataDomain } from './DataDomain.js'\nimport { DomainImpactReport } from './types.js'\nimport { AssociationValidation } from './validation/association_validation.js'\nimport { EntityValidation } from './validation/entity_validation.js'\nimport { PropertyValidation } from './validation/property_validation.js'\nimport { SemanticValidation } from './validation/semantic_validation.js'\n\nexport class DomainValidation {\n private root: DataDomain\n\n constructor(root: DataDomain) {\n this.root = root\n }\n\n validate(): DomainImpactReport {\n const result: DomainImpactReport = {\n key: '',\n kind: DataDomainKind,\n impact: [],\n canProceed: true,\n }\n const entityValidator = new EntityValidation(this.root)\n const propertyValidator = new PropertyValidation(this.root)\n const associationValidator = new AssociationValidation(this.root)\n const semanticValidator = new SemanticValidation(this.root)\n\n let hasEntities = false\n // Validate entities, properties, and associations\n for (const entity of this.root.listEntities()) {\n if (entity.domain.key !== this.root.key) {\n // we don't need to validate foreign entities\n continue\n }\n hasEntities = true\n const report = entityValidator.validate(entity)\n for (const item of report) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n for (const property of entity.properties) {\n const report = propertyValidator.validate(property)\n for (const item of report) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n }\n for (const association of entity.associations) {\n const report = associationValidator.validate(association)\n for (const item of report) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n }\n }\n if (!hasEntities) {\n // no entities, no need to validate anything else\n return result\n }\n // Validate semantics\n const semanticReport = semanticValidator.validate()\n for (const item of semanticReport) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n\n return result\n }\n}\n"]}
1
+ {"version":3,"file":"DomainValidation.js","sourceRoot":"","sources":["../../../src/modeling/DomainValidation.ts"],"names":[],"mappings":"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","sourcesContent":["import { DataDomainKind } from '../models/kinds.js'\nimport { DataDomain } from './DataDomain.js'\nimport { DomainImpactReport } from './types.js'\nimport { AssociationValidation } from './validation/association_validation.js'\nimport { EntityValidation } from './validation/entity_validation.js'\nimport { PropertyValidation } from './validation/property_validation.js'\nimport { SemanticValidation } from './validation/semantic_validation.js'\n\n/**\n * DomainValidation performs comprehensive validation on a data domain and its components.\n *\n * This class orchestrates validation across all domain elements including entities, properties,\n * associations, and semantics. It ensures that the data domain is well-formed and follows\n * established conventions before it can be published or used in API generation.\n *\n * ## Validation Scope\n *\n * The validation process covers:\n * - **Entities**: Structure, naming, primary keys, and inheritance\n * - **Properties**: Naming conventions, data types, and constraints\n * - **Associations**: Relationships, targets, and naming\n * - **Semantics**: Recommended patterns and best practices\n *\n * ## Validation Severity Levels\n *\n * - **Error**: Blocking issues that prevent domain publication\n * - **Warning**: Issues that may cause problems but don't block publication\n * - **Info**: Recommendations for best practices\n *\n * ## Usage\n *\n * ```typescript\n * const domain = new DataDomain()\n * // ... add entities, properties, associations\n *\n * const validator = new DomainValidation(domain)\n * const report = validator.validate()\n *\n * if (report.canProceed) {\n * // Domain is valid and can be published\n * } else {\n * // Handle validation errors\n * console.log(report.impact)\n * }\n * ```\n *\n * ## Validation Rules\n *\n * ### Entity Validation Rules\n * - **Primary Key**: Each entity must have a primary key (can be inherited)\n * - **Minimum Properties**: Entities should have properties or associations (can be inherited)\n * - **Naming**: Entity names must follow PostgreSQL naming conventions\n * - **Uniqueness**: Entity names must be unique within the domain\n *\n * ### Property Validation Rules\n * - **Naming**: Properties must follow PostgreSQL column naming conventions\n * - **Length**: Names must be 2-59 characters long\n * - **Format**: Names must start with letter/underscore, contain only alphanumeric/underscore\n * - **Reserved Words**: Names cannot be PostgreSQL reserved keywords\n * - **Case**: Snake case is recommended (lowercase with underscores)\n *\n * ### Association Validation Rules\n * - **Targets**: Associations must have at least one target entity\n * - **Target Existence**: Target entities must exist in the domain\n * - **Naming**: Same rules as properties\n *\n * ### Semantic Validation Rules\n * - **User Entity**: Recommended to have at least one entity with User semantic\n * - **Timestamps**: Recommended to have CreatedTimestamp and UpdatedTimestamp properties\n * - **Soft Delete**: Recommended to have soft delete capability for entities\n * - **Data Types**: Semantic-specific data type validation\n *\n * @see {@link EntityValidation} for detailed entity validation rules\n * @see {@link PropertyValidation} for detailed property validation rules\n * @see {@link AssociationValidation} for detailed association validation rules\n * @see {@link SemanticValidation} for detailed semantic validation rules\n */\nexport class DomainValidation {\n private root: DataDomain\n\n constructor(root: DataDomain) {\n this.root = root\n }\n\n /**\n * Performs comprehensive validation on the entire data domain.\n *\n * This method validates all entities, properties, associations, and semantics\n * in the domain. It returns a detailed report of all validation issues found,\n * categorized by severity level.\n *\n * @returns A comprehensive validation report with all issues found\n */\n validate(): DomainImpactReport {\n const result: DomainImpactReport = {\n key: '',\n kind: DataDomainKind,\n impact: [],\n canProceed: true,\n }\n const entityValidator = new EntityValidation(this.root)\n const propertyValidator = new PropertyValidation(this.root)\n const associationValidator = new AssociationValidation(this.root)\n const semanticValidator = new SemanticValidation(this.root)\n\n let hasEntities = false\n // Validate entities, properties, and associations\n for (const entity of this.root.listEntities()) {\n if (entity.domain.key !== this.root.key) {\n // we don't need to validate foreign entities\n continue\n }\n hasEntities = true\n const report = entityValidator.validate(entity)\n for (const item of report) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n for (const property of entity.properties) {\n const report = propertyValidator.validate(property)\n for (const item of report) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n }\n for (const association of entity.associations) {\n const report = associationValidator.validate(association)\n for (const item of report) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n }\n }\n if (!hasEntities) {\n // no entities, no need to validate anything else\n return result\n }\n // Validate semantics\n const semanticReport = semanticValidator.validate()\n for (const item of semanticReport) {\n const blocking = item.severity === 'error'\n result.canProceed = result.canProceed && !blocking\n result.impact.push({\n key: item.key,\n kind: item.kind,\n type: 'publish',\n impact: item.message,\n resolution: item.help,\n severity: item.severity,\n parent: item.parent,\n })\n }\n\n return result\n }\n}\n"]}
@@ -14,15 +14,29 @@ export declare class EntityValidation {
14
14
  /**
15
15
  * Performs all the validation rules on the entity.
16
16
  * If you are interested in a specific rule, use the specific method.
17
- * @param target The target entity to validate. Can be a string with the entity key or a DomainEntity object.
17
+ * @param target The target entity to validate. Can be a string with
18
+ * the entity key or a DomainEntity object.
18
19
  */
19
20
  validate(target: string | DomainEntity): DomainValidation[];
20
21
  /**
21
- * Validates the entity against the primary key validation rules.
22
+ * Validates the entity primary key.
22
23
  * @param entity The entity to validate
23
- * @returns The list of validation messages.
24
24
  */
25
25
  validatePrimaryKey(entity: DomainEntity): DomainValidation[];
26
+ /**
27
+ * Checks if an entity has properties through its entire inheritance chain.
28
+ * This includes direct properties and properties inherited from any level of parent entities.
29
+ * @param entity The entity to check
30
+ * @returns True if the entity has properties either directly or through inheritance
31
+ */
32
+ private hasPropertiesInherited;
33
+ /**
34
+ * Checks if an entity has associations through its entire inheritance chain.
35
+ * This includes direct associations and associations inherited from any level of parent entities.
36
+ * @param entity The entity to check
37
+ * @returns True if the entity has associations either directly or through inheritance
38
+ */
39
+ private hasAssociationsInherited;
26
40
  /**
27
41
  * Checks if the entity has the minimum required properties.
28
42
  * @param entity The entity to validate
@@ -1 +1 @@
1
- {"version":3,"file":"entity_validation.d.ts","sourceRoot":"","sources":["../../../../src/modeling/validation/entity_validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;GAMG;AACH,qBAAa,gBAAgB;IACf,SAAS,CAAC,MAAM,EAAE,UAAU;gBAAlB,MAAM,EAAE,UAAU;IAExC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,gBAAgB,EAAE;IAiC3D;;;;OAIG;IACH,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAmB5D;;;OAGG;IACH,yBAAyB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAkBnE;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAuFtD;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;CAwCrD"}
1
+ {"version":3,"file":"entity_validation.d.ts","sourceRoot":"","sources":["../../../../src/modeling/validation/entity_validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;GAMG;AACH,qBAAa,gBAAgB;IACf,SAAS,CAAC,MAAM,EAAE,UAAU;gBAAlB,MAAM,EAAE,UAAU;IAExC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,gBAAgB,EAAE;IAiC3D;;;OAGG;IACH,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAmB5D;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAgB9B;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAgBhC;;;OAGG;IACH,yBAAyB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAuBnE;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAuFtD;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE;CAwCrD"}
@@ -15,7 +15,8 @@ export class EntityValidation {
15
15
  /**
16
16
  * Performs all the validation rules on the entity.
17
17
  * If you are interested in a specific rule, use the specific method.
18
- * @param target The target entity to validate. Can be a string with the entity key or a DomainEntity object.
18
+ * @param target The target entity to validate. Can be a string with
19
+ * the entity key or a DomainEntity object.
19
20
  */
20
21
  validate(target) {
21
22
  const results = [];
@@ -40,20 +41,19 @@ export class EntityValidation {
40
41
  });
41
42
  return results;
42
43
  }
43
- const primary = this.validatePrimaryKey(entity);
44
- results.push(...primary);
45
- const minimum = this.minimumRequiredProperties(entity);
46
- results.push(...minimum);
44
+ const primaryKey = this.validatePrimaryKey(entity);
45
+ results.push(...primaryKey);
46
+ const minimumProperties = this.minimumRequiredProperties(entity);
47
+ results.push(...minimumProperties);
47
48
  const name = this.validateName(entity);
48
49
  results.push(...name);
49
- const uniqueName = this.uniqueName(entity);
50
- results.push(...uniqueName);
50
+ const unique = this.uniqueName(entity);
51
+ results.push(...unique);
51
52
  return results;
52
53
  }
53
54
  /**
54
- * Validates the entity against the primary key validation rules.
55
+ * Validates the entity primary key.
55
56
  * @param entity The entity to validate
56
- * @returns The list of validation messages.
57
57
  */
58
58
  validatePrimaryKey(entity) {
59
59
  const results = [];
@@ -73,13 +73,54 @@ export class EntityValidation {
73
73
  }
74
74
  return results;
75
75
  }
76
+ /**
77
+ * Checks if an entity has properties through its entire inheritance chain.
78
+ * This includes direct properties and properties inherited from any level of parent entities.
79
+ * @param entity The entity to check
80
+ * @returns True if the entity has properties either directly or through inheritance
81
+ */
82
+ hasPropertiesInherited(entity) {
83
+ // Check direct properties first
84
+ if (entity.hasProperties()) {
85
+ return true;
86
+ }
87
+ // Check all parents recursively
88
+ for (const parent of entity.listParents()) {
89
+ if (this.hasPropertiesInherited(parent)) {
90
+ return true;
91
+ }
92
+ }
93
+ return false;
94
+ }
95
+ /**
96
+ * Checks if an entity has associations through its entire inheritance chain.
97
+ * This includes direct associations and associations inherited from any level of parent entities.
98
+ * @param entity The entity to check
99
+ * @returns True if the entity has associations either directly or through inheritance
100
+ */
101
+ hasAssociationsInherited(entity) {
102
+ // Check direct associations first
103
+ if (entity.hasAssociations()) {
104
+ return true;
105
+ }
106
+ // Check all parents recursively
107
+ for (const parent of entity.listParents()) {
108
+ if (this.hasAssociationsInherited(parent)) {
109
+ return true;
110
+ }
111
+ }
112
+ return false;
113
+ }
76
114
  /**
77
115
  * Checks if the entity has the minimum required properties.
78
116
  * @param entity The entity to validate
79
117
  */
80
118
  minimumRequiredProperties(entity) {
81
119
  const results = [];
82
- if (!entity.hasProperties() && !entity.hasAssociations()) {
120
+ // Check if entity has properties or associations through entire inheritance chain
121
+ const hasProperties = this.hasPropertiesInherited(entity);
122
+ const hasAssociations = this.hasAssociationsInherited(entity);
123
+ if (!hasProperties && !hasAssociations) {
83
124
  const message = `The "${entity.info.getLabel()}" entity has no properties. It will be ignored.`;
84
125
  const help = `Entities that have no properties are ignored in the data domain. No schema will be generated for it.`;
85
126
  results.push({
@@ -1 +1 @@
1
- {"version":3,"file":"entity_validation.js","sourceRoot":"","sources":["../../../../src/modeling/validation/entity_validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { DomainEntityKind } from '../../models/kinds.js'\nimport type { DataDomain } from '../DataDomain.js'\nimport type { DomainEntity } from '../DomainEntity.js'\nimport { ReservedKeywords } from './postgresql.js'\nimport type { DomainValidation } from './rules.js'\n\n/**\n * EntityValidation is a class that performs validation on entities in a data domain.\n *\n * @remarks\n * - We do not need to check for parent uniqueness here, because in the graph there can only be one edge\n * between two nodes. Parent relationships are described by an edge in the graph.\n */\nexport class EntityValidation {\n constructor(protected domain: DataDomain) {}\n\n /**\n * Performs all the validation rules on the entity.\n * If you are interested in a specific rule, use the specific method.\n * @param target The target entity to validate. Can be a string with the entity key or a DomainEntity object.\n */\n validate(target: string | DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n let entity: DomainEntity | undefined\n if (typeof target === 'string') {\n entity = this.domain.findEntity(target)\n } else {\n entity = target\n }\n if (!entity) {\n const message = `The \"${target}\" entity does not exist.`\n const help = `The entity must be defined in the domain.`\n results.push({\n field: '*',\n rule: 'exists',\n message,\n help,\n key: target as string,\n kind: DomainEntityKind,\n severity: 'error',\n })\n return results\n }\n const primary = this.validatePrimaryKey(entity)\n results.push(...primary)\n const minimum = this.minimumRequiredProperties(entity)\n results.push(...minimum)\n const name = this.validateName(entity)\n results.push(...name)\n const uniqueName = this.uniqueName(entity)\n results.push(...uniqueName)\n return results\n }\n\n /**\n * Validates the entity against the primary key validation rules.\n * @param entity The entity to validate\n * @returns The list of validation messages.\n */\n validatePrimaryKey(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n const primary = entity.primaryKey()\n if (!primary) {\n const message = `The \"${entity.info.getLabel()}\" entity has no identifier.`\n const help = `An entity that can exists by itself must have identifier defined.`\n results.push({\n field: 'properties',\n rule: 'primary_key',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n return results\n }\n\n /**\n * Checks if the entity has the minimum required properties.\n * @param entity The entity to validate\n */\n minimumRequiredProperties(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n if (!entity.hasProperties() && !entity.hasAssociations()) {\n const message = `The \"${entity.info.getLabel()}\" entity has no properties. It will be ignored.`\n const help = `Entities that have no properties are ignored in the data domain. No schema will be generated for it.`\n results.push({\n field: 'properties',\n rule: 'required',\n message,\n help,\n severity: 'warning',\n key: entity.key,\n kind: entity.kind,\n })\n }\n return results\n }\n\n /**\n * Validates the entity name.\n *\n * @remarks\n * - An entity must have a name defined.\n * - The name has to follow the same rules as the names in a PostgreSQL database.\n * - Table names must start with a letter (a-z) or underscore (_).\n * - Subsequent characters can be letters, digits (0-9), or underscores (_).\n * - Names are case-insensitive.\n * - The maximum length of a table name is 31 characters\n * - Should be snake case (it's a convention, not an error).\n * - Should not be a reserved word (for example: \"IN\", \"SELECT\", \"FROM\", etc.).\n * @param entity The entity to validate\n */\n validateName(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n const label = entity.info.getLabel()\n if (!entity.info.name) {\n const message = `The \"${label}\" entity has no name.`\n const help = `An entity must have a name.`\n results.push({\n field: 'name',\n rule: 'required',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n return results\n }\n\n const name = entity.info.name\n if (name.length < 2) {\n const message = `The \"${label}\" entity name is too short.`\n const help = `The name must be at least 2 characters long.`\n results.push({\n field: 'name',\n rule: 'length',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (name.length > 31) {\n const message = `The \"${label}\" entity name is too long.`\n const help = `The name must be at most 31 characters long.`\n results.push({\n field: 'name',\n rule: 'length',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n const message = `The \"${label}\" entity name is invalid.`\n const help = `The name must start with a letter (a-z) or underscore (_). Subsequent characters can be letters, digits (0-9), or underscores (_).`\n results.push({\n field: 'name',\n rule: 'format',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (/^[A-Z]/.test(name)) {\n const message = `The \"${label}\" entity name is not in snake case.`\n const help = `The name should be in snake case (lowercase letters and underscores).`\n results.push({\n field: 'name',\n rule: 'snake_case',\n message,\n help,\n severity: 'info',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (ReservedKeywords.has(name.toUpperCase())) {\n const message = `The \"${label}\" entity name is a reserved keyword.`\n const help = `The name should not be a reserved keyword.`\n results.push({\n field: 'name',\n rule: 'reserved',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n return results\n }\n\n /**\n * Checks if the entity name is unique in the data domain.\n * @param entity The entity to validate\n */\n uniqueName(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n const name = entity.info.name?.toLowerCase()\n if (!name) {\n return results\n }\n // We need to check the unique names in all entities, including foreign ones.\n for (const other of this.domain.listEntities()) {\n if (other.info.name?.toLowerCase() === name && other.key !== entity.key) {\n const message = `The \"${name}\" entity name is already used in the data domain.`\n const help = `The name must be unique. This includes references to other data domains.`\n results.push({\n field: 'name',\n rule: 'unique',\n message,\n help,\n severity: 'error',\n key: other.key,\n kind: other.kind,\n })\n }\n }\n for (const other of this.domain.listAllForeignEntities()) {\n if (other.info.name?.toLowerCase() === name && other.key !== entity.key) {\n const message = `The \"${name}\" entity name is already used in the foreign data domain.`\n const help = `The name must be unique. This includes references to other data domains.`\n results.push({\n field: 'name',\n rule: 'unique',\n message,\n help,\n severity: 'error',\n key: other.key,\n kind: other.kind,\n parent: other.domain.key,\n })\n }\n }\n return results\n }\n}\n"]}
1
+ {"version":3,"file":"entity_validation.js","sourceRoot":"","sources":["../../../../src/modeling/validation/entity_validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { DomainEntityKind } from '../../models/kinds.js'\nimport type { DataDomain } from '../DataDomain.js'\nimport type { DomainEntity } from '../DomainEntity.js'\nimport { ReservedKeywords } from './postgresql.js'\nimport type { DomainValidation } from './rules.js'\n\n/**\n * EntityValidation is a class that performs validation on entities in a data domain.\n *\n * @remarks\n * - We do not need to check for parent uniqueness here, because in the graph there can only be one edge\n * between two nodes. Parent relationships are described by an edge in the graph.\n */\nexport class EntityValidation {\n constructor(protected domain: DataDomain) {}\n\n /**\n * Performs all the validation rules on the entity.\n * If you are interested in a specific rule, use the specific method.\n * @param target The target entity to validate. Can be a string with\n * the entity key or a DomainEntity object.\n */\n validate(target: string | DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n let entity: DomainEntity | undefined\n if (typeof target === 'string') {\n entity = this.domain.findEntity(target)\n } else {\n entity = target\n }\n if (!entity) {\n const message = `The \"${target}\" entity does not exist.`\n const help = `The entity must be defined in the domain.`\n results.push({\n field: '*',\n rule: 'exists',\n message,\n help,\n key: target as string,\n kind: DomainEntityKind,\n severity: 'error',\n })\n return results\n }\n const primaryKey = this.validatePrimaryKey(entity)\n results.push(...primaryKey)\n const minimumProperties = this.minimumRequiredProperties(entity)\n results.push(...minimumProperties)\n const name = this.validateName(entity)\n results.push(...name)\n const unique = this.uniqueName(entity)\n results.push(...unique)\n return results\n }\n\n /**\n * Validates the entity primary key.\n * @param entity The entity to validate\n */\n validatePrimaryKey(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n const primary = entity.primaryKey()\n if (!primary) {\n const message = `The \"${entity.info.getLabel()}\" entity has no identifier.`\n const help = `An entity that can exists by itself must have identifier defined.`\n results.push({\n field: 'properties',\n rule: 'primary_key',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n return results\n }\n\n /**\n * Checks if an entity has properties through its entire inheritance chain.\n * This includes direct properties and properties inherited from any level of parent entities.\n * @param entity The entity to check\n * @returns True if the entity has properties either directly or through inheritance\n */\n private hasPropertiesInherited(entity: DomainEntity): boolean {\n // Check direct properties first\n if (entity.hasProperties()) {\n return true\n }\n\n // Check all parents recursively\n for (const parent of entity.listParents()) {\n if (this.hasPropertiesInherited(parent)) {\n return true\n }\n }\n\n return false\n }\n\n /**\n * Checks if an entity has associations through its entire inheritance chain.\n * This includes direct associations and associations inherited from any level of parent entities.\n * @param entity The entity to check\n * @returns True if the entity has associations either directly or through inheritance\n */\n private hasAssociationsInherited(entity: DomainEntity): boolean {\n // Check direct associations first\n if (entity.hasAssociations()) {\n return true\n }\n\n // Check all parents recursively\n for (const parent of entity.listParents()) {\n if (this.hasAssociationsInherited(parent)) {\n return true\n }\n }\n\n return false\n }\n\n /**\n * Checks if the entity has the minimum required properties.\n * @param entity The entity to validate\n */\n minimumRequiredProperties(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n\n // Check if entity has properties or associations through entire inheritance chain\n const hasProperties = this.hasPropertiesInherited(entity)\n const hasAssociations = this.hasAssociationsInherited(entity)\n\n if (!hasProperties && !hasAssociations) {\n const message = `The \"${entity.info.getLabel()}\" entity has no properties. It will be ignored.`\n const help = `Entities that have no properties are ignored in the data domain. No schema will be generated for it.`\n results.push({\n field: 'properties',\n rule: 'required',\n message,\n help,\n severity: 'warning',\n key: entity.key,\n kind: entity.kind,\n })\n }\n return results\n }\n\n /**\n * Validates the entity name.\n *\n * @remarks\n * - An entity must have a name defined.\n * - The name has to follow the same rules as the names in a PostgreSQL database.\n * - Table names must start with a letter (a-z) or underscore (_).\n * - Subsequent characters can be letters, digits (0-9), or underscores (_).\n * - Names are case-insensitive.\n * - The maximum length of a table name is 31 characters\n * - Should be snake case (it's a convention, not an error).\n * - Should not be a reserved word (for example: \"IN\", \"SELECT\", \"FROM\", etc.).\n * @param entity The entity to validate\n */\n validateName(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n const label = entity.info.getLabel()\n if (!entity.info.name) {\n const message = `The \"${label}\" entity has no name.`\n const help = `An entity must have a name.`\n results.push({\n field: 'name',\n rule: 'required',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n return results\n }\n\n const name = entity.info.name\n if (name.length < 2) {\n const message = `The \"${label}\" entity name is too short.`\n const help = `The name must be at least 2 characters long.`\n results.push({\n field: 'name',\n rule: 'length',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (name.length > 31) {\n const message = `The \"${label}\" entity name is too long.`\n const help = `The name must be at most 31 characters long.`\n results.push({\n field: 'name',\n rule: 'length',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n const message = `The \"${label}\" entity name is invalid.`\n const help = `The name must start with a letter (a-z) or underscore (_). Subsequent characters can be letters, digits (0-9), or underscores (_).`\n results.push({\n field: 'name',\n rule: 'format',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (/^[A-Z]/.test(name)) {\n const message = `The \"${label}\" entity name is not in snake case.`\n const help = `The name should be in snake case (lowercase letters and underscores).`\n results.push({\n field: 'name',\n rule: 'snake_case',\n message,\n help,\n severity: 'info',\n key: entity.key,\n kind: entity.kind,\n })\n }\n if (ReservedKeywords.has(name.toUpperCase())) {\n const message = `The \"${label}\" entity name is a reserved keyword.`\n const help = `The name should not be a reserved keyword.`\n results.push({\n field: 'name',\n rule: 'reserved',\n message,\n help,\n severity: 'error',\n key: entity.key,\n kind: entity.kind,\n })\n }\n return results\n }\n\n /**\n * Checks if the entity name is unique in the data domain.\n * @param entity The entity to validate\n */\n uniqueName(entity: DomainEntity): DomainValidation[] {\n const results: DomainValidation[] = []\n const name = entity.info.name?.toLowerCase()\n if (!name) {\n return results\n }\n // We need to check the unique names in all entities, including foreign ones.\n for (const other of this.domain.listEntities()) {\n if (other.info.name?.toLowerCase() === name && other.key !== entity.key) {\n const message = `The \"${name}\" entity name is already used in the data domain.`\n const help = `The name must be unique. This includes references to other data domains.`\n results.push({\n field: 'name',\n rule: 'unique',\n message,\n help,\n severity: 'error',\n key: other.key,\n kind: other.kind,\n })\n }\n }\n for (const other of this.domain.listAllForeignEntities()) {\n if (other.info.name?.toLowerCase() === name && other.key !== entity.key) {\n const message = `The \"${name}\" entity name is already used in the foreign data domain.`\n const help = `The name must be unique. This includes references to other data domains.`\n results.push({\n field: 'name',\n rule: 'unique',\n message,\n help,\n severity: 'error',\n key: other.key,\n kind: other.kind,\n parent: other.domain.key,\n })\n }\n }\n return results\n }\n}\n"]}