From 04970ccf23179644d26cba75a7f29c368b4b5c05 Mon Sep 17 00:00:00 2001 From: Kelly Mears Date: Fri, 20 Oct 2023 13:35:52 -0400 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20improve(patch):=20cli=20and=20loggi?= =?UTF-8?q?ng=20(#2481)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit generally improves observability for the user: - adds `bud env` command for reviewing envvars available through `bud.env` - adds `bud config` command for reviewing config files and the generated config values ## Type of change **PATCH: backwards compatible change** --- .../bud-api/src/methods/minimize/index.ts | 5 +- .../bud-api/src/methods/persist/index.ts | 4 +- sources/@roots/bud-api/test/persist.test.ts | 6 +- sources/@roots/bud-build/src/config/entry.ts | 4 +- sources/@roots/bud-build/src/rule/index.ts | 3 +- sources/@roots/bud-build/src/service/index.ts | 10 +- .../@roots/bud-compiler/src/service/index.tsx | 1 - sources/@roots/bud-dashboard/src/service.tsx | 22 +-- .../src/bud/commands/bud.eslint.command.tsx | 9 +- .../bud-extensions/src/service/index.ts | 4 +- .../src/webpack-lifecycle-plugin/index.ts | 18 +- sources/@roots/bud-framework/src/bootstrap.ts | 38 ++-- sources/@roots/bud-framework/src/bud.ts | 162 +++++++++--------- .../bud-framework/src/extension/index.ts | 98 +++++++---- sources/@roots/bud-framework/src/fs.ts | 18 +- .../src/methods/setPath/index.ts | 18 +- sources/@roots/bud-framework/src/project.ts | 4 +- .../src/services/dashboard/index.ts | 5 - sources/@roots/bud-hooks/src/base/base.ts | 3 + sources/@roots/bud-hooks/src/event/event.ts | 15 +- .../@roots/bud-preset-wordpress/src/index.ts | 4 +- .../@roots/bud-purgecss/src/extension/base.ts | 4 +- .../bud-purgecss/src/extension/model.ts | 7 +- .../@roots/bud-purgecss/src/facade/index.ts | 4 +- sources/@roots/bud-purgecss/src/index.ts | 2 +- .../@roots/bud-react/src/extension/index.ts | 4 +- .../bud-react/src/react-refresh/index.ts | 5 +- .../@roots/bud-react/src/swc-refresh/index.ts | 6 +- .../@roots/bud-server/src/service/index.ts | 27 ++- .../@roots/bud-support/src/logger/index.ts | 57 +++--- .../@roots/bud-support/src/utilities/files.ts | 4 - .../@roots/bud-support/src/utilities/paths.ts | 24 +-- .../bud-support/src/which-pm/pmString.ts | 3 +- .../@roots/bud-typescript/src/extension.ts | 149 +++++++++++++--- .../src/extension.ts | 54 +++++- .../bud-wordpress-externals/src/extension.ts | 18 +- .../commands/config/displayConfigFiles.tsx | 34 ++++ .../config/displayGeneratedConfig.tsx | 27 +++ .../bud/src/cli/commands/config/index.tsx | 34 +--- .../bud/src/cli/commands/doctor/index.tsx | 135 ++++++++------- .../bud/src/cli/commands/env/displayEnv.tsx | 29 ++++ .../@roots/bud/src/cli/commands/env/index.tsx | 24 +-- sources/@roots/bud/src/cli/commands/index.tsx | 13 +- .../bud/src/cli/commands/upgrade/index.tsx | 11 +- .../@roots/bud/src/cli/components/Menu.tsx | 8 +- sources/@roots/sage/src/sage/index.ts | 7 +- 46 files changed, 689 insertions(+), 452 deletions(-) create mode 100644 sources/@roots/bud/src/cli/commands/config/displayConfigFiles.tsx create mode 100644 sources/@roots/bud/src/cli/commands/config/displayGeneratedConfig.tsx create mode 100644 sources/@roots/bud/src/cli/commands/env/displayEnv.tsx diff --git a/sources/@roots/bud-api/src/methods/minimize/index.ts b/sources/@roots/bud-api/src/methods/minimize/index.ts index 907785881a..164928cb35 100644 --- a/sources/@roots/bud-api/src/methods/minimize/index.ts +++ b/sources/@roots/bud-api/src/methods/minimize/index.ts @@ -48,6 +48,9 @@ export const minimize: minimize = function (this: Bud, value = true) { return this } - value.map(key => this.minify[key].enable(true)) + value.map(key => { + this.minify[key].enable(true) + }) + return this } diff --git a/sources/@roots/bud-api/src/methods/persist/index.ts b/sources/@roots/bud-api/src/methods/persist/index.ts index c5ea6384a0..a49a248906 100644 --- a/sources/@roots/bud-api/src/methods/persist/index.ts +++ b/sources/@roots/bud-api/src/methods/persist/index.ts @@ -11,14 +11,14 @@ export interface persist { export const persist: persist = function (this: Bud, type = `filesystem`) { if (type === false) { this.cache.enabled = false - this.success(`cache disabled`) + this.api.logger.success(`cache disabled`) return this } this.cache.enabled = true this.cache.type = isString(type) ? type : `filesystem` - this.success(`cache enabled`) + this.api.logger.success(`cache enabled`) return this } diff --git a/sources/@roots/bud-api/test/persist.test.ts b/sources/@roots/bud-api/test/persist.test.ts index e30ae29f86..179c30a61d 100644 --- a/sources/@roots/bud-api/test/persist.test.ts +++ b/sources/@roots/bud-api/test/persist.test.ts @@ -37,19 +37,19 @@ describe(`bud.persist`, () => { }) it(`should call bud.success to log param`, () => { - const successSpy = vi.spyOn(bud, `success`) + const successSpy = vi.spyOn(bud.api.logger, `success`) subject() expect(successSpy).toHaveBeenCalledWith(`cache enabled`) }) it(`should call bud.success to log param`, () => { - const successSpy = vi.spyOn(bud, `success`) + const successSpy = vi.spyOn(bud.api.logger, `success`) subject(true) expect(successSpy).toHaveBeenCalledWith(`cache enabled`) }) it(`should call bud.success to log param`, () => { - const successSpy = vi.spyOn(bud, `success`) + const successSpy = vi.spyOn(bud.api.logger, `success`) subject(false) expect(successSpy).toHaveBeenCalledWith(`cache disabled`) }) diff --git a/sources/@roots/bud-build/src/config/entry.ts b/sources/@roots/bud-build/src/config/entry.ts index 052f8fb785..3b6829618f 100644 --- a/sources/@roots/bud-build/src/config/entry.ts +++ b/sources/@roots/bud-build/src/config/entry.ts @@ -1,7 +1,9 @@ import type {Factory} from '@roots/bud-build/config' export const entry: Factory<`entry`> = async ({hooks}) => { - const entrypoints = hooks.filter(`build.entry`, {main: {import: [`index`]}}) + const entrypoints = hooks.filter(`build.entry`, { + main: {import: [`index`]}, + }) return Object.entries(entrypoints).reduce((acc, [key, value]) => { value.import = [...new Set(value.import)] diff --git a/sources/@roots/bud-build/src/rule/index.ts b/sources/@roots/bud-build/src/rule/index.ts index 4918d362fd..b366acbe1a 100644 --- a/sources/@roots/bud-build/src/rule/index.ts +++ b/sources/@roots/bud-build/src/rule/index.ts @@ -11,6 +11,7 @@ import Registrable from '@roots/bud-build/helpers/registrable' import {bind} from '@roots/bud-support/decorators/bind' import isFunction from '@roots/bud-support/lodash/isFunction' import isString from '@roots/bud-support/lodash/isString' +import logger from '@roots/bud-support/logger' /** * RuleSetRule @@ -273,7 +274,7 @@ class Rule extends Registrable implements Interface { return {...a, [k]: v} }, {}) - this.app.info(`built rule`, output) + logger.info(`built rule`, output) return output } diff --git a/sources/@roots/bud-build/src/service/index.ts b/sources/@roots/bud-build/src/service/index.ts index f233b9dfe4..09b6a3f6df 100644 --- a/sources/@roots/bud-build/src/service/index.ts +++ b/sources/@roots/bud-build/src/service/index.ts @@ -101,7 +101,7 @@ class Build extends Service implements BudBuild { if (isUndefined(value)) return this.config[prop] = value - this.logger.success(`built`, prop) + this.logger.log(`built`, prop) } catch (error) { throw error } @@ -109,7 +109,7 @@ class Build extends Service implements BudBuild { ), ) - this.logger.success(`configuration successfully built`) + this.logger.log(`configuration successfully built`) this.logger.info(this.config) await this.app.hooks.fire(`build.after`, this.app) @@ -157,7 +157,7 @@ class Build extends Service implements BudBuild { : this.makeItem(maybeOptionsCallback) this.items[ident] = item - this.logger.info(`set item`, item) + this.logger.info(item) return this } @@ -177,7 +177,7 @@ class Build extends Service implements BudBuild { : this.makeLoader(definition) this.loaders[name] = loader - this.logger.info(`set loader`, loader) + this.logger.info(loader) return this } @@ -198,7 +198,7 @@ class Build extends Service implements BudBuild { : this.makeRule(definition as any) this.rules[name] = rule - this.logger.info(`set rule`, rule) + this.logger.info(rule) return this } diff --git a/sources/@roots/bud-compiler/src/service/index.tsx b/sources/@roots/bud-compiler/src/service/index.tsx index 09716dda20..dea9114764 100644 --- a/sources/@roots/bud-compiler/src/service/index.tsx +++ b/sources/@roots/bud-compiler/src/service/index.tsx @@ -177,7 +177,6 @@ class Compiler extends Service implements BudCompiler { }) this.logger.timeEnd(`initialize`) - this.app.dashboard.updateStatus(`compiling`) try { this.instance = this.implementation(this.config) diff --git a/sources/@roots/bud-dashboard/src/service.tsx b/sources/@roots/bud-dashboard/src/service.tsx index 3f01d80f2e..f164889746 100644 --- a/sources/@roots/bud-dashboard/src/service.tsx +++ b/sources/@roots/bud-dashboard/src/service.tsx @@ -59,7 +59,7 @@ export class Dashboard extends Service implements BudDashboard { public declare status?: false | string /** - * {@link BudDashboard.stdout} + * {@link BudDashboard.stderr} */ public stderr = stderr @@ -69,7 +69,7 @@ export class Dashboard extends Service implements BudDashboard { public stdin = stdin /** - * {@link BudDashboard.stderr} + * {@link BudDashboard.stdout} */ public stdout = stdout @@ -85,7 +85,6 @@ export class Dashboard extends Service implements BudDashboard { this.stderr = this.app.context.stderr ?? stderr this.formatStatsErrors = makeErrorFormatter(this.app) - this.updateStatus(`Initializing`) this.render() } @@ -277,21 +276,4 @@ export class Dashboard extends Service implements BudDashboard { this.render() return this } - - /** - * {@link BudDashboard.updateStatus} - */ - @bind - public updateStatus(status: string): BudDashboard { - /** - * Update the status prop - */ - this.status = status - - /** - * Render or re-render the application - */ - this.render() - return this - } } diff --git a/sources/@roots/bud-eslint/src/bud/commands/bud.eslint.command.tsx b/sources/@roots/bud-eslint/src/bud/commands/bud.eslint.command.tsx index 1b553d26bd..7838525365 100644 --- a/sources/@roots/bud-eslint/src/bud/commands/bud.eslint.command.tsx +++ b/sources/@roots/bud-eslint/src/bud/commands/bud.eslint.command.tsx @@ -19,7 +19,6 @@ export class BudEslintCommand extends BudCommand { examples: [[`Run eslint on source files`, `$0 eslint`]], }) - public options = Option.Proxy({name: `eslint passthrough options`}) /** @@ -29,12 +28,16 @@ export class BudEslintCommand extends BudCommand { await this.makeBud() await this.bud.run() - const eslintrc = Object.values(this.bud.context.files).find((file) => file.name.includes(`eslintrc`) || file.name.includes(`eslint.config`))?.path + const eslintrc = Object.values(this.bud.context.files).find( + file => + file.name.includes(`eslintrc`) || + file.name.includes(`eslint.config`), + )?.path await this.run([`eslint`, `bin`, `eslint.js`], this.options, [ `--ext`, `.js,.jsx,.ts,.tsx`, - ...(eslintrc ? [`--config`, eslintrc]: []), + ...(eslintrc ? [`--config`, eslintrc] : []), this.bud.relPath(`@src`), ]) } diff --git a/sources/@roots/bud-extensions/src/service/index.ts b/sources/@roots/bud-extensions/src/service/index.ts index e22234c8af..419f1bdfa5 100644 --- a/sources/@roots/bud-extensions/src/service/index.ts +++ b/sources/@roots/bud-extensions/src/service/index.ts @@ -479,8 +479,8 @@ class Extensions extends Service implements BudExtensions { @bind public set(value: Extension): this { const key = (value.label ?? randomUUID()) as any - this.repository[key] = value - this.logger.success(`set`, key) + Object.assign(this.repository, {[key]: value}) + this.logger.info(`set`, key, `=>`, value) return this } diff --git a/sources/@roots/bud-extensions/src/webpack-lifecycle-plugin/index.ts b/sources/@roots/bud-extensions/src/webpack-lifecycle-plugin/index.ts index bb1f5614a4..6fb1889f4e 100644 --- a/sources/@roots/bud-extensions/src/webpack-lifecycle-plugin/index.ts +++ b/sources/@roots/bud-extensions/src/webpack-lifecycle-plugin/index.ts @@ -12,12 +12,6 @@ import {bind, label} from '@roots/bud-framework/extension/decorators' */ @label(`@roots/bud-extensions/webpack-lifecycle-plugin`) export default class BudWebpackLifecyclePlugin extends Extension { - @bind - public afterCompile(compilation: Compilation) { - this.logger.log(`compilation completed:`, compilation.hash) - this.logger.timeEnd(`compile`) - } - /** * {@link Extension.apply} * {@link WebpackPluginInstance.apply} @@ -66,11 +60,23 @@ export default class BudWebpackLifecyclePlugin extends Extension { ) } + /** + * Before compile hook + */ @bind public beforeCompile(compilation: Compilation) { this.logger.time(`compile`) } + /** + * After compile hook + */ + @bind + public afterCompile(compilation: Compilation) { + this.logger.log(`compilation completed:`, compilation.hash) + this.logger.timeEnd(`compile`) + } + @bind public emit(compilation: Compilation) { this.logger.time(`emit`) diff --git a/sources/@roots/bud-framework/src/bootstrap.ts b/sources/@roots/bud-framework/src/bootstrap.ts index d5448d7afe..1ff0c46223 100644 --- a/sources/@roots/bud-framework/src/bootstrap.ts +++ b/sources/@roots/bud-framework/src/bootstrap.ts @@ -75,6 +75,8 @@ export const lifecycle = { 'server.before': `serverBefore`, } +export const services: Array = [] + /** * Define a filter function to validate services based on the current application context. * This function returns true if the service is valid in the current context, false otherwise. @@ -108,31 +110,23 @@ const instantiateServices = throw error instanceof BudError ? BudError.normalize(error) : error }) - let service: BudService - - try { - service = new Service(() => app) - } catch (error) { - const normalError = - error instanceof BudError ? BudError.normalize(error) : error - normalError.message = `Error instantiating service ${signifier}: ${normalError.message}` - return normalError - } - + const value: BudService = new Service(() => app) const label = - service.label ?? service.constructor?.name - ? camelCase(service.constructor.name) + value.label ?? value.constructor?.name + ? camelCase(value.constructor.name) : signifier - app[label] = service + Object.defineProperties(app, { + [label]: { + configurable: true, + value, + writable: true, + }, + }) - logger.log( - chalk.blue(`bud.${label}`), - figures.arrowLeft, - chalk.cyan(!isString(signifier) ? `[object]` : signifier), - ) + logger.log(chalk.blue(label), figures.arrowLeft, chalk.cyan(signifier)) - app.services.push(label) + services.push(label) } /** @@ -209,7 +203,7 @@ export const bootstrap = async function (bud: Bud) { ) Object.entries(lifecycle).map(([eventHandle, callbackName]) => - [...bud.services] + [...services] .map(service => bud[service]) .filter(Boolean) .filter(instance => callbackName in instance) @@ -242,4 +236,6 @@ export const bootstrap = async function (bud: Bud) { ) bud.after(bud.module.after) + + return bud } diff --git a/sources/@roots/bud-framework/src/bud.ts b/sources/@roots/bud-framework/src/bud.ts index 471c204b2f..c196becbc0 100644 --- a/sources/@roots/bud-framework/src/bud.ts +++ b/sources/@roots/bud-framework/src/bud.ts @@ -111,8 +111,6 @@ export class Bud { public declare server?: Service & Server - public declare services: Array - public declare setPath: typeof methods.setPath public declare setPublicPath: typeof methods.setPublicPath @@ -131,6 +129,67 @@ export class Bud { */ public declare yml: FS['yml'] + /** + * True when child compilers + * @readonly + */ + public get hasChildren(): boolean { + return this.children && Object.entries(this.children).length > 0 + } + + /** + * True when current instance is a child instance + * @readonly + */ + public get isChild(): boolean { + return this.root?.context?.label !== this.context?.label + } + + /** + * True when {@link Bud.mode} is `development` + * @readonly + */ + public get isDevelopment(): boolean { + return this.mode === `development` + } + + /** + * True when {@link Bud.mode} is `production` + * @readonly + */ + public get isProduction(): boolean { + return this.mode === `production` + } + + /** + * True when current instance is the parent instance + * @readonly + */ + public get isRoot(): boolean { + return this.root?.context?.label === this.context?.label + } + + /** + * Label + * @readonly + */ + public get label() { + return this.context?.label ?? `bud` + } + + /** + * Compilation mode + * + * @remarks + * Either `production` or `development`. + * + * @readonly + * @defaultValue `production` + */ + public get mode(): `development` | `production` { + return this.context?.mode ?? `production` + } + /** * Boot application services */ @@ -182,14 +241,6 @@ export class Bud { ).catch(this.catch) } - /** - * True when child compilers - * @readonly - */ - public get hasChildren(): boolean { - return this.children && Object.entries(this.children).length > 0 - } - /** * Log info * @deprecated Import logger instance from `@roots/bud-support/logger` @@ -205,68 +256,16 @@ export class Bud { */ @bind public async initialize(context: Context): Promise { - logger.time(`initialize`) - Object.entries(methods).forEach(([key, value]) => { - this[key] = value.bind(this) - }) - - this.set(`services`, []) + this.set(`context`, {...context}) .set(`promised`, Promise.resolve()) - .set(`context`, {...context}) - - await bootstrap(this).catch(this.catch) + .set(`implementation`, this.constructor as any) - return this - } - - /** - * True when current instance is a child instance - * @readonly - */ - public get isChild(): boolean { - return this.root?.context?.label !== this.context?.label - } - - /** - * True when {@link Bud.mode} is `development` - * @readonly - */ - public get isDevelopment(): boolean { - return this.mode === `development` - } - - /** - * True when {@link Bud.mode} is `production` - * @readonly - */ - public get isProduction(): boolean { - return this.mode === `production` - } - - /** - * True when current instance is the parent instance - * @readonly - */ - public get isRoot(): boolean { - return this.root?.context?.label === this.context?.label - } - - /** - * Label - * @readonly - */ - public get label() { - return this.context?.label ?? `bud` - } + Object.entries(methods).reduce( + (_, [k, v]) => this.set(k as any, v.bind(this)), + {}, + ) - /** - * Log message - * @deprecated Import logger instance from `@roots/bud-support/logger` - */ - @bind - public log(...messages: any[]) { - logger.scope(this.label).log(...messages) - return this + return await bootstrap(this).catch(this.catch) } /** @@ -336,19 +335,6 @@ export class Bud { return this } - /** - * Compilation mode - * - * @remarks - * Either `production` or `development`. - * - * @readonly - * @defaultValue `production` - */ - public get mode(): `development` | `production` { - return this.context.mode ?? `production` - } - /** * Await all promised tasks */ @@ -400,13 +386,23 @@ export class Bud { return this } + /** + * Log message + * @deprecated Import logger instance from `@roots/bud-support/logger` + */ + @bind + public log(...messages: any[]) { + logger.scope(this.label).log(...messages) + return this + } + /** * Log success * @deprecated Import logger instance from `@roots/bud-support/logger` */ @bind public success(...messages: any[]) { - logger.scope(this.label).success(...messages) + logger.scope(this.label).log(...messages) return this } diff --git a/sources/@roots/bud-framework/src/extension/index.ts b/sources/@roots/bud-framework/src/extension/index.ts index 83503a2e34..a4e6166cbf 100644 --- a/sources/@roots/bud-framework/src/extension/index.ts +++ b/sources/@roots/bud-framework/src/extension/index.ts @@ -157,11 +157,12 @@ export class Extension< * - {@link Extension.make} */ public enabled: boolean = true - public get = this.getOption + /** * The module name */ public label: `${keyof Modules & string}` + /** * Extension meta */ @@ -172,17 +173,18 @@ export class Extension< configAfter: false, register: false, } + /** * Extension options * * @readonly */ public options: ExtensionOptions + /** * Plugin constructor */ public plugin?: ApplyPluginConstructor - public set = this.setOption /** * Class constructor @@ -204,6 +206,7 @@ export class Extension< public get app(): Bud { return this._app() } + /** * {@link ApplyPlugin.apply} */ @@ -212,10 +215,12 @@ export class Extension< * `boot` callback */ public async boot?(app: Bud): Promise + /** * `buildAfter` callback */ public async buildAfter?(app: Bud): Promise + /** * `buildBefore` callback */ @@ -243,6 +248,7 @@ export class Extension< }, ) } + /** * `configAfter` callback */ @@ -255,6 +261,7 @@ export class Extension< public disable() { this.enabled = false } + /** * Return to bud instance from extension */ @@ -262,21 +269,34 @@ export class Extension< public done(): Bud { return this.app } + /** * Enable extension */ @bind public enable(enabled: boolean = true) { + this.logger.info(`enabled`, this.label) this.enabled = enabled + return this } + /** - * Get extension option + * Get option */ @bind public getOption(key: K): ExtensionOptions[K] { return get(this.options, key) } + /** + * Get an option value + */ + public get = this.getOption + + /** + * Get options + */ + @bind public getOptions(): ExtensionOptions { return Object.entries(this._options).reduce((acc, [key, value]) => { if (isUndefined(value)) return acc @@ -299,6 +319,7 @@ export class Extension< return {...acc, [key]: unwrapped} }, {} as ExtensionOptions) } + /** * Import ESM module */ @@ -315,6 +336,7 @@ export class Extension< .import(signifier, context, options) .catch(this.catch) } + /** * Is extension enabled? */ @@ -322,6 +344,7 @@ export class Extension< public isEnabled(): boolean { return this.when(this.app, this.options) } + /** * Logger instance */ @@ -332,10 +355,12 @@ export class Extension< * `make` callback */ public async make?(app: Bud, options?: ExtensionOptions): Promise + /** * {@link Extension.register} */ public async register?(app: Bud): Promise + /** * Resolve module using `import.meta.resolve` api */ @@ -344,19 +369,20 @@ export class Extension< signifier: string, context: string, ): Promise { - try { - return await this.app.module.resolve(signifier, context) - } catch (error) { - this.catch( - new ExtensionError(`could not resolve ${signifier}`, { - origin: error, - thrownBy: this.label, - }), - ) - } + return await this.app.module + .resolve(signifier, context) + .catch(error => { + this.catch( + new ExtensionError(`could not resolve ${signifier}`, { + origin: error, + thrownBy: this.label, + }), + ) + }) } + /** - * Set extension option + * Set option */ @bind public setOption( @@ -364,22 +390,33 @@ export class Extension< valueOrCallback: OptionCallbackValue, ): this { if (isFunction(valueOrCallback)) { - set(this._options, key, valueOrCallback(this.get(key))) + const resolved = valueOrCallback(this.get(key)) + set(this._options, key, resolved) + this.logger.info(`set`, key, `=>`, resolved) return this } set(this._options, key, valueOrCallback) + this.logger.info(`set`, key, `=>`, valueOrCallback) return this } + /** - * Set extension options + * Set option + */ + public set = this.setOption + + /** + * Set options */ public setOptions( value: Partial>, ): this { + this.logger.info(`set options`, value) this._options = value return this } + /** * Function returning a boolean indicating if the {@link Extension} should be utilized. * @@ -389,6 +426,20 @@ export class Extension< public when(bud: Bud, options?: ExtensionOptions): boolean { return this.enabled } + + /** + * `register` callback handler + */ + @bind + public async _register() { + if (isUndefined(this.register)) return + + if (this.meta[`register`] === true) return + this.meta[`register`] = true + + await this.register(this.app).catch(this.catch) + } + /** * `boot` callback handler */ @@ -453,7 +504,7 @@ export class Extension< try { if (!isUndefined(this.apply)) { - this.logger.info(`apply prop found. return extension instance`) + this.logger.info(`apply method found. return extension instance.`) return this } @@ -472,19 +523,6 @@ export class Extension< this.catch(error) } } - - /** - * `register` callback handler - */ - @bind - public async _register() { - if (isUndefined(this.register)) return - - if (this.meta[`register`] === true) return - this.meta[`register`] = true - - await this.register(this.app).catch(this.catch) - } } export {DynamicOption} diff --git a/sources/@roots/bud-framework/src/fs.ts b/sources/@roots/bud-framework/src/fs.ts index fe09034a36..3a2a318798 100644 --- a/sources/@roots/bud-framework/src/fs.ts +++ b/sources/@roots/bud-framework/src/fs.ts @@ -158,9 +158,9 @@ export class FS extends Filesystem implements Contract { keep?: false | number source?: string }): this { - if (!this.s3) { + if (!this.s3.config.credentials) { throw new BudError( - `S3 is not configured. See https://budjs.dev/reference/bud.fs/s3`, + `S3 is not configured. See https://bud.js.org/reference/bud.fs/s3`, ) } @@ -178,7 +178,7 @@ export class FS extends Filesystem implements Contract { destination ? join(destination, path) : path this.app.after(async () => { - this.app.dashboard.updateStatus(`Deploying files to S3`) + console.log(`Uploading...`) await globby(files, {cwd: source}).then(async files => { const descriptions = await Promise.all( @@ -202,11 +202,11 @@ export class FS extends Filesystem implements Contract { await Promise.all( descriptions.map(async ({contents, file}) => { - this.logger.await(`Upload ${file} to ${this.s3.ident}`) + this.logger.time(`Upload ${file} to ${this.s3.ident}`) try { await this.s3.write(s3Path(file), contents) - this.logger.success(`Upload ${file} to ${this.s3.ident}`) + this.logger.timeEnd(`Upload ${file} to ${this.s3.ident}`) } catch (error) { this.catch(error) } @@ -234,17 +234,17 @@ export class FS extends Filesystem implements Contract { const fileExists = await this.s3.exists(key) if (!fileExists) return - this.logger.await( + this.logger.time( `Remove ${key} from ${this.s3.ident} (stale)`, ) await this.s3.delete(key) - this.logger.success( + this.logger.timeEnd( `Remove ${key} from ${this.s3.ident} (stale)`, ) }), ) - this.logger.await(`Write upload-manifest.json to ${this.s3.ident}`) + this.logger.time(`Write upload-manifest.json to ${this.s3.ident}`) await this.s3.write({ Body: Buffer.from( @@ -256,7 +256,7 @@ export class FS extends Filesystem implements Contract { Key: s3Path(`upload-manifest.json`), }) - this.logger.success( + this.logger.timeEnd( `Write upload-manifest.json to ${this.s3.ident}`, ) }) diff --git a/sources/@roots/bud-framework/src/methods/setPath/index.ts b/sources/@roots/bud-framework/src/methods/setPath/index.ts index 3fec8e0835..cbf6dbc28f 100644 --- a/sources/@roots/bud-framework/src/methods/setPath/index.ts +++ b/sources/@roots/bud-framework/src/methods/setPath/index.ts @@ -87,12 +87,18 @@ const makeCallback = const normal = !isAbsolute(value) ? bud.relPath(value) : value bud.hooks.on(`location.${key}` as keyof SyncRegistry, normal) - logger.log(key, `set to`, normal) - - bud.hooks.async(`build.resolve.alias`, async (paths = {}) => ({ - ...paths, - [key]: isAbsolute(value) ? value : bud.path(value), - })) + logger.success(`set path`, `\`${key}\``, `=>`, `\`${normal}\``) + + bud.hooks.async(`build.resolve.alias`, async (paths = {}) => { + const alias = isAbsolute(value) ? value : bud.path(value) + logger.success( + `set import alias`, + `\`${key}\``, + `=>`, + `\`${alias}\``, + ) + return {...paths, [key]: alias} + }) return bud } diff --git a/sources/@roots/bud-framework/src/project.ts b/sources/@roots/bud-framework/src/project.ts index 33dac53332..9645d27154 100644 --- a/sources/@roots/bud-framework/src/project.ts +++ b/sources/@roots/bud-framework/src/project.ts @@ -44,7 +44,7 @@ export default class Project extends Service { }) }) .finally(() => { - this.logger.success(`profile.yml written to disk`) + this.logger.log(`profile.yml written to disk`) }) await bud.fs @@ -59,7 +59,7 @@ export default class Project extends Service { }) }) .finally(() => { - this.logger.success(`webpack.output.yml written to disk`) + this.logger.log(`webpack.output.yml written to disk`) }) }) } diff --git a/sources/@roots/bud-framework/src/services/dashboard/index.ts b/sources/@roots/bud-framework/src/services/dashboard/index.ts index a427c3056f..63402b87ef 100644 --- a/sources/@roots/bud-framework/src/services/dashboard/index.ts +++ b/sources/@roots/bud-framework/src/services/dashboard/index.ts @@ -76,9 +76,4 @@ export interface Dashboard { * Update the stats */ updateStats(stats?: StatsCompilation): Dashboard - - /** - * Update the status message - */ - updateStatus(status?: string): Dashboard } diff --git a/sources/@roots/bud-hooks/src/base/base.ts b/sources/@roots/bud-hooks/src/base/base.ts index c84980085a..a02719fdb7 100644 --- a/sources/@roots/bud-hooks/src/base/base.ts +++ b/sources/@roots/bud-hooks/src/base/base.ts @@ -32,6 +32,9 @@ export abstract class Hooks { @bind public catch(e: Error, id?: string, iteration?: number): void { + if (!id) { + throw new BudError(e.message ?? `${e}`) + } throw new BudError(`problem running hook ${id}`, {origin: e}) } diff --git a/sources/@roots/bud-hooks/src/event/event.ts b/sources/@roots/bud-hooks/src/event/event.ts index 79e53a83bc..7e4623eec3 100644 --- a/sources/@roots/bud-hooks/src/event/event.ts +++ b/sources/@roots/bud-hooks/src/event/event.ts @@ -19,18 +19,13 @@ export class EventHooks extends Hooks { ): Promise { if (!(id in this.store) || !this.store[id].length) return this.app - this.app.hooks.logger.time(id) - this.app.dashboard?.updateStatus(id) - await Promise.all( this.store[id].map(async (action: any) => { await action(...value).catch((error: Error) => { throw error }) }), - ).catch(error => { - throw error - }) + ).catch(this.catch) return this.app } @@ -42,12 +37,8 @@ export class EventHooks extends Hooks { ): Bud { if (!(id in this.store)) this.store[id] = [] - input.map((value, iteration) => { - this.app.hooks.logger.info( - `registered ${id} callback`, - `(${iteration + 1}/${input.length})`, - ) - + input.map(value => { + this.app.hooks.logger.info(`registered ${id} callback`) this.store[id].push(value as any) }) diff --git a/sources/@roots/bud-preset-wordpress/src/index.ts b/sources/@roots/bud-preset-wordpress/src/index.ts index dd8a78f77d..ff66f2cc7c 100644 --- a/sources/@roots/bud-preset-wordpress/src/index.ts +++ b/sources/@roots/bud-preset-wordpress/src/index.ts @@ -8,7 +8,9 @@ * @see https://github.com/roots/bud */ -import BudPresetWordPress, {type PublicExtension} from '@roots/bud-preset-wordpress/extension' +import BudPresetWordPress, { + type PublicExtension, +} from '@roots/bud-preset-wordpress/extension' declare module '@roots/bud-framework' { interface Bud { diff --git a/sources/@roots/bud-purgecss/src/extension/base.ts b/sources/@roots/bud-purgecss/src/extension/base.ts index 8ebf39dbdc..98b976ff36 100644 --- a/sources/@roots/bud-purgecss/src/extension/base.ts +++ b/sources/@roots/bud-purgecss/src/extension/base.ts @@ -1,8 +1,8 @@ -import type { UserDefinedOptions as Options } from '@fullhuman/postcss-purgecss' +import type {UserDefinedOptions as Options} from '@fullhuman/postcss-purgecss' import {Extension} from '@roots/bud-framework/extension' -import type { BudPurgeCSSPublicInterface } from './model.js' +import type {BudPurgeCSSPublicInterface} from './model.js' export default class BudPurgeCSSPublicAPI extends Extension { public declare blocklist: BudPurgeCSSPublicInterface[`blocklist`] diff --git a/sources/@roots/bud-purgecss/src/extension/model.ts b/sources/@roots/bud-purgecss/src/extension/model.ts index d01d419c13..77a983ba4c 100644 --- a/sources/@roots/bud-purgecss/src/extension/model.ts +++ b/sources/@roots/bud-purgecss/src/extension/model.ts @@ -1,9 +1,6 @@ -import type { UserDefinedOptions as Options } from '@fullhuman/postcss-purgecss' +import type {UserDefinedOptions as Options} from '@fullhuman/postcss-purgecss' import {type StrictPublicExtensionApi} from '@roots/bud-framework/extension' export interface BudPurgeCSSPublicInterface - extends StrictPublicExtensionApi< - BudPurgeCSSPublicInterface, - Options - > {} + extends StrictPublicExtensionApi {} diff --git a/sources/@roots/bud-purgecss/src/facade/index.ts b/sources/@roots/bud-purgecss/src/facade/index.ts index 2e3b4196cf..1a5ea80959 100644 --- a/sources/@roots/bud-purgecss/src/facade/index.ts +++ b/sources/@roots/bud-purgecss/src/facade/index.ts @@ -1,7 +1,9 @@ import type {UserDefinedOptions} from '@fullhuman/postcss-purgecss' import type {Bud} from '@roots/bud-framework' -type Options = ((options?: UserDefinedOptions) => UserDefinedOptions) | UserDefinedOptions +type Options = + | ((options?: UserDefinedOptions) => UserDefinedOptions) + | UserDefinedOptions export interface purgecss { (this: Bud, options: Options): Bud diff --git a/sources/@roots/bud-purgecss/src/index.ts b/sources/@roots/bud-purgecss/src/index.ts index c34179cf23..c731e03c21 100644 --- a/sources/@roots/bud-purgecss/src/index.ts +++ b/sources/@roots/bud-purgecss/src/index.ts @@ -12,7 +12,7 @@ import type {purgecss} from '@roots/bud-purgecss/facade' import BudPurgeCSS from '@roots/bud-purgecss/extension' -import type { BudPurgeCSSPublicInterface } from './extension/model.js' +import type {BudPurgeCSSPublicInterface} from './extension/model.js' declare module '@roots/bud-framework' { interface Bud { diff --git a/sources/@roots/bud-react/src/extension/index.ts b/sources/@roots/bud-react/src/extension/index.ts index 20372892db..944f140ee2 100644 --- a/sources/@roots/bud-react/src/extension/index.ts +++ b/sources/@roots/bud-react/src/extension/index.ts @@ -30,9 +30,7 @@ export default class BudReact extends Extension { */ @bind public override async boot(bud: Bud) { - bud.provide( - await this.resolve(`react`, import.meta.url), [`React`] - ) + bud.provide(await this.resolve(`react`, import.meta.url), [`React`]) await bud.extensions.add(`@roots/bud-react/react-refresh`) diff --git a/sources/@roots/bud-react/src/react-refresh/index.ts b/sources/@roots/bud-react/src/react-refresh/index.ts index 0454eb23b0..f114372173 100644 --- a/sources/@roots/bud-react/src/react-refresh/index.ts +++ b/sources/@roots/bud-react/src/react-refresh/index.ts @@ -116,7 +116,10 @@ export default class BudReactRefresh extends Extension< * {@link Extension.make} */ @bind - public override async make(bud: Bud, options: Options): Promise { + public override async make( + bud: Bud, + options: Options, + ): Promise { return new RefreshPlugin(omit(this.options, [`compilerExtension`])) } diff --git a/sources/@roots/bud-react/src/swc-refresh/index.ts b/sources/@roots/bud-react/src/swc-refresh/index.ts index b1bf0187b5..3cfb670dc8 100644 --- a/sources/@roots/bud-react/src/swc-refresh/index.ts +++ b/sources/@roots/bud-react/src/swc-refresh/index.ts @@ -26,8 +26,10 @@ export default class BudSWCRefresh extends Extension { */ public async registerTransform({isDevelopment, swc}: Bud) { this.logger.log(`Registering swc react-refresh transformer`) - if(!swc) { - this.logger.warn(`SWC not found. Skipping registration of ${this.constructor.name}.`) + if (!swc) { + this.logger.warn( + `SWC not found. Skipping registration of ${this.constructor.name}.`, + ) return this } diff --git a/sources/@roots/bud-server/src/service/index.ts b/sources/@roots/bud-server/src/service/index.ts index ad96588911..309ace8f2c 100644 --- a/sources/@roots/bud-server/src/service/index.ts +++ b/sources/@roots/bud-server/src/service/index.ts @@ -35,14 +35,13 @@ export class Server extends Service implements BudServer { */ public declare watcher: Watcher - /** + /** * {@link BudServer.appliedMiddleware} */ - public appliedMiddleware: Partial< + public appliedMiddleware: Partial< Record > = {} - /** * {@link BudServer.proxyUrl} * @readonly @@ -103,7 +102,9 @@ export class Server extends Service implements BudServer { .catch(this.catch) /** save reference to middleware instance */ - this.appliedMiddleware[key] = factory(this.app) + Object.defineProperty(this.appliedMiddleware, key, { + value: factory(this.app), + }) if (typeof this.appliedMiddleware[key] !== `function`) { this.logger @@ -122,10 +123,12 @@ export class Server extends Service implements BudServer { }, ), ).catch(error => { - this.catch(new ServerError(`Error instantiating middleware`, { - origin: BudError.normalize(error), - thrownBy: `bud.server.applyMiddleware`, - })) + this.catch( + new ServerError(`Error instantiating middleware`, { + origin: BudError.normalize(error), + thrownBy: `bud.server.applyMiddleware`, + }), + ) }) } @@ -225,16 +228,12 @@ export class Server extends Service implements BudServer { public async run() { if (this.app.context.dry === true) return - await this.app.hooks - .fire(`server.before`, this.app) - .catch(this.catch) + await this.app.hooks.fire(`server.before`, this.app).catch(this.catch) await this.connection.createServer(this.application).catch(this.catch) await this.connection.listen() - await this.app.hooks - .fire(`server.after`, this.app) - .catch(this.catch) + await this.app.hooks.fire(`server.after`, this.app).catch(this.catch) } /** diff --git a/sources/@roots/bud-support/src/logger/index.ts b/sources/@roots/bud-support/src/logger/index.ts index d5337a8469..dae10e144b 100644 --- a/sources/@roots/bud-support/src/logger/index.ts +++ b/sources/@roots/bud-support/src/logger/index.ts @@ -8,6 +8,9 @@ import isUndefined from '@roots/bud-support/lodash/isUndefined' import args from '@roots/bud-support/utilities/args' import Signale from 'signale' +/** + * Logger + */ class Logger { /** * Enabled @@ -28,32 +31,32 @@ class Logger { * Class constructor */ public constructor(public options: SignaleOptions = {}) { - if (args.log === false || this.options.disabled) this.enabled = false - - this.options.secrets = - options?.secrets ?? - Object.entries(global.process.env) - .filter( - ( - entry: [string, string | undefined], - ): entry is [string, string] => - !isUndefined(entry[1]) && entry[0].includes(`SECRET`), - ) - .map(([k, v]): string => v) + if (!args.silent) { + if (args.log) this.enabled = true + if ( + this.options.logLevel && + [`info`, `log`].includes(this.options.logLevel) + ) + this.enabled = true + } + + if (args.verbose) { + this.verbose = true + this.options.logLevel === `info` + } - this.instance = new Signale.Signale(this.options) - this.instance.config({displayLabel: false}) + const secretEnv = Object.entries(global.process.env) + .filter(([k, v]) => !isUndefined(v) && k.includes(`SECRET`)) + .map(([_, value]) => `${value}`) - if (args.verbose || this.options.logLevel === `info`) - this.verbose = true + secretEnv.push(process.cwd()) + + this.options.secrets = this.options.secrets + ? [...this.options.secrets, ...secretEnv] + : secretEnv - if ( - args.log || - (this.options.logLevel && - [`info`, `log`].includes(this.options.logLevel)) - ) - this.enabled = true - if (args.silent) this.enabled = false + this.instance = new Signale.Signale(this.options) + this.instance.config({displayBadge: true, displayLabel: false}) } @bind @@ -93,11 +96,11 @@ class Logger { @bind public scope(...scopes: Array) { if (scopes.length === 0) return this - this.instance = this.instance.scope( - ...(scopes.filter(Boolean) ?? [`bud.js`]), - ) + this.instance = this.instance.scope(...scopes) + return this } + @bind public success(...messages: Array) { if (!this.enabled) return this @@ -142,4 +145,4 @@ export const initialize = (options: SignaleOptions) => { return instance } -export {instance, instance as default, Logger} +export {instance as default, Logger} diff --git a/sources/@roots/bud-support/src/utilities/files.ts b/sources/@roots/bud-support/src/utilities/files.ts index 14f3676484..44ae3c062f 100644 --- a/sources/@roots/bud-support/src/utilities/files.ts +++ b/sources/@roots/bud-support/src/utilities/files.ts @@ -45,8 +45,6 @@ const get = async (basedir: string) => { return data } - logger.scope(`fs`).time(`Initializing filesystem`) - files = [] data = {} @@ -221,8 +219,6 @@ async function esTransform({ file: File outfile: string }): Promise { - logger.scope(`fs`).time(`compiling ${file.name}`) - if (!transformer) { transformer = await import(`@roots/bud-support/esbuild`) .then( diff --git a/sources/@roots/bud-support/src/utilities/paths.ts b/sources/@roots/bud-support/src/utilities/paths.ts index a5182c82e0..91384af970 100644 --- a/sources/@roots/bud-support/src/utilities/paths.ts +++ b/sources/@roots/bud-support/src/utilities/paths.ts @@ -2,6 +2,7 @@ import {createHash} from 'node:crypto' import {join} from 'node:path' import {BudError} from '@roots/bud-support/errors' +import logger from '@roots/bud-support/logger' import args from '@roots/bud-support/utilities/args' import * as envBootstrap from '@roots/bud-support/utilities/env' import envPaths from 'env-paths' @@ -55,10 +56,10 @@ const systemPaths = envPaths(`bud`) */ let paths: paths -const get = (directory?: string): paths => { +const get = (basedir?: string): paths => { if (paths) return paths - if (!directory) + if (!basedir) throw new BudError( `directory is required if paths not already initialized`, { @@ -71,19 +72,20 @@ This is most likely a problem with the internals of bud.js.`, }, ) - let basedir: string = directory - let sha1 = createHash(`sha1`).update(directory) + let sha1 = createHash(`sha1`).update(basedir) let hash: string - let env = envBootstrap.get(directory) + let env = envBootstrap.get(basedir) const specified = args.basedir ?? env.APP_BASE_PATH - if (specified && !directory.endsWith(specified)) { - basedir = join( - directory, - specified, - ) + if (specified && !basedir.endsWith(specified)) { + logger.scope(`paths`).log(`using specified basedir:`, specified) + + basedir = join(basedir, specified) + sha1.update(basedir) - env = envBootstrap.get(basedir) + env.basedir = basedir + + logger.scope(`paths`).success(`set basedir to`, basedir) } hash = sha1.digest(`base64url`) diff --git a/sources/@roots/bud-support/src/which-pm/pmString.ts b/sources/@roots/bud-support/src/which-pm/pmString.ts index aaea56d633..7a83845374 100644 --- a/sources/@roots/bud-support/src/which-pm/pmString.ts +++ b/sources/@roots/bud-support/src/which-pm/pmString.ts @@ -3,7 +3,8 @@ export const parse = ( ): `yarn` | `yarn-classic` | `npm` | `pnpm` | false => { if (!pmString) return false - if (pmString.includes(`yarn/3`) || pmString.includes(`yarn@3`)) return `yarn` + if (pmString.includes(`yarn/3`) || pmString.includes(`yarn@3`)) + return `yarn` if (pmString.includes(`yarn`)) return `yarn-classic` if (pmString.includes(`npm`)) return `npm` diff --git a/sources/@roots/bud-typescript/src/extension.ts b/sources/@roots/bud-typescript/src/extension.ts index fa4a552293..96b9272896 100644 --- a/sources/@roots/bud-typescript/src/extension.ts +++ b/sources/@roots/bud-typescript/src/extension.ts @@ -67,41 +67,137 @@ interface Options extends TsLoader.Options { }) @dependsOn([`@roots/bud-typescript/typecheck`]) export default class BudTypeScript extends Extension { - public declare appendTsSuffixTo: Option[`value`] - public declare getAppendTsSuffixTo: Option[`get`] - public declare setAppendTsSuffixTo: Option[`set`] + public declare appendTsSuffixTo: Option< + BudTypeScript, + Options, + `appendTsSuffixTo` + >[`value`] + public declare getAppendTsSuffixTo: Option< + BudTypeScript, + Options, + `appendTsSuffixTo` + >[`get`] + public declare setAppendTsSuffixTo: Option< + BudTypeScript, + Options, + `appendTsSuffixTo` + >[`set`] - public declare appendTsxSuffixTo: Option[`value`] - public declare getAppendTsxSuffixTo: () => Option[`get`] - public declare setAppendTsxSuffixTo: Option[`set`] + public declare appendTsxSuffixTo: Option< + BudTypeScript, + Options, + `appendTsxSuffixTo` + >[`value`] + public declare getAppendTsxSuffixTo: () => Option< + BudTypeScript, + Options, + `appendTsxSuffixTo` + >[`get`] + public declare setAppendTsxSuffixTo: Option< + BudTypeScript, + Options, + `appendTsxSuffixTo` + >[`set`] public declare babel: Option[`value`] public declare getBabel: Option[`get`] public declare setBabel: Option[`set`] - public declare compilerOptions: Option[`value`] - public declare getCompilerOptions: Option[`get`] - public declare setCompilerOptions: Option[`set`] + public declare compilerOptions: Option< + BudTypeScript, + Options, + `compilerOptions` + >[`value`] + public declare getCompilerOptions: Option< + BudTypeScript, + Options, + `compilerOptions` + >[`get`] + public declare setCompilerOptions: Option< + BudTypeScript, + Options, + `compilerOptions` + >[`set`] - public declare configFile: Option[`value`] - public declare getConfigFile: Option[`get`] - public declare setConfigFile: Option[`set`] + public declare configFile: Option< + BudTypeScript, + Options, + `configFile` + >[`value`] + public declare getConfigFile: Option< + BudTypeScript, + Options, + `configFile` + >[`get`] + public declare setConfigFile: Option< + BudTypeScript, + Options, + `configFile` + >[`set`] - public declare context: Option[`value`] - public declare getContext: Option[`get`] - public declare setContext: Option[`set`] + public declare context: Option< + BudTypeScript, + Options, + `context` + >[`value`] + public declare getContext: Option< + BudTypeScript, + Options, + `context` + >[`get`] + public declare setContext: Option< + BudTypeScript, + Options, + `context` + >[`set`] - public declare getCustomTransformers: Option[`value`] - public declare getGetCustomTransformers: Option[`get`] - public declare setGetCustomTransformers: Option[`set`] + public declare getCustomTransformers: Option< + BudTypeScript, + Options, + `getCustomTransformers` + >[`value`] + public declare getGetCustomTransformers: Option< + BudTypeScript, + Options, + `getCustomTransformers` + >[`get`] + public declare setGetCustomTransformers: Option< + BudTypeScript, + Options, + `getCustomTransformers` + >[`set`] - public declare instance: Option[`value`] - public declare getInstance: Option[`get`] - public declare setInstance: Option[`set`] + public declare instance: Option< + BudTypeScript, + Options, + `instance` + >[`value`] + public declare getInstance: Option< + BudTypeScript, + Options, + `instance` + >[`get`] + public declare setInstance: Option< + BudTypeScript, + Options, + `instance` + >[`set`] - public declare transpileOnly: Option[`value`] - public declare getTranspileOnly: Option[`get`] - public declare setTranspileOnly: Option[`set`] + public declare transpileOnly: Option< + BudTypeScript, + Options, + `transpileOnly` + >[`value`] + public declare getTranspileOnly: Option< + BudTypeScript, + Options, + `transpileOnly` + >[`get`] + public declare setTranspileOnly: Option< + BudTypeScript, + Options, + `transpileOnly` + >[`set`] /** * {@link Extension.configAfter} @@ -131,7 +227,10 @@ export default class BudTypeScript extends Extension { const loader = await this.resolve(`ts-loader`, import.meta.url) if (!loader) return this.logger.error(`ts-loader not found`) - const typescriptPath = await this.resolve(`typescript`, import.meta.url) + const typescriptPath = await this.resolve( + `typescript`, + import.meta.url, + ) if (!typescriptPath) { return this.logger.error(`typescript not found`) } diff --git a/sources/@roots/bud-wordpress-dependencies/src/extension.ts b/sources/@roots/bud-wordpress-dependencies/src/extension.ts index 264f8311b3..36cd51036c 100644 --- a/sources/@roots/bud-wordpress-dependencies/src/extension.ts +++ b/sources/@roots/bud-wordpress-dependencies/src/extension.ts @@ -30,15 +30,51 @@ export default class BudWordPressDependencies extends Extension< Options, WordPressDependenciesWebpackPlugin > { - public declare exclude: Option[`value`] - public declare getExclude: Option[`get`] - public declare setExclude: Option[`set`] + public declare exclude: Option< + BudWordPressDependencies, + Options, + `exclude` + >[`value`] + public declare getExclude: Option< + BudWordPressDependencies, + Options, + `exclude` + >[`get`] + public declare setExclude: Option< + BudWordPressDependencies, + Options, + `exclude` + >[`set`] - public declare emitWordPressJson: Option[`value`] - public declare getEmitWordPressJson: Option[`get`] - public declare setEmitWordPressJson: Option[`set`] + public declare emitWordPressJson: Option< + BudWordPressDependencies, + Options, + `emitWordPressJson` + >[`value`] + public declare getEmitWordPressJson: Option< + BudWordPressDependencies, + Options, + `emitWordPressJson` + >[`get`] + public declare setEmitWordPressJson: Option< + BudWordPressDependencies, + Options, + `emitWordPressJson` + >[`set`] - public declare entrypointsPlugin: Option[`value`] - public declare getEntrypointsPlugin: Option[`set`] - public declare setEntrypointsPlugin: Option[`get`] + public declare entrypointsPlugin: Option< + BudWordPressDependencies, + Options, + `entrypointsPlugin` + >[`value`] + public declare getEntrypointsPlugin: Option< + BudWordPressDependencies, + Options, + `entrypointsPlugin` + >[`set`] + public declare setEntrypointsPlugin: Option< + BudWordPressDependencies, + Options, + `entrypointsPlugin` + >[`get`] } diff --git a/sources/@roots/bud-wordpress-externals/src/extension.ts b/sources/@roots/bud-wordpress-externals/src/extension.ts index cee15a9c64..71bb8bcfc2 100644 --- a/sources/@roots/bud-wordpress-externals/src/extension.ts +++ b/sources/@roots/bud-wordpress-externals/src/extension.ts @@ -20,7 +20,11 @@ export default class BudWordPressExternals extends Extension< /** * Excluded packages */ - public declare exclude: Option[`value`] + public declare exclude: Option< + BudWordPressExternals, + Options, + `exclude` + >[`value`] /** * Get excluded packages * @@ -29,7 +33,11 @@ export default class BudWordPressExternals extends Extension< * extension.getExclude() * ``` */ - public declare getExclude: Option[`get`] + public declare getExclude: Option< + BudWordPressExternals, + Options, + `exclude` + >[`get`] /** * Set excluded packages * @@ -45,5 +53,9 @@ export default class BudWordPressExternals extends Extension< * extension.setExclude((exclude = []) => [...exclude, 'jquery']) * ``` */ - public declare setExclude: Option[`set`] + public declare setExclude: Option< + BudWordPressExternals, + Options, + `exclude` + >[`set`] } diff --git a/sources/@roots/bud/src/cli/commands/config/displayConfigFiles.tsx b/sources/@roots/bud/src/cli/commands/config/displayConfigFiles.tsx new file mode 100644 index 0000000000..f420f8bfb2 --- /dev/null +++ b/sources/@roots/bud/src/cli/commands/config/displayConfigFiles.tsx @@ -0,0 +1,34 @@ +import type {Bud} from '@roots/bud' +import {Box, Text} from '@roots/bud-support/ink' + +const DisplayConfigFiles = ({bud}: {bud: Bud}) => { + const configs = Object.values(bud.context.files) + + if (!configs?.length) { + return ( + + + {`\n`} Configuration files{`\n`} + + No configuration files found in project + + ) + } + + return ( + + + {`\n`}Configuration files{`\n`} + + + {configs.map(({bud: isBudConfig, path}, i) => ( + + {path.replace(bud.path(), `.`)} + {isBudConfig && {` (bud config)`}} + + ))} + + ) +} + +export {DisplayConfigFiles as default} diff --git a/sources/@roots/bud/src/cli/commands/config/displayGeneratedConfig.tsx b/sources/@roots/bud/src/cli/commands/config/displayGeneratedConfig.tsx new file mode 100644 index 0000000000..f226a153dc --- /dev/null +++ b/sources/@roots/bud/src/cli/commands/config/displayGeneratedConfig.tsx @@ -0,0 +1,27 @@ +import type {Bud} from '@roots/bud' +import {Box, Text} from '@roots/bud-support/ink' +import format from '@roots/bud-support/pretty-format' + +const DisplayGeneratedConfig = ({bud}: {bud: Bud}) => { + if (!bud.build?.config) { + return ( + + + {`\n`} Generated config{`\n`} + + The configuration could not be generated + + ) + } + + return ( + + + {`\n`}Generated config{`\n`} + + {format(bud.build.config)} + + ) +} + +export {DisplayGeneratedConfig as default} diff --git a/sources/@roots/bud/src/cli/commands/config/index.tsx b/sources/@roots/bud/src/cli/commands/config/index.tsx index 049a86cd11..2d800daa8f 100644 --- a/sources/@roots/bud/src/cli/commands/config/index.tsx +++ b/sources/@roots/bud/src/cli/commands/config/index.tsx @@ -1,6 +1,8 @@ import BudCommand from '@roots/bud/cli/commands' import {Command} from '@roots/bud-support/clipanion' -import {Box, Text} from '@roots/bud-support/ink' + +import DisplayConfigFiles from './displayConfigFiles.js' +import DisplayGeneratedConfig from './displayGeneratedConfig.js' /** * bud env command @@ -24,33 +26,7 @@ export default class ConfigCommand extends BudCommand { await this.makeBud() await this.bud.run() - const configs = Object.values(this.bud.context.files) - - if (!configs.length) { - return ConfigCommand.renderStatic( - - - {`\n`} Configuration files{`\n`} - - No configuration files found in project - , - ) - } - - ConfigCommand.renderStatic( - - - {`\n`}Configuration files{`\n`} - - {configs.map(({bud, path}, i) => ( - - - {path.replace(this.bud.context.basedir, `.`)} - - {bud && {` (bud config)`}} - - ))} - , - ) + ConfigCommand.renderStatic() + ConfigCommand.renderStatic() } } diff --git a/sources/@roots/bud/src/cli/commands/doctor/index.tsx b/sources/@roots/bud/src/cli/commands/doctor/index.tsx index 4e4cdd7052..0d83afa4ae 100644 --- a/sources/@roots/bud/src/cli/commands/doctor/index.tsx +++ b/sources/@roots/bud/src/cli/commands/doctor/index.tsx @@ -1,5 +1,4 @@ /* eslint-disable react/no-unescaped-entities */ -import type {Bud} from '@roots/bud' import type {Extension} from '@roots/bud-framework/extension' import {platform} from 'node:os' @@ -13,6 +12,8 @@ import {Box, Text} from '@roots/bud-support/ink' import webpack from '@roots/bud-support/webpack' import {WinError} from './WinError.js' +import DisplayConfigFiles from '../config/displayConfigFiles.js' +import DisplayEnv from '../env/displayEnv.js' /** * bud doctor command @@ -41,8 +42,6 @@ for a lot of edge cases so it might return a false positive. ], }) - public configuration: Bud[`build`][`config`] - public disabledExtensions: Array<[string, Extension]> = [] public enabledExtensions: Array<[string, Extension]> = [] @@ -72,7 +71,6 @@ for a lot of edge cases so it might return a false positive. const buildTimer = this.makeTimer() await this.makeBud() - await this.bud.run() this.timings.build = buildTimer() @@ -109,6 +107,13 @@ for a lot of edge cases so it might return a false positive. ) } + DoctorCommand.renderStatic( + + Mode + {this.bud.mode} + , + ) + DoctorCommand.renderStatic( Project paths @@ -153,19 +158,18 @@ for a lot of edge cases so it might return a false positive. , ) - DoctorCommand.renderStatic( - - Mode - {this.bud.mode} - , - ) + try { + await this.bud.build.make() + } catch (error) { + console.error(error) + } - await this.cli.run([`config`]) + DoctorCommand.renderStatic() + DoctorCommand.renderStatic() try { - this.configuration = await this.bud.build.make() - this.entrypoints = this.configuration.entry - ? Object.entries(this.configuration.entry) + this.entrypoints = this.bud.build.config.entry + ? Object.entries(this.bud.build.config.entry) : [] await Promise.all( @@ -179,54 +183,47 @@ for a lot of edge cases so it might return a false positive. ), ) } catch (error) { - DoctorCommand.renderStatic( - , - ) + console.error(error) } - await this.cli.run([`env`]) + DoctorCommand.renderStatic( + + Enabled extensions{`\n`} + {this.mapExtensions(this.enabledExtensions)} + , + ) + DoctorCommand.renderStatic( + + Disabled extensions{`\n`} + {this.mapExtensions(this.disabledExtensions)} + , + ) - if (this.enabledExtensions) { - try { - DoctorCommand.renderStatic( - - Enabled extensions{`\n`} - {this.mapExtensions(this.enabledExtensions)} - , - ) - DoctorCommand.renderStatic( - - Disabled extensions{`\n`} - {this.mapExtensions(this.disabledExtensions)} - , - ) - } catch (error) { + try { + if ( + !this.bud.hasChildren && + this.entrypoints && + this.entrypoints.length === 1 && + this.entrypoints[0][0] === `main` && + this.entrypoints[0][1].import[0] === `index` && + !(await this.bud.fs.exists(this.bud.path(`@src/index.js`))) + ) { DoctorCommand.renderStatic( - , + , ) } - } - - if ( - !this.bud.hasChildren && - this.entrypoints.length === 1 && - this.entrypoints[0][0] === `main` && - this.entrypoints[0][1].import[0] === `index` && - !(await this.bud.fs.exists(this.bud.path(`@src/index.js`))) - ) { - DoctorCommand.renderStatic( - , - ) + } catch (error) { + this.catch(error) } if (this.bud.mode === `development`) { @@ -236,24 +233,30 @@ for a lot of edge cases so it might return a false positive. URL: - {` `}{this.bud.server.url.href} + {` `} + {this.bud.server.url.href} - {this.bud.server?.enabledMiddleware && Object.keys(this.bud.server.enabledMiddleware).includes(`proxy`) && this.bud.server.proxyUrl && ( - - Proxy: - - {` `}{this.bud.server.proxyUrl.href} - - - )} + {this.bud.server?.enabledMiddleware && + Object.keys(this.bud.server.enabledMiddleware).includes( + `proxy`, + ) && + this.bud.server.proxyUrl && ( + + Proxy: + + {` `} + {this.bud.server.proxyUrl.href} + + + )} , ) } try { - webpack.validate(this.configuration) + webpack.validate(this.bud.build.config) DoctorCommand.renderStatic( diff --git a/sources/@roots/bud/src/cli/commands/env/displayEnv.tsx b/sources/@roots/bud/src/cli/commands/env/displayEnv.tsx new file mode 100644 index 0000000000..bc3834fa32 --- /dev/null +++ b/sources/@roots/bud/src/cli/commands/env/displayEnv.tsx @@ -0,0 +1,29 @@ +import type {Bud} from '@roots/bud' +import {Box, Text} from '@roots/bud-support/ink' + +const DisplayEnv = ({bud}: {bud: Bud}) => { + return ( + + + {`\n`}Environment variables{`\n`} + + + {bud.env + .getEntries() + .sort((a, b) => + a[0].toLowerCase().localeCompare(b[0].toLowerCase()), + ) + .map(([key, value]) => { + return ( + + + {key}={`${value}`} + + + ) + })} + + ) +} + +export {DisplayEnv as default} diff --git a/sources/@roots/bud/src/cli/commands/env/index.tsx b/sources/@roots/bud/src/cli/commands/env/index.tsx index f1e4613788..e099f1711a 100644 --- a/sources/@roots/bud/src/cli/commands/env/index.tsx +++ b/sources/@roots/bud/src/cli/commands/env/index.tsx @@ -1,6 +1,7 @@ import BudCommand from '@roots/bud/cli/commands' import {Command} from '@roots/bud-support/clipanion' -import {Box, Text} from '@roots/bud-support/ink' + +import DisplayEnv from './displayEnv.js' /** * bud env command @@ -25,25 +26,6 @@ export default class EnvCommand extends BudCommand { await this.makeBud() await this.bud.run() - EnvCommand.renderStatic( - - {`\n`}Environment variables{`\n`} - - {this.bud.env - .getEntries() - .sort((a, b) => - a[0].toLowerCase().localeCompare(b[0].toLowerCase()), - ) - .map(([key, value]) => { - return ( - - - {key}={`${value}`} - - - ) - })} - , - ) + EnvCommand.renderStatic() } } diff --git a/sources/@roots/bud/src/cli/commands/index.tsx b/sources/@roots/bud/src/cli/commands/index.tsx index 0d1db97500..5c830ca485 100644 --- a/sources/@roots/bud/src/cli/commands/index.tsx +++ b/sources/@roots/bud/src/cli/commands/index.tsx @@ -310,10 +310,15 @@ export default class BudCommand extends Command { @bind public async makeBud() { const applyCliOptionsCallback = async (bud: Bud) => { - await bud.promise(async bud => await Promise.all([ - this.applyBudManifestOptions(bud), - this.applyBudArguments(bud), - ]).catch(this.catch)).catch(this.catch) + await bud + .promise( + async bud => + await Promise.all([ + this.applyBudManifestOptions(bud), + this.applyBudArguments(bud), + ]).catch(this.catch), + ) + .catch(this.catch) } this.context.dry = this.dry diff --git a/sources/@roots/bud/src/cli/commands/upgrade/index.tsx b/sources/@roots/bud/src/cli/commands/upgrade/index.tsx index 6bf5dfe823..232cb7102b 100644 --- a/sources/@roots/bud/src/cli/commands/upgrade/index.tsx +++ b/sources/@roots/bud/src/cli/commands/upgrade/index.tsx @@ -405,11 +405,12 @@ export default class BudUpgradeCommand extends BudCommand { logger.log(this.bin, this.subcommand, ...signifiers, ...flags) - await this.$(this.bin, [ - this.subcommand, - ...signifiers, - ...flags, - ], undefined, () => {}).catch(error => { + await this.$( + this.bin, + [this.subcommand, ...signifiers, ...flags], + undefined, + () => {}, + ).catch(error => { logger.error(error) }) } diff --git a/sources/@roots/bud/src/cli/components/Menu.tsx b/sources/@roots/bud/src/cli/components/Menu.tsx index cb5c6a1303..8aae67fcfe 100644 --- a/sources/@roots/bud/src/cli/components/Menu.tsx +++ b/sources/@roots/bud/src/cli/components/Menu.tsx @@ -24,9 +24,11 @@ export const Menu = ({cli}: {cli: BudCommand[`cli`]}) => { .reduce((acc, cmd, id) => { return [ ...acc, - cmd.examples?.map(([description, path]) => { - return {cmd, description, id, path} - }).shift(), + cmd.examples + ?.map(([description, path]) => { + return {cmd, description, id, path} + }) + .shift(), ].filter(Boolean) }, []), ) diff --git a/sources/@roots/sage/src/sage/index.ts b/sources/@roots/sage/src/sage/index.ts index 91cf3462af..b65268e490 100644 --- a/sources/@roots/sage/src/sage/index.ts +++ b/sources/@roots/sage/src/sage/index.ts @@ -50,7 +50,12 @@ class Sage extends Extension { () => bud.hash(), () => bud.devtool(), ) - .hooks.on(`build.output.uniqueName`, bud.label !== `sage` ? `@roots/bud/sage/${bud.label}` : `@roots/bud/sage`) + .hooks.on( + `build.output.uniqueName`, + bud.label !== `sage` + ? `@roots/bud/sage/${bud.label}` + : `@roots/bud/sage`, + ) } /**