Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
brusc is a lightweight but powerful Dependency Container to enable Inversion Of Control for Javascript projects (Node/Browser).
Index
Start using Brusc:
Also:
npm install brusc --save
Create an inject
function shared across your context to be used in the classes / functions / wherever declaring dependencies to inject:
inject.js
const inject = key => inject.provide(key)
export default inject
The
provide
function will be added by Brusc in next step. This is needed to be created this way in order to enable any class/function to use it likeaProperty=inject('aPropertyKey'')
.
Define your inject
bindings to a Brusc Container:
MovieApplicationInitializer.js
// imports...
import Brusc from 'brusc'
import inject from './inject'
export class MovieApplicationInitializer {
static init() {
Brusc.define(inject)
.singleton('getMoviesUseCase', () => new GetMoviesUseCase())
.singleton('saveMovieUseCase', () => new SaveMovieUseCase())
.singleton('movieRepository', () => new MovieRepositoryHttpImpl())
.singleton('httpClient', () => new AxiosHttpClient())
.create()
return new MovieApplication()
}
}
Use the inject function to assign the instances where they're needed.
In the last snippet, suppose that the MovieApplication
is the library facade, which uses the Use Cases, and each one need the MovieRepository
which also will need a Http Client to perform the actions.
After defining the inject
function in Brusc and creating the container with instance provider declarations like .singleton(key => instance_provider_function)
you'll be able to create each application component (use case, service, repository, ...) assigning its dependencies in the constructor (preferably) like:
GetMoviesUseCase.js
import inject from './inject'
export class GetMoviesUseCase {
constructor({movieRepository = inject('movieRepository')} = {}) {
// ...
}
}
MovieApplication.js
import inject from './inject'
export class MovieApplication {
constructor({getMoviesUseCase = inject('getMoviesUseCase'), saveMovieUseCase = inject('saveMovieUseCase')} = {}) {
// ...
}
}
And so on, easy like that :)
You'll be able to test the your full application's facade API the same way it'll be used, allowing instance mocks replacing defined instance providers if needed:
// ...
import inject from './inject'
describe('MovieApplication', () => {
it('should request the movies collection', async () => {
const httpClientMock = {
fetch: (url) => Promise.resolve(...)
}
const fetchSpy = sinon.spy(httpClientMock, 'fetch')
// this instance providers will be used by the Brusc Container instead of defined ones,
// and defaults are cleared after container creation to avoid being used in next creations
// of another tests, so instance providers can be specified for each test and also be declared in a beforeEach.
inject.defaults = {
httpClient: () => httpClientMock
}
// assuming the example of MovieApplicationInitializer in the "Defining the Brusc Container" section,
// init will create the container to be used in the real Movie Application
const movieApplication = MovieApplicationInitializer.init()
await movieApplication.getMovies({title: 'robocop'})
expect(fetchSpy.getCall(0).args[0]).to.include('title=%robocop%')
})
})
Brusc acts as a Container builder exposing the methods:
.define(injectFunction)
Receives an injectFunction
to which the Container's instance provider will be assigned in the injectFunction.provide(key)
function.
Should be called only once in the Brusc definition chain.
See Creating an inject function
.singleton(key, instanceProviderFunction, isEager)
Binds a key
to an instance provider function to declare a singleton instance in the Container.
A singleton is an instance which after first instantiation will be kept in the container and any further requests to the container for the same key will be resolved with that first instantiated instance.
This method can be called from zero times to each key/singleton instance provider binding.
key
(required) must be any value assignable to a Map key (p.ex. a string like 'userRepository'
, but also a class declaration like UserRepository
if using class as interface declarations would be accepted).instanceProviderFunction
(required) must be a function which must return a value when called, no matter if it's a constant, a function or a new class instantiation.isEager
(optional, defaults to false) indicates if an instance must be loaded just when the Brusc container ends with its declaration (eager), or will be instantiated on the first inject(key)
usage (lazy)..prototype(key, instanceProviderFunction)
Binds a key
to an instance provider function to declare prototype instances in the Container.
A prototype will be instantiated for each
inject(key)
usage, returning a fresh value for the injection.In most situations, singletons are preferrable over prototypes, but if a component must have a mutable state consider using prototypes.
This method can be called from zero times to each key/prototype instance provider binding.
key
(required) must be any value assignable to a Map key.instanceProviderFunction
(required) must be a function which must return a value when called, no matter if it's a constant, a function or a new class instantiation..adapter({name, match, adapt})
Allow instances to be decorated / proxied / adapted to any custom need, based on key matching, when instances are instantiated in the Container and before they are injected.
This method can be called from zero times to each instance adapter requirement
name
(optional, but defaults to UnnamedAdapter) the name of the adapter, only for debug / error trace intentions.match(key)
(required) is a function that will be used to detect instances to which apply the modification if returns true
.adapt(instance, key)
(required) is a function that must return an instance which can be the original one, but also a decorated one, proxied, ....adapter({
name: 'UseCaseTimeLogger',
match: key => key.endsWith('UseCase'),
adapt: (instance, key) => ({ // just for the sample, a specific class would be better :)
execute: async params => {
const start = Date.now()
try {
const result = await instance.execute(params)
return result
} finally {
console.log(`${key} spent ${Date.now() - start}ms to execute`)
}
}
})
})
In this case, instead of injecting the original instance defined with p.ex. .singleton('getMoviesUseCase')
, the injected use case will be a decorated instance to measure the time spent in the use case's execute
method.
.create
Ends with the Brusc Container declaration for the inject
method and assigns a provide
function to it.
So, after this, the given inject
function will be enabled for dependency injection, using it like:
const anInstance = inject('anInstanceKey')
Remember that to allow this, the inject function should be declared like
export const inject = key => inject.provide(key)
create
method is called on Brusc declaration will cause an exception.:wrench: Maintenance info
npm run...
Use the PR template to explain:
This project uses Travis CI for:
To create a new Release, take in mind:
FAQs
IOC Container for Effective JS development
The npm package brusc receives a total of 1,288 weekly downloads. As such, brusc popularity was classified as popular.
We found that brusc demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.