@roots/bud-build
Version:
bud.js core module
224 lines (188 loc) • 5.24 kB
text/typescript
import type {Bud, Build as BudBuild} from '@roots/bud-framework'
import type {Items, Loaders, Rules} from '@roots/bud-framework'
import type {Configuration} from '@roots/bud-framework/config'
import Item from '@roots/bud-build/item'
import Loader from '@roots/bud-build/loader'
import {register} from '@roots/bud-build/registry'
import Rule, {type Options as RuleOptions} from '@roots/bud-build/rule'
import {Service} from '@roots/bud-framework/service'
import {bind} from '@roots/bud-support/decorators/bind'
import isFunction from '@roots/bud-support/isFunction'
import isUndefined from '@roots/bud-support/isUndefined'
/**
* {@link BudBuild}
*/
class Build extends Service implements BudBuild {
/**
* {@link BudBuild.config}
*/
public config: Partial<Configuration> = {}
/**
* {@link BudBuild.items}
*/
public declare items: Items
/**
* {@link BudBuild.loaders}
*/
public declare loaders: Loaders
/**
* {@link BudBuild.register}
*/
public override register? = register.bind(this)
/**
* {@link BudBuild.rules}
*/
public declare rules: Rules
/**
* {@link Service.register}
*/
public override async bootstrap?(app: Bud) {
this.items = {} as Items
this.loaders = {} as Loaders
this.rules = {} as Rules
}
/**
* {@link BudBuild.getItem}
*/
public getItem(name: `${keyof Items & string}`): Item {
if (!this.items[name])
this.logger.error(
`loader ${name} was requested but is not registered`,
)
return this.items[name]
}
/**
* {@link BudBuild.getLoader}
*/
public getLoader(name: string): Loader {
if (!this.loaders[name])
this.logger.error(
`loader ${name} was requested but is not registered`,
)
return this.loaders[name]
}
/**
* {@link BudBuild.getRule}
*/
public getRule<K extends `${keyof Rules & string}`>(ident: K): Rules[K] {
return this.rules[ident]
}
/**
* {@link BudBuild.make}
*/
public async make(): Promise<Partial<Configuration>> {
this.logger.log(`bud.build.make called`)
await this.app.hooks.fire(`build.before`, this.app)
await import(` /bud-build/config`)
.then(
async records =>
await Promise.all(
Object.entries(records).map(async ([prop, factory]) => {
const value = await factory(this.app).catch(this.catch)
if (isUndefined(value)) {
return
}
Object.defineProperty(this.config, prop, {
configurable: true,
enumerable: true,
value,
writable: true,
})
this.logger
.log(`Defined:`, prop, `(${typeof this.config[prop]})`)
.info(prop, `info:`, this.config[prop])
}),
),
)
.catch(this.catch)
this.logger.scope(this.app.label, `build`).info(`built`, this.config)
await this.app.hooks.fire(`build.after`, this.app).catch(this.catch)
return Object.entries(this.config).reduce((a, [k, v]) => {
if (isUndefined(v)) return a
return {...a, [k]: v}
}, {})
}
/**
* {@link BudBuild.makeItem}
*/
public makeItem(options?: Partial<Item['options']>): Item {
return new Item(() => this.app, options)
}
/**
* {@link BudBuild.makeLoader}
*/
public makeLoader(src?: string, definition?: string): Loader {
return new Loader(() => this.app, src, definition)
}
/**
* {@link BudBuild.makeRule}
*/
public makeRule(options?: RuleOptions): Rule {
return new Rule(() => this.app, options)
}
/**
* {@link BudBuild.setItem}
*/
public setItem<K extends `${keyof Items & string}`>(
ident: K,
definition?: ((item: Items[K]) => Items[K]) | Items[K],
): this {
this.logger.log(`Registered item:`, ident)
const maybeOptionsCallback = isUndefined(definition)
? {ident, loader: ident}
: definition
const item = isFunction(maybeOptionsCallback)
? maybeOptionsCallback(this.makeItem())
: this.makeItem(maybeOptionsCallback)
this.items[ident] = item
this.logger.info(item)
return this
}
/**
* {@link BudBuild.setLoader}
*/
public setLoader<K extends `${keyof Loaders & string}`>(
name: K,
definition?: any,
): this {
this.logger.log(`Registered loader:`, name)
const loader = isUndefined(definition)
? this.makeLoader(name)
: definition instanceof Loader
? definition
: this.makeLoader(definition)
this.loaders[name] = loader
this.logger.info(loader)
return this
}
/**
* {@link BudBuild.setRule}
*/
public setRule<K extends `${keyof Rules & string}`>(
name: K,
definition?: Rule | RuleOptions,
): this {
this.logger.log(`Registered rule:`, name)
const rule =
definition instanceof Rule
? definition
: isFunction(definition)
? definition(this.makeRule())
: this.makeRule(definition as any)
this.rules[name] = rule
this.logger.info(rule)
return this
}
}
export {Build as default}