197 lines
6.9 KiB
TypeScript
197 lines
6.9 KiB
TypeScript
/**
|
|
* LinkML Schema Loader
|
|
*
|
|
* Utilities for loading and parsing LinkML schema files.
|
|
*/
|
|
|
|
import yaml from 'js-yaml';
|
|
|
|
export interface LinkMLSlot {
|
|
name: string;
|
|
description?: string;
|
|
range?: string;
|
|
required?: boolean;
|
|
multivalued?: boolean;
|
|
slot_uri?: string;
|
|
pattern?: string;
|
|
}
|
|
|
|
export interface LinkMLClass {
|
|
name: string;
|
|
description?: string;
|
|
class_uri?: string;
|
|
abstract?: boolean;
|
|
slots?: string[];
|
|
slot_usage?: Record<string, Partial<LinkMLSlot>>;
|
|
exact_mappings?: string[];
|
|
close_mappings?: string[];
|
|
comments?: string[];
|
|
}
|
|
|
|
export interface LinkMLEnum {
|
|
name: string;
|
|
description?: string;
|
|
permissible_values?: Record<string, { description?: string; meaning?: string }>;
|
|
}
|
|
|
|
export interface LinkMLSchema {
|
|
id: string;
|
|
name: string;
|
|
title?: string;
|
|
description?: string;
|
|
version?: string;
|
|
prefixes?: Record<string, string>;
|
|
imports?: string[];
|
|
classes?: Record<string, LinkMLClass>;
|
|
slots?: Record<string, LinkMLSlot>;
|
|
enums?: Record<string, LinkMLEnum>;
|
|
comments?: string[];
|
|
}
|
|
|
|
export interface SchemaFile {
|
|
name: string;
|
|
path: string;
|
|
category: 'main' | 'class' | 'slot' | 'enum' | 'module';
|
|
}
|
|
|
|
/**
|
|
* List of all LinkML schema files organized by category
|
|
*/
|
|
export const SCHEMA_FILES: SchemaFile[] = [
|
|
// Main schema
|
|
{ name: '01_custodian_name_modular', path: '01_custodian_name_modular.yaml', category: 'main' },
|
|
|
|
// Classes
|
|
{ name: 'Custodian', path: 'modules/classes/Custodian.yaml', category: 'class' },
|
|
{ name: 'CustodianName', path: 'modules/classes/CustodianName.yaml', category: 'class' },
|
|
{ name: 'CustodianObservation', path: 'modules/classes/CustodianObservation.yaml', category: 'class' },
|
|
{ name: 'CustodianLegalStatus', path: 'modules/classes/CustodianLegalStatus.yaml', category: 'class' },
|
|
{ name: 'CustodianPlace', path: 'modules/classes/CustodianPlace.yaml', category: 'class' },
|
|
{ name: 'CustodianCollection', path: 'modules/classes/CustodianCollection.yaml', category: 'class' },
|
|
{ name: 'CustodianType', path: 'modules/classes/CustodianType.yaml', category: 'class' },
|
|
{ name: 'ArchiveOrganizationType', path: 'modules/classes/ArchiveOrganizationType.yaml', category: 'class' },
|
|
{ name: 'MuseumType', path: 'modules/classes/MuseumType.yaml', category: 'class' },
|
|
{ name: 'LibraryType', path: 'modules/classes/LibraryType.yaml', category: 'class' },
|
|
{ name: 'GalleryType', path: 'modules/classes/GalleryType.yaml', category: 'class' },
|
|
{ name: 'DigitalPlatform', path: 'modules/classes/DigitalPlatform.yaml', category: 'class' },
|
|
{ name: 'OrganizationalStructure', path: 'modules/classes/OrganizationalStructure.yaml', category: 'class' },
|
|
{ name: 'OrganizationalChangeEvent', path: 'modules/classes/OrganizationalChangeEvent.yaml', category: 'class' },
|
|
{ name: 'PersonObservation', path: 'modules/classes/PersonObservation.yaml', category: 'class' },
|
|
{ name: 'Identifier', path: 'modules/classes/Identifier.yaml', category: 'class' },
|
|
{ name: 'ReconstructionActivity', path: 'modules/classes/ReconstructionActivity.yaml', category: 'class' },
|
|
{ name: 'SourceDocument', path: 'modules/classes/SourceDocument.yaml', category: 'class' },
|
|
{ name: 'TimeSpan', path: 'modules/classes/TimeSpan.yaml', category: 'class' },
|
|
{ name: 'EncompassingBody', path: 'modules/classes/EncompassingBody.yaml', category: 'class' },
|
|
{ name: 'Country', path: 'modules/classes/Country.yaml', category: 'class' },
|
|
{ name: 'Subregion', path: 'modules/classes/Subregion.yaml', category: 'class' },
|
|
{ name: 'Settlement', path: 'modules/classes/Settlement.yaml', category: 'class' },
|
|
|
|
// Enums
|
|
{ name: 'CustodianPrimaryTypeEnum', path: 'modules/enums/CustodianPrimaryTypeEnum.yaml', category: 'enum' },
|
|
{ name: 'LegalStatusEnum', path: 'modules/enums/LegalStatusEnum.yaml', category: 'enum' },
|
|
{ name: 'PlaceSpecificityEnum', path: 'modules/enums/PlaceSpecificityEnum.yaml', category: 'enum' },
|
|
{ name: 'OrganizationalUnitTypeEnum', path: 'modules/enums/OrganizationalUnitTypeEnum.yaml', category: 'enum' },
|
|
{ name: 'OrganizationalChangeEventTypeEnum', path: 'modules/enums/OrganizationalChangeEventTypeEnum.yaml', category: 'enum' },
|
|
{ name: 'StaffRoleTypeEnum', path: 'modules/enums/StaffRoleTypeEnum.yaml', category: 'enum' },
|
|
{ name: 'FeatureTypeEnum', path: 'modules/enums/FeatureTypeEnum.yaml', category: 'enum' },
|
|
{ name: 'EncompassingBodyTypeEnum', path: 'modules/enums/EncompassingBodyTypeEnum.yaml', category: 'enum' },
|
|
];
|
|
|
|
const SCHEMA_BASE_PATH = '/schemas/20251121/linkml';
|
|
|
|
/**
|
|
* Load a LinkML schema file by path
|
|
*/
|
|
export async function loadSchema(schemaPath: string): Promise<LinkMLSchema | null> {
|
|
try {
|
|
const response = await fetch(`${SCHEMA_BASE_PATH}/${schemaPath}`);
|
|
if (!response.ok) {
|
|
console.error(`Failed to load schema: ${schemaPath}`, response.status);
|
|
return null;
|
|
}
|
|
const content = await response.text();
|
|
const parsed = yaml.load(content) as LinkMLSchema;
|
|
return parsed;
|
|
} catch (error) {
|
|
console.error(`Error loading schema ${schemaPath}:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load schema file content as raw YAML text
|
|
*/
|
|
export async function loadSchemaRaw(schemaPath: string): Promise<string | null> {
|
|
try {
|
|
const response = await fetch(`${SCHEMA_BASE_PATH}/${schemaPath}`);
|
|
if (!response.ok) {
|
|
console.error(`Failed to load schema: ${schemaPath}`, response.status);
|
|
return null;
|
|
}
|
|
return await response.text();
|
|
} catch (error) {
|
|
console.error(`Error loading schema ${schemaPath}:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all schema files by category
|
|
*/
|
|
export function getSchemasByCategory(category: SchemaFile['category']): SchemaFile[] {
|
|
return SCHEMA_FILES.filter(s => s.category === category);
|
|
}
|
|
|
|
/**
|
|
* Get all unique categories
|
|
*/
|
|
export function getCategories(): SchemaFile['category'][] {
|
|
return ['main', 'class', 'enum', 'slot', 'module'];
|
|
}
|
|
|
|
/**
|
|
* Get category display name
|
|
*/
|
|
export function getCategoryDisplayName(category: SchemaFile['category']): string {
|
|
const names: Record<SchemaFile['category'], string> = {
|
|
main: 'Main Schema',
|
|
class: 'Classes',
|
|
slot: 'Slots',
|
|
enum: 'Enumerations',
|
|
module: 'Modules',
|
|
};
|
|
return names[category];
|
|
}
|
|
|
|
/**
|
|
* Extract class information from a parsed schema
|
|
*/
|
|
export function extractClasses(schema: LinkMLSchema): LinkMLClass[] {
|
|
if (!schema.classes) return [];
|
|
return Object.entries(schema.classes).map(([key, cls]) => ({
|
|
...cls,
|
|
name: key,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Extract slot information from a parsed schema
|
|
*/
|
|
export function extractSlots(schema: LinkMLSchema): LinkMLSlot[] {
|
|
if (!schema.slots) return [];
|
|
return Object.entries(schema.slots).map(([key, slot]) => ({
|
|
...slot,
|
|
name: key,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Extract enum information from a parsed schema
|
|
*/
|
|
export function extractEnums(schema: LinkMLSchema): LinkMLEnum[] {
|
|
if (!schema.enums) return [];
|
|
return Object.entries(schema.enums).map(([key, enumDef]) => ({
|
|
...enumDef,
|
|
name: key,
|
|
}));
|
|
}
|