mirror of
https://github.com/LukeHagar/aperture.git
synced 2025-12-06 04:19:09 +00:00
116 lines
3.6 KiB
TypeScript
116 lines
3.6 KiB
TypeScript
import * as path from 'path';
|
|
import * as fs from 'fs';
|
|
|
|
export interface SchemaManifest {
|
|
roots: Record<string, string>;
|
|
fragments: Record<string, string>;
|
|
version: string;
|
|
}
|
|
|
|
export interface SchemaCollection {
|
|
roots: Record<string, any>;
|
|
fragments: Record<string, any>;
|
|
readJson: (filePath: string) => any;
|
|
toUri: (schema: any) => string;
|
|
}
|
|
|
|
export class SchemaLoader {
|
|
private packageRoot: string | null = null;
|
|
private manifest: SchemaManifest | null = null;
|
|
private cache: Map<string, any> = new Map();
|
|
|
|
constructor() {
|
|
this.initializePackageRoot();
|
|
}
|
|
|
|
private initializePackageRoot(): void {
|
|
try {
|
|
// Try to resolve the external types package
|
|
const packagePath = require.resolve('@your/openapi-types/package.json');
|
|
this.packageRoot = path.dirname(packagePath);
|
|
} catch (e) {
|
|
console.warn('Could not resolve @your/openapi-types package. Using fallback.');
|
|
// Fallback to a local path or handle gracefully
|
|
this.packageRoot = null;
|
|
}
|
|
}
|
|
|
|
async loadManifest(): Promise<SchemaManifest> {
|
|
if (this.manifest) {
|
|
return this.manifest;
|
|
}
|
|
|
|
if (!this.packageRoot) {
|
|
throw new Error('Package root not found. @your/openapi-types package is required.');
|
|
}
|
|
|
|
const manifestPath = path.join(this.packageRoot, 'schema-manifest.json');
|
|
|
|
try {
|
|
const manifestContent = fs.readFileSync(manifestPath, 'utf8');
|
|
this.manifest = JSON.parse(manifestContent);
|
|
if (!this.manifest) {
|
|
throw new Error('Manifest is null');
|
|
}
|
|
return this.manifest;
|
|
} catch (e) {
|
|
throw new Error(`Failed to load schema manifest from ${manifestPath}: ${e}`);
|
|
}
|
|
}
|
|
|
|
async getAllSchemas(): Promise<SchemaCollection> {
|
|
const manifest = await this.loadManifest();
|
|
const roots: Record<string, any> = {};
|
|
const fragments: Record<string, any> = {};
|
|
|
|
// Load root schemas
|
|
for (const [version, schemaPath] of Object.entries(manifest.roots)) {
|
|
const fullPath = path.join(this.packageRoot!, schemaPath);
|
|
roots[version] = this.readJson(fullPath);
|
|
}
|
|
|
|
// Load fragment schemas
|
|
for (const [name, schemaPath] of Object.entries(manifest.fragments)) {
|
|
const fullPath = path.join(this.packageRoot!, schemaPath);
|
|
fragments[name] = this.readJson(fullPath);
|
|
}
|
|
|
|
return {
|
|
roots,
|
|
fragments,
|
|
readJson: this.readJson.bind(this),
|
|
toUri: this.toUri.bind(this)
|
|
};
|
|
}
|
|
|
|
readJson(filePath: string): any {
|
|
if (this.cache.has(filePath)) {
|
|
return this.cache.get(filePath);
|
|
}
|
|
|
|
try {
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
const parsed = JSON.parse(content);
|
|
this.cache.set(filePath, parsed);
|
|
return parsed;
|
|
} catch (e) {
|
|
throw new Error(`Failed to read JSON from ${filePath}: ${e}`);
|
|
}
|
|
}
|
|
|
|
toUri(schema: any): string {
|
|
// Generate a URI for the schema (used by language services)
|
|
return `aperture://schema/${Date.now()}`;
|
|
}
|
|
|
|
async getSchemaForVersion(version: string): Promise<any> {
|
|
const schemas = await this.getAllSchemas();
|
|
return schemas.roots[version] || null;
|
|
}
|
|
|
|
async getFragmentSchema(name: string): Promise<any> {
|
|
const schemas = await this.getAllSchemas();
|
|
return schemas.fragments[name] || null;
|
|
}
|
|
}
|