UNPKG

@enspirit/emb

Version:

A replacement for our Makefile-for-monorepos

50 lines (49 loc) 1.87 kB
const TPL_REGEX = /(?<!\\)\${(?:(\w+):)?(\w+)(?::-(.*?))?}/g; export class TemplateExpander { expansions = []; get expansionCount() { return this.expansions.length; } async expand(str, options = {}) { return (str || '') .toString() .replaceAll(TPL_REGEX, (match, source, key, fallback) => { const src = source ?? options.default ?? ''; const provider = options.sources?.[src]; if (!provider) { if (fallback !== undefined) { return this.track(src, key, fallback); } throw new Error(`Invalid expand provider '${source}' ('${match}')`); } const val = provider[key]; if (!val && fallback === undefined) { throw new Error(`Could not expand '${match}' and no default value provided`); } if (val !== undefined && val !== null) { return this.track(src, key, val); } return this.track(src, key, fallback ?? ''); }) .replaceAll('\\${', '${'); } async expandRecord(record, options) { if (typeof record === 'string') { const out = await this.expand(record, options); return out; } if (Array.isArray(record)) { const out = await Promise.all(record.map((v) => this.expandRecord(v, options))); return out; } const entries = await Promise.all(Object.entries(record).map(async ([k, v]) => { const expandedValue = await this.expandRecord(v, options); return [k, expandedValue]; })); return Object.fromEntries(entries); } track(source, variable, value) { this.expansions.push({ source, value, variable }); return String(value); } }