-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: move boot related stuff from core to a mixin
- Loading branch information
Showing
62 changed files
with
481 additions
and
1,599 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Copyright IBM Corp. 2018. All Rights Reserved. | ||
// Node module: @loopback/boot | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
import {Constructor, Binding, BindingScope, Context} from '@loopback/context'; | ||
import {Booter, BootOptions, Bootable} from './interfaces'; | ||
import {BootComponent} from './boot.component'; | ||
import {Bootstrapper} from './bootstrapper'; | ||
import {BootBindings} from './keys'; | ||
|
||
// Binding is re-exported as Binding / Booter types are needed when consuming | ||
// BootMixin and this allows a user to import them from the same package (UX!) | ||
export {Binding}; | ||
|
||
/** | ||
* Mixin for @loopback/boot. This Mixin provides the following: | ||
* - Implements the Bootable Interface as follows. | ||
* - Add a `projectRoot` property to the Class | ||
* - Adds an optional `bootOptions` property to the Class that can be used to | ||
* store the Booter conventions. | ||
* - Adds the `BootComponent` to the Class (which binds the Bootstrapper and default Booters) | ||
* - Provides the `boot()` convenience method to call Bootstrapper.boot() | ||
* - Provides the `booter()` convenience method to bind a Booter(s) to the Application | ||
* - Override `component()` to call `mountComponentBooters` | ||
* - Adds `mountComponentBooters` which binds Booters to the application from `component.booters[]` | ||
* | ||
* ******************** NOTE ******************** | ||
* Trying to constrain the type of this Mixin (or any Mixin) will cause errors. | ||
* For example, constraining this Mixin to type Application require all types using by | ||
* Application to be imported (including it's dependencies such as ResolutionSession). | ||
* Another issue was that if a Mixin that is type constrained is used with another Mixin | ||
* that is not, it will result in an error. | ||
* Example (class MyApp extends BootMixin(RepositoryMixin(Application))) {}; | ||
********************* END OF NOTE ******************** | ||
*/ | ||
// tslint:disable-next-line:no-any | ||
export function BootMixin<T extends Constructor<any>>(superClass: T) { | ||
return class extends superClass implements Bootable { | ||
projectRoot: string; | ||
bootOptions?: BootOptions; | ||
|
||
// tslint:disable-next-line:no-any | ||
constructor(...args: any[]) { | ||
super(...args); | ||
this.component(BootComponent); | ||
|
||
// We Dynamically bind the Project Root and Boot Options so these values can | ||
// be used to resolve an instance of the Bootstrapper (as they are dependencies) | ||
this.bind(BootBindings.PROJECT_ROOT).toDynamicValue( | ||
() => this.projectRoot, | ||
); | ||
this.bind(BootBindings.BOOT_OPTIONS).toDynamicValue( | ||
() => this.bootOptions, | ||
); | ||
} | ||
|
||
/** | ||
* Convenience method to call bootstrapper.boot() by resolving bootstrapper | ||
*/ | ||
async boot(): Promise<void> { | ||
// Get a instance of the BootStrapper | ||
const bootstrapper: Bootstrapper = await this.get( | ||
BootBindings.BOOTSTRAPPER_KEY, | ||
); | ||
|
||
await bootstrapper.boot(); | ||
} | ||
|
||
/** | ||
* Given a N number of Booter Classes, this method binds them using the | ||
* prefix and tag expected by the Bootstrapper. | ||
* | ||
* @param booterCls Booter classes to bind to the Application | ||
* | ||
* ```ts | ||
* app.booters(MyBooter, MyOtherBooter) | ||
* ``` | ||
*/ | ||
booters(...booterCls: Constructor<Booter>[]): Binding[] { | ||
// tslint:disable-next-line:no-any | ||
return booterCls.map(cls => _bindBooter(<Context>(<any>this), cls)); | ||
} | ||
|
||
/** | ||
* Override to ensure any Booter's on a Component are also mounted. | ||
* | ||
* @param component The component to add. | ||
* | ||
* ```ts | ||
* | ||
* export class ProductComponent { | ||
* booters = [ControllerBooter, RepositoryBooter]; | ||
* providers = { | ||
* [AUTHENTICATION_STRATEGY]: AuthStrategy, | ||
* [AUTHORIZATION_ROLE]: Role, | ||
* }; | ||
* }; | ||
* | ||
* app.component(ProductComponent); | ||
* ``` | ||
*/ | ||
public component(component: Constructor<{}>) { | ||
super.component(component); | ||
this.mountComponentBooters(component); | ||
} | ||
|
||
/** | ||
* Get an instance of a component and mount all it's | ||
* booters. This function is intended to be used internally | ||
* by component() | ||
* | ||
* @param component The component to mount booters of | ||
*/ | ||
mountComponentBooters(component: Constructor<{}>) { | ||
const componentKey = `components.${component.name}`; | ||
const compInstance = this.getSync(componentKey); | ||
|
||
if (compInstance.booters) { | ||
this.booters(...compInstance.booters); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Method which binds a given Booter to a given Context with the Prefix and | ||
* Tags expected by the Bootstrapper | ||
* | ||
* @param ctx The Context to bind the Booter Class | ||
* @param booterCls Booter class to be bound | ||
*/ | ||
export function _bindBooter( | ||
ctx: Context, | ||
booterCls: Constructor<Booter>, | ||
): Binding { | ||
return ctx | ||
.bind(`${BootBindings.BOOTER_PREFIX}.${booterCls.name}`) | ||
.toClass(booterCls) | ||
.inScope(BindingScope.CONTEXT) | ||
.tag(BootBindings.BOOTER_TAG); | ||
} |
Oops, something went wrong.