import { parseManifest, type SimManifest } from './manifest.ts'; import type { MFile } from './mrender.ts'; /** * Discovery: every ../simulated_instruments//instrument.json, with * that repo's matlab/*.m sources, bundled at build time. A repo without a * manifest is simply not an instrument; a manifest that fails validation * is reported and skipped rather than taking the app down. */ const manifestModules = import.meta.glob('../../../../../simulated_instruments/*/instrument.json', { eager: true, query: '?raw', import: 'default', }) as Record; const mModules = import.meta.glob('../../../../../simulated_instruments/*/matlab/*.m', { eager: true, query: '?raw', import: 'default', }) as Record; export interface SimInstrumentDef { manifest: SimManifest; mfiles: MFile[]; } export function loadCatalog(): SimInstrumentDef[] { const out: SimInstrumentDef[] = []; for (const [path, text] of Object.entries(manifestModules)) { const dir = path.slice(0, path.lastIndexOf('/')); let manifest: SimManifest; try { manifest = parseManifest(text); } catch (err) { console.warn(`skipping ${path}: ${err instanceof Error ? err.message : String(err)}`); continue; } const mfiles: MFile[] = Object.entries(mModules) .filter(([p]) => p.startsWith(dir + '/matlab/')) .map(([p, source]) => ({ name: p.split('/').pop()!, source })) .sort((a, b) => a.name.localeCompare(b.name)); if (mfiles.length === 0) { console.warn(`skipping ${path}: no matlab/*.m sources found`); continue; } out.push({ manifest, mfiles }); } out.sort((a, b) => a.manifest.name.localeCompare(b.manifest.name)); return out; }