Skip to content

Commit

Permalink
feat: update ioc,config module
Browse files Browse the repository at this point in the history
  • Loading branch information
nailiable committed Oct 29, 2024
1 parent cdf4d5a commit 33fe0d0
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 20 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@
"ioc": "container",
"rpc": "server",
".vitepress": "vuepress",
"unplugin-rpc": "plugin"
"unplugin-rpc": "plugin",
"rpc-protocol": "interface",
"jexl": "src"
},
"vite.autoStart": false
}
10 changes: 10 additions & 0 deletions fixtures/backend/src/custom-configuration.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { UserInputConfig } from 'c12'
import { Configuration } from '@nailyjs/config'
import { Service } from '@nailyjs/ioc'

@Service(Configuration)
export class CustomConfigurationService implements Configuration {
configure(defaultConfiguration: UserInputConfig): UserInputConfig | Promise<UserInputConfig> {
return defaultConfiguration
}
}
5 changes: 3 additions & 2 deletions fixtures/backend/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { NodeBootstrap } from '@nailyjs/backend/node-adapter'
import { Configuration } from '@nailyjs/config'
import { ConfigurationPlugin } from '@nailyjs/config'
import './custom-configuration.service'
import './test.controller'
import './test.filter'

new NodeBootstrap()
.use(Configuration())
.use(ConfigurationPlugin())
.then(bootstrap => bootstrap.run(3000))
.then(() => console.log(`Backend started on port http://localhost:3000`))
45 changes: 45 additions & 0 deletions packages/config/src/config-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { ResolvedConfig, UserInputConfig } from 'c12'
import { Container, Injectable } from '@nailyjs/ioc'
// eslint-disable-next-line ts/consistent-type-imports
import { JexlExecutor } from '@nailyjs/jexl'
import { loadConfig } from 'c12'
import { Configuration as ConfigurationSymbol } from './plugin-protocol'

@Injectable()
export class ConfigProvider {
constructor(private readonly jexlExecutor: JexlExecutor) {}

private getDefaultConfiguration(): UserInputConfig {
return {
name: 'naily',
}
}

private c12InstanceCache: ResolvedConfig | undefined
private async getC12Instance(config: UserInputConfig = this.getDefaultConfiguration()): ReturnType<typeof loadConfig> {
if (this.c12InstanceCache) return this.c12InstanceCache
const c12Instance = await loadConfig(config || this.getDefaultConfiguration())
this.c12InstanceCache = c12Instance
return c12Instance
}

private getCustomConfigurationTarget(bootstrap: Container): ConfigurationSymbol | undefined {
const customTarget = bootstrap.getInjectableTargetByToken(ConfigurationSymbol)
if (!customTarget) return undefined
return customTarget.getOrCreateInstance()
}

async readConfiguration(bootstrap: Container = new Container()): ReturnType<typeof loadConfig> {
const customTargetInstance = this.getCustomConfigurationTarget(bootstrap)
if (!customTargetInstance) return await this.getC12Instance()

if (!customTargetInstance.configure || typeof customTargetInstance.configure !== 'function')
return await this.getC12Instance()
const configuration = await customTargetInstance.configure(this.getDefaultConfiguration())
return await this.getC12Instance(configuration)
}

async evaluateExpression<El extends string>(el: El): Promise<any> {
return this.jexlExecutor.evalSync(el, (await this.readConfiguration()).config)
}
}
2 changes: 2 additions & 0 deletions packages/config/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './config-provider'
export * from './decorators'
export * from './plugin'
export * from './plugin-protocol'
export * from './types'
6 changes: 6 additions & 0 deletions packages/config/src/plugin-protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { UserInputConfig } from 'c12'

export const Configuration = '__naily_config_custom_configuration__'
export interface Configuration {
configure(defaultConfiguration: UserInputConfig): UserInputConfig | Promise<UserInputConfig>
}
18 changes: 7 additions & 11 deletions packages/config/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ import type { Container, PluginProtocol } from '@nailyjs/ioc'
import type { ValueMetadata } from './decorators'
import { InjectableWrapper } from '@nailyjs/ioc'
import { JexlExecutor } from '@nailyjs/jexl'
import { loadConfig } from 'c12'

class ConfigurationPlugin implements PluginProtocol {
private readConfiguration(): ReturnType<typeof loadConfig> {
return loadConfig({
name: 'naily',
})
}
import { ConfigProvider } from './config-provider'

class ConfigurationPluginImpl implements PluginProtocol {
async install(bootstrap: Container): Promise<void> {
const injectableContainer = bootstrap.getInjectableContainer()
const jexlExecutor: JexlExecutor = InjectableWrapper.getOrCreateInjectableWrapper(JexlExecutor).getOrCreateInstance()
const configuration = await this.readConfiguration()
const configProvider: ConfigProvider = InjectableWrapper.getOrCreateInjectableWrapper(ConfigProvider).getOrCreateInstance()

const configuration = await configProvider.readConfiguration(bootstrap)
const newInjectableContainer = new Set<InjectableWrapper>()

for (const wrapper of injectableContainer) {
Expand Down Expand Up @@ -52,6 +48,6 @@ class ConfigurationPlugin implements PluginProtocol {
}
}

export function Configuration(): PluginProtocol {
return new ConfigurationPlugin()
export function ConfigurationPlugin(): PluginProtocol {
return new ConfigurationPluginImpl()
}
16 changes: 11 additions & 5 deletions packages/ioc/src/decorators/injectable.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,23 @@ export function Injectable(options: Partial<InjectableOptions> = {}): ClassDecor
/**
* Mark a class as an injectable service.
*
* @export
* @param {Partial<InjectableOptions>} [options] Options for the injectable service.
* @exports
* @param {InjectionToken} injectionToken Injection token for the injectable service.
* @param {Omit<Partial<InjectableOptions>, 'injectionToken'>} extraOptions Options for the injectable service.
* @return {ClassDecorator}
*/
export const Service = Injectable
export function Service(injectionToken: InjectionToken, extraOptions?: Omit<Partial<InjectableOptions>, 'injectionToken'>): ClassDecorator {
return Injectable({ ...extraOptions, injectionToken })
}

/**
* Mark a class as an injectable service.
*
* @exports
* @param {Partial<InjectableOptions>} [options] Options for the injectable service.
* @param {InjectionToken} injectionToken Injection token for the injectable service.
* @param {Omit<Partial<InjectableOptions>, 'injectionToken'>} extraOptions Options for the injectable service.
* @return {ClassDecorator}
*/
export const Component = Injectable
export function Component(injectionToken?: InjectionToken, extraOptions?: Omit<Partial<InjectableOptions>, 'injectionToken'>): ClassDecorator {
return Injectable({ ...extraOptions, injectionToken })
}
7 changes: 6 additions & 1 deletion packages/ioc/src/injectable-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ export class InjectableWrapper<TClass extends Class = Class> extends Container i
/**
* ### Get the injectable options of the target class.
*
* If the options `injectionToken` is not provided, it will return the target class.
*
* @return {InjectableOptions}
* @memberof InjectableWrapper
*/
getInjectableOptions(): InjectableOptions {
return Reflect.getMetadata(InjectableSymbol, this.target) || {}
const options: InjectableOptions = Reflect.getMetadata(InjectableSymbol, this.target) || {}
if (!options.injectionToken || (Array.isArray(options.injectionToken) && options.injectionToken.length === 0))
options.injectionToken = this.target
return options
}

/**
Expand Down

0 comments on commit 33fe0d0

Please sign in to comment.