UNPKG

@roots/bud

Version:

Configurable, extensible build tools for modern single and multi-page web applications

145 lines (144 loc) 3.89 kB
import { dirname, join } from 'node:path/posix'; import { fileURLToPath } from 'node:url'; import { filesystem as fs } from '@roots/bud-support/filesystem'; import { resolve } from '@roots/bud-support/import-meta-resolve'; import isString from '@roots/bud-support/isString'; /** * Command finder class */ export class Finder { context; application; /** * Command paths */ paths; /** * Class constructor */ constructor(context, application) { this.context = context; this.application = application; } /** * Is cacheable */ get cacheable() { return (!this.context.use && this.context.cache !== false && this.context.force !== true); } /** * Clear cache */ async cacheClear() { try { if (await fs.exists(this.cachePath)) await fs.remove(this.cachePath); } catch (error) { } } /** * Cache path */ get cachePath() { return join(this.context.paths.storage, `bud.commands.yml`); } /** * Read cache */ async cacheRead() { return await fs.read(this.cachePath); } /** * Write cache */ async cacheWrite() { if (this.paths && this.cacheable) await fs.write(this.cachePath, this.paths); } /** * Get registration module paths */ async getModules() { this.paths = await this.resolve(this.getSignifiers()) .then(this.getPaths) .then(this.resolve); return this.paths; } /** * Get paths */ getPaths(paths) { return paths .map(dirname) .map(path => join(path, join(`bud`, `commands`, `index.js`))); } /** * Get array of project dependencies */ getSignifiers() { return [ ...Object.keys({ ...(this.context.manifest?.dependencies ?? {}), ...(this.context.manifest?.devDependencies ?? {}), }), ...(this.context.use ?? []).flatMap(pkg => pkg.split(`,`)), ].filter(signifier => !signifier.startsWith(`@types`)); } /** * Import commands */ async importCommands() { return await Promise.all(this.paths.map(async (path) => { try { return [ path, await import(path).then(({ default: register }) => register), ]; } catch (error) { await this.cacheClear(); } })).catch(this.cacheClear); } /** * Initialize */ async init() { const path = join(this.context.paths.storage, `bud.commands.yml`); try { if ((await fs.exists(path)) && this.cacheable) { this.paths = await fs.read(path); if (Array.isArray(this.paths)) return this; else throw new Error(`Invalid cache`); } } catch (error) { } await this.getModules(); await this.cacheWrite(); return this; } /** * Resolve signifiers against import.meta.url */ async resolve(paths) { return await Promise.all(paths.map(async (path) => { try { return resolve(path, import.meta.url); } catch (error) { } })) .then(paths => paths.filter(isString).map(path => fileURLToPath(path))) .then(async (paths) => await Promise.all(paths.map(async (path) => { try { const exists = await fs.exists(path); if (exists) return path; } catch (error) { } })).then(paths => paths.filter(Boolean))); } }