glam/frontend/scripts/generate-schema-manifest.cjs
kempersc ab5ad23699 Add parsimonious LinkML package and metadata
- Created manifest.json for the parsimonious LinkML package.
- Added metadata.yaml with detailed information about the Heritage Custodian Parsimony Ontology.
- Established directory structure for classes, enums, mappings, and slots with corresponding README files.
- Each module directory includes a brief description of its purpose and planned scale.
2026-03-13 16:48:32 +01:00

194 lines
5 KiB
JavaScript

#!/usr/bin/env node
/**
* LinkML Schema Manifest Generator
*
* Generates a manifest.json file for the frontend to dynamically load
* schema files from the public/schemas directory.
*
* This script is run as part of the build process:
* pnpm run generate-manifest
*
* It scans the synced schema files (after sync-schemas) and creates
* a structured manifest that the LinkML viewer can consume.
*/
const fs = require('fs');
const path = require('path');
const ROOT_SCHEMAS_DIR = path.join(__dirname, '../public/schemas/20251121/linkml');
// Category configuration
const CATEGORIES = [
{
name: 'main',
displayName: 'Main Schemas',
scan: false, // Main schemas are at root level
scanPath: null
},
{
name: 'class',
displayName: 'Classes',
scan: true,
scanPath: 'modules/classes'
},
{
name: 'enum',
displayName: 'Enumerations',
scan: true,
scanPath: 'modules/enums'
},
{
name: 'slot',
displayName: 'Slots',
scan: true,
scanPath: 'modules/slots'
},
{
name: 'module',
displayName: 'Modules',
scan: true,
scanPath: 'modules',
excludeSubdirs: ['classes', 'enums', 'slots', 'archive']
}
];
/**
* Recursively scan a directory for YAML files
*/
function scanDirectory(dir, category, relativePath = '', excludeSubdirs = []) {
const files = [];
if (!fs.existsSync(dir)) {
console.warn(`Directory not found: ${dir}`);
return files;
}
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
// Skip archive and deprecated directories, and backup files
if (entry.name === 'archive' || entry.name.startsWith('archive_') || entry.name === 'deprecated') {
continue;
}
if (entry.isDirectory()) {
// Skip excluded subdirectories
if (excludeSubdirs.includes(entry.name)) {
continue;
}
// Recurse into subdirectories
const subPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
files.push(...scanDirectory(
path.join(dir, entry.name),
category,
subPath,
[] // Don't propagate excludeSubdirs to recursive calls
));
} else if (entry.isFile() && entry.name.endsWith('.yaml') && !entry.name.includes('.bak')) {
const name = entry.name.replace('.yaml', '');
const filePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
files.push({
name,
path: filePath,
category
});
}
}
return files.sort((a, b) => a.name.localeCompare(b.name));
}
/**
* Scan root directory for main schema files
*/
function scanMainSchemas(baseDir) {
const files = [];
if (!fs.existsSync(baseDir)) {
console.warn(`Schema directory not found: ${baseDir}`);
return files;
}
const entries = fs.readdirSync(baseDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isFile() && entry.name.endsWith('.yaml') && !entry.name.includes('.bak')) {
const name = entry.name.replace('.yaml', '');
files.push({
name,
path: entry.name,
category: 'main'
});
}
}
return files.sort((a, b) => a.name.localeCompare(b.name));
}
/**
* Generate the manifest
*/
function generateManifest(baseDir, schemaRoot) {
const outputFile = path.join(baseDir, 'manifest.json');
console.log(`Scanning LinkML schemas in: ${baseDir}`);
const categories = [];
let totalFiles = 0;
const categoryCounts = {};
for (const catConfig of CATEGORIES) {
let files;
if (catConfig.name === 'main') {
// Special handling for main schemas at root level
files = scanMainSchemas(baseDir);
} else if (catConfig.scan && catConfig.scanPath) {
const scanDir = path.join(baseDir, catConfig.scanPath);
files = scanDirectory(
scanDir,
catConfig.name,
catConfig.scanPath,
catConfig.excludeSubdirs || []
);
} else {
files = [];
}
if (files.length > 0) {
categories.push({
name: catConfig.name,
displayName: catConfig.displayName,
files
});
categoryCounts[catConfig.name] = files.length;
totalFiles += files.length;
}
}
const manifest = {
generated: new Date().toISOString(),
schemaRoot,
totalFiles,
categoryCounts,
categories
};
// Ensure output directory exists
const outputDir = path.dirname(outputFile);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Write manifest
fs.writeFileSync(outputFile, JSON.stringify(manifest, null, 2));
// Print summary
console.log(`Generated manifest with ${totalFiles} schema files`);
for (const cat of categories) {
console.log(` - ${cat.displayName}: ${cat.files.length}`);
}
console.log(`Output: ${outputFile}`);
}
generateManifest(ROOT_SCHEMAS_DIR, '/schemas/20251121/linkml');
generateManifest(path.join(ROOT_SCHEMAS_DIR, 'parsimony'), '/schemas/20251121/linkml/parsimony');