'use strict'; const fs = require('fs'); const path = require('path'); /** * FileBackend — reads JSON payloads from a directory on disk. * * Two layouts supported: * - 'per-id' one file per id (filename minus .json is the id) * - 'single-file' one file containing an array; index by a field name * * Returns Map. Case-insensitive lookups by default — * matches how loadCurve worked historically. */ class FileBackend { constructor(opts = {}) { const { baseDir, layout = 'per-id', filePath, arrayKey, indexField, exclude = [], caseInsensitive = true, } = opts; if (!baseDir) throw new TypeError('FileBackend: baseDir is required'); if (layout !== 'per-id' && layout !== 'single-file') { throw new TypeError(`FileBackend: unsupported layout '${layout}'`); } if (layout === 'single-file' && !filePath) { throw new TypeError('FileBackend: single-file layout requires filePath'); } this.baseDir = baseDir; this.layout = layout; this.filePath = filePath; this.arrayKey = arrayKey; this.indexField = indexField; this.exclude = new Set(exclude); this.caseInsensitive = caseInsensitive; } _norm(k) { return this.caseInsensitive ? String(k).toLowerCase() : String(k); } loadAll() { if (this.layout === 'per-id') return this._loadPerId(); return this._loadSingleFile(); } async refresh() { // No actual I/O penalty on local disk; the async surface exists so // callers can `await resolver.refresh()` symmetrically with future // HttpBackend implementations. return this.loadAll(); } _loadPerId() { const map = new Map(); if (!fs.existsSync(this.baseDir)) return map; const entries = fs.readdirSync(this.baseDir, { withFileTypes: true }); for (const entry of entries) { if (!entry.isFile()) continue; if (!entry.name.endsWith('.json')) continue; const id = path.basename(entry.name, '.json'); if (this.exclude.has(id)) continue; const raw = fs.readFileSync(path.join(this.baseDir, entry.name), 'utf8'); const data = JSON.parse(raw); map.set(this._norm(id), data); } return map; } _loadSingleFile() { const full = path.resolve(this.baseDir, this.filePath); if (!fs.existsSync(full)) return new Map(); const data = JSON.parse(fs.readFileSync(full, 'utf8')); const arr = this.arrayKey ? data[this.arrayKey] : data; if (!Array.isArray(arr)) { throw new Error( `FileBackend(single-file): expected array at ${this.arrayKey || ''} in ${full}`, ); } const map = new Map(); for (const entry of arr) { const k = entry && this.indexField ? entry[this.indexField] : null; if (k != null) map.set(this._norm(k), entry); } return map; } } module.exports = FileBackend;