@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.
Files changed (165) hide show
  1. package/dist/canons/Canon.d.ts +2 -0
  2. package/dist/canons/Canon.js +2 -0
  3. package/dist/canons/DefinedCanon.d.ts +5 -0
  4. package/dist/canons/DefinedCanon.js +4 -0
  5. package/dist/canons/EmbeddedCanon.d.ts +3 -0
  6. package/dist/canons/EmbeddedCanon.js +3 -0
  7. package/dist/canons/ReferenceCanon.d.ts +6 -0
  8. package/dist/canons/ReferenceCanon.js +10 -0
  9. package/dist/canons/SubjectCanon.d.ts +6 -0
  10. package/dist/canons/SubjectCanon.js +6 -0
  11. package/dist/canons/index.d.ts +5 -0
  12. package/dist/canons/index.js +5 -0
  13. package/dist/ctl/CtlCanonUri.d.ts +28 -0
  14. package/dist/ctl/CtlCanonUri.js +230 -0
  15. package/dist/ctl/CtlGraphResolver.d.ts +14 -0
  16. package/dist/ctl/CtlGraphResolver.js +411 -0
  17. package/dist/ctl/CtlMarkdownRenderer.d.ts +17 -0
  18. package/dist/ctl/CtlMarkdownRenderer.js +262 -0
  19. package/dist/ctl/CtlParser.d.ts +10 -0
  20. package/dist/ctl/CtlParser.js +331 -0
  21. package/dist/ctl/CtlValidator.d.ts +12 -0
  22. package/dist/ctl/CtlValidator.js +207 -0
  23. package/dist/ctl/ResourceTypeClassifier.d.ts +21 -0
  24. package/dist/ctl/ResourceTypeClassifier.js +126 -0
  25. package/dist/ctl/index.d.ts +12 -0
  26. package/dist/ctl/index.js +9 -0
  27. package/dist/filtering/GitIgnoreFilter.d.ts +7 -0
  28. package/dist/filtering/GitIgnoreFilter.js +32 -0
  29. package/dist/filtering/IGitIgnoreFilter.d.ts +3 -0
  30. package/dist/filtering/IGitIgnoreFilter.js +1 -0
  31. package/dist/filtering/index.d.ts +2 -0
  32. package/dist/filtering/index.js +1 -0
  33. package/dist/index.d.ts +19 -0
  34. package/dist/index.js +8 -0
  35. package/dist/parsing/CanonObjectParser.d.ts +21 -0
  36. package/dist/parsing/CanonObjectParser.js +242 -0
  37. package/dist/parsing/CanonParser.d.ts +21 -0
  38. package/dist/parsing/CanonParser.js +457 -0
  39. package/dist/parsing/ICanonObjectParser.d.ts +7 -0
  40. package/dist/parsing/ICanonObjectParser.js +1 -0
  41. package/dist/parsing/PropertyMetadata.d.ts +7 -0
  42. package/dist/parsing/PropertyMetadata.js +7 -0
  43. package/dist/parsing/index.d.ts +6 -0
  44. package/dist/parsing/index.js +3 -0
  45. package/dist/repositories/CompositeCanonDocumentRepository.d.ts +28 -0
  46. package/dist/repositories/CompositeCanonDocumentRepository.js +125 -0
  47. package/dist/repositories/FileSystemCanonDocumentRepository.d.ts +28 -0
  48. package/dist/repositories/FileSystemCanonDocumentRepository.js +295 -0
  49. package/dist/repositories/HttpCanonDocumentRepository.d.ts +24 -0
  50. package/dist/repositories/HttpCanonDocumentRepository.js +79 -0
  51. package/dist/repositories/InMemoryCanonDocumentRepository.d.ts +23 -0
  52. package/dist/repositories/InMemoryCanonDocumentRepository.js +149 -0
  53. package/dist/repositories/PublisherConfig.d.ts +12 -0
  54. package/dist/repositories/PublisherConfig.js +62 -0
  55. package/dist/repositories/PublisherIndex.d.ts +20 -0
  56. package/dist/repositories/PublisherIndex.js +127 -0
  57. package/dist/repositories/RepositoryFactory.d.ts +6 -0
  58. package/dist/repositories/RepositoryFactory.js +13 -0
  59. package/dist/repositories/index.d.ts +9 -0
  60. package/dist/repositories/index.js +7 -0
  61. package/dist/resolution/CanonUri.d.ts +10 -0
  62. package/dist/resolution/CanonUri.js +55 -0
  63. package/dist/resolution/CanonUriBuilder.d.ts +12 -0
  64. package/dist/resolution/CanonUriBuilder.js +51 -0
  65. package/dist/resolution/ResourceResolutionResult.d.ts +9 -0
  66. package/dist/resolution/ResourceResolutionResult.js +1 -0
  67. package/dist/resolution/ResourceResolver.d.ts +27 -0
  68. package/dist/resolution/ResourceResolver.js +266 -0
  69. package/dist/resolution/TypeResolver.d.ts +15 -0
  70. package/dist/resolution/TypeResolver.js +110 -0
  71. package/dist/resolution/index.d.ts +6 -0
  72. package/dist/resolution/index.js +4 -0
  73. package/dist/statements/BooleanStatement.d.ts +3 -0
  74. package/dist/statements/BooleanStatement.js +3 -0
  75. package/dist/statements/EmbeddedStatement.d.ts +4 -0
  76. package/dist/statements/EmbeddedStatement.js +3 -0
  77. package/dist/statements/IStatement.d.ts +2 -0
  78. package/dist/statements/IStatement.js +1 -0
  79. package/dist/statements/ListStatement.d.ts +4 -0
  80. package/dist/statements/ListStatement.js +3 -0
  81. package/dist/statements/NumberStatement.d.ts +4 -0
  82. package/dist/statements/NumberStatement.js +10 -0
  83. package/dist/statements/ReferenceStatement.d.ts +5 -0
  84. package/dist/statements/ReferenceStatement.js +10 -0
  85. package/dist/statements/ScalarStatement.d.ts +3 -0
  86. package/dist/statements/ScalarStatement.js +3 -0
  87. package/dist/statements/Statement.d.ts +6 -0
  88. package/dist/statements/Statement.js +4 -0
  89. package/dist/statements/StringStatement.d.ts +4 -0
  90. package/dist/statements/StringStatement.js +10 -0
  91. package/dist/statements/index.d.ts +9 -0
  92. package/dist/statements/index.js +8 -0
  93. package/dist/validation/CanonObjectValidator.d.ts +21 -0
  94. package/dist/validation/CanonObjectValidator.js +150 -0
  95. package/dist/validation/ICanonObjectValidator.d.ts +7 -0
  96. package/dist/validation/ICanonObjectValidator.js +1 -0
  97. package/dist/validation/OntologyValidationError.d.ts +15 -0
  98. package/dist/validation/OntologyValidationError.js +25 -0
  99. package/dist/validation/OntologyValidationResult.d.ts +7 -0
  100. package/dist/validation/OntologyValidationResult.js +8 -0
  101. package/dist/validation/ValidationContext.d.ts +6 -0
  102. package/dist/validation/ValidationContext.js +10 -0
  103. package/dist/validation/ValidationSeverity.d.ts +4 -0
  104. package/dist/validation/ValidationSeverity.js +5 -0
  105. package/dist/validation/index.d.ts +10 -0
  106. package/dist/validation/index.js +7 -0
  107. package/dist/validation/rules/document/EmbeddedCanonNoExplicitTypeRule.d.ts +8 -0
  108. package/dist/validation/rules/document/EmbeddedCanonNoExplicitTypeRule.js +53 -0
  109. package/dist/validation/rules/document/IDocumentValidationRule.d.ts +6 -0
  110. package/dist/validation/rules/document/IDocumentValidationRule.js +1 -0
  111. package/dist/validation/rules/document/NamespacePrefixRule.d.ts +10 -0
  112. package/dist/validation/rules/document/NamespacePrefixRule.js +51 -0
  113. package/dist/validation/rules/document/PropertyTypeSpecificityRule.d.ts +11 -0
  114. package/dist/validation/rules/document/PropertyTypeSpecificityRule.js +89 -0
  115. package/dist/validation/rules/document/ResourceNamingRule.d.ts +12 -0
  116. package/dist/validation/rules/document/ResourceNamingRule.js +79 -0
  117. package/dist/validation/rules/document/SubjectCanonTypeRequiredRule.d.ts +7 -0
  118. package/dist/validation/rules/document/SubjectCanonTypeRequiredRule.js +33 -0
  119. package/dist/validation/rules/document/index.d.ts +6 -0
  120. package/dist/validation/rules/document/index.js +5 -0
  121. package/dist/validation/rules/normalizeToStringList.d.ts +1 -0
  122. package/dist/validation/rules/normalizeToStringList.js +9 -0
  123. package/dist/validation/rules/repository/AmbiguousReferenceRule.d.ts +14 -0
  124. package/dist/validation/rules/repository/AmbiguousReferenceRule.js +155 -0
  125. package/dist/validation/rules/repository/ClassDefinitionRule.d.ts +12 -0
  126. package/dist/validation/rules/repository/ClassDefinitionRule.js +205 -0
  127. package/dist/validation/rules/repository/ClassHierarchyCycleRule.d.ts +11 -0
  128. package/dist/validation/rules/repository/ClassHierarchyCycleRule.js +98 -0
  129. package/dist/validation/rules/repository/DefinitionPropertyReferenceRule.d.ts +13 -0
  130. package/dist/validation/rules/repository/DefinitionPropertyReferenceRule.js +162 -0
  131. package/dist/validation/rules/repository/IRepositoryValidationRule.d.ts +7 -0
  132. package/dist/validation/rules/repository/IRepositoryValidationRule.js +1 -0
  133. package/dist/validation/rules/repository/ImportExistenceRule.d.ts +12 -0
  134. package/dist/validation/rules/repository/ImportExistenceRule.js +124 -0
  135. package/dist/validation/rules/repository/InstancePropertyReferenceRule.d.ts +13 -0
  136. package/dist/validation/rules/repository/InstancePropertyReferenceRule.js +161 -0
  137. package/dist/validation/rules/repository/NamespaceImportCycleRule.d.ts +11 -0
  138. package/dist/validation/rules/repository/NamespaceImportCycleRule.js +85 -0
  139. package/dist/validation/rules/repository/ObjectPropertyImportRule.d.ts +9 -0
  140. package/dist/validation/rules/repository/ObjectPropertyImportRule.js +113 -0
  141. package/dist/validation/rules/repository/ObjectPropertyValueValidationRule.d.ts +12 -0
  142. package/dist/validation/rules/repository/ObjectPropertyValueValidationRule.js +281 -0
  143. package/dist/validation/rules/repository/PropertyDomainRule.d.ts +14 -0
  144. package/dist/validation/rules/repository/PropertyDomainRule.js +221 -0
  145. package/dist/validation/rules/repository/PropertyHierarchyCycleRule.d.ts +11 -0
  146. package/dist/validation/rules/repository/PropertyHierarchyCycleRule.js +104 -0
  147. package/dist/validation/rules/repository/PropertyRangeReferenceRule.d.ts +13 -0
  148. package/dist/validation/rules/repository/PropertyRangeReferenceRule.js +184 -0
  149. package/dist/validation/rules/repository/PropertyRangeRequiredRule.d.ts +8 -0
  150. package/dist/validation/rules/repository/PropertyRangeRequiredRule.js +40 -0
  151. package/dist/validation/rules/repository/PropertyValueTypeRule.d.ts +11 -0
  152. package/dist/validation/rules/repository/PropertyValueTypeRule.js +171 -0
  153. package/dist/validation/rules/repository/SubClassOfReferenceRule.d.ts +11 -0
  154. package/dist/validation/rules/repository/SubClassOfReferenceRule.js +133 -0
  155. package/dist/validation/rules/repository/SubPropertyOfReferenceRule.d.ts +11 -0
  156. package/dist/validation/rules/repository/SubPropertyOfReferenceRule.js +133 -0
  157. package/dist/validation/rules/repository/TypeAmbiguityRule.d.ts +10 -0
  158. package/dist/validation/rules/repository/TypeAmbiguityRule.js +104 -0
  159. package/dist/validation/rules/repository/UnresolvedReferenceRule.d.ts +11 -0
  160. package/dist/validation/rules/repository/UnresolvedReferenceRule.js +91 -0
  161. package/dist/validation/rules/repository/XsdImportRule.d.ts +11 -0
  162. package/dist/validation/rules/repository/XsdImportRule.js +125 -0
  163. package/dist/validation/rules/repository/index.d.ts +20 -0
  164. package/dist/validation/rules/repository/index.js +19 -0
  165. package/package.json +82 -0
@@ -0,0 +1,127 @@
1
+ import { VersionOperator } from '@canon-protocol/types/document/models/enums';
2
+ import { PublisherConfigResolver } from './PublisherConfig.js';
3
+ export class PublisherIndex {
4
+ indexCache = new Map();
5
+ configResolver;
6
+ constructor(configResolver) {
7
+ this.configResolver = configResolver ?? new PublisherConfigResolver();
8
+ }
9
+ async resolveVersion(publisher, import_) {
10
+ const packageVersions = await this.getPackageVersions(publisher, import_.packageName);
11
+ if (packageVersions.length === 0) {
12
+ return null;
13
+ }
14
+ const compatible = packageVersions.filter(v => this.isVersionCompatible(v, import_.version, import_.versionOperator));
15
+ if (compatible.length === 0) {
16
+ return null;
17
+ }
18
+ compatible.sort((a, b) => this.compareVersionStrings(b, a));
19
+ return compatible[0];
20
+ }
21
+ async getHighestVersion(publisher, packageName) {
22
+ const versions = await this.getPackageVersions(publisher, packageName);
23
+ if (versions.length === 0)
24
+ return null;
25
+ const sorted = [...versions].sort((a, b) => this.compareVersionStrings(b, a));
26
+ return sorted[0];
27
+ }
28
+ async getPackageUrl(publisher, packageName, version) {
29
+ const config = await this.configResolver.getConfig(publisher);
30
+ return this.configResolver.resolvePackageUrl(publisher, packageName, version, config);
31
+ }
32
+ async getPackageVersions(publisher, packageName) {
33
+ let index = this.indexCache.get(publisher);
34
+ if (!index) {
35
+ index = await this.fetchIndex(publisher);
36
+ this.indexCache.set(publisher, index);
37
+ }
38
+ return index.get(packageName) ?? [];
39
+ }
40
+ async fetchIndex(publisher) {
41
+ const config = await this.configResolver.getConfig(publisher);
42
+ const url = this.configResolver.resolveIndexUrl(publisher, config);
43
+ const response = await fetch(url);
44
+ if (!response.ok) {
45
+ throw new Error(`Failed to fetch publisher index: ${url} (${response.status} ${response.statusText})`);
46
+ }
47
+ const text = await response.text();
48
+ return PublisherIndex.parseIndex(text);
49
+ }
50
+ static parseIndex(text) {
51
+ const index = new Map();
52
+ for (const line of text.split('\n')) {
53
+ const trimmed = line.trim();
54
+ if (!trimmed || trimmed.startsWith('#'))
55
+ continue;
56
+ const slashIndex = trimmed.indexOf('/');
57
+ if (slashIndex === -1)
58
+ continue;
59
+ const pkg = trimmed.substring(0, slashIndex);
60
+ const version = trimmed.substring(slashIndex + 1);
61
+ if (!pkg || !version)
62
+ continue;
63
+ const versions = index.get(pkg);
64
+ if (versions) {
65
+ versions.push(version);
66
+ }
67
+ else {
68
+ index.set(pkg, [version]);
69
+ }
70
+ }
71
+ return index;
72
+ }
73
+ isVersionCompatible(candidateStr, requiredVersion, operator) {
74
+ const candidate = PublisherIndex.parseVersion(candidateStr);
75
+ if (!candidate)
76
+ return false;
77
+ switch (operator) {
78
+ case VersionOperator.Any:
79
+ return true;
80
+ case VersionOperator.Exact:
81
+ return (candidate.major === requiredVersion.major &&
82
+ candidate.minor === requiredVersion.minor &&
83
+ candidate.patch === requiredVersion.patch);
84
+ case VersionOperator.Compatible:
85
+ return (candidate.major === requiredVersion.major &&
86
+ candidate.minor === requiredVersion.minor &&
87
+ candidate.patch >= requiredVersion.patch);
88
+ case VersionOperator.Major:
89
+ if (candidate.major !== requiredVersion.major)
90
+ return false;
91
+ if (candidate.minor > requiredVersion.minor)
92
+ return true;
93
+ if (candidate.minor === requiredVersion.minor) {
94
+ return candidate.patch >= requiredVersion.patch;
95
+ }
96
+ return false;
97
+ default:
98
+ return false;
99
+ }
100
+ }
101
+ static parseVersion(str) {
102
+ const parts = str.split('.');
103
+ if (parts.length < 2)
104
+ return null;
105
+ const major = parseInt(parts[0], 10);
106
+ const minor = parseInt(parts[1], 10);
107
+ const patch = parts.length >= 3 ? parseInt(parts[2], 10) : 0;
108
+ if (isNaN(major) || isNaN(minor) || isNaN(patch))
109
+ return null;
110
+ return { major, minor, patch };
111
+ }
112
+ compareVersionStrings(a, b) {
113
+ const va = PublisherIndex.parseVersion(a);
114
+ const vb = PublisherIndex.parseVersion(b);
115
+ if (!va && !vb)
116
+ return 0;
117
+ if (!va)
118
+ return -1;
119
+ if (!vb)
120
+ return 1;
121
+ if (va.major !== vb.major)
122
+ return va.major - vb.major;
123
+ if (va.minor !== vb.minor)
124
+ return va.minor - vb.minor;
125
+ return va.patch - vb.patch;
126
+ }
127
+ }
@@ -0,0 +1,6 @@
1
+ import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
2
+ import type { ICanonParser } from '@canon-protocol/types/document/parsing';
3
+ export declare class RepositoryFactory {
4
+ static createComposite(cachePath?: string, workspacePath?: string, parser?: ICanonParser): ICanonDocumentRepository;
5
+ static createFromEnvironment(parser?: ICanonParser): ICanonDocumentRepository;
6
+ }
@@ -0,0 +1,13 @@
1
+ import { CompositeCanonDocumentRepository } from './CompositeCanonDocumentRepository.js';
2
+ export class RepositoryFactory {
3
+ static createComposite(cachePath, workspacePath, parser) {
4
+ const cache = cachePath ?? '.canon';
5
+ const workspace = workspacePath ?? '.';
6
+ return new CompositeCanonDocumentRepository(cache, workspace, parser);
7
+ }
8
+ static createFromEnvironment(parser) {
9
+ const cachePath = process.env.CANON_PACKAGE_CACHE ?? '.canon';
10
+ const workspacePath = process.env.CANON_WORKSPACE_PATH ?? '.';
11
+ return RepositoryFactory.createComposite(cachePath, workspacePath, parser);
12
+ }
13
+ }
@@ -0,0 +1,9 @@
1
+ export { InMemoryCanonDocumentRepository } from './InMemoryCanonDocumentRepository.js';
2
+ export { FileSystemCanonDocumentRepository } from './FileSystemCanonDocumentRepository.js';
3
+ export { CompositeCanonDocumentRepository, DocumentLocation } from './CompositeCanonDocumentRepository.js';
4
+ export { RepositoryFactory } from './RepositoryFactory.js';
5
+ export { HttpCanonDocumentRepository } from './HttpCanonDocumentRepository.js';
6
+ export { PublisherIndex } from './PublisherIndex.js';
7
+ export { PublisherConfigResolver } from './PublisherConfig.js';
8
+ export type { PublisherConfig } from './PublisherConfig.js';
9
+ export type { ICanonDocumentRepository, CanonDocument, DocumentReference } from '@canon-protocol/types/document/models';
@@ -0,0 +1,7 @@
1
+ export { InMemoryCanonDocumentRepository } from './InMemoryCanonDocumentRepository.js';
2
+ export { FileSystemCanonDocumentRepository } from './FileSystemCanonDocumentRepository.js';
3
+ export { CompositeCanonDocumentRepository, DocumentLocation } from './CompositeCanonDocumentRepository.js';
4
+ export { RepositoryFactory } from './RepositoryFactory.js';
5
+ export { HttpCanonDocumentRepository } from './HttpCanonDocumentRepository.js';
6
+ export { PublisherIndex } from './PublisherIndex.js';
7
+ export { PublisherConfigResolver } from './PublisherConfig.js';
@@ -0,0 +1,10 @@
1
+ import type { Version } from '@canon-protocol/types/document/models/types';
2
+ export declare class CanonUri {
3
+ publisher: string;
4
+ package_: string;
5
+ name: string;
6
+ version: Version;
7
+ constructor(publisher: string, package_: string, name: string, version: Version);
8
+ static parse(canonString: string): CanonUri;
9
+ toString(): string;
10
+ }
@@ -0,0 +1,55 @@
1
+ export class CanonUri {
2
+ publisher;
3
+ package_;
4
+ name;
5
+ version;
6
+ constructor(publisher, package_, name, version) {
7
+ this.publisher = publisher;
8
+ this.package_ = package_;
9
+ this.name = name;
10
+ this.version = version;
11
+ }
12
+ static parse(canonString) {
13
+ if (!canonString || canonString.trim().length === 0) {
14
+ throw new Error('Canon URI string cannot be null or empty');
15
+ }
16
+ const parts = canonString.split('@');
17
+ if (parts.length !== 2) {
18
+ throw new Error(`Invalid canon URI format: ${canonString}. Expected format: publisher/package/name@version`);
19
+ }
20
+ const pathPart = parts[0];
21
+ const versionPart = parts[1];
22
+ const segments = pathPart.split('/');
23
+ if (segments.length !== 3) {
24
+ throw new Error(`Invalid canon URI path format: ${pathPart}. Expected format: publisher/package/name`);
25
+ }
26
+ const versionParts = versionPart.split('.').map(Number);
27
+ const version = {
28
+ major: versionParts[0] || 0,
29
+ minor: versionParts[1] || 0,
30
+ patch: versionParts[2] || 0,
31
+ toString: () => `${versionParts[0] || 0}.${versionParts[1] || 0}.${versionParts[2] || 0}`,
32
+ equals: (obj) => {
33
+ if (!obj || typeof obj !== 'object')
34
+ return false;
35
+ return obj.major === (versionParts[0] || 0) &&
36
+ obj.minor === (versionParts[1] || 0) &&
37
+ obj.patch === (versionParts[2] || 0);
38
+ },
39
+ getHashCode: () => {
40
+ return ((versionParts[0] || 0) << 20) | ((versionParts[1] || 0) << 10) | (versionParts[2] || 0);
41
+ },
42
+ compareTo: (other) => {
43
+ if ((versionParts[0] || 0) !== other.major)
44
+ return (versionParts[0] || 0) - other.major;
45
+ if ((versionParts[1] || 0) !== other.minor)
46
+ return (versionParts[1] || 0) - other.minor;
47
+ return (versionParts[2] || 0) - other.patch;
48
+ }
49
+ };
50
+ return new CanonUri(segments[0], segments[1], segments[2], version);
51
+ }
52
+ toString() {
53
+ return `${this.publisher}/${this.package_}/${this.name}@${this.version.major}.${this.version.minor}.${this.version.patch}`;
54
+ }
55
+ }
@@ -0,0 +1,12 @@
1
+ import type { CanonDocument, Version } from '@canon-protocol/types/document/models/types';
2
+ import type { ResourceResolver } from './ResourceResolver.js';
3
+ import type { ResourceResolutionResult } from './ResourceResolutionResult.js';
4
+ import { CanonUri } from './CanonUri.js';
5
+ export declare class CanonUriBuilder {
6
+ private readonly resourceResolver;
7
+ constructor(resourceResolver: ResourceResolver);
8
+ buildFromNameAsync(entityName: string, currentDocument: CanonDocument): Promise<CanonUri | null>;
9
+ buildFromName(entityName: string, entityIndex: Map<string, ResourceResolutionResult>, currentDocument: CanonDocument): CanonUri | null;
10
+ create(publisher: string, package_: string, name: string, version: Version): CanonUri;
11
+ private findPackageNameForAlias;
12
+ }
@@ -0,0 +1,51 @@
1
+ import { CanonUri } from './CanonUri.js';
2
+ export class CanonUriBuilder {
3
+ resourceResolver;
4
+ constructor(resourceResolver) {
5
+ this.resourceResolver = resourceResolver;
6
+ }
7
+ async buildFromNameAsync(entityName, currentDocument) {
8
+ const result = await this.resourceResolver.resolveEntityAsync(entityName, currentDocument);
9
+ return result?.uri ?? null;
10
+ }
11
+ buildFromName(entityName, entityIndex, currentDocument) {
12
+ if (entityName.includes('.')) {
13
+ const parts = entityName.split('.');
14
+ const alias = parts[0];
15
+ const name = parts[1];
16
+ const packageName = this.findPackageNameForAlias(currentDocument, alias);
17
+ if (packageName) {
18
+ for (const result of entityIndex.values()) {
19
+ if (result.entityName === name && result.uri.package_ === packageName) {
20
+ return result.uri;
21
+ }
22
+ }
23
+ }
24
+ return null;
25
+ }
26
+ const entityResult = entityIndex.get(entityName);
27
+ if (entityResult) {
28
+ return entityResult.uri;
29
+ }
30
+ return null;
31
+ }
32
+ create(publisher, package_, name, version) {
33
+ return new CanonUri(publisher, package_, name, version);
34
+ }
35
+ findPackageNameForAlias(document, alias) {
36
+ if (!document.metadata.imports) {
37
+ return null;
38
+ }
39
+ for (const [_publisher, imports] of Object.entries(document.metadata.imports)) {
40
+ for (const import_ of imports) {
41
+ if (import_.alias === alias) {
42
+ return import_.packageName;
43
+ }
44
+ if (!import_.alias && import_.packageName === alias) {
45
+ return import_.packageName;
46
+ }
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+ }
@@ -0,0 +1,9 @@
1
+ import type { CanonUri } from './CanonUri.js';
2
+ export interface ResourceResolutionResult {
3
+ entityName: string;
4
+ uri: CanonUri;
5
+ entity: Record<string, any>;
6
+ definedInNamespace: string;
7
+ isImported: boolean;
8
+ importPath?: string;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
2
+ import type { CanonDocument } from '@canon-protocol/types/document/models/types';
3
+ import type { ResourceResolutionResult } from './ResourceResolutionResult.js';
4
+ export interface ILogger {
5
+ debug(message: string, ...args: any[]): void;
6
+ info(message: string, ...args: any[]): void;
7
+ warn(message: string, ...args: any[]): void;
8
+ error(message: string, error?: Error, ...args: any[]): void;
9
+ }
10
+ export declare class ResourceResolver {
11
+ private readonly cache;
12
+ private readonly repository;
13
+ private readonly logger;
14
+ constructor(repository: ICanonDocumentRepository, logger?: ILogger);
15
+ resolveEntityAsync(entityName: string, currentDocument: CanonDocument): Promise<ResourceResolutionResult | null>;
16
+ resolveAllEntitiesAsync(entityName: string, currentDocument: CanonDocument): Promise<ResourceResolutionResult[]>;
17
+ private buildAllEntitiesIndexAsync;
18
+ buildEntityIndexAsync(document: CanonDocument): Promise<Map<string, ResourceResolutionResult>>;
19
+ private buildEntityIndexAsyncInternal;
20
+ private findDocumentForAlias;
21
+ clearCache(): void;
22
+ clearCacheForDocument(documentKey: string): void;
23
+ isSubclassOfAsync(className: string, parentClassName: string, document: CanonDocument): Promise<boolean>;
24
+ private isSubclassOfRecursiveAsync;
25
+ isSubpropertyOfAsync(propertyName: string, parentPropertyName: string, document: CanonDocument): Promise<boolean>;
26
+ private isSubpropertyOfRecursiveAsync;
27
+ }
@@ -0,0 +1,266 @@
1
+ import { CanonUri } from './CanonUri.js';
2
+ import { normalizeToStringList } from '../validation/rules/normalizeToStringList.js';
3
+ export class ResourceResolver {
4
+ cache = new Map();
5
+ repository;
6
+ logger;
7
+ constructor(repository, logger) {
8
+ this.repository = repository;
9
+ this.logger = logger;
10
+ }
11
+ async resolveEntityAsync(entityName, currentDocument) {
12
+ const documentKey = currentDocument.metadata?.namespace_?.toString() ?? 'unknown';
13
+ const docCache = this.cache.get(documentKey);
14
+ if (docCache) {
15
+ const cachedResult = docCache.get(entityName);
16
+ if (cachedResult) {
17
+ return cachedResult;
18
+ }
19
+ }
20
+ const entityIndex = await this.buildEntityIndexAsyncInternal(currentDocument, new Set(), '');
21
+ this.cache.set(documentKey, entityIndex);
22
+ return entityIndex.get(entityName) ?? null;
23
+ }
24
+ async resolveAllEntitiesAsync(entityName, currentDocument) {
25
+ const allEntities = await this.buildAllEntitiesIndexAsync(currentDocument, new Set(), '');
26
+ if (entityName.includes('.')) {
27
+ const parts = entityName.split('.');
28
+ const alias = parts[0];
29
+ const name = parts[1];
30
+ const aliasedDoc = await this.findDocumentForAlias(currentDocument, alias);
31
+ if (aliasedDoc) {
32
+ return await this.resolveAllEntitiesAsync(name, aliasedDoc);
33
+ }
34
+ return [];
35
+ }
36
+ return allEntities.filter(e => e.entityName === entityName);
37
+ }
38
+ async buildAllEntitiesIndexAsync(document, visitedNamespaces, importPath) {
39
+ const allEntities = [];
40
+ const currentNamespace = document.metadata?.namespace_?.toString() ?? 'unknown';
41
+ this.logger?.debug?.(`Building ALL entities index for namespace: ${currentNamespace}`);
42
+ if (visitedNamespaces.has(currentNamespace)) {
43
+ this.logger?.debug?.(`Skipping ${currentNamespace} - already visited (circular import prevention)`);
44
+ return allEntities;
45
+ }
46
+ visitedNamespaces.add(currentNamespace);
47
+ const currentPath = importPath.length === 0
48
+ ? currentNamespace
49
+ : `${importPath} → ${currentNamespace}`;
50
+ for (const [entityName, entityDef] of Object.entries(document.body)) {
51
+ if (entityDef && typeof entityDef === 'object' && !Array.isArray(entityDef)) {
52
+ const version = document.metadata.namespace_?.version ?? {
53
+ major: 1,
54
+ minor: 0,
55
+ patch: 0,
56
+ toString: () => '1.0.0',
57
+ equals: () => false,
58
+ getHashCode: () => 0,
59
+ compareTo: () => 0
60
+ };
61
+ allEntities.push({
62
+ entityName,
63
+ uri: new CanonUri(document.metadata.namespace_.publisher, document.metadata.namespace_.package_, entityName, version),
64
+ entity: entityDef,
65
+ definedInNamespace: currentNamespace,
66
+ isImported: importPath.length > 0,
67
+ importPath: currentPath
68
+ });
69
+ }
70
+ }
71
+ this.logger?.debug?.(`Collected ${allEntities.length} entities from ${currentNamespace}`);
72
+ if (document.metadata?.imports) {
73
+ const totalImports = Object.values(document.metadata.imports).reduce((sum, arr) => sum + arr.length, 0);
74
+ this.logger?.debug?.(`Processing ${totalImports} import(s) for ${currentNamespace}`);
75
+ for (const [publisher, imports] of Object.entries(document.metadata.imports)) {
76
+ for (const import_ of imports) {
77
+ try {
78
+ this.logger?.debug?.(`Resolving import: ${publisher}/${import_.packageName}`);
79
+ const importedDoc = await this.repository.getHighestCompatibleVersionAsync(publisher, import_);
80
+ if (importedDoc) {
81
+ this.logger?.debug?.(`Successfully loaded import: ${importedDoc.metadata?.namespace_?.toString()}`);
82
+ const importedEntities = await this.buildAllEntitiesIndexAsync(importedDoc, visitedNamespaces, currentPath);
83
+ allEntities.push(...importedEntities);
84
+ this.logger?.debug?.(`Added ${importedEntities.length} entities from import ${importedDoc.metadata?.namespace_?.toString()}`);
85
+ }
86
+ else {
87
+ this.logger?.warn?.(`Failed to load import: ${publisher}/${import_.packageName}`);
88
+ }
89
+ }
90
+ catch (error) {
91
+ const err = error;
92
+ this.logger?.error?.(`Failed to process import ${publisher}/${import_.packageName} for namespace ${currentNamespace}. Error: ${err.message}`, err);
93
+ throw new Error(`Failed to process import ${publisher}/${import_.packageName} for namespace ${currentNamespace}. ` +
94
+ `See inner exception for details.`, { cause: error });
95
+ }
96
+ }
97
+ }
98
+ }
99
+ return allEntities;
100
+ }
101
+ async buildEntityIndexAsync(document) {
102
+ return await this.buildEntityIndexAsyncInternal(document, new Set(), '');
103
+ }
104
+ async buildEntityIndexAsyncInternal(document, visitedNamespaces, importPath) {
105
+ const index = new Map();
106
+ const currentNamespace = document.metadata?.namespace_?.toString() ?? 'unknown';
107
+ this.logger?.debug?.(`Building entity index for namespace: ${currentNamespace}`);
108
+ if (visitedNamespaces.has(currentNamespace)) {
109
+ this.logger?.debug?.(`Skipping ${currentNamespace} - already visited (circular import prevention)`);
110
+ return index;
111
+ }
112
+ visitedNamespaces.add(currentNamespace);
113
+ const currentPath = importPath.length === 0
114
+ ? currentNamespace
115
+ : `${importPath} → ${currentNamespace}`;
116
+ let entitiesAddedCount = 0;
117
+ for (const [entityName, entityDef] of Object.entries(document.body)) {
118
+ if (entityDef && typeof entityDef === 'object' && !Array.isArray(entityDef)) {
119
+ if (!index.has(entityName)) {
120
+ const version = document.metadata.namespace_?.version ?? {
121
+ major: 1,
122
+ minor: 0,
123
+ patch: 0,
124
+ toString: () => '1.0.0',
125
+ equals: () => false,
126
+ getHashCode: () => 0,
127
+ compareTo: () => 0
128
+ };
129
+ index.set(entityName, {
130
+ entityName,
131
+ uri: new CanonUri(document.metadata.namespace_.publisher, document.metadata.namespace_.package_, entityName, version),
132
+ entity: entityDef,
133
+ definedInNamespace: currentNamespace,
134
+ isImported: importPath.length > 0,
135
+ importPath: currentPath
136
+ });
137
+ entitiesAddedCount++;
138
+ }
139
+ }
140
+ }
141
+ this.logger?.debug?.(`Indexed ${entitiesAddedCount} entities from ${currentNamespace}`);
142
+ if (document.metadata?.imports) {
143
+ const totalImports = Object.values(document.metadata.imports).reduce((sum, arr) => sum + arr.length, 0);
144
+ this.logger?.debug?.(`Processing ${totalImports} import(s) for ${currentNamespace}`);
145
+ for (const [publisher, imports] of Object.entries(document.metadata.imports)) {
146
+ for (const import_ of imports) {
147
+ try {
148
+ this.logger?.debug?.(`Resolving import: ${publisher}/${import_.packageName}`);
149
+ const importedDoc = await this.repository.getHighestCompatibleVersionAsync(publisher, import_);
150
+ if (importedDoc) {
151
+ this.logger?.debug?.(`Successfully loaded import: ${importedDoc.metadata?.namespace_?.toString()}`);
152
+ const importedIndex = await this.buildEntityIndexAsyncInternal(importedDoc, visitedNamespaces, currentPath);
153
+ let mergedCount = 0;
154
+ for (const [name, result] of importedIndex.entries()) {
155
+ if (!index.has(name)) {
156
+ index.set(name, result);
157
+ mergedCount++;
158
+ }
159
+ if (import_.alias && !name.includes('.')) {
160
+ const aliasedName = `${import_.alias}.${name}`;
161
+ if (!index.has(aliasedName)) {
162
+ index.set(aliasedName, result);
163
+ mergedCount++;
164
+ }
165
+ }
166
+ }
167
+ this.logger?.debug?.(`Merged ${mergedCount} entities from import ${importedDoc.metadata?.namespace_?.toString()}`);
168
+ }
169
+ else {
170
+ this.logger?.warn?.(`Failed to load import: ${publisher}/${import_.packageName}`);
171
+ }
172
+ }
173
+ catch (error) {
174
+ const err = error;
175
+ this.logger?.error?.(`Failed to process import ${publisher}/${import_.packageName} for namespace ${currentNamespace}. Error: ${err.message}`, err);
176
+ throw new Error(`Failed to process import ${publisher}/${import_.packageName} for namespace ${currentNamespace}. ` +
177
+ `See inner exception for details.`, { cause: error });
178
+ }
179
+ }
180
+ }
181
+ }
182
+ return index;
183
+ }
184
+ async findDocumentForAlias(document, alias) {
185
+ if (!document.metadata?.imports) {
186
+ return null;
187
+ }
188
+ for (const [publisher, imports] of Object.entries(document.metadata.imports)) {
189
+ for (const import_ of imports) {
190
+ if (import_.alias === alias) {
191
+ return await this.repository.getHighestCompatibleVersionAsync(publisher, import_);
192
+ }
193
+ if (!import_.alias && import_.packageName === alias) {
194
+ return await this.repository.getHighestCompatibleVersionAsync(publisher, import_);
195
+ }
196
+ }
197
+ }
198
+ return null;
199
+ }
200
+ clearCache() {
201
+ this.cache.clear();
202
+ }
203
+ clearCacheForDocument(documentKey) {
204
+ this.cache.delete(documentKey);
205
+ }
206
+ async isSubclassOfAsync(className, parentClassName, document) {
207
+ if (className === parentClassName) {
208
+ return true;
209
+ }
210
+ const visited = new Set();
211
+ return await this.isSubclassOfRecursiveAsync(className, parentClassName, document, visited);
212
+ }
213
+ async isSubclassOfRecursiveAsync(className, parentClassName, document, visited) {
214
+ if (visited.has(className)) {
215
+ return false;
216
+ }
217
+ visited.add(className);
218
+ const classResolution = await this.resolveEntityAsync(className, document);
219
+ if (!classResolution?.entity) {
220
+ return false;
221
+ }
222
+ const subClassOfValue = classResolution.entity['subClassOf'];
223
+ if (subClassOfValue) {
224
+ const parentClasses = normalizeToStringList(subClassOfValue);
225
+ for (const parentClass of parentClasses) {
226
+ if (parentClass === parentClassName) {
227
+ return true;
228
+ }
229
+ if (await this.isSubclassOfRecursiveAsync(parentClass, parentClassName, document, visited)) {
230
+ return true;
231
+ }
232
+ }
233
+ }
234
+ return false;
235
+ }
236
+ async isSubpropertyOfAsync(propertyName, parentPropertyName, document) {
237
+ if (propertyName === parentPropertyName) {
238
+ return true;
239
+ }
240
+ const visited = new Set();
241
+ return await this.isSubpropertyOfRecursiveAsync(propertyName, parentPropertyName, document, visited);
242
+ }
243
+ async isSubpropertyOfRecursiveAsync(propertyName, parentPropertyName, document, visited) {
244
+ if (visited.has(propertyName)) {
245
+ return false;
246
+ }
247
+ visited.add(propertyName);
248
+ const propertyResolution = await this.resolveEntityAsync(propertyName, document);
249
+ if (!propertyResolution?.entity) {
250
+ return false;
251
+ }
252
+ const subPropertyOfValue = propertyResolution.entity['subPropertyOf'];
253
+ if (subPropertyOfValue) {
254
+ const parentProperties = normalizeToStringList(subPropertyOfValue);
255
+ for (const parentProperty of parentProperties) {
256
+ if (parentProperty === parentPropertyName) {
257
+ return true;
258
+ }
259
+ if (await this.isSubpropertyOfRecursiveAsync(parentProperty, parentPropertyName, document, visited)) {
260
+ return true;
261
+ }
262
+ }
263
+ }
264
+ return false;
265
+ }
266
+ }
@@ -0,0 +1,15 @@
1
+ import type { CanonDocument } from '@canon-protocol/types/document/models/types';
2
+ import type { CanonUri } from './CanonUri.js';
3
+ import type { ResourceResolver } from './ResourceResolver.js';
4
+ export declare class TypeResolver {
5
+ private static readonly KNOWN_XSD_DATATYPES;
6
+ private readonly resourceResolver;
7
+ constructor(resourceResolver: ResourceResolver);
8
+ isXsdDatatype(uri: CanonUri | null | undefined): boolean;
9
+ isLiteralType(uri: CanonUri | null | undefined): boolean;
10
+ isKnownXsdDatatypeName(typeName: string): boolean;
11
+ isClassTypeAsync(typeName: string, currentDocument: CanonDocument): Promise<boolean>;
12
+ getPropertyTypeClassification(propertyType: string | null | undefined): string;
13
+ isEffectiveDatatypeProperty(propertyTypeClassification: string, rangeUri: CanonUri | null | undefined): boolean;
14
+ isEffectiveObjectProperty(propertyTypeClassification: string, rangeUri: CanonUri | null | undefined): boolean;
15
+ }