Skip to content

Commit e19161e

Browse files
Merge pull request #83 from uniocjs/dev-groupguanfang
docs(changeset): feat: add custom error handler (#82)
2 parents feaa9a2 + 4c019dc commit e19161e

File tree

5 files changed

+79
-2
lines changed

5 files changed

+79
-2
lines changed

.changeset/little-donuts-act.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@unioc/core": patch
3+
---
4+
5+
feat: add custom error handler (#82)

packages/core/core/src/bootstrap.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ export abstract class AbstractBootstrap extends AbstractContext implements IBoot
6262
async initialize(): Promise<void> {
6363
if (this.isInitialized)
6464
return
65-
6665
const logger = await this.getInternalLogger()
6766
const pluginContext = new PluginContext(this, logger)
6867
const pluginList = await this._pluginResolver.getResolvedPlugins()
6968
const pluginExecutor = new PluginExecutor(pluginList, pluginContext)
7069
super.setPluginExecutor(pluginExecutor)
70+
pluginContext.setPluginExecutor(pluginExecutor)
7171
Service.CONTAINER.forEach(cls => super.createClass(cls))
7272
await pluginExecutor.executeInstall()
7373
this.isInitialized = true

packages/core/core/src/contexts/plugins/plugin-context.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { IBootstrap, IContainer, IInternalLogger, IPluginContext } from '../../types'
1+
import type { IBootstrap, IContainer, IHandleExecutorOptions, IInternalLogger, IPlugin, IPluginContext } from '../../types'
2+
import type { PluginExecutor } from './plugin-executor'
23
import k from 'kleur'
34
import { GLOBAL_CONTAINER } from '../../container/container'
45
import { AbstractContext } from '../context'
@@ -9,6 +10,10 @@ export class PluginContext extends AbstractContext implements IPluginContext {
910
private readonly _logger: IInternalLogger,
1011
) { super() }
1112

13+
setPluginExecutor(pluginExecutor: PluginExecutor): this {
14+
return super.setPluginExecutor(pluginExecutor)
15+
}
16+
1217
getGlobalContainer(): IContainer {
1318
return GLOBAL_CONTAINER
1419
}
@@ -37,4 +42,18 @@ export class PluginContext extends AbstractContext implements IPluginContext {
3742
this._pluginName = pluginName
3843
return this
3944
}
45+
46+
async handle(options: IHandleExecutorOptions): Promise<IPlugin.Handle.Context> {
47+
const pluginExecutor = this.getPluginExecutor()
48+
if (!pluginExecutor)
49+
throw new Error('[UNIOC] Plugin executor is not set in plugin context.')
50+
51+
return await pluginExecutor.executeHandle(
52+
options.classWrapper,
53+
options.propertyKey,
54+
options.methodArguments,
55+
options.error,
56+
'error',
57+
)
58+
}
4059
}

packages/core/core/src/types/plugin.ts

+29
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,42 @@ import type { IContainer } from './container'
66
import type { IContext } from './context'
77
import type { IInternalLogger } from './logger'
88

9+
export interface IHandleExecutorOptions {
10+
/**
11+
* The class wrapper.
12+
*/
13+
classWrapper: IClassWrapper
14+
/**
15+
* The `catch` error.
16+
*/
17+
error: unknown
18+
/**
19+
* The current method property key.
20+
*/
21+
propertyKey: PropertyKey
22+
/**
23+
* The current method arguments.
24+
*/
25+
methodArguments: unknown[]
26+
}
27+
928
export interface IPluginContext extends IContext, IInternalLogger, IBootstrapDeriver {
1029
/**
1130
* ### Get global container
1231
*
1332
* 🌏 Get the global container.
1433
*/
1534
getGlobalContainer(): IContainer
35+
/**
36+
* ### Handle
37+
*
38+
* ❌ A function that is used to handle when a class instance method throw an error.
39+
* It can pass the error to enter the plugin pipe context.
40+
*
41+
* @param options - The position information of the `try/catch block`.
42+
* @returns The plugin handle context.
43+
*/
44+
handle(options: IHandleExecutorOptions): Promise<IPlugin.Handle.Context>
1645
}
1746

1847
export interface IPlugin {

packages/core/core/test/index.test.ts

+24
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,16 @@ describe('plugin Testing', () => {
2929
expect(this.childPropertyService).toBeInstanceOf(ChildService)
3030
expect(this.childPropertyService.foo).toBe('bar')
3131
}
32+
33+
willThrowError() {
34+
throw new Error('Test error!')
35+
}
3236
}
3337

3438
class TestingApp extends AbstractBootstrap {
3539
async run(): Promise<void> {
40+
let hasWillThrowError = false
41+
3642
super.use({
3743
name: 'test',
3844

@@ -42,6 +48,19 @@ describe('plugin Testing', () => {
4248
const testServiceInstance = await testClassWrapper.resolve()
4349
expect(testServiceInstance).toBeInstanceOf(TestService)
4450

51+
// Custom error handler
52+
try {
53+
testServiceInstance.willThrowError()
54+
}
55+
catch (error) {
56+
await this.handle({
57+
classWrapper: testClassWrapper,
58+
error,
59+
propertyKey: 'willThrowError',
60+
methodArguments: [],
61+
})
62+
}
63+
4564
const testValueWrapper = bootstrap.createValue('test-value', 'test-value-token')
4665
expect(isValueWrapper(testValueWrapper)).toBe(true)
4766
expect(testValueWrapper.getValue()).toBe('test-value')
@@ -153,9 +172,14 @@ describe('plugin Testing', () => {
153172
expect(ctx.getPropertyKey()).toBe('onReady')
154173
expect(ctx.getMethodArguments()).toEqual(['test-arg-in-invoke-hook'])
155174
}
175+
176+
if (ctx.getPropertyKey() === 'willThrowError') {
177+
hasWillThrowError = true
178+
}
156179
},
157180
})
158181
await super.initialize()
182+
expect(hasWillThrowError).toBe(true)
159183
}
160184
}
161185

0 commit comments

Comments
 (0)