Skip to content

Commit

Permalink
fix(resolvable): inital generated docs for better dev experience
Browse files Browse the repository at this point in the history
  • Loading branch information
Igmat committed Sep 18, 2018
1 parent 312bb0f commit 3e8f218
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 8 deletions.
29 changes: 28 additions & 1 deletion packages/resolvable/src/AbstractResolvable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,41 @@ export type Injected<T extends Injectable> = T extends Constructable
: T extends Callable
? ReturnType<T>
: never;

/**
* // TODO: comment IInjections
* @description injections
*/
export interface IInjections {
[index: string]: Injectable;
}

/**
* // TODO: comment IDependencies
* @description dependencies
*/
export type IDependencies<T extends IInjections> = {
[K in keyof T]: Injected<T[K]>
};

/**
* // TODO: comment AbstractResolvable
* @description Abstract resolvable
* @template I
*/
export abstract class AbstractResolvable<I extends IInjections> {
constructor(protected readonly dependencies: Readonly<IDependencies<I>>) {

/**
* // TODO: comment dependencies
* @description Dependencies of abstract resolvable
*/
protected readonly dependencies: Readonly<IDependencies<I>>;

/**
* Creates an instance of abstract resolvable.
* @param dependencies
*/
constructor(dependencies: Readonly<IDependencies<I>>) {
this.dependencies = dependencies;
}
}
25 changes: 25 additions & 0 deletions packages/resolvable/src/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ const application = {
isResolverChanged: false,
};

/**
* // TODO: comment resolveFor
* @description Resolves for
* @template I
* @param instance
* @param classImpl
* @param [injections]
* @param [args]
* @returns for
*/
export function resolveFor<I extends IInjections = {}>(
instance: object,
classImpl: Constructable,
Expand All @@ -17,10 +27,25 @@ export function resolveFor<I extends IInjections = {}>(
): IDependencies<I> {
return application.resolveFor(instance, classImpl, injections, args);
}

/**
* // TODO: comment resolveRequirements
* @description Resolves requirements
* @template I
* @param requirements
* @param classImpl
* @returns
*/
export function resolveRequirements<I extends { [index: string]: any } = {}>(requirements: I, classImpl: Constructable) {
return application.resolveRequirements(requirements, classImpl);
}

/**
* // TODO: comment setResolverFn
* @description Sets resolver fn
* @param resolverForImpl
* @param requirementsResolveImpl
*/
export function setResolverFn(resolverForImpl: ResolveForFunction, requirementsResolveImpl: ResolveRequirementsFunction) {
if (application.isResolverChanged) throw new Error('Your application is trying to setup resolver more than once!');
application.resolveFor = resolverForImpl;
Expand Down
7 changes: 7 additions & 0 deletions packages/resolvable/src/Resolvable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ export type Resolvable<I extends IInjections, P> =
? new (...args: ARGS) => AbstractResolvable<I> & R
: new () => AbstractResolvable<I>;

/**
* // TODO: comment resolvable
* @description
* @param [injections] dependencies that will be used by class directly
* @param [requirements] dependencies that should exist in code that use this class
* @param [parent] class that should be a parent for this one
*/
export function Resolvable<
I extends IInjections = {},
R extends { [index: string]: any } = {},
Expand Down
87 changes: 80 additions & 7 deletions packages/resolvable/src/Resolver.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// tslint:disable:prefer-function-over-method
import { IDependencies, IInjections, Injectable, Injected } from './AbstractResolvable';
import { Callable, Constructable } from './utils';

Expand All @@ -19,44 +20,101 @@ export type ResolveRequirementsFunction = <I extends { [index: string]: any } =
// we are using private symbol in order to force users work with override function
// so override always type compatible with original value
const overrideSymbol = Symbol('Overrides');

/**
* // TODO: comment IOverrideResult
* @description override result
* @template T
*/
export interface IOverrideResult<T extends Injectable = any> {
[overrideSymbol]: [T, Injected<T>];
}

/**
* // TODO: comment override
* @description Overrides this
* @template T
* @param key
* @param value
* @returns this
*/
export function override<T extends Injectable = any>(key: T, value: Injected<T>): IOverrideResult<T> {
return {
[overrideSymbol]: [key, value],
};
}

/**
* // TODO: comment Resolver
* @description Resolver
*/
export class Resolver {

/**
* // TODO: comment injectionRoot
* @description Injection root of resolver
*/
protected injectionRoot: WeakMap<Injectable, any>;

/**
* // TODO: comment implementations
* @description Implementations of resolver
*/
protected implementations: WeakMap<Constructable, any>;

/**
* Creates an instance of resolver.
* @param [overrides]
*/
constructor(overrides: IOverrideResult[] = []) {
this.injectionRoot = new WeakMap(overrides.map(overridePair => overridePair[overrideSymbol]));
this.implementations = new WeakMap();
// we want these function to have correct `this` context,
// but can't use arrow functions because
// it breaks normal inheritance flow
// but can't use arrow functions because it breaks normal inheritance flow
this.inject = this.inject.bind(this);
this.resolveFor = this.resolveFor.bind(this);
this.resolveRequirements = this.resolveRequirements.bind(this);
this.initialize = this.initialize.bind(this);
this.setOverride = this.setOverride.bind(this);
}
// this function is pure, but it's possible that ancestors may need
// another solution for initializing instacnes, because of framework
// requirements, conventions and best practices
// tslint:disable-next-line:prefer-function-over-method

/**
* // TODO: comment initialize
* @description Initializes resolver
* @param obj
* @returns
*/
initialize(obj: Injectable) {
// this function is pure, but it's possible that ancestors may need
// another solution for initializing instacnes, because of framework
// requirements, conventions and best practices
if (isConstructor(obj)) return new obj();
if (isCallable(obj)) return obj();
throw new Error(`Dependency expected to be constructable or callable, but got ${typeof obj}`);
}
// tslint:disable-next-line:prefer-function-over-method

/**
* // TODO: comment resolveRequirements
* @description Resolves requirements
* @template I
* @param requirements
* @param classImpl
*/
resolveRequirements<I extends { [index: string]: any } = {}>(requirements: I, classImpl: Constructable) {
// default implementation does nothing, since only Resolver for specific framework
// knows how to apply requirements to particular environment
}

/**
* // TODO: comment resolveFor
* @description Resolves for
* @template I
* @param instance
* @param classImpl
* @param [injections]
* @param [args]
* @returns for
*/
resolveFor<I extends IInjections = {}>(
instance: object,
classImpl: Constructable,
Expand All @@ -73,6 +131,14 @@ export class Resolver {

return resolvedDependencies;
}

/**
* // TODO: comment inject
* @description Injects resolver
* @template T
* @param injectionKey
* @returns inject
*/
protected inject<T extends Injectable>(injectionKey: T): Injected<T> {
if (!this.injectionRoot.has(injectionKey)) {
this.injectionRoot.set(
Expand All @@ -82,6 +148,13 @@ export class Resolver {

return this.injectionRoot.get(injectionKey);
}

/**
* // TODO: comment setOverride
* @description Sets override
* @template T
* @param overridePair
*/
protected setOverride<T extends Injectable = any>(overridePair: IOverrideResult<T>) {
const [key, value] = overridePair[overrideSymbol];
this.injectionRoot.set(key, value);
Expand Down

0 comments on commit 3e8f218

Please sign in to comment.