@declaro/core 2.0.0-y.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{LICENSE → LICENSE.md} +1 -1
- package/README.md +203 -0
- package/dist/browser/index.js +28 -0
- package/dist/browser/index.js.map +133 -0
- package/dist/browser/scope/index.js +3 -0
- package/dist/browser/scope/index.js.map +9 -0
- package/dist/bun/index.js +19011 -0
- package/dist/bun/index.js.map +132 -0
- package/dist/bun/scope/index.js +4 -0
- package/dist/bun/scope/index.js.map +9 -0
- package/dist/node/index.cjs +19039 -0
- package/dist/node/index.cjs.map +132 -0
- package/dist/node/index.js +19010 -0
- package/dist/node/index.js.map +132 -0
- package/dist/node/scope/index.cjs +69 -0
- package/dist/node/scope/index.cjs.map +9 -0
- package/dist/node/scope/index.js +3 -0
- package/dist/node/scope/index.js.map +9 -0
- package/dist/ts/app/app-context.d.ts +9 -0
- package/dist/ts/app/app-context.d.ts.map +1 -0
- package/dist/ts/app/app-lifecycle.d.ts +6 -0
- package/dist/ts/app/app-lifecycle.d.ts.map +1 -0
- package/dist/ts/app/app.d.ts +24 -0
- package/dist/ts/app/app.d.ts.map +1 -0
- package/dist/{app → ts/app}/index.d.ts +1 -0
- package/dist/ts/app/index.d.ts.map +1 -0
- package/dist/ts/application/create-request-context.d.ts +4 -0
- package/dist/ts/application/create-request-context.d.ts.map +1 -0
- package/dist/ts/application/create-request-context.test.d.ts +2 -0
- package/dist/ts/application/create-request-context.test.d.ts.map +1 -0
- package/dist/ts/application/use-declaro.d.ts +3 -0
- package/dist/ts/application/use-declaro.d.ts.map +1 -0
- package/dist/{auth → ts/auth}/permission-validator.d.ts +1 -0
- package/dist/ts/auth/permission-validator.d.ts.map +1 -0
- package/dist/ts/auth/permission-validator.test.d.ts +2 -0
- package/dist/ts/auth/permission-validator.test.d.ts.map +1 -0
- package/dist/ts/context/async-context.d.ts +54 -0
- package/dist/ts/context/async-context.d.ts.map +1 -0
- package/dist/ts/context/async-context.test.d.ts +2 -0
- package/dist/ts/context/async-context.test.d.ts.map +1 -0
- package/dist/{context → ts/context}/context-consumer.d.ts +4 -0
- package/dist/ts/context/context-consumer.d.ts.map +1 -0
- package/dist/ts/context/context.circular-deps.test.d.ts +2 -0
- package/dist/ts/context/context.circular-deps.test.d.ts.map +1 -0
- package/dist/ts/context/context.d.ts +452 -0
- package/dist/ts/context/context.d.ts.map +1 -0
- package/dist/ts/context/context.test.d.ts +2 -0
- package/dist/ts/context/context.test.d.ts.map +1 -0
- package/dist/ts/context/legacy-context.test.d.ts +2 -0
- package/dist/ts/context/legacy-context.test.d.ts.map +1 -0
- package/dist/{context → ts/context}/validators.d.ts +2 -1
- package/dist/ts/context/validators.d.ts.map +1 -0
- package/dist/ts/dataflow/index.d.ts +2 -0
- package/dist/ts/dataflow/index.d.ts.map +1 -0
- package/dist/ts/dataflow/objects.d.ts +7 -0
- package/dist/ts/dataflow/objects.d.ts.map +1 -0
- package/dist/ts/dataflow/objects.test.d.ts +2 -0
- package/dist/ts/dataflow/objects.test.d.ts.map +1 -0
- package/dist/{errors → ts/errors}/errors.d.ts +16 -3
- package/dist/ts/errors/errors.d.ts.map +1 -0
- package/dist/ts/events/event-manager.d.ts +19 -0
- package/dist/ts/events/event-manager.d.ts.map +1 -0
- package/dist/ts/events/event-manager.spec.d.ts +2 -0
- package/dist/ts/events/event-manager.spec.d.ts.map +1 -0
- package/dist/ts/events/index.d.ts +2 -0
- package/dist/ts/events/index.d.ts.map +1 -0
- package/dist/ts/http/headers.d.ts +21 -0
- package/dist/ts/http/headers.d.ts.map +1 -0
- package/dist/ts/http/headers.spec.d.ts +2 -0
- package/dist/ts/http/headers.spec.d.ts.map +1 -0
- package/dist/ts/http/request-context.d.ts +17 -0
- package/dist/ts/http/request-context.d.ts.map +1 -0
- package/dist/ts/http/request-context.spec.d.ts +2 -0
- package/dist/ts/http/request-context.spec.d.ts.map +1 -0
- package/dist/ts/http/request.d.ts +31 -0
- package/dist/ts/http/request.d.ts.map +1 -0
- package/dist/ts/http/request.spec.d.ts +2 -0
- package/dist/ts/http/request.spec.d.ts.map +1 -0
- package/dist/{http → ts/http}/url.d.ts +5 -4
- package/dist/ts/http/url.d.ts.map +1 -0
- package/dist/ts/http/url.spec.d.ts +2 -0
- package/dist/ts/http/url.spec.d.ts.map +1 -0
- package/dist/ts/index.d.ts +47 -0
- package/dist/ts/index.d.ts.map +1 -0
- package/dist/{pipelines → ts/pipelines}/index.d.ts +1 -0
- package/dist/ts/pipelines/index.d.ts.map +1 -0
- package/dist/{pipelines → ts/pipelines}/pipeline-action.d.ts +1 -0
- package/dist/ts/pipelines/pipeline-action.d.ts.map +1 -0
- package/dist/ts/pipelines/pipeline-action.test.d.ts +2 -0
- package/dist/ts/pipelines/pipeline-action.test.d.ts.map +1 -0
- package/dist/{pipelines → ts/pipelines}/pipeline.d.ts +3 -2
- package/dist/ts/pipelines/pipeline.d.ts.map +1 -0
- package/dist/ts/pipelines/pipeline.test.d.ts +2 -0
- package/dist/ts/pipelines/pipeline.test.d.ts.map +1 -0
- package/dist/ts/schema/json-schema.d.ts +12 -0
- package/dist/ts/schema/json-schema.d.ts.map +1 -0
- package/dist/ts/schema/labels.d.ts +14 -0
- package/dist/ts/schema/labels.d.ts.map +1 -0
- package/dist/ts/schema/model-schema.d.ts +75 -0
- package/dist/ts/schema/model-schema.d.ts.map +1 -0
- package/dist/ts/schema/model-schema.test.d.ts +2 -0
- package/dist/ts/schema/model-schema.test.d.ts.map +1 -0
- package/dist/ts/schema/model.d.ts +35 -0
- package/dist/ts/schema/model.d.ts.map +1 -0
- package/dist/ts/schema/schema-mixin.d.ts +24 -0
- package/dist/ts/schema/schema-mixin.d.ts.map +1 -0
- package/dist/ts/schema/test/mock-model.d.ts +8 -0
- package/dist/ts/schema/test/mock-model.d.ts.map +1 -0
- package/dist/ts/scope/index.d.ts +34 -0
- package/dist/ts/scope/index.d.ts.map +1 -0
- package/dist/ts/shared/utils/action-descriptor.d.ts +28 -0
- package/dist/ts/shared/utils/action-descriptor.d.ts.map +1 -0
- package/dist/ts/shared/utils/action-descriptor.test.d.ts +2 -0
- package/dist/ts/shared/utils/action-descriptor.test.d.ts.map +1 -0
- package/dist/ts/shared/utils/schema-utils.d.ts +3 -0
- package/dist/ts/shared/utils/schema-utils.d.ts.map +1 -0
- package/dist/ts/shared/utils/schema-utils.test.d.ts +2 -0
- package/dist/ts/shared/utils/schema-utils.test.d.ts.map +1 -0
- package/dist/ts/shims/async-local-storage.d.ts +36 -0
- package/dist/ts/shims/async-local-storage.d.ts.map +1 -0
- package/dist/ts/shims/async-local-storage.test.d.ts +2 -0
- package/dist/ts/shims/async-local-storage.test.d.ts.map +1 -0
- package/dist/{timing.d.ts → ts/timing.d.ts} +1 -0
- package/dist/ts/timing.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/arrays.d.ts +1 -0
- package/dist/ts/typescript/arrays.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/baseModel.d.ts +1 -0
- package/dist/ts/typescript/baseModel.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/classes.d.ts +1 -0
- package/dist/ts/typescript/classes.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/constant-manipulation/snake-case.d.ts +1 -0
- package/dist/ts/typescript/constant-manipulation/snake-case.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/errors.d.ts +1 -0
- package/dist/ts/typescript/errors.d.ts.map +1 -0
- package/dist/ts/typescript/fetch.d.ts +3 -0
- package/dist/ts/typescript/fetch.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/generics.d.ts +1 -0
- package/dist/ts/typescript/generics.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/index.d.ts +1 -0
- package/dist/ts/typescript/index.d.ts.map +1 -0
- package/dist/ts/typescript/objects.d.ts +26 -0
- package/dist/ts/typescript/objects.d.ts.map +1 -0
- package/dist/{typescript → ts/typescript}/promises.d.ts +1 -0
- package/dist/ts/typescript/promises.d.ts.map +1 -0
- package/dist/{validation → ts/validation}/index.d.ts +1 -0
- package/dist/ts/validation/index.d.ts.map +1 -0
- package/dist/{validation → ts/validation}/validation.d.ts +1 -0
- package/dist/ts/validation/validation.d.ts.map +1 -0
- package/dist/{validation → ts/validation}/validator.d.ts +1 -0
- package/dist/ts/validation/validator.d.ts.map +1 -0
- package/dist/ts/validation/validator.test.d.ts +2 -0
- package/dist/ts/validation/validator.test.d.ts.map +1 -0
- package/package.json +46 -13
- package/src/app/app-context.ts +4 -5
- package/src/app/app-lifecycle.ts +4 -3
- package/src/app/app.ts +7 -5
- package/src/application/create-request-context.test.ts +345 -0
- package/src/application/create-request-context.ts +19 -0
- package/src/application/use-declaro.ts +27 -0
- package/src/auth/permission-validator.test.ts +238 -2
- package/src/auth/permission-validator.ts +3 -3
- package/src/context/async-context.test.ts +348 -0
- package/src/context/async-context.ts +129 -0
- package/src/context/context-consumer.ts +4 -4
- package/src/context/context.circular-deps.test.ts +1047 -0
- package/src/context/context.test.ts +420 -3
- package/src/context/context.ts +590 -87
- package/src/context/legacy-context.test.ts +9 -9
- package/src/dataflow/objects.test.ts +7 -7
- package/src/dataflow/objects.ts +10 -9
- package/src/errors/errors.ts +19 -3
- package/src/events/event-manager.spec.ts +129 -0
- package/src/events/event-manager.ts +25 -14
- package/src/http/headers.ts +17 -2
- package/src/http/request-context.ts +24 -15
- package/src/http/request.ts +27 -6
- package/src/http/url.ts +3 -3
- package/src/index.ts +34 -3
- package/src/pipelines/pipeline.test.ts +11 -9
- package/src/schema/json-schema.ts +16 -0
- package/src/schema/labels.ts +23 -23
- package/src/schema/model-schema.test.ts +282 -0
- package/src/schema/model-schema.ts +197 -0
- package/src/schema/model.ts +143 -0
- package/src/schema/schema-mixin.ts +51 -0
- package/src/schema/test/mock-model.ts +19 -0
- package/src/scope/index.ts +33 -0
- package/src/shared/utils/action-descriptor.test.ts +182 -0
- package/src/shared/utils/action-descriptor.ts +102 -0
- package/src/shared/utils/schema-utils.test.ts +33 -0
- package/src/shared/utils/schema-utils.ts +17 -0
- package/src/shims/async-local-storage.test.ts +258 -0
- package/src/shims/async-local-storage.ts +82 -0
- package/src/typescript/objects.ts +32 -1
- package/src/validation/validator.test.ts +12 -20
- package/dist/app/app-context.d.ts +0 -8
- package/dist/app/app-lifecycle.d.ts +0 -4
- package/dist/app/app.d.ts +0 -22
- package/dist/auth/permission-validator.test.d.ts +0 -1
- package/dist/context/context.d.ts +0 -161
- package/dist/context/context.test.d.ts +0 -1
- package/dist/context/legacy-context.test.d.ts +0 -1
- package/dist/dataflow/index.d.ts +0 -1
- package/dist/dataflow/objects.d.ts +0 -5
- package/dist/dataflow/objects.test.d.ts +0 -1
- package/dist/events/event-manager.d.ts +0 -16
- package/dist/events/event-manager.spec.d.ts +0 -1
- package/dist/events/index.d.ts +0 -1
- package/dist/helpers/index.d.ts +0 -1
- package/dist/helpers/ucfirst.d.ts +0 -1
- package/dist/http/headers.d.ts +0 -4
- package/dist/http/headers.spec.d.ts +0 -1
- package/dist/http/request-context.d.ts +0 -12
- package/dist/http/request-context.spec.d.ts +0 -1
- package/dist/http/request.d.ts +0 -8
- package/dist/http/request.spec.d.ts +0 -1
- package/dist/http/url.spec.d.ts +0 -1
- package/dist/index.d.ts +0 -19
- package/dist/pipelines/pipeline-action.test.d.ts +0 -1
- package/dist/pipelines/pipeline.test.d.ts +0 -1
- package/dist/pkg.cjs +0 -30
- package/dist/pkg.mjs +0 -56612
- package/dist/schema/application.d.ts +0 -83
- package/dist/schema/application.test.d.ts +0 -1
- package/dist/schema/define-model.d.ts +0 -10
- package/dist/schema/define-model.test.d.ts +0 -1
- package/dist/schema/formats.d.ts +0 -10
- package/dist/schema/index.d.ts +0 -10
- package/dist/schema/labels.d.ts +0 -13
- package/dist/schema/labels.test.d.ts +0 -1
- package/dist/schema/module.d.ts +0 -7
- package/dist/schema/module.test.d.ts +0 -1
- package/dist/schema/properties.d.ts +0 -19
- package/dist/schema/response.d.ts +0 -31
- package/dist/schema/response.test.d.ts +0 -1
- package/dist/schema/supported-types.d.ts +0 -12
- package/dist/schema/supported-types.test.d.ts +0 -1
- package/dist/schema/transform-model.d.ts +0 -4
- package/dist/schema/transform-model.test.d.ts +0 -1
- package/dist/schema/types.d.ts +0 -95
- package/dist/schema/types.test.d.ts +0 -1
- package/dist/typescript/fetch.d.ts +0 -2
- package/dist/typescript/objects.d.ts +0 -12
- package/dist/validation/validator.test.d.ts +0 -1
- package/src/helpers/index.ts +0 -1
- package/src/helpers/ucfirst.ts +0 -3
- package/src/schema/application.test.ts +0 -286
- package/src/schema/application.ts +0 -150
- package/src/schema/define-model.test.ts +0 -81
- package/src/schema/define-model.ts +0 -50
- package/src/schema/formats.ts +0 -23
- package/src/schema/index.ts +0 -10
- package/src/schema/labels.test.ts +0 -60
- package/src/schema/module.test.ts +0 -39
- package/src/schema/module.ts +0 -6
- package/src/schema/properties.ts +0 -40
- package/src/schema/response.test.ts +0 -101
- package/src/schema/response.ts +0 -93
- package/src/schema/supported-types.test.ts +0 -20
- package/src/schema/supported-types.ts +0 -15
- package/src/schema/transform-model.test.ts +0 -31
- package/src/schema/transform-model.ts +0 -24
- package/src/schema/types.test.ts +0 -28
- package/src/schema/types.ts +0 -163
- package/tsconfig.json +0 -11
- package/vite.config.ts +0 -24
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { Context } from './context'
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { Context, type DeclaroScope, type ExtractScope } from './context'
|
|
3
|
+
import type { IEvent } from '../events'
|
|
3
4
|
|
|
4
5
|
describe('Context', () => {
|
|
5
6
|
it('Should allow value dependency injection', async () => {
|
|
@@ -238,7 +239,7 @@ describe('Context', () => {
|
|
|
238
239
|
|
|
239
240
|
expect(factoryInstances).toBe(0)
|
|
240
241
|
|
|
241
|
-
await context.
|
|
242
|
+
await context.initializeEagerDependencies()
|
|
242
243
|
|
|
243
244
|
expect(factoryInstances).toBe(1)
|
|
244
245
|
|
|
@@ -632,4 +633,420 @@ describe('Context', () => {
|
|
|
632
633
|
'four calling birds, three French hens, two turtle doves, and a partridge in a pear tree',
|
|
633
634
|
)
|
|
634
635
|
})
|
|
636
|
+
|
|
637
|
+
it('should override an async factory with a new value', async () => {
|
|
638
|
+
type ScopeA = {
|
|
639
|
+
foo: Promise<string>
|
|
640
|
+
bar: Promise<number>
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const contextA = new Context<ScopeA>()
|
|
644
|
+
|
|
645
|
+
contextA.registerAsyncFactory('foo', async () => 'Hello', [], {
|
|
646
|
+
singleton: true,
|
|
647
|
+
})
|
|
648
|
+
contextA.registerAsyncFactory('bar', async () => 42, [], {
|
|
649
|
+
singleton: true,
|
|
650
|
+
})
|
|
651
|
+
|
|
652
|
+
const contextB = new Context<ScopeA>()
|
|
653
|
+
|
|
654
|
+
contextB.extend(contextA)
|
|
655
|
+
contextB.registerAsyncFactory('foo', async () => 'Goodbye', [], {
|
|
656
|
+
singleton: true,
|
|
657
|
+
})
|
|
658
|
+
contextB.registerAsyncFactory('bar', async () => 100, [], {
|
|
659
|
+
singleton: true,
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
const foo = await contextB.resolve('foo')
|
|
663
|
+
const bar = await contextB.resolve('bar')
|
|
664
|
+
|
|
665
|
+
expect(foo).toBe('Goodbye')
|
|
666
|
+
expect(bar).toBe(100)
|
|
667
|
+
})
|
|
668
|
+
|
|
669
|
+
it('should inherit emitter listeners, passing in the new context, when extending', async () => {
|
|
670
|
+
const contextACallback = vi.fn()
|
|
671
|
+
const contextBCallback = vi.fn()
|
|
672
|
+
|
|
673
|
+
type ScopeA = {
|
|
674
|
+
foo: string
|
|
675
|
+
bar: number
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
type ScopeB = ScopeA & {
|
|
679
|
+
baz: string
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
type TestEvent = IEvent & {
|
|
683
|
+
message: string
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const contextA = new Context<ScopeA>()
|
|
687
|
+
contextA.registerValue('foo', 'Hello')
|
|
688
|
+
contextA.registerValue('bar', 42)
|
|
689
|
+
contextA.on<TestEvent>('test', contextACallback)
|
|
690
|
+
|
|
691
|
+
const contextB = new Context<ScopeB>()
|
|
692
|
+
contextB.extend(contextA)
|
|
693
|
+
contextB.registerValue('baz', 'World')
|
|
694
|
+
contextB.on<TestEvent>('test', contextBCallback)
|
|
695
|
+
|
|
696
|
+
const eventA: TestEvent = {
|
|
697
|
+
type: 'test',
|
|
698
|
+
message: 'Hello World',
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
await contextB.emit('test')
|
|
702
|
+
|
|
703
|
+
expect(contextACallback).toHaveBeenCalledTimes(1)
|
|
704
|
+
expect(contextBCallback).toHaveBeenCalledTimes(1)
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
it('should cancel eager initialization when a depedency is overridden', async () => {
|
|
708
|
+
type Scope = {
|
|
709
|
+
foo: string
|
|
710
|
+
bar: Promise<number>
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
const context = new Context<Scope>()
|
|
714
|
+
|
|
715
|
+
const context1Factory = vi.fn(() => 'Hello')
|
|
716
|
+
const context2Factory = vi.fn(() => 'Goodbye')
|
|
717
|
+
const context1AsyncFactory = vi.fn(async () => 42)
|
|
718
|
+
const context2AsyncFactory = vi.fn(async () => 100)
|
|
719
|
+
|
|
720
|
+
context.registerFactory('foo', context1Factory, [], {
|
|
721
|
+
eager: true,
|
|
722
|
+
})
|
|
723
|
+
context.registerAsyncFactory('bar', context1AsyncFactory, [], {
|
|
724
|
+
eager: true,
|
|
725
|
+
})
|
|
726
|
+
|
|
727
|
+
const context2 = new Context<Scope>()
|
|
728
|
+
context2.extend(context)
|
|
729
|
+
context2.registerFactory('foo', context2Factory, [], {
|
|
730
|
+
eager: true,
|
|
731
|
+
})
|
|
732
|
+
context2.registerAsyncFactory('bar', context2AsyncFactory, [], {
|
|
733
|
+
eager: true,
|
|
734
|
+
})
|
|
735
|
+
|
|
736
|
+
context.registerValue('foo', 'Goodbye')
|
|
737
|
+
|
|
738
|
+
await context2.initializeEagerDependencies()
|
|
739
|
+
|
|
740
|
+
expect(context1Factory).toHaveBeenCalledTimes(0)
|
|
741
|
+
expect(context2Factory).toHaveBeenCalledTimes(1)
|
|
742
|
+
expect(context1AsyncFactory).toHaveBeenCalledTimes(0)
|
|
743
|
+
expect(context2AsyncFactory).toHaveBeenCalledTimes(1)
|
|
744
|
+
})
|
|
745
|
+
|
|
746
|
+
it('should not override singletons when extending, without an explicit override', async () => {
|
|
747
|
+
type Scope = {
|
|
748
|
+
foo: {
|
|
749
|
+
message: string
|
|
750
|
+
_id?: number
|
|
751
|
+
}
|
|
752
|
+
bar: {
|
|
753
|
+
message: string
|
|
754
|
+
_id?: number
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const context1 = new Context<Scope>()
|
|
759
|
+
context1.registerFactory('foo', () => ({ message: 'Hello' }), [], {
|
|
760
|
+
singleton: true,
|
|
761
|
+
})
|
|
762
|
+
|
|
763
|
+
const foo1 = context1.resolve('foo')
|
|
764
|
+
foo1._id = 1
|
|
765
|
+
|
|
766
|
+
const context2 = new Context<Scope>()
|
|
767
|
+
context2.extend(context1)
|
|
768
|
+
|
|
769
|
+
const context3 = new Context<Scope>()
|
|
770
|
+
context3.extend(context1)
|
|
771
|
+
|
|
772
|
+
const foo2 = context2.resolve('foo')
|
|
773
|
+
|
|
774
|
+
const foo3 = context3.resolve('foo')
|
|
775
|
+
|
|
776
|
+
expect(foo2).toBe(foo3)
|
|
777
|
+
expect(foo2._id).toBe(1)
|
|
778
|
+
})
|
|
779
|
+
|
|
780
|
+
it('should dispatch event objects and event strings', async () => {
|
|
781
|
+
interface CustomEvent extends IEvent {
|
|
782
|
+
type: 'test'
|
|
783
|
+
message: string
|
|
784
|
+
}
|
|
785
|
+
const event: CustomEvent = {
|
|
786
|
+
type: 'test',
|
|
787
|
+
message: 'Hello World',
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const contextACallback = vi.fn()
|
|
791
|
+
|
|
792
|
+
const contextA = new Context<DeclaroScope>()
|
|
793
|
+
|
|
794
|
+
contextA.on<CustomEvent>('test', contextACallback)
|
|
795
|
+
|
|
796
|
+
await contextA.emit(event)
|
|
797
|
+
|
|
798
|
+
expect(contextACallback).toHaveBeenCalledTimes(1)
|
|
799
|
+
expect(contextACallback.mock.calls[0][1]).toEqual(event)
|
|
800
|
+
expect(contextACallback.mock.calls[0][0]).toBe(contextA)
|
|
801
|
+
})
|
|
802
|
+
|
|
803
|
+
it('should be able to emit events directly through the emitter', async () => {
|
|
804
|
+
interface CustomEvent extends IEvent {
|
|
805
|
+
type: 'test'
|
|
806
|
+
message: string
|
|
807
|
+
}
|
|
808
|
+
const event: CustomEvent = {
|
|
809
|
+
type: 'test',
|
|
810
|
+
message: 'Hello World',
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const contextACallback = vi.fn()
|
|
814
|
+
|
|
815
|
+
const contextA = new Context<DeclaroScope>()
|
|
816
|
+
|
|
817
|
+
contextA.events.on('test', contextACallback)
|
|
818
|
+
|
|
819
|
+
await contextA.events.emitAsync(event)
|
|
820
|
+
|
|
821
|
+
expect(contextACallback).toHaveBeenCalledTimes(1)
|
|
822
|
+
expect(contextACallback.mock.calls[0][0]).toEqual(event)
|
|
823
|
+
})
|
|
824
|
+
|
|
825
|
+
it('should not squash errors in event handlers', async () => {
|
|
826
|
+
const context = new Context<DeclaroScope>()
|
|
827
|
+
const callback = vi.fn()
|
|
828
|
+
|
|
829
|
+
context.on('test', () => {
|
|
830
|
+
callback()
|
|
831
|
+
throw new Error('Test error')
|
|
832
|
+
})
|
|
833
|
+
|
|
834
|
+
expect(callback).not.toHaveBeenCalled()
|
|
835
|
+
await expect(context.emit('test')).rejects.toThrow('Test error')
|
|
836
|
+
})
|
|
837
|
+
|
|
838
|
+
it('should be able to define an extracted scope type', () => {
|
|
839
|
+
type Scope = {
|
|
840
|
+
foo: string
|
|
841
|
+
bar: number
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const context = new Context<Scope>()
|
|
845
|
+
|
|
846
|
+
type ExtractedScope = ExtractScope<typeof context>
|
|
847
|
+
|
|
848
|
+
const extractedScope: ExtractedScope = {
|
|
849
|
+
foo: 'Hello',
|
|
850
|
+
bar: 42,
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const _: Context<Scope> = new Context<ExtractedScope>()
|
|
854
|
+
|
|
855
|
+
expect(extractedScope.foo).toBe('Hello')
|
|
856
|
+
expect(extractedScope.bar).toBe(42)
|
|
857
|
+
})
|
|
858
|
+
|
|
859
|
+
it('should be able to use middleware that requires a subset of the context scope', () => {
|
|
860
|
+
type Scope = {
|
|
861
|
+
foo: string
|
|
862
|
+
bar: number
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
type ModuleScope = {
|
|
866
|
+
bar: number
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const middleware = (context: Context<ModuleScope>) => {
|
|
870
|
+
// This middleware only needs 'bar', not 'foo'
|
|
871
|
+
expect(context.resolve('bar')).toBe(42)
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
const context = new Context<Scope>()
|
|
875
|
+
context.registerValue('foo', 'test')
|
|
876
|
+
context.registerValue('bar', 42)
|
|
877
|
+
|
|
878
|
+
// This should work - the context has more than what the middleware needs
|
|
879
|
+
return context.use(middleware)
|
|
880
|
+
})
|
|
881
|
+
|
|
882
|
+
it('should be able to apply a full context to a partial', () => {
|
|
883
|
+
type Scope = {
|
|
884
|
+
foo: string
|
|
885
|
+
bar: number
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
type ModuleScope = {
|
|
889
|
+
bar: number
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
const context = new Context<Scope>()
|
|
893
|
+
|
|
894
|
+
// Using the type-safe narrow method - this provides the proper covariance
|
|
895
|
+
const partialContext: Context<ModuleScope> = context.narrow<ModuleScope>()
|
|
896
|
+
|
|
897
|
+
expect(context).toBeInstanceOf(Context)
|
|
898
|
+
expect(partialContext).toBeInstanceOf(Context)
|
|
899
|
+
// Both references point to the same instance
|
|
900
|
+
expect(partialContext).toBe(context)
|
|
901
|
+
})
|
|
902
|
+
|
|
903
|
+
it('should cache singleton dependencies of dependencies correctly', async () => {
|
|
904
|
+
interface ServiceA {
|
|
905
|
+
id: string
|
|
906
|
+
message: string
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
interface ServiceB {
|
|
910
|
+
id: string
|
|
911
|
+
serviceA: ServiceA
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
interface ServiceC {
|
|
915
|
+
id: string
|
|
916
|
+
serviceA: ServiceA
|
|
917
|
+
serviceB: ServiceB
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
interface ServiceD {
|
|
921
|
+
id: string
|
|
922
|
+
serviceA: ServiceA
|
|
923
|
+
serviceB: ServiceB
|
|
924
|
+
serviceC: ServiceC
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
type Scope = {
|
|
928
|
+
serviceA: Promise<ServiceA>
|
|
929
|
+
serviceB: Promise<ServiceB>
|
|
930
|
+
serviceC: Promise<ServiceC>
|
|
931
|
+
serviceD: Promise<ServiceD>
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
const context = new Context<Scope>()
|
|
935
|
+
|
|
936
|
+
let serviceAInstances = 0
|
|
937
|
+
let serviceBInstances = 0
|
|
938
|
+
let serviceCInstances = 0
|
|
939
|
+
let serviceDInstances = 0
|
|
940
|
+
|
|
941
|
+
// ServiceA - async factory - singleton
|
|
942
|
+
context.registerAsyncFactory(
|
|
943
|
+
'serviceA',
|
|
944
|
+
async (): Promise<ServiceA> => {
|
|
945
|
+
serviceAInstances++
|
|
946
|
+
return {
|
|
947
|
+
id: `serviceA-${serviceAInstances}`,
|
|
948
|
+
message: 'I am Service A',
|
|
949
|
+
}
|
|
950
|
+
},
|
|
951
|
+
[],
|
|
952
|
+
{ singleton: true },
|
|
953
|
+
)
|
|
954
|
+
|
|
955
|
+
// ServiceB - async factory depends on ServiceA - singleton
|
|
956
|
+
context.registerAsyncFactory(
|
|
957
|
+
'serviceB',
|
|
958
|
+
async (serviceA: ServiceA): Promise<ServiceB> => {
|
|
959
|
+
serviceBInstances++
|
|
960
|
+
return {
|
|
961
|
+
id: `serviceB-${serviceBInstances}`,
|
|
962
|
+
serviceA,
|
|
963
|
+
}
|
|
964
|
+
},
|
|
965
|
+
['serviceA'],
|
|
966
|
+
{ singleton: true },
|
|
967
|
+
)
|
|
968
|
+
|
|
969
|
+
// ServiceC - async factory depends on ServiceB and ServiceA - singleton
|
|
970
|
+
context.registerAsyncFactory(
|
|
971
|
+
'serviceC',
|
|
972
|
+
async (serviceA: ServiceA, serviceB: ServiceB): Promise<ServiceC> => {
|
|
973
|
+
serviceCInstances++
|
|
974
|
+
return {
|
|
975
|
+
id: `serviceC-${serviceCInstances}`,
|
|
976
|
+
serviceA,
|
|
977
|
+
serviceB,
|
|
978
|
+
}
|
|
979
|
+
},
|
|
980
|
+
['serviceA', 'serviceB'],
|
|
981
|
+
{ singleton: true },
|
|
982
|
+
)
|
|
983
|
+
|
|
984
|
+
// ServiceD - async factory depends on ServiceA, ServiceB, and ServiceC - NOT a singleton
|
|
985
|
+
context.registerAsyncFactory(
|
|
986
|
+
'serviceD',
|
|
987
|
+
async (serviceA: ServiceA, serviceB: ServiceB, serviceC: ServiceC): Promise<ServiceD> => {
|
|
988
|
+
serviceDInstances++
|
|
989
|
+
return {
|
|
990
|
+
id: `serviceD-${serviceDInstances}`,
|
|
991
|
+
serviceA,
|
|
992
|
+
serviceB,
|
|
993
|
+
serviceC,
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
['serviceA', 'serviceB', 'serviceC'],
|
|
997
|
+
)
|
|
998
|
+
|
|
999
|
+
// First resolution - all should be created
|
|
1000
|
+
const serviceD1 = await context.resolve('serviceD')
|
|
1001
|
+
|
|
1002
|
+
expect(serviceAInstances).toBe(1) // ServiceA should only be created once
|
|
1003
|
+
expect(serviceBInstances).toBe(1) // ServiceB should only be created once
|
|
1004
|
+
expect(serviceCInstances).toBe(1) // ServiceC should only be created once
|
|
1005
|
+
expect(serviceDInstances).toBe(1) // ServiceD should be created
|
|
1006
|
+
|
|
1007
|
+
// Second resolution - only ServiceD should be recreated
|
|
1008
|
+
const serviceD2 = await context.resolve('serviceD')
|
|
1009
|
+
|
|
1010
|
+
expect(serviceAInstances).toBe(1) // ServiceA should still be only created once
|
|
1011
|
+
expect(serviceBInstances).toBe(1) // ServiceB should still be only created once
|
|
1012
|
+
expect(serviceCInstances).toBe(1) // ServiceC should still be only created once
|
|
1013
|
+
expect(serviceDInstances).toBe(2) // ServiceD should be created again
|
|
1014
|
+
|
|
1015
|
+
// Third resolution - again only ServiceD should be recreated
|
|
1016
|
+
const serviceD3 = await context.resolve('serviceD')
|
|
1017
|
+
|
|
1018
|
+
expect(serviceAInstances).toBe(1) // ServiceA should still be only created once
|
|
1019
|
+
expect(serviceBInstances).toBe(1) // ServiceB should still be only created once
|
|
1020
|
+
expect(serviceCInstances).toBe(1) // ServiceC should still be only created once
|
|
1021
|
+
expect(serviceDInstances).toBe(3) // ServiceD should be created again
|
|
1022
|
+
|
|
1023
|
+
// Verify that singleton dependencies are the same instances (use toEqual since we have proxy objects)
|
|
1024
|
+
expect(serviceD1.serviceA).toEqual(serviceD2.serviceA)
|
|
1025
|
+
expect(serviceD1.serviceA).toEqual(serviceD3.serviceA)
|
|
1026
|
+
expect(serviceD1.serviceB).toEqual(serviceD2.serviceB)
|
|
1027
|
+
expect(serviceD1.serviceB).toEqual(serviceD3.serviceB)
|
|
1028
|
+
expect(serviceD1.serviceC).toEqual(serviceD2.serviceC)
|
|
1029
|
+
expect(serviceD1.serviceC).toEqual(serviceD3.serviceC)
|
|
1030
|
+
|
|
1031
|
+
// Verify nested dependencies are also the same
|
|
1032
|
+
expect(serviceD1.serviceB.serviceA).toEqual(serviceD2.serviceB.serviceA)
|
|
1033
|
+
expect(serviceD1.serviceC.serviceA).toEqual(serviceD2.serviceC.serviceA)
|
|
1034
|
+
expect(serviceD1.serviceC.serviceB).toEqual(serviceD2.serviceC.serviceB)
|
|
1035
|
+
|
|
1036
|
+
// Verify the IDs to confirm singletons were reused
|
|
1037
|
+
expect(serviceD1.serviceA.id).toBe('serviceA-1')
|
|
1038
|
+
expect(serviceD1.serviceB.id).toBe('serviceB-1')
|
|
1039
|
+
expect(serviceD1.serviceC.id).toBe('serviceC-1')
|
|
1040
|
+
expect(serviceD1.id).toBe('serviceD-1')
|
|
1041
|
+
|
|
1042
|
+
expect(serviceD2.serviceA.id).toBe('serviceA-1') // Same instance
|
|
1043
|
+
expect(serviceD2.serviceB.id).toBe('serviceB-1') // Same instance
|
|
1044
|
+
expect(serviceD2.serviceC.id).toBe('serviceC-1') // Same instance
|
|
1045
|
+
expect(serviceD2.id).toBe('serviceD-2') // New instance
|
|
1046
|
+
|
|
1047
|
+
expect(serviceD3.serviceA.id).toBe('serviceA-1') // Same instance
|
|
1048
|
+
expect(serviceD3.serviceB.id).toBe('serviceB-1') // Same instance
|
|
1049
|
+
expect(serviceD3.serviceC.id).toBe('serviceC-1') // Same instance
|
|
1050
|
+
expect(serviceD3.id).toBe('serviceD-3') // New instance
|
|
1051
|
+
})
|
|
635
1052
|
})
|