Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V6 binding abstractions #1336

Draft
wants to merge 36 commits into
base: v6-binding-abstractions
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
be130d8
binding provideValue method
tonyhallett May 4, 2021
de71cf8
create and assign value providers in bindingtosyntax
tonyhallett May 4, 2021
b492db3
correct signatures
tonyhallett May 4, 2021
8f477a2
FactoryTypeValueProvider
tonyhallett May 4, 2021
046e520
clone value provider
tonyhallett May 4, 2021
f232d52
do not reset the binding scope when clone
tonyhallett May 4, 2021
7f1e6e6
remove non caching properties from Binding
tonyhallett May 4, 2021
158b66a
Scope type
tonyhallett May 4, 2021
1a9e2e9
remove cache and activated from binding
tonyhallett May 4, 2021
145b113
use InstanceValueProvider
tonyhallett May 4, 2021
0216d37
give singleton scope clone same behaviours w.r.t rejecting promises
tonyhallett May 4, 2021
caf5f0f
remove scope responsibility from value provider
tonyhallett May 5, 2021
4d8de8d
ScopeManager
tonyhallett May 5, 2021
007c75b
rename files to adhere to naming convention
tonyhallett May 5, 2021
3b9205b
refactor planner - sub requests required as not instantiated
tonyhallett May 5, 2021
c33a919
make valueproviderfactory public, hidden by interface
tonyhallett May 5, 2021
c60ad71
remaining value provider tests
tonyhallett May 5, 2021
1b5504b
tests for 100% coverage
tonyhallett May 5, 2021
b463a07
scope to return undefined instead of null
tonyhallett May 5, 2021
8472480
move scope tests from features to scope folder
tonyhallett May 5, 2021
a23684e
RootRequestScope ( and custom scope )
tonyhallett May 5, 2021
6cc4aa4
move non public interfaces from interfaces
tonyhallett May 6, 2021
5e59e82
rename test file to test file name
tonyhallett May 6, 2021
20e8bc4
value provider discriminated union
tonyhallett May 6, 2021
2b3f649
scope discriminated union and improve binding enums
tonyhallett May 6, 2021
42cc523
remove null as possible type of binding.valueProvider
tonyhallett May 6, 2021
0361ee0
remove BindingScopeScope from interfaces
tonyhallett May 6, 2021
fcd4a8d
type tidy
tonyhallett May 6, 2021
9d2f7bb
NotConfiguredScope
tonyhallett May 6, 2021
166b59e
reorder methods
tonyhallett May 6, 2021
b7a8bc9
NotConfiguredValueProvider and correction of value provider cloning
tonyhallett May 6, 2021
cd534ba
delete commented code
tonyhallett May 7, 2021
a8a4c30
correct parameter type
tonyhallett May 7, 2021
f772ebe
context hierarchy options
tonyhallett May 7, 2021
9777284
add missing enum values
tonyhallett May 7, 2021
2d0be7e
correction to binding scope enums
tonyhallett May 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 12 additions & 43 deletions src/bindings/binding.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,20 @@
import { BindingScopeEnum, BindingTypeEnum } from "../constants/literal_types";
import { interfaces } from "../interfaces/interfaces";
import { id } from "../utils/id";
import { NotConfiguredScope } from "../scope/not-configured-scope";
import { NotConfiguredValueProvider } from "./not-configured-value-provider";

class Binding<TActivated> implements interfaces.Binding<TActivated> {

public id: number;
public moduleId: interfaces.ContainerModuleBase["id"];

// Determines weather the bindings has been already activated
// The activation action takes place when an instance is resolved
// If the scope is singleton it only happens once
public activated: boolean;

// A runtime identifier because at runtime we don't have interfaces
public serviceIdentifier: interfaces.ServiceIdentifier<TActivated>;

// constructor from binding to or toConstructor
public implementationType: interfaces.Newable<TActivated> | TActivated | null;

// Cache used to allow singleton scope and BindingType.ConstantValue bindings
public cache: TActivated | Promise<TActivated> | null;

// Cache used to allow BindingType.DynamicValue bindings
public dynamicValue: interfaces.DynamicValue<TActivated> | null;

// The scope mode to be used
public scope: interfaces.BindingScope;
// Scope
public scope: interfaces.ResolveScope<TActivated>;

// The kind of binding
public type: interfaces.BindingType;

// A factory method used in BindingType.Factory bindings
public factory: interfaces.FactoryCreator<unknown> | null;

// An async factory method used in BindingType.Provider bindings
public provider: interfaces.ProviderCreator<unknown> | null;
public valueProvider:interfaces.ValueProviderType<TActivated>;

// A constraint used to limit the contexts in which this binding is applicable
public constraint: (request: interfaces.Request) => boolean;
Expand All @@ -45,35 +25,24 @@ class Binding<TActivated> implements interfaces.Binding<TActivated> {
// On deactivation handler (invoked just before an instance is unbinded and removed from container)
public onDeactivation: interfaces.BindingDeactivation<TActivated> | null;

public constructor(serviceIdentifier: interfaces.ServiceIdentifier<TActivated>, scope: interfaces.BindingScope) {
public constructor(serviceIdentifier: interfaces.ServiceIdentifier<TActivated>) {
this.id = id();
this.activated = false;
this.serviceIdentifier = serviceIdentifier;
this.scope = scope;
this.type = BindingTypeEnum.Invalid;
this.scope = new NotConfiguredScope(serviceIdentifier);
this.valueProvider = new NotConfiguredValueProvider(serviceIdentifier);
this.constraint = (request: interfaces.Request) => true;
this.implementationType = null;
this.cache = null;
this.factory = null;
this.provider = null;
this.onActivation = null;
this.onDeactivation = null;
this.dynamicValue = null;
}

public clone(): interfaces.Binding<TActivated> {
const clone = new Binding(this.serviceIdentifier, this.scope);
clone.activated = (clone.scope === BindingScopeEnum.Singleton) ? this.activated : false;
clone.implementationType = this.implementationType;
clone.dynamicValue = this.dynamicValue;
clone.scope = this.scope;
clone.type = this.type;
clone.factory = this.factory;
clone.provider = this.provider;
const clone = new Binding(this.serviceIdentifier);
clone.valueProvider = this.valueProvider.clone() as interfaces.ValueProviderType<TActivated>;
clone.scope = this.scope.clone();
clone.constraint = this.constraint;
clone.onActivation = this.onActivation;
clone.onDeactivation = this.onDeactivation;
clone.cache = this.cache;

return clone;
}

Expand Down
12 changes: 12 additions & 0 deletions src/bindings/constant-value-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { interfaces } from "../interfaces/interfaces";
import { ValueFromProvider } from "./value-from-provider";

export class ConstantValueProvider<TActivated> extends ValueFromProvider<TActivated>
implements interfaces.ConstantValueProvider<TActivated>{
type: "ConstantValue" = "ConstantValue"
clone(){
const clone = new ConstantValueProvider<TActivated>();
clone.valueFrom = this.valueFrom;
return clone;
}
}
11 changes: 11 additions & 0 deletions src/bindings/constructor-value-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ValueFromProvider } from "./value-from-provider";
import { interfaces } from "../interfaces/interfaces";
export class ConstructorValueProvider<TActivated> extends ValueFromProvider<TActivated>
implements interfaces.ConstructorValueProvider<TActivated>{
type: "Constructor" = "Constructor"
clone(){
const clone = new ConstructorValueProvider<TActivated>();
clone.valueFrom = this.valueFrom;
return clone;
}
}
14 changes: 14 additions & 0 deletions src/bindings/dynamic-value-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { interfaces } from "../interfaces/interfaces";
export class DynamicValueProvider<TActivated> implements interfaces.DynamicValueProvider<TActivated>{
type: "DynamicValue" = "DynamicValue"
factoryType:"toDynamicValue" = "toDynamicValue"
valueFrom: interfaces.DynamicValue<TActivated>;
provideValue(context:interfaces.Context, _:interfaces.Request[]): TActivated|Promise<TActivated>{
return this.valueFrom(context);
}
clone(){
const clone = new DynamicValueProvider<TActivated>();
clone.valueFrom = this.valueFrom;
return clone;
}
}
10 changes: 10 additions & 0 deletions src/bindings/factory-value-provider-base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { interfaces } from "../interfaces/interfaces";

export abstract class FactoryValueProviderBase<TActivated>
implements interfaces.ValueProvider<TActivated, (context:interfaces.Context) => TActivated>{
valueFrom: (context:interfaces.Context) => TActivated
provideValue(context:interfaces.Context, _:interfaces.Request[]): TActivated | Promise<TActivated> {
return this.valueFrom(context);
}
abstract clone():FactoryValueProviderBase<TActivated>
}
13 changes: 13 additions & 0 deletions src/bindings/factory-value-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { interfaces } from "../interfaces/interfaces";
import { FactoryValueProviderBase } from "./factory-value-provider-base";

export class FactoryValueProvider<TActivated> extends FactoryValueProviderBase<TActivated>
implements interfaces.FactoryValueProvider<TActivated>{
type: "Factory" = "Factory"
factoryType:"toFactory"= "toFactory";
clone(){
const clone = new FactoryValueProvider<TActivated>();
clone.valueFrom = this.valueFrom;
return clone;
}
}
20 changes: 20 additions & 0 deletions src/bindings/instance-value-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { interfaces } from "../interfaces/interfaces";
import { resolveInstance } from "../resolution/instantiation";

export class InstanceValueProvider<TActivated> implements interfaces.InstanceValueProvider<TActivated>{
type: "Instance" = "Instance";
valueFrom: interfaces.Newable<TActivated>;
provideValue(context:interfaces.Context, childRequests:interfaces.Request[]): TActivated {
const binding = context.currentRequest.bindings[0];
return resolveInstance(
binding,
binding.valueProvider!.valueFrom as interfaces.Newable<TActivated>,
childRequests,
);
}
clone(){
const clone = new InstanceValueProvider<TActivated>();
clone.valueFrom = this.valueFrom;
return clone;
}
}
9 changes: 9 additions & 0 deletions src/bindings/not-configured-value-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { interfaces } from "../interfaces/interfaces";
import { NotConfigured } from "../utils/binding_utils";

export class NotConfiguredValueProvider extends NotConfigured implements interfaces.NotConfiguredValueProvider{
valueFrom:never;
provideValue():never{
this._throwAccessedUnconfigured();
}
}
13 changes: 13 additions & 0 deletions src/bindings/provider-value-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { interfaces } from "../interfaces/interfaces";
import { FactoryValueProviderBase } from "./factory-value-provider-base";

export class ProviderValueProvider<TActivated> extends FactoryValueProviderBase<TActivated>
implements interfaces.ProviderValueProvider<TActivated>{
type:"Provider" = "Provider"
factoryType:"toProvider" = "toProvider"
clone(){
const clone = new ProviderValueProvider<TActivated>();
clone.valueFrom = this.valueFrom;
return clone;
}
}
9 changes: 9 additions & 0 deletions src/bindings/value-from-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { interfaces } from "../interfaces/interfaces";

export abstract class ValueFromProvider<TActivated> implements interfaces.ValueProvider<TActivated,TActivated>{
valueFrom: TActivated;
provideValue(): TActivated|Promise<TActivated>{
return this.valueFrom;
}
abstract clone():ValueFromProvider<TActivated>
}
10 changes: 10 additions & 0 deletions src/bindings/value-provider-factory-interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { interfaces } from "../interfaces/interfaces";

export interface ValueProviderFactory<T>{
toInstance():interfaces.InstanceValueProvider<T>
toConstantValue():interfaces.ConstantValueProvider<T>
toDynamicValue():interfaces.DynamicValueProvider<T>
toConstructor():interfaces.ConstructorValueProvider<T>
toFactory(): interfaces.FactoryValueProvider<T>
toProvider(): interfaces.ProviderValueProvider<T>
}
31 changes: 31 additions & 0 deletions src/bindings/value-provider-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { interfaces } from "../interfaces/interfaces";
import { ConstantValueProvider } from "./constant-value-provider";
import { ConstructorValueProvider } from "./constructor-value-provider";
import { DynamicValueProvider } from "./dynamic-value-provider";
import { FactoryValueProvider } from "./factory-value-provider";
import { InstanceValueProvider } from "./instance-value-provider";
import { ProviderValueProvider } from "./provider-value-provider";
import { ValueProviderFactory as ValueProviderFactoryInterface } from "./value-provider-factory-interface"

export class ValueProviderFactory<T> implements ValueProviderFactoryInterface<T>{
toInstance(): interfaces.InstanceValueProvider<T> {
return new InstanceValueProvider<T>();
}
toConstantValue(): interfaces.ConstantValueProvider<T> {
return new ConstantValueProvider();
}
toDynamicValue(): interfaces.DynamicValueProvider<T> {
return new DynamicValueProvider();
}
toConstructor(): interfaces.ConstructorValueProvider<T> {
return new ConstructorValueProvider();
}
toFactory(): interfaces.FactoryValueProvider<T> {
return new FactoryValueProvider<T>();
}

toProvider(): interfaces.ProviderValueProvider<T> {
return new ProviderValueProvider<T>();
}

}
23 changes: 18 additions & 5 deletions src/constants/literal_types.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
import { interfaces } from "../interfaces/interfaces";

const ContextHierarchyOptionEnum: interfaces.ContextHierarchyOptionEnum = {
Disallow: "Disallow",
Allow: "Allow",
IfBindedInCustomOrRootRequestScope: "IfBindedInCustomOrRootRequestScope"
}

const BindingScopeEnum: interfaces.BindingScopeEnum = {
Request: "Request",
Singleton: "Singleton",
Transient: "Transient"
Transient: "Transient",
RootRequest: "RootRequest",
Custom: "Custom",
NotConfigured: "NotConfigured"
};

const ConfigurableBindingScopeEnum: interfaces.ConfigurableBindingScopeEnum = {
...BindingScopeEnum,
Custom:"Custom"
};

const BindingTypeEnum: interfaces.BindingTypeEnum = {
ConstantValue: "ConstantValue",
Constructor: "Constructor",
DynamicValue: "DynamicValue",
Factory: "Factory",
Function: "Function",
Instance: "Instance",
Invalid: "Invalid",
Provider: "Provider"
Provider: "Provider",
NotConfigured: "NotConfigured"
};

const TargetTypeEnum: interfaces.TargetTypeEnum = {
Expand All @@ -23,4 +36,4 @@ const TargetTypeEnum: interfaces.TargetTypeEnum = {
Variable: "Variable"
};

export { BindingScopeEnum, BindingTypeEnum, TargetTypeEnum };
export { BindingScopeEnum, ConfigurableBindingScopeEnum, BindingTypeEnum, TargetTypeEnum, ContextHierarchyOptionEnum };
Loading