const fs = require('fs'); const path = require('path'); class AssetCategoryManager { constructor(relPath = '.') { this.assetDir = path.resolve(__dirname, relPath); this.cache = new Map(); } getCategory(softwareType) { if (!softwareType) { throw new Error('softwareType is required'); } if (this.cache.has(softwareType)) { return this.cache.get(softwareType); } const filePath = path.resolve(this.assetDir, `${softwareType}.json`); if (!fs.existsSync(filePath)) { throw new Error(`Asset data '${softwareType}' not found in ${this.assetDir}`); } const raw = fs.readFileSync(filePath, 'utf8'); const parsed = JSON.parse(raw); this.cache.set(softwareType, parsed); return parsed; } hasCategory(softwareType) { const filePath = path.resolve(this.assetDir, `${softwareType}.json`); return fs.existsSync(filePath); } listCategories({ withMeta = false } = {}) { const files = fs.readdirSync(this.assetDir, { withFileTypes: true }); return files .filter( (entry) => entry.isFile() && entry.name.endsWith('.json') && entry.name !== 'index.json' && entry.name !== 'assetData.json' ) .map((entry) => path.basename(entry.name, '.json')) .map((name) => { if (!withMeta) { return name; } const data = this.getCategory(name); return { softwareType: data.softwareType || name, label: data.label || name, file: `${name}.json` }; }); } searchCategories(query) { const term = (query || '').trim().toLowerCase(); if (!term) { return []; } return this.listCategories({ withMeta: true }).filter( ({ softwareType, label }) => softwareType.toLowerCase().includes(term) || label.toLowerCase().includes(term) ); } clearCache() { this.cache.clear(); } } const assetCategoryManager = new AssetCategoryManager(); module.exports = { AssetCategoryManager, assetCategoryManager, getCategory: (softwareType) => assetCategoryManager.getCategory(softwareType), listCategories: (options) => assetCategoryManager.listCategories(options), searchCategories: (query) => assetCategoryManager.searchCategories(query), hasCategory: (softwareType) => assetCategoryManager.hasCategory(softwareType), clearCache: () => assetCategoryManager.clearCache() };