Socket
Socket
Sign inDemoInstall

@loopback/context

Package Overview
Dependencies
Maintainers
20
Versions
195
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@loopback/context - npm Package Compare versions

Comparing version 4.0.0-alpha.8 to 4.0.0-alpha.9

lib/src/is-promise.d.ts

31

lib/src/binding.d.ts

@@ -7,9 +7,25 @@ import { Context } from './context';

export declare class Binding {
isLocked: boolean;
static PROPERTY_SEPARATOR: string;
/**
* Validate the binding key format. Please note that `#` is reserved.
* @param key Binding key, such as `a, a.b, a:b, a/b
*/
static validateKey(key: string): string;
/**
* Remove the segament that denotes a property path
* @param key Binding key, such as `a, a.b, a:b, a/b, a.b#x, a:b#x.y, a/b#x.y`
*/
static normalizeKey(key: string): string;
/**
* Get the property path separated by `#`
* @param key Binding key
*/
static getKeyPath(key: string): string | undefined;
private readonly _key;
isLocked: boolean;
private _tagName;
private _tags;
valueConstructor: Constructor<BoundValue>;
constructor(_key: string, isLocked?: boolean);
readonly key: string;
readonly tagName: string;
readonly tags: Set<string>;
/**

@@ -19,3 +35,4 @@ * This is an internal function optimized for performance.

*
* Get the value bound to this key. Depending on `isSync`, this function returns either:
* Get the value bound to this key. Depending on `isSync`, this
* function returns either:
* - the bound value

@@ -38,3 +55,3 @@ * - a promise of the bound value

lock(): this;
tag(tagName: string): this;
tag(tagName: string | string[]): this;
/**

@@ -76,6 +93,2 @@ * Bind the key to a constant value.

/**
* get an instance of the provider
*/
getProviderInstance<T>(ctx: Context): Promise<Provider<T>>;
/**
* Bind the key to an instance of the given class.

@@ -82,0 +95,0 @@ *

@@ -8,15 +8,58 @@ "use strict";

const resolver_1 = require("./resolver");
// FIXME(bajtos) The binding class should be parameterized by the value type stored
const is_promise_1 = require("./is-promise");
// FIXME(bajtos) The binding class should be parameterized by the value
// type stored
class Binding {
constructor(_key, isLocked = false) {
this.isLocked = isLocked;
this._tags = new Set();
Binding.validateKey(_key);
this._key = _key;
this.isLocked = isLocked;
}
get key() { return this._key; }
get tagName() { return this._tagName; }
/**
* Validate the binding key format. Please note that `#` is reserved.
* @param key Binding key, such as `a, a.b, a:b, a/b
*/
static validateKey(key) {
if (!key)
throw new Error('Binding key must be provided.');
if (key.indexOf(Binding.PROPERTY_SEPARATOR) !== -1) {
throw new Error(`Binding key ${key} cannot contain`
+ ` '${Binding.PROPERTY_SEPARATOR}'.`);
}
return key;
}
/**
* Remove the segament that denotes a property path
* @param key Binding key, such as `a, a.b, a:b, a/b, a.b#x, a:b#x.y, a/b#x.y`
*/
static normalizeKey(key) {
const index = key.indexOf(Binding.PROPERTY_SEPARATOR);
if (index !== -1)
key = key.substr(0, index);
key = key.trim();
return key;
}
/**
* Get the property path separated by `#`
* @param key Binding key
*/
static getKeyPath(key) {
const index = key.indexOf(Binding.PROPERTY_SEPARATOR);
if (index !== -1)
return key.substr(index + 1);
return undefined;
}
get key() {
return this._key;
}
get tags() {
return this._tags;
}
/**
* This is an internal function optimized for performance.
* Users should use `@inject(key)` or `ctx.get(key)` instead.
*
* Get the value bound to this key. Depending on `isSync`, this function returns either:
* Get the value bound to this key. Depending on `isSync`, this
* function returns either:
* - the bound value

@@ -45,3 +88,10 @@ * - a promise of the bound value

tag(tagName) {
this._tagName = tagName;
if (typeof tagName === 'string') {
this._tags.add(tagName);
}
else {
tagName.forEach(t => {
this._tags.add(t);
});
}
return this;

@@ -84,3 +134,3 @@ }

// TODO(bajtos) allow factoryFn with @inject arguments
this.getValue = (ctx) => factoryFn();
this.getValue = ctx => factoryFn();
return this;

@@ -92,19 +142,14 @@ }

toProvider(providerClass) {
this.getProviderInstance = async (ctx) => {
this.getValue = ctx => {
const providerOrPromise = resolver_1.instantiateClass(providerClass, ctx);
return resolver_1.resolveValueOrPromise(providerOrPromise);
if (is_promise_1.isPromise(providerOrPromise)) {
return providerOrPromise.then(p => p.value());
}
else {
return providerOrPromise.value();
}
};
this.getValue = async (ctx) => {
const providerInstance = await this.getProviderInstance(ctx);
return providerInstance.value();
};
return this;
}
/**
* get an instance of the provider
*/
async getProviderInstance(ctx) {
return Promise.reject(new Error(`No provider is attached to binding ${this._key}.`));
}
/**
* Bind the key to an instance of the given class.

@@ -126,3 +171,4 @@ *

}
Binding.PROPERTY_SEPARATOR = '#';
exports.Binding = Binding;
//# sourceMappingURL=binding.js.map

@@ -8,3 +8,3 @@ "use strict";

const binding_1 = require("./binding");
const isPromise_1 = require("./isPromise");
const is_promise_1 = require("./is-promise");
class Context {

@@ -16,2 +16,4 @@ constructor(_parent) {

bind(key) {
binding_1.Binding.validateKey(key);
key = binding_1.Binding.normalizeKey(key);
const keyExists = this.registry.has(key);

@@ -22,3 +24,3 @@ if (keyExists) {

if (bindingIsLocked)
throw new Error(`Cannot rebind key "${key}", associated binding is locked`);
throw new Error(`Cannot rebind key "${key}" to a locked binding`);
}

@@ -30,2 +32,3 @@ const binding = new binding_1.Binding(key);

contains(key) {
key = binding_1.Binding.normalizeKey(key);
return this.registry.has(key);

@@ -37,2 +40,3 @@ }

// TODO(@superkhau): swap with production grade glob to regex lib
pattern = binding_1.Binding.normalizeKey(pattern);
const glob = new RegExp('^' + pattern.split('*').join('.*') + '$');

@@ -56,3 +60,3 @@ this.registry.forEach(binding => {

this.registry.forEach(binding => {
const isMatch = glob.test(binding.tagName);
const isMatch = Array.from(binding.tags).some(tag => glob.test(tag));
if (isMatch)

@@ -75,4 +79,5 @@ bindings.push(binding);

try {
const path = binding_1.Binding.getKeyPath(key);
const binding = this.getBinding(key);
return Promise.resolve(binding.getValue(this));
return Promise.resolve(binding.getValue(this)).then(val => getValue(val, path));
}

@@ -84,11 +89,12 @@ catch (err) {

getSync(key) {
const path = binding_1.Binding.getKeyPath(key);
const binding = this.getBinding(key);
const valueOrPromise = binding.getValue(this);
if (isPromise_1.isPromise(valueOrPromise)) {
throw new Error(`Cannot get ${key} synchronously: ` +
`the value requires async computation`);
if (is_promise_1.isPromise(valueOrPromise)) {
throw new Error(`Cannot get ${key} synchronously: the value is a promise`);
}
return valueOrPromise;
return getValue(valueOrPromise, path);
}
getBinding(key) {
key = binding_1.Binding.normalizeKey(key);
const binding = this.registry.get(key);

@@ -105,2 +111,21 @@ if (binding) {

exports.Context = Context;
/**
* Get the value by `.` notation
* @param obj The source value
* @param path A path to the nested property, such as `x`, `x.y`, `x.length`,
* or `x.0`
*/
function getValue(obj, path) {
if (!path)
return obj;
const props = path.split('.');
let val = undefined;
for (const p of props) {
val = obj[p];
if (val == null)
return val;
obj = val;
}
return val;
}
//# sourceMappingURL=context.js.map
export { Binding, BoundValue } from './binding';
export { Context } from './context';
export { Constructor, resolveValueOrPromise } from './resolver';
export { Constructor } from './resolver';
export { inject } from './inject';
export { NamespacedReflect } from './reflect';
export { Provider } from './provider';
export { isPromise } from './isPromise';
export { isPromise } from './is-promise';
export { instantiateClass } from './resolver';
export { describeInjectedArguments, describeInjectedProperties } from './inject';
export { describeInjectedArguments, describeInjectedProperties, Injection } from './inject';
export { Reflector } from './reflect';

@@ -11,4 +11,2 @@ "use strict";

exports.Context = context_1.Context;
var resolver_1 = require("./resolver");
exports.resolveValueOrPromise = resolver_1.resolveValueOrPromise;
var inject_1 = require("./inject");

@@ -18,7 +16,7 @@ exports.inject = inject_1.inject;

exports.NamespacedReflect = reflect_1.NamespacedReflect;
var isPromise_1 = require("./isPromise");
exports.isPromise = isPromise_1.isPromise;
var is_promise_1 = require("./is-promise");
exports.isPromise = is_promise_1.isPromise;
// internals for testing
var resolver_2 = require("./resolver");
exports.instantiateClass = resolver_2.instantiateClass;
var resolver_1 = require("./resolver");
exports.instantiateClass = resolver_1.instantiateClass;
var inject_2 = require("./inject");

@@ -25,0 +23,0 @@ exports.describeInjectedArguments = inject_2.describeInjectedArguments;

@@ -1,2 +0,12 @@

import { BoundValue } from './binding';
import { BoundValue, ValueOrPromise } from './binding';
import { Context } from './context';
/**
* A function to provide resolution of injected values
*/
export interface ResolverFunction {
(ctx: Context, injection: Injection): ValueOrPromise<BoundValue>;
}
/**
* Descriptor for an injection point
*/
export interface Injection {

@@ -7,2 +17,3 @@ bindingKey: string;

};
resolve?: ResolverFunction;
}

@@ -32,17 +43,20 @@ /**

* @param metadata Optional metadata to help the injection
* @param resolve Optional function to resolve the injection
*
*/
export declare function inject(bindingKey: string, metadata?: Object): (target: any, propertyKey?: string | symbol | undefined, propertyDescriptorOrParameterIndex?: number | TypedPropertyDescriptor<any> | undefined) => void;
export declare function inject(bindingKey: string, metadata?: Object, resolve?: ResolverFunction): (target: any, propertyKey?: string | symbol | undefined, propertyDescriptorOrParameterIndex?: number | TypedPropertyDescriptor<any> | undefined) => void;
/**
* Return an array of injection objects for constructor parameters
* @param target The target class
* Return an array of injection objects for parameters
* @param target The target class for constructor or static methods,
* or the prototype for instance methods
* @param methodName Method name, undefined for constructor
*/
export declare function describeInjectedArguments(target: Function): Injection[];
export declare function describeInjectedArguments(target: any, method?: string | symbol): Injection[];
/**
* Return a map of injection objects for properties
* @param target The target class. Please note a property decorator function receives
* the target.prototype
* @param target The target class for static properties or
* prototype for instance properties.
*/
export declare function describeInjectedProperties(target: Function): {
export declare function describeInjectedProperties(target: any): {
[p: string]: Injection;
};

@@ -8,4 +8,4 @@ "use strict";

const reflect_1 = require("./reflect");
const REFLECTION_CDI_KEY = 'loopback:inject:constructor';
const REFLECTION_PDI_KEY = 'loopback:inject:properties';
const PARAMETERS_KEY = 'inject:parameters';
const PROPERTIES_KEY = 'inject:properties';
/**

@@ -34,22 +34,32 @@ * A decorator to annotate method arguments for automatic injection

* @param metadata Optional metadata to help the injection
* @param resolve Optional function to resolve the injection
*
*/
function inject(bindingKey, metadata) {
// tslint:disable-next-line:no-any
return function markArgumentAsInjected(target, propertyKey, propertyDescriptorOrParameterIndex) {
function inject(bindingKey, metadata, resolve) {
return function markParameterOrPropertyAsInjected(
// tslint:disable-next-line:no-any
target, propertyKey, propertyDescriptorOrParameterIndex) {
if (typeof propertyDescriptorOrParameterIndex === 'number') {
// The decorator is applied to a method parameter
// Please note propertyKey is `undefined` for constructor
const injectedArgs = reflect_1.Reflector.getOwnMetadata(REFLECTION_CDI_KEY, target, propertyKey) || [];
injectedArgs[propertyDescriptorOrParameterIndex] = { bindingKey, metadata };
reflect_1.Reflector.defineMetadata(REFLECTION_CDI_KEY, injectedArgs, target, propertyKey);
const injectedArgs = reflect_1.Reflector.getOwnMetadata(PARAMETERS_KEY, target, propertyKey) || [];
injectedArgs[propertyDescriptorOrParameterIndex] = {
bindingKey,
metadata,
resolve,
};
reflect_1.Reflector.defineMetadata(PARAMETERS_KEY, injectedArgs, target, propertyKey);
}
else if (propertyKey) {
if (typeof Object.getPrototypeOf(target) === 'function') {
const prop = target.name + '.' + propertyKey.toString();
throw new Error('@inject is not supported for a static property: ' + prop);
}
// The decorator is applied to a property
const injections = reflect_1.Reflector.getOwnMetadata(REFLECTION_PDI_KEY, target) || {};
injections[propertyKey] = { bindingKey, metadata };
reflect_1.Reflector.defineMetadata(REFLECTION_PDI_KEY, injections, target);
const injections = reflect_1.Reflector.getOwnMetadata(PROPERTIES_KEY, target) || {};
injections[propertyKey] = { bindingKey, metadata, resolve };
reflect_1.Reflector.defineMetadata(PROPERTIES_KEY, injections, target);
}
else {
throw new Error('@inject can be used on properties or method parameters.');
throw new Error('@inject can only be used on properties or method parameters.');
}

@@ -60,7 +70,16 @@ };

/**
* Return an array of injection objects for constructor parameters
* @param target The target class
* Return an array of injection objects for parameters
* @param target The target class for constructor or static methods,
* or the prototype for instance methods
* @param methodName Method name, undefined for constructor
*/
function describeInjectedArguments(target) {
return reflect_1.Reflector.getOwnMetadata(REFLECTION_CDI_KEY, target) || [];
function describeInjectedArguments(
// tslint:disable-next-line:no-any
target, method) {
if (method) {
return reflect_1.Reflector.getMetadata(PARAMETERS_KEY, target, method) || [];
}
else {
return reflect_1.Reflector.getMetadata(PARAMETERS_KEY, target) || [];
}
}

@@ -70,9 +89,28 @@ exports.describeInjectedArguments = describeInjectedArguments;

* Return a map of injection objects for properties
* @param target The target class. Please note a property decorator function receives
* the target.prototype
* @param target The target class for static properties or
* prototype for instance properties.
*/
function describeInjectedProperties(target) {
return reflect_1.Reflector.getOwnMetadata(REFLECTION_PDI_KEY, target.prototype) || {};
function describeInjectedProperties(
// tslint:disable-next-line:no-any
target) {
const metadata = {};
let obj = target;
while (true) {
const m = reflect_1.Reflector.getOwnMetadata(PROPERTIES_KEY, obj);
if (m) {
// Adding non-existent properties
for (const p in m) {
if (!(p in metadata)) {
metadata[p] = m[p];
}
}
}
// Recurse into the prototype chain
obj = Object.getPrototypeOf(obj);
if (!obj)
break;
}
return metadata;
}
exports.describeInjectedProperties = describeInjectedProperties;
//# sourceMappingURL=inject.js.map
import { ValueOrPromise } from './binding';
/**
* @exports Provider<T> : interface definition for a provider of a value of type T
* @summary Providers allow binding of a value provider class instead of the value itself
* @exports Provider<T> : interface definition for a provider of a value
* of type T
* @summary Providers allow binding of a value provider class instead of the
* value itself
* @example:

@@ -6,0 +8,0 @@ * ```ts

import { Context } from './context';
import { BoundValue, ValueOrPromise } from './binding';
import { BoundValue } from './binding';
export declare type Constructor<T> = new (...args: any[]) => T;

@@ -31,5 +31,1 @@ /**

export declare function resolveInjectedProperties(fn: Function, ctx: Context): KV | Promise<KV>;
/**
* resolve a ValueOrPromise<T> to T
*/
export declare function resolveValueOrPromise<T>(instanceOrPromise: ValueOrPromise<T>): Promise<T>;

@@ -7,3 +7,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const isPromise_1 = require("./isPromise");
const is_promise_1 = require("./is-promise");
const inject_1 = require("./inject");

@@ -24,3 +24,3 @@ /**

let inst;
if (isPromise_1.isPromise(argsOrPromise)) {
if (is_promise_1.isPromise(argsOrPromise)) {
// Instantiate the class asynchronously

@@ -33,5 +33,5 @@ inst = argsOrPromise.then(args => new ctor(...args));

}
if (isPromise_1.isPromise(propertiesOrPromise)) {
return propertiesOrPromise.then((props) => {
if (isPromise_1.isPromise(inst)) {
if (is_promise_1.isPromise(propertiesOrPromise)) {
return propertiesOrPromise.then(props => {
if (is_promise_1.isPromise(inst)) {
// Inject the properties asynchrounously

@@ -47,3 +47,3 @@ return inst.then(obj => Object.assign(obj, props));

else {
if (isPromise_1.isPromise(inst)) {
if (is_promise_1.isPromise(inst)) {
// Inject the properties asynchrounously

@@ -60,2 +60,16 @@ return inst.then(obj => Object.assign(obj, propertiesOrPromise));

/**
* Resolve the value or promise for a given injection
* @param ctx Context
* @param injection Descriptor of the injection
*/
function resolve(ctx, injection) {
if (injection.resolve) {
// A custom resolve function is provided
return injection.resolve(ctx, injection);
}
// Default to resolve the value from the context by binding key
const binding = ctx.getBinding(injection.bindingKey);
return binding.getValue(ctx);
}
/**
* Given a function with arguments decorated with `@inject`,

@@ -80,13 +94,12 @@ * return the list of arguments resolved using the values

for (let ix = 0; ix < fn.length; ix++) {
const bindingKey = injectedArgs[ix].bindingKey;
if (!bindingKey) {
const injection = injectedArgs[ix];
if (!injection.bindingKey && !injection.resolve) {
throw new Error(`Cannot resolve injected arguments for function ${fn.name}: ` +
`The argument ${ix + 1} was not decorated for dependency injection.`);
}
const binding = ctx.getBinding(bindingKey);
const valueOrPromise = binding.getValue(ctx);
if (isPromise_1.isPromise(valueOrPromise)) {
const valueOrPromise = resolve(ctx, injection);
if (is_promise_1.isPromise(valueOrPromise)) {
if (!asyncResolvers)
asyncResolvers = [];
asyncResolvers.push(valueOrPromise.then((v) => args[ix] = v));
asyncResolvers.push(valueOrPromise.then((v) => (args[ix] = v)));
}

@@ -106,15 +119,14 @@ else {

function resolveInjectedProperties(fn, ctx) {
const injectedProperties = inject_1.describeInjectedProperties(fn);
const injectedProperties = inject_1.describeInjectedProperties(fn.prototype);
const properties = {};
let asyncResolvers = undefined;
const propertyResolver = (p) => ((v) => properties[p] = v);
const propertyResolver = (p) => (v) => (properties[p] = v);
for (const p in injectedProperties) {
const bindingKey = injectedProperties[p].bindingKey;
if (!bindingKey) {
const injection = injectedProperties[p];
if (!injection.bindingKey && !injection.resolve) {
throw new Error(`Cannot resolve injected property for class ${fn.name}: ` +
`The property ${p} was not decorated for dependency injection.`);
}
const binding = ctx.getBinding(bindingKey);
const valueOrPromise = binding.getValue(ctx);
if (isPromise_1.isPromise(valueOrPromise)) {
const valueOrPromise = resolve(ctx, injection);
if (is_promise_1.isPromise(valueOrPromise)) {
if (!asyncResolvers)

@@ -136,17 +148,2 @@ asyncResolvers = [];

exports.resolveInjectedProperties = resolveInjectedProperties;
/**
* resolve a ValueOrPromise<T> to T
*/
async function resolveValueOrPromise(instanceOrPromise) {
if (isPromise_1.isPromise(instanceOrPromise)) {
const providerPromise = instanceOrPromise;
const instance = await providerPromise;
return instance;
}
else {
const instance = instanceOrPromise;
return instance;
}
}
exports.resolveValueOrPromise = resolveValueOrPromise;
//# sourceMappingURL=resolver.js.map

@@ -7,9 +7,25 @@ import { Context } from './context';

export declare class Binding {
isLocked: boolean;
static PROPERTY_SEPARATOR: string;
/**
* Validate the binding key format. Please note that `#` is reserved.
* @param key Binding key, such as `a, a.b, a:b, a/b
*/
static validateKey(key: string): string;
/**
* Remove the segament that denotes a property path
* @param key Binding key, such as `a, a.b, a:b, a/b, a.b#x, a:b#x.y, a/b#x.y`
*/
static normalizeKey(key: string): string;
/**
* Get the property path separated by `#`
* @param key Binding key
*/
static getKeyPath(key: string): string | undefined;
private readonly _key;
isLocked: boolean;
private _tagName;
private _tags;
valueConstructor: Constructor<BoundValue>;
constructor(_key: string, isLocked?: boolean);
readonly key: string;
readonly tagName: string;
readonly tags: Set<string>;
/**

@@ -19,3 +35,4 @@ * This is an internal function optimized for performance.

*
* Get the value bound to this key. Depending on `isSync`, this function returns either:
* Get the value bound to this key. Depending on `isSync`, this
* function returns either:
* - the bound value

@@ -38,3 +55,3 @@ * - a promise of the bound value

lock(): this;
tag(tagName: string): this;
tag(tagName: string | string[]): this;
/**

@@ -76,6 +93,2 @@ * Bind the key to a constant value.

/**
* get an instance of the provider
*/
getProviderInstance<T>(ctx: Context): Promise<Provider<T>>;
/**
* Bind the key to an instance of the given class.

@@ -82,0 +95,0 @@ *

@@ -6,25 +6,60 @@ "use strict";

// License text available at https://opensource.org/licenses/MIT
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const resolver_1 = require("./resolver");
// FIXME(bajtos) The binding class should be parameterized by the value type stored
const is_promise_1 = require("./is-promise");
// FIXME(bajtos) The binding class should be parameterized by the value
// type stored
class Binding {
constructor(_key, isLocked = false) {
this.isLocked = isLocked;
this._tags = new Set();
Binding.validateKey(_key);
this._key = _key;
this.isLocked = isLocked;
}
get key() { return this._key; }
get tagName() { return this._tagName; }
/**
* Validate the binding key format. Please note that `#` is reserved.
* @param key Binding key, such as `a, a.b, a:b, a/b
*/
static validateKey(key) {
if (!key)
throw new Error('Binding key must be provided.');
if (key.indexOf(Binding.PROPERTY_SEPARATOR) !== -1) {
throw new Error(`Binding key ${key} cannot contain`
+ ` '${Binding.PROPERTY_SEPARATOR}'.`);
}
return key;
}
/**
* Remove the segament that denotes a property path
* @param key Binding key, such as `a, a.b, a:b, a/b, a.b#x, a:b#x.y, a/b#x.y`
*/
static normalizeKey(key) {
const index = key.indexOf(Binding.PROPERTY_SEPARATOR);
if (index !== -1)
key = key.substr(0, index);
key = key.trim();
return key;
}
/**
* Get the property path separated by `#`
* @param key Binding key
*/
static getKeyPath(key) {
const index = key.indexOf(Binding.PROPERTY_SEPARATOR);
if (index !== -1)
return key.substr(index + 1);
return undefined;
}
get key() {
return this._key;
}
get tags() {
return this._tags;
}
/**
* This is an internal function optimized for performance.
* Users should use `@inject(key)` or `ctx.get(key)` instead.
*
* Get the value bound to this key. Depending on `isSync`, this function returns either:
* Get the value bound to this key. Depending on `isSync`, this
* function returns either:
* - the bound value

@@ -53,3 +88,10 @@ * - a promise of the bound value

tag(tagName) {
this._tagName = tagName;
if (typeof tagName === 'string') {
this._tags.add(tagName);
}
else {
tagName.forEach(t => {
this._tags.add(t);
});
}
return this;

@@ -92,3 +134,3 @@ }

// TODO(bajtos) allow factoryFn with @inject arguments
this.getValue = (ctx) => factoryFn();
this.getValue = ctx => factoryFn();
return this;

@@ -100,21 +142,14 @@ }

toProvider(providerClass) {
this.getProviderInstance = (ctx) => __awaiter(this, void 0, void 0, function* () {
this.getValue = ctx => {
const providerOrPromise = resolver_1.instantiateClass(providerClass, ctx);
return resolver_1.resolveValueOrPromise(providerOrPromise);
});
this.getValue = (ctx) => __awaiter(this, void 0, void 0, function* () {
const providerInstance = yield this.getProviderInstance(ctx);
return providerInstance.value();
});
if (is_promise_1.isPromise(providerOrPromise)) {
return providerOrPromise.then(p => p.value());
}
else {
return providerOrPromise.value();
}
};
return this;
}
/**
* get an instance of the provider
*/
getProviderInstance(ctx) {
return __awaiter(this, void 0, void 0, function* () {
return Promise.reject(new Error(`No provider is attached to binding ${this._key}.`));
});
}
/**
* Bind the key to an instance of the given class.

@@ -136,3 +171,4 @@ *

}
Binding.PROPERTY_SEPARATOR = '#';
exports.Binding = Binding;
//# sourceMappingURL=binding.js.map

@@ -8,3 +8,3 @@ "use strict";

const binding_1 = require("./binding");
const isPromise_1 = require("./isPromise");
const is_promise_1 = require("./is-promise");
class Context {

@@ -16,2 +16,4 @@ constructor(_parent) {

bind(key) {
binding_1.Binding.validateKey(key);
key = binding_1.Binding.normalizeKey(key);
const keyExists = this.registry.has(key);

@@ -22,3 +24,3 @@ if (keyExists) {

if (bindingIsLocked)
throw new Error(`Cannot rebind key "${key}", associated binding is locked`);
throw new Error(`Cannot rebind key "${key}" to a locked binding`);
}

@@ -30,2 +32,3 @@ const binding = new binding_1.Binding(key);

contains(key) {
key = binding_1.Binding.normalizeKey(key);
return this.registry.has(key);

@@ -37,2 +40,3 @@ }

// TODO(@superkhau): swap with production grade glob to regex lib
pattern = binding_1.Binding.normalizeKey(pattern);
const glob = new RegExp('^' + pattern.split('*').join('.*') + '$');

@@ -56,3 +60,3 @@ this.registry.forEach(binding => {

this.registry.forEach(binding => {
const isMatch = glob.test(binding.tagName);
const isMatch = Array.from(binding.tags).some(tag => glob.test(tag));
if (isMatch)

@@ -75,4 +79,5 @@ bindings.push(binding);

try {
const path = binding_1.Binding.getKeyPath(key);
const binding = this.getBinding(key);
return Promise.resolve(binding.getValue(this));
return Promise.resolve(binding.getValue(this)).then(val => getValue(val, path));
}

@@ -84,11 +89,12 @@ catch (err) {

getSync(key) {
const path = binding_1.Binding.getKeyPath(key);
const binding = this.getBinding(key);
const valueOrPromise = binding.getValue(this);
if (isPromise_1.isPromise(valueOrPromise)) {
throw new Error(`Cannot get ${key} synchronously: ` +
`the value requires async computation`);
if (is_promise_1.isPromise(valueOrPromise)) {
throw new Error(`Cannot get ${key} synchronously: the value is a promise`);
}
return valueOrPromise;
return getValue(valueOrPromise, path);
}
getBinding(key) {
key = binding_1.Binding.normalizeKey(key);
const binding = this.registry.get(key);

@@ -105,2 +111,21 @@ if (binding) {

exports.Context = Context;
/**
* Get the value by `.` notation
* @param obj The source value
* @param path A path to the nested property, such as `x`, `x.y`, `x.length`,
* or `x.0`
*/
function getValue(obj, path) {
if (!path)
return obj;
const props = path.split('.');
let val = undefined;
for (const p of props) {
val = obj[p];
if (val == null)
return val;
obj = val;
}
return val;
}
//# sourceMappingURL=context.js.map
export { Binding, BoundValue } from './binding';
export { Context } from './context';
export { Constructor, resolveValueOrPromise } from './resolver';
export { Constructor } from './resolver';
export { inject } from './inject';
export { NamespacedReflect } from './reflect';
export { Provider } from './provider';
export { isPromise } from './isPromise';
export { isPromise } from './is-promise';
export { instantiateClass } from './resolver';
export { describeInjectedArguments, describeInjectedProperties } from './inject';
export { describeInjectedArguments, describeInjectedProperties, Injection } from './inject';
export { Reflector } from './reflect';

@@ -11,4 +11,2 @@ "use strict";

exports.Context = context_1.Context;
var resolver_1 = require("./resolver");
exports.resolveValueOrPromise = resolver_1.resolveValueOrPromise;
var inject_1 = require("./inject");

@@ -18,7 +16,7 @@ exports.inject = inject_1.inject;

exports.NamespacedReflect = reflect_1.NamespacedReflect;
var isPromise_1 = require("./isPromise");
exports.isPromise = isPromise_1.isPromise;
var is_promise_1 = require("./is-promise");
exports.isPromise = is_promise_1.isPromise;
// internals for testing
var resolver_2 = require("./resolver");
exports.instantiateClass = resolver_2.instantiateClass;
var resolver_1 = require("./resolver");
exports.instantiateClass = resolver_1.instantiateClass;
var inject_2 = require("./inject");

@@ -25,0 +23,0 @@ exports.describeInjectedArguments = inject_2.describeInjectedArguments;

@@ -1,2 +0,12 @@

import { BoundValue } from './binding';
import { BoundValue, ValueOrPromise } from './binding';
import { Context } from './context';
/**
* A function to provide resolution of injected values
*/
export interface ResolverFunction {
(ctx: Context, injection: Injection): ValueOrPromise<BoundValue>;
}
/**
* Descriptor for an injection point
*/
export interface Injection {

@@ -7,2 +17,3 @@ bindingKey: string;

};
resolve?: ResolverFunction;
}

@@ -32,17 +43,20 @@ /**

* @param metadata Optional metadata to help the injection
* @param resolve Optional function to resolve the injection
*
*/
export declare function inject(bindingKey: string, metadata?: Object): (target: any, propertyKey?: string | symbol | undefined, propertyDescriptorOrParameterIndex?: number | TypedPropertyDescriptor<any> | undefined) => void;
export declare function inject(bindingKey: string, metadata?: Object, resolve?: ResolverFunction): (target: any, propertyKey?: string | symbol | undefined, propertyDescriptorOrParameterIndex?: number | TypedPropertyDescriptor<any> | undefined) => void;
/**
* Return an array of injection objects for constructor parameters
* @param target The target class
* Return an array of injection objects for parameters
* @param target The target class for constructor or static methods,
* or the prototype for instance methods
* @param methodName Method name, undefined for constructor
*/
export declare function describeInjectedArguments(target: Function): Injection[];
export declare function describeInjectedArguments(target: any, method?: string | symbol): Injection[];
/**
* Return a map of injection objects for properties
* @param target The target class. Please note a property decorator function receives
* the target.prototype
* @param target The target class for static properties or
* prototype for instance properties.
*/
export declare function describeInjectedProperties(target: Function): {
export declare function describeInjectedProperties(target: any): {
[p: string]: Injection;
};

@@ -8,4 +8,4 @@ "use strict";

const reflect_1 = require("./reflect");
const REFLECTION_CDI_KEY = 'loopback:inject:constructor';
const REFLECTION_PDI_KEY = 'loopback:inject:properties';
const PARAMETERS_KEY = 'inject:parameters';
const PROPERTIES_KEY = 'inject:properties';
/**

@@ -34,22 +34,32 @@ * A decorator to annotate method arguments for automatic injection

* @param metadata Optional metadata to help the injection
* @param resolve Optional function to resolve the injection
*
*/
function inject(bindingKey, metadata) {
// tslint:disable-next-line:no-any
return function markArgumentAsInjected(target, propertyKey, propertyDescriptorOrParameterIndex) {
function inject(bindingKey, metadata, resolve) {
return function markParameterOrPropertyAsInjected(
// tslint:disable-next-line:no-any
target, propertyKey, propertyDescriptorOrParameterIndex) {
if (typeof propertyDescriptorOrParameterIndex === 'number') {
// The decorator is applied to a method parameter
// Please note propertyKey is `undefined` for constructor
const injectedArgs = reflect_1.Reflector.getOwnMetadata(REFLECTION_CDI_KEY, target, propertyKey) || [];
injectedArgs[propertyDescriptorOrParameterIndex] = { bindingKey, metadata };
reflect_1.Reflector.defineMetadata(REFLECTION_CDI_KEY, injectedArgs, target, propertyKey);
const injectedArgs = reflect_1.Reflector.getOwnMetadata(PARAMETERS_KEY, target, propertyKey) || [];
injectedArgs[propertyDescriptorOrParameterIndex] = {
bindingKey,
metadata,
resolve,
};
reflect_1.Reflector.defineMetadata(PARAMETERS_KEY, injectedArgs, target, propertyKey);
}
else if (propertyKey) {
if (typeof Object.getPrototypeOf(target) === 'function') {
const prop = target.name + '.' + propertyKey.toString();
throw new Error('@inject is not supported for a static property: ' + prop);
}
// The decorator is applied to a property
const injections = reflect_1.Reflector.getOwnMetadata(REFLECTION_PDI_KEY, target) || {};
injections[propertyKey] = { bindingKey, metadata };
reflect_1.Reflector.defineMetadata(REFLECTION_PDI_KEY, injections, target);
const injections = reflect_1.Reflector.getOwnMetadata(PROPERTIES_KEY, target) || {};
injections[propertyKey] = { bindingKey, metadata, resolve };
reflect_1.Reflector.defineMetadata(PROPERTIES_KEY, injections, target);
}
else {
throw new Error('@inject can be used on properties or method parameters.');
throw new Error('@inject can only be used on properties or method parameters.');
}

@@ -60,7 +70,16 @@ };

/**
* Return an array of injection objects for constructor parameters
* @param target The target class
* Return an array of injection objects for parameters
* @param target The target class for constructor or static methods,
* or the prototype for instance methods
* @param methodName Method name, undefined for constructor
*/
function describeInjectedArguments(target) {
return reflect_1.Reflector.getOwnMetadata(REFLECTION_CDI_KEY, target) || [];
function describeInjectedArguments(
// tslint:disable-next-line:no-any
target, method) {
if (method) {
return reflect_1.Reflector.getMetadata(PARAMETERS_KEY, target, method) || [];
}
else {
return reflect_1.Reflector.getMetadata(PARAMETERS_KEY, target) || [];
}
}

@@ -70,9 +89,28 @@ exports.describeInjectedArguments = describeInjectedArguments;

* Return a map of injection objects for properties
* @param target The target class. Please note a property decorator function receives
* the target.prototype
* @param target The target class for static properties or
* prototype for instance properties.
*/
function describeInjectedProperties(target) {
return reflect_1.Reflector.getOwnMetadata(REFLECTION_PDI_KEY, target.prototype) || {};
function describeInjectedProperties(
// tslint:disable-next-line:no-any
target) {
const metadata = {};
let obj = target;
while (true) {
const m = reflect_1.Reflector.getOwnMetadata(PROPERTIES_KEY, obj);
if (m) {
// Adding non-existent properties
for (const p in m) {
if (!(p in metadata)) {
metadata[p] = m[p];
}
}
}
// Recurse into the prototype chain
obj = Object.getPrototypeOf(obj);
if (!obj)
break;
}
return metadata;
}
exports.describeInjectedProperties = describeInjectedProperties;
//# sourceMappingURL=inject.js.map
import { ValueOrPromise } from './binding';
/**
* @exports Provider<T> : interface definition for a provider of a value of type T
* @summary Providers allow binding of a value provider class instead of the value itself
* @exports Provider<T> : interface definition for a provider of a value
* of type T
* @summary Providers allow binding of a value provider class instead of the
* value itself
* @example:

@@ -6,0 +8,0 @@ * ```ts

import { Context } from './context';
import { BoundValue, ValueOrPromise } from './binding';
import { BoundValue } from './binding';
export declare type Constructor<T> = new (...args: any[]) => T;

@@ -31,5 +31,1 @@ /**

export declare function resolveInjectedProperties(fn: Function, ctx: Context): KV | Promise<KV>;
/**
* resolve a ValueOrPromise<T> to T
*/
export declare function resolveValueOrPromise<T>(instanceOrPromise: ValueOrPromise<T>): Promise<T>;

@@ -6,12 +6,4 @@ "use strict";

// License text available at https://opensource.org/licenses/MIT
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const isPromise_1 = require("./isPromise");
const is_promise_1 = require("./is-promise");
const inject_1 = require("./inject");

@@ -32,3 +24,3 @@ /**

let inst;
if (isPromise_1.isPromise(argsOrPromise)) {
if (is_promise_1.isPromise(argsOrPromise)) {
// Instantiate the class asynchronously

@@ -41,5 +33,5 @@ inst = argsOrPromise.then(args => new ctor(...args));

}
if (isPromise_1.isPromise(propertiesOrPromise)) {
return propertiesOrPromise.then((props) => {
if (isPromise_1.isPromise(inst)) {
if (is_promise_1.isPromise(propertiesOrPromise)) {
return propertiesOrPromise.then(props => {
if (is_promise_1.isPromise(inst)) {
// Inject the properties asynchrounously

@@ -55,3 +47,3 @@ return inst.then(obj => Object.assign(obj, props));

else {
if (isPromise_1.isPromise(inst)) {
if (is_promise_1.isPromise(inst)) {
// Inject the properties asynchrounously

@@ -68,2 +60,16 @@ return inst.then(obj => Object.assign(obj, propertiesOrPromise));

/**
* Resolve the value or promise for a given injection
* @param ctx Context
* @param injection Descriptor of the injection
*/
function resolve(ctx, injection) {
if (injection.resolve) {
// A custom resolve function is provided
return injection.resolve(ctx, injection);
}
// Default to resolve the value from the context by binding key
const binding = ctx.getBinding(injection.bindingKey);
return binding.getValue(ctx);
}
/**
* Given a function with arguments decorated with `@inject`,

@@ -88,13 +94,12 @@ * return the list of arguments resolved using the values

for (let ix = 0; ix < fn.length; ix++) {
const bindingKey = injectedArgs[ix].bindingKey;
if (!bindingKey) {
const injection = injectedArgs[ix];
if (!injection.bindingKey && !injection.resolve) {
throw new Error(`Cannot resolve injected arguments for function ${fn.name}: ` +
`The argument ${ix + 1} was not decorated for dependency injection.`);
}
const binding = ctx.getBinding(bindingKey);
const valueOrPromise = binding.getValue(ctx);
if (isPromise_1.isPromise(valueOrPromise)) {
const valueOrPromise = resolve(ctx, injection);
if (is_promise_1.isPromise(valueOrPromise)) {
if (!asyncResolvers)
asyncResolvers = [];
asyncResolvers.push(valueOrPromise.then((v) => args[ix] = v));
asyncResolvers.push(valueOrPromise.then((v) => (args[ix] = v)));
}

@@ -114,15 +119,14 @@ else {

function resolveInjectedProperties(fn, ctx) {
const injectedProperties = inject_1.describeInjectedProperties(fn);
const injectedProperties = inject_1.describeInjectedProperties(fn.prototype);
const properties = {};
let asyncResolvers = undefined;
const propertyResolver = (p) => ((v) => properties[p] = v);
const propertyResolver = (p) => (v) => (properties[p] = v);
for (const p in injectedProperties) {
const bindingKey = injectedProperties[p].bindingKey;
if (!bindingKey) {
const injection = injectedProperties[p];
if (!injection.bindingKey && !injection.resolve) {
throw new Error(`Cannot resolve injected property for class ${fn.name}: ` +
`The property ${p} was not decorated for dependency injection.`);
}
const binding = ctx.getBinding(bindingKey);
const valueOrPromise = binding.getValue(ctx);
if (isPromise_1.isPromise(valueOrPromise)) {
const valueOrPromise = resolve(ctx, injection);
if (is_promise_1.isPromise(valueOrPromise)) {
if (!asyncResolvers)

@@ -144,19 +148,2 @@ asyncResolvers = [];

exports.resolveInjectedProperties = resolveInjectedProperties;
/**
* resolve a ValueOrPromise<T> to T
*/
function resolveValueOrPromise(instanceOrPromise) {
return __awaiter(this, void 0, void 0, function* () {
if (isPromise_1.isPromise(instanceOrPromise)) {
const providerPromise = instanceOrPromise;
const instance = yield providerPromise;
return instance;
}
else {
const instance = instanceOrPromise;
return instance;
}
});
}
exports.resolveValueOrPromise = resolveValueOrPromise;
//# sourceMappingURL=resolver.js.map
{
"name": "@loopback/context",
"version": "4.0.0-alpha.8",
"version": "4.0.0-alpha.9",
"description": "LoopBack's container for Inversion of Control",

@@ -23,3 +23,3 @@ "scripts": {

"devDependencies": {
"@loopback/testlab": "^4.0.0-alpha.4",
"@loopback/testlab": "^4.0.0-alpha.5",
"@types/bluebird": "^3.5.2",

@@ -26,0 +26,0 @@ "bluebird": "^3.5.0",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc