glam/apps/archief-assistent/src/lib/linkml/schema-loader.ts
2025-12-30 03:43:31 +01:00

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,
}));
}