@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,457 @@
|
|
|
1
|
+
import * as yaml from 'js-yaml';
|
|
2
|
+
export class CanonParser {
|
|
3
|
+
parse(yamlText) {
|
|
4
|
+
const result = this.parseWithErrors(yamlText);
|
|
5
|
+
if (!result.isValid) {
|
|
6
|
+
const firstError = result.errors[0];
|
|
7
|
+
throw new Error(`YAML parse error at line ${firstError.line}, column ${firstError.column}: ${firstError.message}`);
|
|
8
|
+
}
|
|
9
|
+
return result.document;
|
|
10
|
+
}
|
|
11
|
+
parseWithErrors(yamlText) {
|
|
12
|
+
const errors = [];
|
|
13
|
+
let document = undefined;
|
|
14
|
+
try {
|
|
15
|
+
yamlText = yamlText.replace(/^\uFEFF/, '');
|
|
16
|
+
const rawData = yaml.load(yamlText);
|
|
17
|
+
if (!rawData || typeof rawData !== 'object') {
|
|
18
|
+
document = {
|
|
19
|
+
metadata: this.createEmptyMetadata(),
|
|
20
|
+
body: {},
|
|
21
|
+
toString: () => 'CanonDocument(empty)'
|
|
22
|
+
};
|
|
23
|
+
return { document, errors, isValid: true };
|
|
24
|
+
}
|
|
25
|
+
const metadata = this.extractMetadata(rawData);
|
|
26
|
+
const body = this.extractBody(rawData, metadata);
|
|
27
|
+
document = {
|
|
28
|
+
metadata,
|
|
29
|
+
body,
|
|
30
|
+
toString: function () {
|
|
31
|
+
return this.metadata.namespace_
|
|
32
|
+
? `CanonDocument(${this.metadata.namespace_.publisher}/${this.metadata.namespace_.package_})`
|
|
33
|
+
: 'CanonDocument(no namespace)';
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return { document, errors, isValid: true };
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const err = error;
|
|
40
|
+
const parseError = {
|
|
41
|
+
message: err.message || 'Unknown parse error',
|
|
42
|
+
line: err.mark?.line ?? 0,
|
|
43
|
+
column: err.mark?.column ?? 0,
|
|
44
|
+
errorType: err.name === 'YAMLException' ? 'SyntaxError' : 'Unknown',
|
|
45
|
+
toString: () => `${err.name === 'YAMLException' ? 'SyntaxError' : 'Unknown'} at line ${err.mark?.line ?? 0}: ${err.message || 'Unknown parse error'}`
|
|
46
|
+
};
|
|
47
|
+
errors.push(parseError);
|
|
48
|
+
return { document: undefined, errors, isValid: false };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
save(document) {
|
|
52
|
+
const output = {};
|
|
53
|
+
if (document.metadata.namespace_) {
|
|
54
|
+
const ns = document.metadata.namespace_;
|
|
55
|
+
const packageEntry = {
|
|
56
|
+
type: 'Package',
|
|
57
|
+
publisher: ns.publisher
|
|
58
|
+
};
|
|
59
|
+
if (ns.version) {
|
|
60
|
+
packageEntry.version = `${ns.version.major}.${ns.version.minor}.${ns.version.patch}`;
|
|
61
|
+
}
|
|
62
|
+
if (document.metadata.imports) {
|
|
63
|
+
packageEntry.imports = this.serializeImports(document.metadata.imports);
|
|
64
|
+
}
|
|
65
|
+
output[ns.package_] = packageEntry;
|
|
66
|
+
}
|
|
67
|
+
Object.assign(output, document.body);
|
|
68
|
+
return yaml.dump(output, {
|
|
69
|
+
indent: 2,
|
|
70
|
+
noRefs: true,
|
|
71
|
+
sortKeys: false
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
createEmptyMetadata() {
|
|
75
|
+
return {
|
|
76
|
+
get allImports() {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
addAllImportsGetter(metadata) {
|
|
82
|
+
const imports = metadata.imports;
|
|
83
|
+
Object.defineProperty(metadata, 'allImports', {
|
|
84
|
+
get: function () {
|
|
85
|
+
if (!imports)
|
|
86
|
+
return [];
|
|
87
|
+
const result = [];
|
|
88
|
+
for (const importList of Object.values(imports)) {
|
|
89
|
+
result.push(...importList);
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
},
|
|
93
|
+
enumerable: true,
|
|
94
|
+
configurable: true
|
|
95
|
+
});
|
|
96
|
+
return metadata;
|
|
97
|
+
}
|
|
98
|
+
createVersion(major, minor, patch) {
|
|
99
|
+
const version = {
|
|
100
|
+
major,
|
|
101
|
+
minor,
|
|
102
|
+
patch,
|
|
103
|
+
toString: () => `${major}.${minor}.${patch}`,
|
|
104
|
+
equals: (obj) => {
|
|
105
|
+
if (!obj || typeof obj !== 'object')
|
|
106
|
+
return false;
|
|
107
|
+
return obj.major === major && obj.minor === minor && obj.patch === patch;
|
|
108
|
+
},
|
|
109
|
+
getHashCode: () => {
|
|
110
|
+
return (major << 20) | (minor << 10) | patch;
|
|
111
|
+
},
|
|
112
|
+
compareTo: (other) => {
|
|
113
|
+
if (major !== other.major)
|
|
114
|
+
return major - other.major;
|
|
115
|
+
if (minor !== other.minor)
|
|
116
|
+
return minor - other.minor;
|
|
117
|
+
return patch - other.patch;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
return version;
|
|
121
|
+
}
|
|
122
|
+
extractMetadata(rawData) {
|
|
123
|
+
const metadata = this.createEmptyMetadata();
|
|
124
|
+
for (const [key, value] of Object.entries(rawData)) {
|
|
125
|
+
if (value && typeof value === 'object' && value.type === 'Package') {
|
|
126
|
+
metadata.type_ = 'Package';
|
|
127
|
+
const packageName = key;
|
|
128
|
+
const publisher = value.publisher;
|
|
129
|
+
const version = value.version ? this.parseVersion(value.version) : undefined;
|
|
130
|
+
if (publisher && packageName) {
|
|
131
|
+
metadata.namespace_ = {
|
|
132
|
+
publisher,
|
|
133
|
+
package_: packageName,
|
|
134
|
+
version,
|
|
135
|
+
toString: function () {
|
|
136
|
+
return `${this.publisher}/${this.package_}@${this.version?.major ?? 1}.${this.version?.minor ?? 0}.${this.version?.patch ?? 0}`;
|
|
137
|
+
},
|
|
138
|
+
equals: (obj) => {
|
|
139
|
+
if (!obj || typeof obj !== 'object')
|
|
140
|
+
return false;
|
|
141
|
+
return obj.publisher === publisher && obj.package_ === packageName &&
|
|
142
|
+
(!version || !obj.version || version.equals(obj.version));
|
|
143
|
+
},
|
|
144
|
+
getHashCode: () => {
|
|
145
|
+
let hash = 0;
|
|
146
|
+
for (let i = 0; i < publisher.length; i++)
|
|
147
|
+
hash = ((hash << 5) - hash) + publisher.charCodeAt(i);
|
|
148
|
+
for (let i = 0; i < packageName.length; i++)
|
|
149
|
+
hash = ((hash << 5) - hash) + packageName.charCodeAt(i);
|
|
150
|
+
return hash | 0;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (value.imports && Array.isArray(value.imports)) {
|
|
155
|
+
metadata.imports = this.parseImportsV3(value.imports);
|
|
156
|
+
}
|
|
157
|
+
return this.addAllImportsGetter(metadata);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (rawData.canon && typeof rawData.canon === 'object') {
|
|
161
|
+
const canonSection = rawData.canon;
|
|
162
|
+
if (canonSection.publisher || canonSection.package || canonSection.version) {
|
|
163
|
+
metadata.namespace_ = this.parseNamespace(canonSection);
|
|
164
|
+
}
|
|
165
|
+
if (canonSection.imports && typeof canonSection.imports === 'object') {
|
|
166
|
+
metadata.imports = this.parseImportsLegacy(canonSection.imports);
|
|
167
|
+
}
|
|
168
|
+
return this.addAllImportsGetter(metadata);
|
|
169
|
+
}
|
|
170
|
+
return metadata;
|
|
171
|
+
}
|
|
172
|
+
extractBody(rawData, metadata) {
|
|
173
|
+
const body = {};
|
|
174
|
+
let packageEntryKey;
|
|
175
|
+
for (const [key, value] of Object.entries(rawData)) {
|
|
176
|
+
if (value && typeof value === 'object' && value.type === 'Package') {
|
|
177
|
+
packageEntryKey = key;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
for (const [key, value] of Object.entries(rawData)) {
|
|
182
|
+
if (key !== packageEntryKey && key !== 'canon' && key !== 'namespace' && key !== 'imports') {
|
|
183
|
+
body[key] = value;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return body;
|
|
187
|
+
}
|
|
188
|
+
parseNamespace(ns) {
|
|
189
|
+
if (typeof ns === 'string') {
|
|
190
|
+
const match = ns.match(/^([^/]+)\/([^@]+)(?:@(.+))?$/);
|
|
191
|
+
if (match) {
|
|
192
|
+
const version = match[3] ? this.parseVersion(match[3]) : this.createVersion(1, 0, 0);
|
|
193
|
+
return {
|
|
194
|
+
publisher: match[1],
|
|
195
|
+
package_: match[2],
|
|
196
|
+
version,
|
|
197
|
+
toString: () => ns,
|
|
198
|
+
equals: (obj) => {
|
|
199
|
+
if (!obj || typeof obj !== 'object')
|
|
200
|
+
return false;
|
|
201
|
+
return obj.publisher === match[1] && obj.package_ === match[2] &&
|
|
202
|
+
(!version || !obj.version || version.equals(obj.version));
|
|
203
|
+
},
|
|
204
|
+
getHashCode: () => {
|
|
205
|
+
let hash = 0;
|
|
206
|
+
for (let i = 0; i < match[1].length; i++)
|
|
207
|
+
hash = ((hash << 5) - hash) + match[1].charCodeAt(i);
|
|
208
|
+
for (let i = 0; i < match[2].length; i++)
|
|
209
|
+
hash = ((hash << 5) - hash) + match[2].charCodeAt(i);
|
|
210
|
+
return hash | 0;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const publisher = ns.publisher || '';
|
|
216
|
+
const package_ = ns.package || '';
|
|
217
|
+
const version = ns.version ? this.parseVersion(ns.version) : this.createVersion(1, 0, 0);
|
|
218
|
+
return {
|
|
219
|
+
publisher,
|
|
220
|
+
package_,
|
|
221
|
+
version,
|
|
222
|
+
toString: function () {
|
|
223
|
+
return `${this.publisher}/${this.package_}@${this.version?.major ?? 1}.${this.version?.minor ?? 0}.${this.version?.patch ?? 0}`;
|
|
224
|
+
},
|
|
225
|
+
equals: (obj) => {
|
|
226
|
+
if (!obj || typeof obj !== 'object')
|
|
227
|
+
return false;
|
|
228
|
+
return obj.publisher === publisher && obj.package_ === package_ &&
|
|
229
|
+
(!version || !obj.version || version.equals(obj.version));
|
|
230
|
+
},
|
|
231
|
+
getHashCode: () => {
|
|
232
|
+
let hash = 0;
|
|
233
|
+
for (let i = 0; i < publisher.length; i++)
|
|
234
|
+
hash = ((hash << 5) - hash) + publisher.charCodeAt(i);
|
|
235
|
+
for (let i = 0; i < package_.length; i++)
|
|
236
|
+
hash = ((hash << 5) - hash) + package_.charCodeAt(i);
|
|
237
|
+
return hash | 0;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
parseVersion(version) {
|
|
242
|
+
if (typeof version === 'string') {
|
|
243
|
+
const parts = version.split('.').map(Number);
|
|
244
|
+
return this.createVersion(parts[0] || 0, parts[1] || 0, parts[2] || 0);
|
|
245
|
+
}
|
|
246
|
+
return this.createVersion(version.major || 0, version.minor || 0, version.patch || 0);
|
|
247
|
+
}
|
|
248
|
+
parseImportsV3(imports) {
|
|
249
|
+
const result = {};
|
|
250
|
+
for (const item of imports) {
|
|
251
|
+
if (!item || typeof item !== 'object')
|
|
252
|
+
continue;
|
|
253
|
+
if (item.packages && Array.isArray(item.packages)) {
|
|
254
|
+
const publisher = item.publisher;
|
|
255
|
+
if (!publisher) {
|
|
256
|
+
throw new Error("PublisherImport requires 'publisher' property");
|
|
257
|
+
}
|
|
258
|
+
if (!result[publisher]) {
|
|
259
|
+
result[publisher] = [];
|
|
260
|
+
}
|
|
261
|
+
for (const pkgItem of item.packages) {
|
|
262
|
+
if (!pkgItem || typeof pkgItem !== 'object')
|
|
263
|
+
continue;
|
|
264
|
+
const imp = this.parseImportFromEmbeddedObject(pkgItem, publisher);
|
|
265
|
+
result[publisher].push(imp);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
const imp = this.parseImportFromEmbeddedObject(item, item.publisher);
|
|
270
|
+
const publisher = imp.publisher || '';
|
|
271
|
+
if (!result[publisher]) {
|
|
272
|
+
result[publisher] = [];
|
|
273
|
+
}
|
|
274
|
+
result[publisher].push(imp);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
parseImportsLegacy(imports) {
|
|
280
|
+
const result = {};
|
|
281
|
+
for (const [publisher, packages] of Object.entries(imports)) {
|
|
282
|
+
if (!Array.isArray(packages))
|
|
283
|
+
continue;
|
|
284
|
+
result[publisher] = packages.map(pkg => this.parseImport(pkg, publisher));
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
parseImportFromEmbeddedObject(obj, publisher) {
|
|
289
|
+
const packageName = obj.package;
|
|
290
|
+
if (!packageName) {
|
|
291
|
+
throw new Error("Import requires 'package' property");
|
|
292
|
+
}
|
|
293
|
+
const match = obj.match;
|
|
294
|
+
if (!match) {
|
|
295
|
+
throw new Error("Import requires 'match' property");
|
|
296
|
+
}
|
|
297
|
+
const versionStr = obj.version;
|
|
298
|
+
if (!versionStr) {
|
|
299
|
+
throw new Error("Import requires 'version' property");
|
|
300
|
+
}
|
|
301
|
+
const version = this.parseVersion(versionStr);
|
|
302
|
+
const versionOperator = this.parseVersionOperator(match);
|
|
303
|
+
const maxVersion = this.calculateMaxVersion(match, version);
|
|
304
|
+
const alias = obj.alias;
|
|
305
|
+
return {
|
|
306
|
+
package_: `${packageName} ${match} ${version.toString()}`,
|
|
307
|
+
publisher,
|
|
308
|
+
packageName,
|
|
309
|
+
versionOperator,
|
|
310
|
+
version,
|
|
311
|
+
alias,
|
|
312
|
+
minVersion: version,
|
|
313
|
+
maxVersion,
|
|
314
|
+
toEmbeddedObject: () => {
|
|
315
|
+
const result = {
|
|
316
|
+
package: packageName,
|
|
317
|
+
match,
|
|
318
|
+
version: version.toString()
|
|
319
|
+
};
|
|
320
|
+
if (alias)
|
|
321
|
+
result.alias = alias;
|
|
322
|
+
return result;
|
|
323
|
+
},
|
|
324
|
+
toString: () => alias
|
|
325
|
+
? `${packageName} ${match} ${version.toString()} as ${alias}`
|
|
326
|
+
: `${packageName} ${match} ${version.toString()}`
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
parseImport(pkg, publisher) {
|
|
330
|
+
if (typeof pkg === 'string') {
|
|
331
|
+
const aliasMatch = pkg.match(/^(.+?)\s*([~^=*])\s*(\S+)\s+as\s+(\S+)$/);
|
|
332
|
+
if (aliasMatch) {
|
|
333
|
+
const packageName = aliasMatch[1].trim();
|
|
334
|
+
const operator = aliasMatch[2];
|
|
335
|
+
const version = this.parseVersion(aliasMatch[3].trim());
|
|
336
|
+
const alias = aliasMatch[4].trim();
|
|
337
|
+
const versionOperator = this.parseVersionOperator(operator);
|
|
338
|
+
const maxVersion = this.calculateMaxVersion(operator, version);
|
|
339
|
+
return {
|
|
340
|
+
package_: pkg,
|
|
341
|
+
publisher,
|
|
342
|
+
packageName,
|
|
343
|
+
versionOperator,
|
|
344
|
+
version,
|
|
345
|
+
alias,
|
|
346
|
+
minVersion: version,
|
|
347
|
+
maxVersion,
|
|
348
|
+
toEmbeddedObject: () => {
|
|
349
|
+
const result = {
|
|
350
|
+
package: packageName,
|
|
351
|
+
match: operator,
|
|
352
|
+
version: version.toString()
|
|
353
|
+
};
|
|
354
|
+
if (alias)
|
|
355
|
+
result.alias = alias;
|
|
356
|
+
return result;
|
|
357
|
+
},
|
|
358
|
+
toString: () => `${packageName} ${operator} ${version.toString()} as ${alias}`
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
const match = pkg.match(/^(.+?)\s*([~^=*])\s*(.+)$/);
|
|
362
|
+
if (match) {
|
|
363
|
+
const packageName = match[1].trim();
|
|
364
|
+
const operator = match[2];
|
|
365
|
+
const version = this.parseVersion(match[3].trim());
|
|
366
|
+
const versionOperator = this.parseVersionOperator(operator);
|
|
367
|
+
const maxVersion = this.calculateMaxVersion(operator, version);
|
|
368
|
+
return {
|
|
369
|
+
package_: pkg,
|
|
370
|
+
publisher,
|
|
371
|
+
packageName,
|
|
372
|
+
versionOperator,
|
|
373
|
+
version,
|
|
374
|
+
alias: undefined,
|
|
375
|
+
minVersion: version,
|
|
376
|
+
maxVersion,
|
|
377
|
+
toEmbeddedObject: () => ({
|
|
378
|
+
package: packageName,
|
|
379
|
+
match: operator,
|
|
380
|
+
version: version.toString()
|
|
381
|
+
}),
|
|
382
|
+
toString: () => `${packageName} ${operator} ${version.toString()}`
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const versionOperator = this.parseVersionOperator(pkg.operator || '~');
|
|
387
|
+
const version = this.parseVersion(pkg.version || '1.0.0');
|
|
388
|
+
const packageName = pkg.packageName || pkg.package || '';
|
|
389
|
+
const operator = ['=', '~', '^', '*'][versionOperator];
|
|
390
|
+
const maxVersion = this.calculateMaxVersion(pkg.operator || '~', version);
|
|
391
|
+
return {
|
|
392
|
+
package_: pkg.package || '',
|
|
393
|
+
publisher,
|
|
394
|
+
packageName,
|
|
395
|
+
versionOperator,
|
|
396
|
+
version,
|
|
397
|
+
alias: pkg.alias,
|
|
398
|
+
minVersion: version,
|
|
399
|
+
maxVersion,
|
|
400
|
+
toEmbeddedObject: () => {
|
|
401
|
+
const result = {
|
|
402
|
+
package: packageName,
|
|
403
|
+
match: operator,
|
|
404
|
+
version: version.toString()
|
|
405
|
+
};
|
|
406
|
+
if (pkg.alias)
|
|
407
|
+
result.alias = pkg.alias;
|
|
408
|
+
return result;
|
|
409
|
+
},
|
|
410
|
+
toString: () => `${packageName} ${operator} ${version.toString()}`
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
parseVersionOperator(op) {
|
|
414
|
+
switch (op) {
|
|
415
|
+
case '=': return 0; // Exact
|
|
416
|
+
case '~': return 1; // Compatible
|
|
417
|
+
case '^': return 2; // Major
|
|
418
|
+
case '*': return 3; // Any
|
|
419
|
+
default: return 1; // Default to Compatible
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
calculateMaxVersion(operator, version) {
|
|
423
|
+
switch (operator) {
|
|
424
|
+
case '~': // Compatible: < next minor
|
|
425
|
+
return this.createVersion(version.major, version.minor + 1, 0);
|
|
426
|
+
case '^': // Major: < next major (or next minor for 0.x)
|
|
427
|
+
if (version.major === 0) {
|
|
428
|
+
return this.createVersion(0, version.minor + 1, 0);
|
|
429
|
+
}
|
|
430
|
+
return this.createVersion(version.major + 1, 0, 0);
|
|
431
|
+
default:
|
|
432
|
+
return this.createVersion(999, 999, 999);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
serializeImports(imports) {
|
|
436
|
+
const result = [];
|
|
437
|
+
for (const [publisher, importList] of Object.entries(imports)) {
|
|
438
|
+
const publisherImport = {
|
|
439
|
+
publisher,
|
|
440
|
+
packages: importList.map(imp => {
|
|
441
|
+
const operator = ['=', '~', '^', '*'][imp.versionOperator];
|
|
442
|
+
const pkgObj = {
|
|
443
|
+
package: imp.packageName,
|
|
444
|
+
match: operator,
|
|
445
|
+
version: `${imp.version.major}.${imp.version.minor}.${imp.version.patch}`
|
|
446
|
+
};
|
|
447
|
+
if (imp.alias) {
|
|
448
|
+
pkgObj.alias = imp.alias;
|
|
449
|
+
}
|
|
450
|
+
return pkgObj;
|
|
451
|
+
})
|
|
452
|
+
};
|
|
453
|
+
result.push(publisherImport);
|
|
454
|
+
}
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
|
|
2
|
+
import type { Canon } from '../canons/Canon.js';
|
|
3
|
+
export interface ICanonObjectParser {
|
|
4
|
+
parseCanons(documentRepository: ICanonDocumentRepository): Promise<Canon[]>;
|
|
5
|
+
saveCanons(canons: Canon[], documentRepository: ICanonDocumentRepository): Promise<void>;
|
|
6
|
+
serializeToYaml(canons: Canon[], namespaceString: string): Promise<string>;
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CanonParser } from './CanonParser.js';
|
|
2
|
+
export { CanonObjectParser } from './CanonObjectParser.js';
|
|
3
|
+
export type { ICanonObjectParser } from './ICanonObjectParser.js';
|
|
4
|
+
export { PropertyMetadata } from './PropertyMetadata.js';
|
|
5
|
+
export type { ICanonParser } from '@canon-protocol/types/document/parsing';
|
|
6
|
+
export type { CanonDocument, CanonMetadata, Namespace, Import, Version, ParseResult, ParseError } from '@canon-protocol/types/document/models/types';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CanonDocument, Import, DocumentReference } from '@canon-protocol/types/document/models/types';
|
|
2
|
+
import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
|
|
3
|
+
import type { ICanonParser } from '@canon-protocol/types/document/parsing';
|
|
4
|
+
import { FileSystemCanonDocumentRepository } from './FileSystemCanonDocumentRepository.js';
|
|
5
|
+
export declare enum DocumentLocation {
|
|
6
|
+
NotFound = "NotFound",
|
|
7
|
+
Workspace = "Workspace",
|
|
8
|
+
Cache = "Cache"
|
|
9
|
+
}
|
|
10
|
+
export declare class CompositeCanonDocumentRepository implements ICanonDocumentRepository {
|
|
11
|
+
private readonly cache;
|
|
12
|
+
private readonly workspace;
|
|
13
|
+
constructor(cachePath: string, workspacePath: string, parser?: ICanonParser);
|
|
14
|
+
getCache(): FileSystemCanonDocumentRepository;
|
|
15
|
+
getWorkspace(): FileSystemCanonDocumentRepository;
|
|
16
|
+
getAllDocumentsAsync(): Promise<CanonDocument[]>;
|
|
17
|
+
getDocumentAsync(identifier: string): Promise<CanonDocument | null>;
|
|
18
|
+
getDocumentsByNamespaceAsync(publisher: string, packageName: string): Promise<CanonDocument[]>;
|
|
19
|
+
getHighestCompatibleVersionAsync(publisher: string, import_: Import): Promise<CanonDocument | null>;
|
|
20
|
+
saveDocumentAsync(document: CanonDocument, identifier: string): Promise<void>;
|
|
21
|
+
saveToCacheAsync(document: CanonDocument, identifier: string): Promise<void>;
|
|
22
|
+
deleteDocumentAsync(identifier: string): Promise<void>;
|
|
23
|
+
clearNamespaceAsync(publisher: string, packageName: string): Promise<void>;
|
|
24
|
+
getAllDocumentReferencesAsync(): Promise<DocumentReference[]>;
|
|
25
|
+
getDocumentContentAsync(identifier: string): Promise<string | null>;
|
|
26
|
+
getDocumentUriAsync(identifier: string): Promise<string | null>;
|
|
27
|
+
getDocumentLocationAsync(identifier: string): Promise<DocumentLocation>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { FileSystemCanonDocumentRepository } from './FileSystemCanonDocumentRepository.js';
|
|
2
|
+
import { CanonParser } from '../parsing/CanonParser.js';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
export var DocumentLocation;
|
|
5
|
+
(function (DocumentLocation) {
|
|
6
|
+
DocumentLocation["NotFound"] = "NotFound";
|
|
7
|
+
DocumentLocation["Workspace"] = "Workspace";
|
|
8
|
+
DocumentLocation["Cache"] = "Cache";
|
|
9
|
+
})(DocumentLocation || (DocumentLocation = {}));
|
|
10
|
+
export class CompositeCanonDocumentRepository {
|
|
11
|
+
cache;
|
|
12
|
+
workspace;
|
|
13
|
+
constructor(cachePath, workspacePath, parser) {
|
|
14
|
+
const canonParser = parser ?? new CanonParser();
|
|
15
|
+
if (!fs.existsSync(cachePath)) {
|
|
16
|
+
fs.mkdirSync(cachePath, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
if (!fs.existsSync(workspacePath)) {
|
|
19
|
+
fs.mkdirSync(workspacePath, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
this.cache = new FileSystemCanonDocumentRepository(cachePath, true, canonParser);
|
|
22
|
+
this.workspace = new FileSystemCanonDocumentRepository(workspacePath, true, canonParser);
|
|
23
|
+
}
|
|
24
|
+
getCache() {
|
|
25
|
+
return this.cache;
|
|
26
|
+
}
|
|
27
|
+
getWorkspace() {
|
|
28
|
+
return this.workspace;
|
|
29
|
+
}
|
|
30
|
+
async getAllDocumentsAsync() {
|
|
31
|
+
const workspaceDocs = await this.workspace.getAllDocumentsAsync();
|
|
32
|
+
const cacheDocs = await this.cache.getAllDocumentsAsync();
|
|
33
|
+
const allDocs = new Map();
|
|
34
|
+
for (const doc of cacheDocs) {
|
|
35
|
+
if (doc.metadata.namespace_) {
|
|
36
|
+
const key = doc.metadata.namespace_.toString();
|
|
37
|
+
allDocs.set(key, doc);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const doc of workspaceDocs) {
|
|
41
|
+
if (doc.metadata.namespace_) {
|
|
42
|
+
const key = doc.metadata.namespace_.toString();
|
|
43
|
+
allDocs.set(key, doc);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return Array.from(allDocs.values());
|
|
47
|
+
}
|
|
48
|
+
async getDocumentAsync(identifier) {
|
|
49
|
+
const doc = await this.workspace.getDocumentAsync(identifier);
|
|
50
|
+
if (doc) {
|
|
51
|
+
return doc;
|
|
52
|
+
}
|
|
53
|
+
return await this.cache.getDocumentAsync(identifier);
|
|
54
|
+
}
|
|
55
|
+
async getDocumentsByNamespaceAsync(publisher, packageName) {
|
|
56
|
+
const workspaceDocs = await this.workspace.getDocumentsByNamespaceAsync(publisher, packageName);
|
|
57
|
+
const cacheDocs = await this.cache.getDocumentsByNamespaceAsync(publisher, packageName);
|
|
58
|
+
const allDocs = new Map();
|
|
59
|
+
for (const doc of cacheDocs) {
|
|
60
|
+
if (doc.metadata.namespace_?.version) {
|
|
61
|
+
const key = doc.metadata.namespace_.version.toString();
|
|
62
|
+
allDocs.set(key, doc);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const doc of workspaceDocs) {
|
|
66
|
+
if (doc.metadata.namespace_?.version) {
|
|
67
|
+
const key = doc.metadata.namespace_.version.toString();
|
|
68
|
+
allDocs.set(key, doc);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return Array.from(allDocs.values());
|
|
72
|
+
}
|
|
73
|
+
async getHighestCompatibleVersionAsync(publisher, import_) {
|
|
74
|
+
const workspaceDoc = await this.workspace.getHighestCompatibleVersionAsync(publisher, import_);
|
|
75
|
+
if (workspaceDoc) {
|
|
76
|
+
return workspaceDoc;
|
|
77
|
+
}
|
|
78
|
+
return await this.cache.getHighestCompatibleVersionAsync(publisher, import_);
|
|
79
|
+
}
|
|
80
|
+
async saveDocumentAsync(document, identifier) {
|
|
81
|
+
await this.workspace.saveDocumentAsync(document, identifier);
|
|
82
|
+
}
|
|
83
|
+
async saveToCacheAsync(document, identifier) {
|
|
84
|
+
await this.cache.saveDocumentAsync(document, identifier);
|
|
85
|
+
}
|
|
86
|
+
async deleteDocumentAsync(identifier) {
|
|
87
|
+
await this.workspace.deleteDocumentAsync(identifier);
|
|
88
|
+
}
|
|
89
|
+
async clearNamespaceAsync(publisher, packageName) {
|
|
90
|
+
await this.workspace.clearNamespaceAsync(publisher, packageName);
|
|
91
|
+
}
|
|
92
|
+
async getAllDocumentReferencesAsync() {
|
|
93
|
+
const workspaceRefs = await this.workspace.getAllDocumentReferencesAsync();
|
|
94
|
+
const cacheRefs = await this.cache.getAllDocumentReferencesAsync();
|
|
95
|
+
const allRefs = [];
|
|
96
|
+
allRefs.push(...workspaceRefs);
|
|
97
|
+
allRefs.push(...cacheRefs);
|
|
98
|
+
return allRefs;
|
|
99
|
+
}
|
|
100
|
+
async getDocumentContentAsync(identifier) {
|
|
101
|
+
const content = await this.workspace.getDocumentContentAsync(identifier);
|
|
102
|
+
if (content) {
|
|
103
|
+
return content;
|
|
104
|
+
}
|
|
105
|
+
return await this.cache.getDocumentContentAsync(identifier);
|
|
106
|
+
}
|
|
107
|
+
async getDocumentUriAsync(identifier) {
|
|
108
|
+
const uri = await this.workspace.getDocumentUriAsync(identifier);
|
|
109
|
+
if (uri) {
|
|
110
|
+
return uri;
|
|
111
|
+
}
|
|
112
|
+
return await this.cache.getDocumentUriAsync(identifier);
|
|
113
|
+
}
|
|
114
|
+
async getDocumentLocationAsync(identifier) {
|
|
115
|
+
const workspaceDoc = await this.workspace.getDocumentAsync(identifier);
|
|
116
|
+
if (workspaceDoc) {
|
|
117
|
+
return DocumentLocation.Workspace;
|
|
118
|
+
}
|
|
119
|
+
const cacheDoc = await this.cache.getDocumentAsync(identifier);
|
|
120
|
+
if (cacheDoc) {
|
|
121
|
+
return DocumentLocation.Cache;
|
|
122
|
+
}
|
|
123
|
+
return DocumentLocation.NotFound;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ICanonDocumentRepository } from '@canon-protocol/types/document/models';
|
|
2
|
+
import type { CanonDocument, Import, DocumentReference } from '@canon-protocol/types/document/models/types';
|
|
3
|
+
import type { ICanonParser } from '@canon-protocol/types/document/parsing';
|
|
4
|
+
export declare class FileSystemCanonDocumentRepository implements ICanonDocumentRepository {
|
|
5
|
+
private readonly rootPath;
|
|
6
|
+
private readonly recursive;
|
|
7
|
+
private readonly parser;
|
|
8
|
+
private readonly documentCache;
|
|
9
|
+
private readonly filePathsByIdentifier;
|
|
10
|
+
private cacheInitialized;
|
|
11
|
+
private cacheInitPromise;
|
|
12
|
+
readonly parsingErrors: Map<string, string>;
|
|
13
|
+
constructor(rootPath: string, recursive?: boolean, parser?: ICanonParser);
|
|
14
|
+
getAllDocumentsAsync(): Promise<CanonDocument[]>;
|
|
15
|
+
getDocumentAsync(identifier: string): Promise<CanonDocument | null>;
|
|
16
|
+
getDocumentsByNamespaceAsync(publisher: string, package_: string): Promise<CanonDocument[]>;
|
|
17
|
+
getHighestCompatibleVersionAsync(publisher: string, import_: Import): Promise<CanonDocument | null>;
|
|
18
|
+
saveDocumentAsync(document: CanonDocument, identifier: string): Promise<void>;
|
|
19
|
+
deleteDocumentAsync(identifier: string): Promise<void>;
|
|
20
|
+
clearNamespaceAsync(publisher: string, package_: string): Promise<void>;
|
|
21
|
+
getAllDocumentReferencesAsync(): Promise<DocumentReference[]>;
|
|
22
|
+
getDocumentContentAsync(identifier: string): Promise<string | null>;
|
|
23
|
+
getDocumentUriAsync(identifier: string): Promise<string | null>;
|
|
24
|
+
refreshAsync(): Promise<void>;
|
|
25
|
+
private ensureCacheInitialized;
|
|
26
|
+
private loadDocuments;
|
|
27
|
+
private findYamlFiles;
|
|
28
|
+
}
|