Using services

Basic usage

To use a service in Diabolo, you need to use the createFunction function.

import * as DI from 'diabolo'

const mainFunction = DI.createFunction(function* () {
  // ...
})

Note

The createFunction function does nothing other than returning what you pass to it. It is used to improve your development experience, but you can use the function* syntax directly if you want.

Now, you can use the yield * DI.requireService function to get the service you want.

import * as DI from 'diabolo'

const mainFunction = DI.createFunction(function* () {
  const myService = yield * DI.requireService(myService)
  myService.myFunction()
})

Your function can also be asynchronous.

import * as DI from 'diabolo'

const mainFunction = DI.createFunction(async function* () {
  const myService = yield * DI.requireService(myService)
  await myService.myFunction()
})

Composing functions

You can run a function inside another function by using the yield * syntax.

import * as DI from 'diabolo'

const function1 = DI.createFunction(function* () {
  const myService = yield * DI.requireService(myService)
  myService.myFunction()
})

const function2 = DI.createFunction(function* () {
  yield * function1()
})

Stateful services

When you use the requireService function, it will run the lazy implementation of the service if it has not been run yet. Otherwise, if you already required the service, it will return the same instance.

In other words, by default, services have a state.

It means that you can access and modify the same state in different functions.

import * as DI from 'diabolo'

interface CounterService extends DI.Service<'Counter', {
  increment: () => void
  state: number
}> { }

const counterService = DI.createService<CounterService>('Counter')

const counterServiceImpl = DI.lazyCreateServiceImpl<CounterService>(() => {
  let state = 0
  return {
    increment: () => {
      state++
    },
    get state() { return state },
  }
})

const function1 = DI.createFunction(function* () {
  const counter = yield * DI.requireService(counterService)
  counter.increment()
})

const function2 = DI.createFunction(function* () {
  const counter = yield * DI.requireService(counterService)
  counter.increment()
})

const function3 = DI.createFunction(function* () {
  const counter = yield * DI.requireService(counterService)
  return counter.state
})

const mainFunction = DI.createFunction(function* () {
  yield * function1()
  yield * function2()
  const state = yield * function3()
  return state
})

const result = DI.provide(mainFunction, {
  Counter: counterServiceImpl
})()

// result === 2