@canon-protocol/sdk 8.0.0
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/dist/canons/Canon.d.ts +2 -0
- package/dist/canons/Canon.js +2 -0
- package/dist/canons/DefinedCanon.d.ts +5 -0
- package/dist/canons/DefinedCanon.js +4 -0
- package/dist/canons/EmbeddedCanon.d.ts +3 -0
- package/dist/canons/EmbeddedCanon.js +3 -0
- package/dist/canons/ReferenceCanon.d.ts +6 -0
- package/dist/canons/ReferenceCanon.js +10 -0
- package/dist/canons/SubjectCanon.d.ts +6 -0
- package/dist/canons/SubjectCanon.js +6 -0
- package/dist/canons/index.d.ts +5 -0
- package/dist/canons/index.js +5 -0
- package/dist/ctl/CtlCanonUri.d.ts +28 -0
- package/dist/ctl/CtlCanonUri.js +230 -0
- package/dist/ctl/CtlGraphResolver.d.ts +14 -0
- package/dist/ctl/CtlGraphResolver.js +411 -0
- package/dist/ctl/CtlMarkdownRenderer.d.ts +17 -0
- package/dist/ctl/CtlMarkdownRenderer.js +262 -0
- package/dist/ctl/CtlParser.d.ts +10 -0
- package/dist/ctl/CtlParser.js +331 -0
- package/dist/ctl/CtlValidator.d.ts +12 -0
- package/dist/ctl/CtlValidator.js +207 -0
- package/dist/ctl/ResourceTypeClassifier.d.ts +21 -0
- package/dist/ctl/ResourceTypeClassifier.js +126 -0
- package/dist/ctl/index.d.ts +12 -0
- package/dist/ctl/index.js +9 -0
- package/dist/filtering/GitIgnoreFilter.d.ts +7 -0
- package/dist/filtering/GitIgnoreFilter.js +32 -0
- package/dist/filtering/IGitIgnoreFilter.d.ts +3 -0
- package/dist/filtering/IGitIgnoreFilter.js +1 -0
- package/dist/filtering/index.d.ts +2 -0
- package/dist/filtering/index.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +8 -0
- package/dist/parsing/CanonObjectParser.d.ts +21 -0
- package/dist/parsing/CanonObjectParser.js +242 -0
- package/dist/parsing/CanonParser.d.ts +21 -0
- package/dist/parsing/CanonParser.js +457 -0
- package/dist/parsing/ICanonObjectParser.d.ts +7 -0
- package/dist/parsing/ICanonObjectParser.js +1 -0
- package/dist/parsing/PropertyMetadata.d.ts +7 -0
- package/dist/parsing/PropertyMetadata.js +7 -0
- package/dist/parsing/index.d.ts +6 -0
- package/dist/parsing/index.js +3 -0
- package/dist/repositories/CompositeCanonDocumentRepository.d.ts +28 -0
- package/dist/repositories/CompositeCanonDocumentRepository.js +125 -0
- package/dist/repositories/FileSystemCanonDocumentRepository.d.ts +28 -0
- package/dist/repositories/FileSystemCanonDocumentRepository.js +295 -0
- package/dist/repositories/HttpCanonDocumentRepository.d.ts +24 -0
- package/dist/repositories/HttpCanonDocumentRepository.js +79 -0
- package/dist/repositories/InMemoryCanonDocumentRepository.d.ts +23 -0
- package/dist/repositories/InMemoryCanonDocumentRepository.js +149 -0
- package/dist/repositories/PublisherConfig.d.ts +12 -0
- package/dist/repositories/PublisherConfig.js +62 -0
- package/dist/repositories/PublisherIndex.d.ts +20 -0
- package/dist/repositories/PublisherIndex.js +127 -0
- package/dist/repositories/RepositoryFactory.d.ts +6 -0
- package/dist/repositories/RepositoryFactory.js +13 -0
- package/dist/repositories/index.d.ts +9 -0
- package/dist/repositories/index.js +7 -0
- package/dist/resolution/CanonUri.d.ts +10 -0
- package/dist/resolution/CanonUri.js +55 -0
- package/dist/resolution/CanonUriBuilder.d.ts +12 -0
- package/dist/resolution/CanonUriBuilder.js +51 -0
- package/dist/resolution/ResourceResolutionResult.d.ts +9 -0
- package/dist/resolution/ResourceResolutionResult.js +1 -0
- package/dist/resolution/ResourceResolver.d.ts +27 -0
- package/dist/resolution/ResourceResolver.js +266 -0
- package/dist/resolution/TypeResolver.d.ts +15 -0
- package/dist/resolution/TypeResolver.js +110 -0
- package/dist/resolution/index.d.ts +6 -0
- package/dist/resolution/index.js +4 -0
- package/dist/statements/BooleanStatement.d.ts +3 -0
- package/dist/statements/BooleanStatement.js +3 -0
- package/dist/statements/EmbeddedStatement.d.ts +4 -0
- package/dist/statements/EmbeddedStatement.js +3 -0
- package/dist/statements/IStatement.d.ts +2 -0
- package/dist/statements/IStatement.js +1 -0
- package/dist/statements/ListStatement.d.ts +4 -0
- package/dist/statements/ListStatement.js +3 -0
- package/dist/statements/NumberStatement.d.ts +4 -0
- package/dist/statements/NumberStatement.js +10 -0
- package/dist/statements/ReferenceStatement.d.ts +5 -0
- package/dist/statements/ReferenceStatement.js +10 -0
- package/dist/statements/ScalarStatement.d.ts +3 -0
- package/dist/statements/ScalarStatement.js +3 -0
- package/dist/statements/Statement.d.ts +6 -0
- package/dist/statements/Statement.js +4 -0
- package/dist/statements/StringStatement.d.ts +4 -0
- package/dist/statements/StringStatement.js +10 -0
- package/dist/statements/index.d.ts +9 -0
- package/dist/statements/index.js +8 -0
- package/dist/validation/CanonObjectValidator.d.ts +21 -0
- package/dist/validation/CanonObjectValidator.js +150 -0
- package/dist/validation/ICanonObjectValidator.d.ts +7 -0
- package/dist/validation/ICanonObjectValidator.js +1 -0
- package/dist/validation/OntologyValidationError.d.ts +15 -0
- package/dist/validation/OntologyValidationError.js +25 -0
- package/dist/validation/OntologyValidationResult.d.ts +7 -0
- package/dist/validation/OntologyValidationResult.js +8 -0
- package/dist/validation/ValidationContext.d.ts +6 -0
- package/dist/validation/ValidationContext.js +10 -0
- package/dist/validation/ValidationSeverity.d.ts +4 -0
- package/dist/validation/ValidationSeverity.js +5 -0
- package/dist/validation/index.d.ts +10 -0
- package/dist/validation/index.js +7 -0
- package/dist/validation/rules/document/EmbeddedCanonNoExplicitTypeRule.d.ts +8 -0
- package/dist/validation/rules/document/EmbeddedCanonNoExplicitTypeRule.js +53 -0
- package/dist/validation/rules/document/IDocumentValidationRule.d.ts +6 -0
- package/dist/validation/rules/document/IDocumentValidationRule.js +1 -0
- package/dist/validation/rules/document/NamespacePrefixRule.d.ts +10 -0
- package/dist/validation/rules/document/NamespacePrefixRule.js +51 -0
- package/dist/validation/rules/document/PropertyTypeSpecificityRule.d.ts +11 -0
- package/dist/validation/rules/document/PropertyTypeSpecificityRule.js +89 -0
- package/dist/validation/rules/document/ResourceNamingRule.d.ts +12 -0
- package/dist/validation/rules/document/ResourceNamingRule.js +79 -0
- package/dist/validation/rules/document/SubjectCanonTypeRequiredRule.d.ts +7 -0
- package/dist/validation/rules/document/SubjectCanonTypeRequiredRule.js +33 -0
- package/dist/validation/rules/document/index.d.ts +6 -0
- package/dist/validation/rules/document/index.js +5 -0
- package/dist/validation/rules/normalizeToStringList.d.ts +1 -0
- package/dist/validation/rules/normalizeToStringList.js +9 -0
- package/dist/validation/rules/repository/AmbiguousReferenceRule.d.ts +14 -0
- package/dist/validation/rules/repository/AmbiguousReferenceRule.js +155 -0
- package/dist/validation/rules/repository/ClassDefinitionRule.d.ts +12 -0
- package/dist/validation/rules/repository/ClassDefinitionRule.js +205 -0
- package/dist/validation/rules/repository/ClassHierarchyCycleRule.d.ts +11 -0
- package/dist/validation/rules/repository/ClassHierarchyCycleRule.js +98 -0
- package/dist/validation/rules/repository/DefinitionPropertyReferenceRule.d.ts +13 -0
- package/dist/validation/rules/repository/DefinitionPropertyReferenceRule.js +162 -0
- package/dist/validation/rules/repository/IRepositoryValidationRule.d.ts +7 -0
- package/dist/validation/rules/repository/IRepositoryValidationRule.js +1 -0
- package/dist/validation/rules/repository/ImportExistenceRule.d.ts +12 -0
- package/dist/validation/rules/repository/ImportExistenceRule.js +124 -0
- package/dist/validation/rules/repository/InstancePropertyReferenceRule.d.ts +13 -0
- package/dist/validation/rules/repository/InstancePropertyReferenceRule.js +161 -0
- package/dist/validation/rules/repository/NamespaceImportCycleRule.d.ts +11 -0
- package/dist/validation/rules/repository/NamespaceImportCycleRule.js +85 -0
- package/dist/validation/rules/repository/ObjectPropertyImportRule.d.ts +9 -0
- package/dist/validation/rules/repository/ObjectPropertyImportRule.js +113 -0
- package/dist/validation/rules/repository/ObjectPropertyValueValidationRule.d.ts +12 -0
- package/dist/validation/rules/repository/ObjectPropertyValueValidationRule.js +281 -0
- package/dist/validation/rules/repository/PropertyDomainRule.d.ts +14 -0
- package/dist/validation/rules/repository/PropertyDomainRule.js +221 -0
- package/dist/validation/rules/repository/PropertyHierarchyCycleRule.d.ts +11 -0
- package/dist/validation/rules/repository/PropertyHierarchyCycleRule.js +104 -0
- package/dist/validation/rules/repository/PropertyRangeReferenceRule.d.ts +13 -0
- package/dist/validation/rules/repository/PropertyRangeReferenceRule.js +184 -0
- package/dist/validation/rules/repository/PropertyRangeRequiredRule.d.ts +8 -0
- package/dist/validation/rules/repository/PropertyRangeRequiredRule.js +40 -0
- package/dist/validation/rules/repository/PropertyValueTypeRule.d.ts +11 -0
- package/dist/validation/rules/repository/PropertyValueTypeRule.js +171 -0
- package/dist/validation/rules/repository/SubClassOfReferenceRule.d.ts +11 -0
- package/dist/validation/rules/repository/SubClassOfReferenceRule.js +133 -0
- package/dist/validation/rules/repository/SubPropertyOfReferenceRule.d.ts +11 -0
- package/dist/validation/rules/repository/SubPropertyOfReferenceRule.js +133 -0
- package/dist/validation/rules/repository/TypeAmbiguityRule.d.ts +10 -0
- package/dist/validation/rules/repository/TypeAmbiguityRule.js +104 -0
- package/dist/validation/rules/repository/UnresolvedReferenceRule.d.ts +11 -0
- package/dist/validation/rules/repository/UnresolvedReferenceRule.js +91 -0
- package/dist/validation/rules/repository/XsdImportRule.d.ts +11 -0
- package/dist/validation/rules/repository/XsdImportRule.js +125 -0
- package/dist/validation/rules/repository/index.d.ts +20 -0
- package/dist/validation/rules/repository/index.js +19 -0
- package/package.json +82 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { OntologyValidationError } from '../../OntologyValidationError.js';
|
|
2
|
+
import { ValidationSeverity } from '../../ValidationSeverity.js';
|
|
3
|
+
import { normalizeToStringList } from '../normalizeToStringList.js';
|
|
4
|
+
export class SubPropertyOfReferenceRule {
|
|
5
|
+
builtInProperties = new Set([
|
|
6
|
+
'type',
|
|
7
|
+
'label',
|
|
8
|
+
'comment',
|
|
9
|
+
'domain',
|
|
10
|
+
'range',
|
|
11
|
+
'subPropertyOf',
|
|
12
|
+
'subClassOf',
|
|
13
|
+
'inverseOf',
|
|
14
|
+
'sameAs',
|
|
15
|
+
'seeAlso',
|
|
16
|
+
'isDefinedBy',
|
|
17
|
+
'functional',
|
|
18
|
+
'required'
|
|
19
|
+
]);
|
|
20
|
+
get ruleName() {
|
|
21
|
+
return 'SubPropertyOfReference';
|
|
22
|
+
}
|
|
23
|
+
async validateAsync(document, repository) {
|
|
24
|
+
const errors = [];
|
|
25
|
+
const definedProperties = new Set();
|
|
26
|
+
for (const [entityName, entityDef] of Object.entries(document.body)) {
|
|
27
|
+
if (typeof entityDef === 'object' && entityDef !== null && !Array.isArray(entityDef)) {
|
|
28
|
+
const entity = entityDef;
|
|
29
|
+
const type = entity['type']?.toString();
|
|
30
|
+
if (type === 'DatatypeProperty' || type === 'ObjectProperty' || type === 'AnnotationProperty') {
|
|
31
|
+
definedProperties.add(entityName);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const [entityName, entityDef] of Object.entries(document.body)) {
|
|
36
|
+
if (typeof entityDef === 'object' && entityDef !== null && !Array.isArray(entityDef)) {
|
|
37
|
+
const entity = entityDef;
|
|
38
|
+
const parentProperties = normalizeToStringList(entity['subPropertyOf']);
|
|
39
|
+
for (let i = 0; i < parentProperties.length; i++) {
|
|
40
|
+
const parentProperty = parentProperties[i];
|
|
41
|
+
if (this.builtInProperties.has(parentProperty)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (definedProperties.has(parentProperty)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const isAvailable = await this.isPropertyAvailableInImports(document, repository, parentProperty);
|
|
48
|
+
if (!isAvailable) {
|
|
49
|
+
const indexSuffix = parentProperties.length > 1 ? `[${i}]` : '';
|
|
50
|
+
const error = new OntologyValidationError();
|
|
51
|
+
error.ruleType = this.ruleName;
|
|
52
|
+
error.severity = ValidationSeverity.Error;
|
|
53
|
+
error.message = `Property '${parentProperty}' referenced in subPropertyOf${indexSuffix} is not defined or imported`;
|
|
54
|
+
error.suggestion = `Define '${parentProperty}' as a DatatypeProperty or ObjectProperty, or import a namespace that contains it`;
|
|
55
|
+
error.entityName = entityName;
|
|
56
|
+
error.propertyName = 'subPropertyOf';
|
|
57
|
+
error.actualValue = parentProperty;
|
|
58
|
+
error.expectedValue = 'Defined or imported property';
|
|
59
|
+
errors.push(error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return errors;
|
|
65
|
+
}
|
|
66
|
+
async isPropertyAvailableInImports(document, repository, propertyName) {
|
|
67
|
+
if (!document.metadata.imports) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
let namespaceAlias = null;
|
|
71
|
+
let actualPropertyName = propertyName;
|
|
72
|
+
if (propertyName.includes('.')) {
|
|
73
|
+
const parts = propertyName.split('.', 2);
|
|
74
|
+
namespaceAlias = parts[0];
|
|
75
|
+
actualPropertyName = parts[1];
|
|
76
|
+
}
|
|
77
|
+
for (const [publisher, imports] of Object.entries(document.metadata.imports)) {
|
|
78
|
+
for (const import_ of imports) {
|
|
79
|
+
if (namespaceAlias !== null && import_.alias !== namespaceAlias) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const importedDoc = await repository.getHighestCompatibleVersionAsync(publisher, import_);
|
|
83
|
+
if (importedDoc) {
|
|
84
|
+
const lookupName = namespaceAlias !== null ? actualPropertyName : propertyName;
|
|
85
|
+
const entityDef = importedDoc.body[lookupName];
|
|
86
|
+
if (entityDef && typeof entityDef === 'object' && !Array.isArray(entityDef)) {
|
|
87
|
+
const entity = entityDef;
|
|
88
|
+
const type = entity['type']?.toString();
|
|
89
|
+
if (type === 'DatatypeProperty' || type === 'ObjectProperty' || type === 'AnnotationProperty') {
|
|
90
|
+
return true; // Found the property definition
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const visitedDocs = new Set();
|
|
94
|
+
if (await this.isPropertyAvailableInImportsRecursive(importedDoc, repository, lookupName, visitedDocs)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
async isPropertyAvailableInImportsRecursive(document, repository, propertyName, visitedDocs) {
|
|
103
|
+
const docId = document.metadata.namespace_?.toString() ?? '';
|
|
104
|
+
if (docId && visitedDocs.has(docId)) {
|
|
105
|
+
return false; // Already checked this document
|
|
106
|
+
}
|
|
107
|
+
if (docId) {
|
|
108
|
+
visitedDocs.add(docId);
|
|
109
|
+
}
|
|
110
|
+
if (!document.metadata.imports) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
for (const [publisher, imports] of Object.entries(document.metadata.imports)) {
|
|
114
|
+
for (const import_ of imports) {
|
|
115
|
+
const importedDoc = await repository.getHighestCompatibleVersionAsync(publisher, import_);
|
|
116
|
+
if (importedDoc) {
|
|
117
|
+
const entityDef = importedDoc.body[propertyName];
|
|
118
|
+
if (entityDef && typeof entityDef === 'object' && !Array.isArray(entityDef)) {
|
|
119
|
+
const entity = entityDef;
|
|
120
|
+
const type = entity['type']?.toString();
|
|
121
|
+
if (type === 'DatatypeProperty' || type === 'ObjectProperty' || type === 'AnnotationProperty') {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (await this.isPropertyAvailableInImportsRecursive(importedDoc, repository, propertyName, visitedDocs)) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
|
|
2
|
+
import type { CanonDocument } from '@canon-protocol/types/document/models/types';
|
|
3
|
+
import { OntologyValidationError } from '../../OntologyValidationError.js';
|
|
4
|
+
import type { IRepositoryValidationRule } from './IRepositoryValidationRule.js';
|
|
5
|
+
export declare class TypeAmbiguityRule implements IRepositoryValidationRule {
|
|
6
|
+
readonly ruleName = "TypeAmbiguity";
|
|
7
|
+
validateAsync(document: CanonDocument, repository: ICanonDocumentRepository): Promise<OntologyValidationError[]>;
|
|
8
|
+
private checkAmbiguousReference;
|
|
9
|
+
private getTransitiveImportsAsync;
|
|
10
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { OntologyValidationError } from '../../OntologyValidationError.js';
|
|
2
|
+
import { ValidationSeverity } from '../../ValidationSeverity.js';
|
|
3
|
+
import { normalizeToStringList } from '../normalizeToStringList.js';
|
|
4
|
+
export class TypeAmbiguityRule {
|
|
5
|
+
ruleName = 'TypeAmbiguity';
|
|
6
|
+
async validateAsync(document, repository) {
|
|
7
|
+
const errors = [];
|
|
8
|
+
const typeDefinitions = new Map();
|
|
9
|
+
const importedDocs = [];
|
|
10
|
+
if (document.metadata?.imports) {
|
|
11
|
+
for (const [publisher, imports] of Object.entries(document.metadata.imports)) {
|
|
12
|
+
for (const import_ of imports) {
|
|
13
|
+
const importedDoc = await repository.getHighestCompatibleVersionAsync(publisher, import_);
|
|
14
|
+
if (importedDoc) {
|
|
15
|
+
importedDocs.push({ doc: importedDoc, import: import_, publisher });
|
|
16
|
+
const transitiveImports = await this.getTransitiveImportsAsync(repository, importedDoc, new Set());
|
|
17
|
+
importedDocs.push(...transitiveImports.map(doc => ({ doc, import: null, publisher })));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const { doc: importedDoc, import: import_ } of importedDocs) {
|
|
23
|
+
const namespaceName = importedDoc.metadata?.namespace_?.toString() ?? 'unknown';
|
|
24
|
+
for (const entityName of Object.keys(importedDoc.body)) {
|
|
25
|
+
if (!typeDefinitions.has(entityName)) {
|
|
26
|
+
typeDefinitions.set(entityName, []);
|
|
27
|
+
}
|
|
28
|
+
typeDefinitions.get(entityName).push({ namespace: namespaceName, import: import_ });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const [entityName, entityValue] of Object.entries(document.body)) {
|
|
32
|
+
if (entityValue && typeof entityValue === 'object' && !Array.isArray(entityValue)) {
|
|
33
|
+
const entityDict = entityValue;
|
|
34
|
+
this.checkAmbiguousReference(entityDict, 'type', typeDefinitions, entityName, errors);
|
|
35
|
+
this.checkAmbiguousReference(entityDict, 'subClassOf', typeDefinitions, entityName, errors);
|
|
36
|
+
this.checkAmbiguousReference(entityDict, 'subPropertyOf', typeDefinitions, entityName, errors);
|
|
37
|
+
this.checkAmbiguousReference(entityDict, 'domain', typeDefinitions, entityName, errors);
|
|
38
|
+
this.checkAmbiguousReference(entityDict, 'range', typeDefinitions, entityName, errors);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return errors;
|
|
42
|
+
}
|
|
43
|
+
checkAmbiguousReference(entityDict, propertyName, typeDefinitions, entityName, errors) {
|
|
44
|
+
const value = entityDict[propertyName];
|
|
45
|
+
if (!value) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const referencedTypes = normalizeToStringList(value);
|
|
49
|
+
for (const referencedType of referencedTypes) {
|
|
50
|
+
if (referencedType.includes('.')) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const definitions = typeDefinitions.get(referencedType);
|
|
54
|
+
if (definitions && definitions.length > 1) {
|
|
55
|
+
const namespaces = definitions.map(d => d.namespace).join(', ');
|
|
56
|
+
const suggestions = [];
|
|
57
|
+
for (const { namespace: ns, import: import_ } of definitions) {
|
|
58
|
+
if (import_?.alias) {
|
|
59
|
+
suggestions.push(`${import_.alias}.${referencedType}`);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const parts = ns.split('/');
|
|
63
|
+
const lastPart = parts[parts.length - 1];
|
|
64
|
+
const packageName = lastPart?.split('@')[0] ?? 'alias';
|
|
65
|
+
suggestions.push(`${packageName}.${referencedType}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const suggestionText = suggestions.length > 0
|
|
69
|
+
? `Use one of: ${suggestions.join(', ')}`
|
|
70
|
+
: 'Consider adding namespace aliases to your imports';
|
|
71
|
+
const error = new OntologyValidationError();
|
|
72
|
+
error.ruleType = this.ruleName;
|
|
73
|
+
error.severity = ValidationSeverity.Warning;
|
|
74
|
+
error.entityName = entityName;
|
|
75
|
+
error.propertyName = propertyName;
|
|
76
|
+
error.actualValue = referencedType;
|
|
77
|
+
error.message = `Type '${referencedType}' is ambiguous. It's defined in: ${namespaces}`;
|
|
78
|
+
error.suggestion = suggestionText;
|
|
79
|
+
errors.push(error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async getTransitiveImportsAsync(repository, document, visited) {
|
|
84
|
+
const result = [];
|
|
85
|
+
const docId = document.metadata?.namespace_?.toString() ?? '';
|
|
86
|
+
if (visited.has(docId)) {
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
visited.add(docId);
|
|
90
|
+
if (document.metadata?.imports) {
|
|
91
|
+
for (const [publisher, imports] of Object.entries(document.metadata.imports)) {
|
|
92
|
+
for (const import_ of imports) {
|
|
93
|
+
const importedDoc = await repository.getHighestCompatibleVersionAsync(publisher, import_);
|
|
94
|
+
if (importedDoc) {
|
|
95
|
+
result.push(importedDoc);
|
|
96
|
+
const transitive = await this.getTransitiveImportsAsync(repository, importedDoc, visited);
|
|
97
|
+
result.push(...transitive);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
|
|
2
|
+
import type { CanonDocument } from '@canon-protocol/types/document/models/types';
|
|
3
|
+
import { OntologyValidationError } from '../../OntologyValidationError.js';
|
|
4
|
+
import type { IRepositoryValidationRule } from './IRepositoryValidationRule.js';
|
|
5
|
+
export declare class UnresolvedReferenceRule implements IRepositoryValidationRule {
|
|
6
|
+
readonly ruleName = "UnresolvedReference";
|
|
7
|
+
validateAsync(document: CanonDocument, repository: ICanonDocumentRepository): Promise<OntologyValidationError[]>;
|
|
8
|
+
private validateReferenceValue;
|
|
9
|
+
private createUnresolvedReferenceError;
|
|
10
|
+
private getPropertyValue;
|
|
11
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ResourceResolver } from '../../../resolution/ResourceResolver.js';
|
|
2
|
+
import { OntologyValidationError } from '../../OntologyValidationError.js';
|
|
3
|
+
import { ValidationSeverity } from '../../ValidationSeverity.js';
|
|
4
|
+
export class UnresolvedReferenceRule {
|
|
5
|
+
ruleName = 'UnresolvedReference';
|
|
6
|
+
async validateAsync(document, repository) {
|
|
7
|
+
const errors = [];
|
|
8
|
+
const resourceResolver = new ResourceResolver(repository);
|
|
9
|
+
const entityIndex = await resourceResolver.buildEntityIndexAsync(document);
|
|
10
|
+
const objectProperties = new Set();
|
|
11
|
+
for (const [entityName, resourceResolution] of entityIndex.entries()) {
|
|
12
|
+
const typeValue = resourceResolution.entity['type'];
|
|
13
|
+
if (typeValue) {
|
|
14
|
+
const type = typeValue.toString();
|
|
15
|
+
if (type === 'ObjectProperty' || type.endsWith('.ObjectProperty')) {
|
|
16
|
+
objectProperties.add(entityName);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
for (const [entityName, entityDef] of Object.entries(document.body)) {
|
|
21
|
+
if (!entityDef || typeof entityDef !== 'object' || Array.isArray(entityDef)) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const entity = entityDef;
|
|
25
|
+
const entityType = this.getPropertyValue(entity, 'type');
|
|
26
|
+
if (!entityType ||
|
|
27
|
+
entityType === 'Class' ||
|
|
28
|
+
entityType.endsWith('Property') ||
|
|
29
|
+
entityType === 'AnnotationProperty') {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
for (const [propName, propValue] of Object.entries(entity)) {
|
|
33
|
+
if (propName === 'type' || propName === 'label' || propName === 'comment') {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const isObjectProperty = objectProperties.has(propName) ||
|
|
37
|
+
Array.from(objectProperties).some(p => p.endsWith(`.${propName}`));
|
|
38
|
+
if (!isObjectProperty) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
await this.validateReferenceValue(entityName, propName, propValue, document, resourceResolver, errors);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return errors;
|
|
45
|
+
}
|
|
46
|
+
async validateReferenceValue(entityName, propertyName, value, document, resourceResolver, errors) {
|
|
47
|
+
if (value == null) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === 'string') {
|
|
51
|
+
const resolution = await resourceResolver.resolveEntityAsync(value, document);
|
|
52
|
+
if (!resolution) {
|
|
53
|
+
errors.push(this.createUnresolvedReferenceError(entityName, propertyName, value));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (Array.isArray(value)) {
|
|
57
|
+
for (let i = 0; i < value.length; i++) {
|
|
58
|
+
const item = value[i];
|
|
59
|
+
if (typeof item === 'string') {
|
|
60
|
+
const resolution = await resourceResolver.resolveEntityAsync(item, document);
|
|
61
|
+
if (!resolution) {
|
|
62
|
+
errors.push(this.createUnresolvedReferenceError(entityName, `${propertyName}[${i}]`, item));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
createUnresolvedReferenceError(entityName, propertyName, referencedEntity) {
|
|
69
|
+
const suggestion = `The entity '${referencedEntity}' cannot be found in the current document or any imported namespaces.\n\n` +
|
|
70
|
+
'Possible solutions:\n' +
|
|
71
|
+
' • Add import if the entity is defined in another namespace:\n' +
|
|
72
|
+
' canon namespace add-import <publisher>/<package>@<version>\n' +
|
|
73
|
+
` • Check for typos in the reference name '${referencedEntity}'\n` +
|
|
74
|
+
` • Define '${referencedEntity}' in the current namespace or an appropriate namespace\n` +
|
|
75
|
+
` • Use 'canon search type ${referencedEntity} --include-imports' to locate the entity`;
|
|
76
|
+
const error = new OntologyValidationError();
|
|
77
|
+
error.ruleType = this.ruleName;
|
|
78
|
+
error.severity = ValidationSeverity.Warning;
|
|
79
|
+
error.entityName = entityName;
|
|
80
|
+
error.propertyName = propertyName;
|
|
81
|
+
error.actualValue = referencedEntity;
|
|
82
|
+
error.message = `Reference to '${referencedEntity}' could not be resolved`;
|
|
83
|
+
error.suggestion = suggestion;
|
|
84
|
+
error.expectedValue = 'A valid entity reference that exists in the current document or imported namespaces';
|
|
85
|
+
return error;
|
|
86
|
+
}
|
|
87
|
+
getPropertyValue(dict, propertyName) {
|
|
88
|
+
const value = dict[propertyName];
|
|
89
|
+
return value ? value.toString() : null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CanonDocument } from '@canon-protocol/types/document/models/types';
|
|
2
|
+
import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
|
|
3
|
+
import type { IRepositoryValidationRule } from './IRepositoryValidationRule.js';
|
|
4
|
+
import { OntologyValidationError } from '../../OntologyValidationError.js';
|
|
5
|
+
export declare class XsdImportRule implements IRepositoryValidationRule {
|
|
6
|
+
private readonly xsdTypes;
|
|
7
|
+
get ruleName(): string;
|
|
8
|
+
validateAsync(document: CanonDocument, repository: ICanonDocumentRepository): Promise<OntologyValidationError[]>;
|
|
9
|
+
private checkXsdImportAsync;
|
|
10
|
+
private getPropertyValue;
|
|
11
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { OntologyValidationError } from '../../OntologyValidationError.js';
|
|
2
|
+
import { ValidationSeverity } from '../../ValidationSeverity.js';
|
|
3
|
+
export class XsdImportRule {
|
|
4
|
+
xsdTypes = new Set([
|
|
5
|
+
'string',
|
|
6
|
+
'integer',
|
|
7
|
+
'boolean',
|
|
8
|
+
'decimal',
|
|
9
|
+
'float',
|
|
10
|
+
'double',
|
|
11
|
+
'date',
|
|
12
|
+
'dateTime',
|
|
13
|
+
'time',
|
|
14
|
+
'duration',
|
|
15
|
+
'anyURI',
|
|
16
|
+
'base64Binary',
|
|
17
|
+
'hexBinary',
|
|
18
|
+
'long',
|
|
19
|
+
'int',
|
|
20
|
+
'short',
|
|
21
|
+
'byte',
|
|
22
|
+
'unsignedLong',
|
|
23
|
+
'unsignedInt',
|
|
24
|
+
'unsignedShort',
|
|
25
|
+
'unsignedByte',
|
|
26
|
+
'positiveInteger',
|
|
27
|
+
'nonPositiveInteger',
|
|
28
|
+
'negativeInteger',
|
|
29
|
+
'nonNegativeInteger',
|
|
30
|
+
'normalizedString',
|
|
31
|
+
'token',
|
|
32
|
+
'language',
|
|
33
|
+
'Name',
|
|
34
|
+
'NCName',
|
|
35
|
+
'ENTITY',
|
|
36
|
+
'ENTITIES',
|
|
37
|
+
'IDREF',
|
|
38
|
+
'IDREFS',
|
|
39
|
+
'NMTOKEN',
|
|
40
|
+
'NMTOKENS'
|
|
41
|
+
]);
|
|
42
|
+
get ruleName() {
|
|
43
|
+
return 'XsdImport';
|
|
44
|
+
}
|
|
45
|
+
async validateAsync(document, repository) {
|
|
46
|
+
const errors = [];
|
|
47
|
+
const usedXsdTypes = new Set();
|
|
48
|
+
const datatypeProperties = [];
|
|
49
|
+
for (const [entityName, entityDef] of Object.entries(document.body)) {
|
|
50
|
+
if (typeof entityDef === 'object' && entityDef !== null && !Array.isArray(entityDef)) {
|
|
51
|
+
const entity = entityDef;
|
|
52
|
+
let isDatatypeProperty = false;
|
|
53
|
+
const typeValue = entity['type'];
|
|
54
|
+
if (Array.isArray(typeValue)) {
|
|
55
|
+
for (const type of typeValue) {
|
|
56
|
+
if (type?.toString() === 'DatatypeProperty') {
|
|
57
|
+
isDatatypeProperty = true;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (typeValue?.toString() === 'DatatypeProperty') {
|
|
63
|
+
isDatatypeProperty = true;
|
|
64
|
+
}
|
|
65
|
+
if (isDatatypeProperty) {
|
|
66
|
+
datatypeProperties.push(entityName);
|
|
67
|
+
const rangeValue = this.getPropertyValue(entity, 'range');
|
|
68
|
+
if (rangeValue && this.xsdTypes.has(rangeValue)) {
|
|
69
|
+
usedXsdTypes.add(rangeValue);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (usedXsdTypes.size > 0) {
|
|
75
|
+
const hasXsdImport = await this.checkXsdImportAsync(document.metadata, repository);
|
|
76
|
+
if (!hasXsdImport) {
|
|
77
|
+
const xsdTypesList = Array.from(usedXsdTypes).sort().join(', ');
|
|
78
|
+
const propertyList = datatypeProperties.sort().join(', ');
|
|
79
|
+
const error = new OntologyValidationError();
|
|
80
|
+
error.ruleType = this.ruleName;
|
|
81
|
+
error.severity = ValidationSeverity.Error;
|
|
82
|
+
error.message = `XSD namespace not imported but XSD types are used: ${xsdTypesList}`;
|
|
83
|
+
error.suggestion = `Add an XSD import to the imports section. The core XSD types package is 'core-xsd' from publisher 'canon-protocol.org'. Used by properties: ${propertyList}`;
|
|
84
|
+
error.entityName = 'imports';
|
|
85
|
+
errors.push(error);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return errors;
|
|
89
|
+
}
|
|
90
|
+
async checkXsdImportAsync(metadata, repository, visitedPackages = new Set()) {
|
|
91
|
+
if (!metadata?.imports) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const currentPackage = metadata.namespace_?.toString() ?? '';
|
|
95
|
+
if (currentPackage && visitedPackages.has(currentPackage)) {
|
|
96
|
+
return false; // Already visited, prevent cycle
|
|
97
|
+
}
|
|
98
|
+
if (currentPackage) {
|
|
99
|
+
visitedPackages.add(currentPackage);
|
|
100
|
+
}
|
|
101
|
+
for (const [, imports] of Object.entries(metadata.imports)) {
|
|
102
|
+
for (const import_ of imports) {
|
|
103
|
+
if (import_.packageName === 'xsd' || import_.packageName.toLowerCase().endsWith('-xsd')) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (const [publisher, imports] of Object.entries(metadata.imports)) {
|
|
109
|
+
for (const import_ of imports) {
|
|
110
|
+
const importedDoc = await repository.getHighestCompatibleVersionAsync(publisher, import_);
|
|
111
|
+
if (importedDoc?.metadata) {
|
|
112
|
+
const hasXsd = await this.checkXsdImportAsync(importedDoc.metadata, repository, visitedPackages);
|
|
113
|
+
if (hasXsd) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
getPropertyValue(dict, propertyName) {
|
|
122
|
+
const value = dict[propertyName];
|
|
123
|
+
return value?.toString();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type { IRepositoryValidationRule } from './IRepositoryValidationRule.js';
|
|
2
|
+
export { ImportExistenceRule } from './ImportExistenceRule.js';
|
|
3
|
+
export { UnresolvedReferenceRule } from './UnresolvedReferenceRule.js';
|
|
4
|
+
export { TypeAmbiguityRule } from './TypeAmbiguityRule.js';
|
|
5
|
+
export { ClassHierarchyCycleRule } from './ClassHierarchyCycleRule.js';
|
|
6
|
+
export { PropertyHierarchyCycleRule } from './PropertyHierarchyCycleRule.js';
|
|
7
|
+
export { PropertyRangeRequiredRule } from './PropertyRangeRequiredRule.js';
|
|
8
|
+
export { SubClassOfReferenceRule } from './SubClassOfReferenceRule.js';
|
|
9
|
+
export { SubPropertyOfReferenceRule } from './SubPropertyOfReferenceRule.js';
|
|
10
|
+
export { NamespaceImportCycleRule } from './NamespaceImportCycleRule.js';
|
|
11
|
+
export { InstancePropertyReferenceRule } from './InstancePropertyReferenceRule.js';
|
|
12
|
+
export { DefinitionPropertyReferenceRule } from './DefinitionPropertyReferenceRule.js';
|
|
13
|
+
export { XsdImportRule } from './XsdImportRule.js';
|
|
14
|
+
export { AmbiguousReferenceRule } from './AmbiguousReferenceRule.js';
|
|
15
|
+
export { PropertyRangeReferenceRule } from './PropertyRangeReferenceRule.js';
|
|
16
|
+
export { ObjectPropertyImportRule } from './ObjectPropertyImportRule.js';
|
|
17
|
+
export { ObjectPropertyValueValidationRule } from './ObjectPropertyValueValidationRule.js';
|
|
18
|
+
export { PropertyDomainRule } from './PropertyDomainRule.js';
|
|
19
|
+
export { PropertyValueTypeRule } from './PropertyValueTypeRule.js';
|
|
20
|
+
export { ClassDefinitionRule } from './ClassDefinitionRule.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { ImportExistenceRule } from './ImportExistenceRule.js';
|
|
2
|
+
export { UnresolvedReferenceRule } from './UnresolvedReferenceRule.js';
|
|
3
|
+
export { TypeAmbiguityRule } from './TypeAmbiguityRule.js';
|
|
4
|
+
export { ClassHierarchyCycleRule } from './ClassHierarchyCycleRule.js';
|
|
5
|
+
export { PropertyHierarchyCycleRule } from './PropertyHierarchyCycleRule.js';
|
|
6
|
+
export { PropertyRangeRequiredRule } from './PropertyRangeRequiredRule.js';
|
|
7
|
+
export { SubClassOfReferenceRule } from './SubClassOfReferenceRule.js';
|
|
8
|
+
export { SubPropertyOfReferenceRule } from './SubPropertyOfReferenceRule.js';
|
|
9
|
+
export { NamespaceImportCycleRule } from './NamespaceImportCycleRule.js';
|
|
10
|
+
export { InstancePropertyReferenceRule } from './InstancePropertyReferenceRule.js';
|
|
11
|
+
export { DefinitionPropertyReferenceRule } from './DefinitionPropertyReferenceRule.js';
|
|
12
|
+
export { XsdImportRule } from './XsdImportRule.js';
|
|
13
|
+
export { AmbiguousReferenceRule } from './AmbiguousReferenceRule.js';
|
|
14
|
+
export { PropertyRangeReferenceRule } from './PropertyRangeReferenceRule.js';
|
|
15
|
+
export { ObjectPropertyImportRule } from './ObjectPropertyImportRule.js';
|
|
16
|
+
export { ObjectPropertyValueValidationRule } from './ObjectPropertyValueValidationRule.js';
|
|
17
|
+
export { PropertyDomainRule } from './PropertyDomainRule.js';
|
|
18
|
+
export { PropertyValueTypeRule } from './PropertyValueTypeRule.js';
|
|
19
|
+
export { ClassDefinitionRule } from './ClassDefinitionRule.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@canon-protocol/sdk",
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": "Canon Protocol SDK - Document repository and parsing implementations for TypeScript",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./repositories": {
|
|
14
|
+
"types": "./dist/repositories/index.d.ts",
|
|
15
|
+
"default": "./dist/repositories/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./parsing": {
|
|
18
|
+
"types": "./dist/parsing/index.d.ts",
|
|
19
|
+
"default": "./dist/parsing/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./resolution": {
|
|
22
|
+
"types": "./dist/resolution/index.d.ts",
|
|
23
|
+
"default": "./dist/resolution/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./validation": {
|
|
26
|
+
"types": "./dist/validation/index.d.ts",
|
|
27
|
+
"default": "./dist/validation/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./filtering": {
|
|
30
|
+
"types": "./dist/filtering/index.d.ts",
|
|
31
|
+
"default": "./dist/filtering/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./ctl": {
|
|
34
|
+
"types": "./dist/ctl/index.d.ts",
|
|
35
|
+
"default": "./dist/ctl/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist/**/*",
|
|
40
|
+
"README.md"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc",
|
|
44
|
+
"clean": "rimraf dist",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"test": "jest",
|
|
47
|
+
"docs": "typedoc",
|
|
48
|
+
"docs:watch": "typedoc --watch",
|
|
49
|
+
"prepublishOnly": "npm run build"
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/canon-protocol/canon-protocol.git"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"canon",
|
|
57
|
+
"ontology",
|
|
58
|
+
"semantic-web",
|
|
59
|
+
"typescript",
|
|
60
|
+
"sdk",
|
|
61
|
+
"document-repository",
|
|
62
|
+
"yaml-parser"
|
|
63
|
+
],
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@canon-protocol/types": "^8.0.0",
|
|
66
|
+
"ignore": "^7.0.5",
|
|
67
|
+
"js-yaml": "^4.1.0"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@types/jest": "^29.5.0",
|
|
71
|
+
"@types/js-yaml": "^4.0.9",
|
|
72
|
+
"@types/node": "^20.19.25",
|
|
73
|
+
"jest": "^29.7.0",
|
|
74
|
+
"rimraf": "^5.0.0",
|
|
75
|
+
"ts-jest": "^29.1.0",
|
|
76
|
+
"typedoc": "^0.28.14",
|
|
77
|
+
"typescript": "^5.3.0"
|
|
78
|
+
},
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": ">=18.0.0"
|
|
81
|
+
}
|
|
82
|
+
}
|