New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@travetto/di

Package Overview
Dependencies
Maintainers
1
Versions
319
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@travetto/di - npm Package Compare versions

Comparing version 2.0.0-alpha.3 to 2.0.0-alpha.4

test-support/suite.ts

45

package.json
{
"author": {
"email": "travetto.framework@gmail.com",
"name": "Travetto Framework"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@travetto/registry": "^2.0.0-alpha.3"
},
"devDependencies": {
"@travetto/config": "^2.0.0-alpha.2"
},
"title": "Dependency Injection",
"name": "@travetto/di",
"displayName": "Dependency Injection",
"version": "2.0.0-alpha.4",
"description": "Dependency registration/management and injection support.",
"homepage": "https://travetto.io",
"keywords": [

@@ -26,10 +14,15 @@ "ast-transformations",

],
"homepage": "https://travetto.io",
"license": "MIT",
"main": "index.ts",
"author": {
"email": "travetto.framework@gmail.com",
"name": "Travetto Framework"
},
"files": [
"index.ts",
"src",
"support"
"support",
"test-support"
],
"name": "@travetto/di",
"main": "index.ts",
"repository": {

@@ -39,4 +32,16 @@ "url": "https://github.com/travetto/travetto.git",

},
"version": "2.0.0-alpha.3",
"gitHead": "2f2ca49b7cb4cb89ba7f565b8cf2bd5d63fb0696"
"dependencies": {
"@travetto/transformer": "2.0.0-alpha.3",
"@travetto/registry": "2.0.0-alpha.4"
},
"devDependencies": {
"@travetto/config": "2.0.0-alpha.3"
},
"docDependencies": {
"@travetto/model-mongo": "2.0.0-alpha.4",
"@travetto/rest": "2.0.0-alpha.5"
},
"publishConfig": {
"access": "public"
}
}

@@ -1,3 +0,3 @@

<!-- This file was generated by the framweork and should not be modified directly -->
<!-- Please modify https://github.com/travetto/travetto/tree/master/module/di/doc.ts and execute "npm run docs" to rebuild -->
<!-- This file was generated by @travetto/doc and should not be modified directly -->
<!-- Please modify https://github.com/travetto/travetto/tree/master/module/di/doc.ts and execute "npx trv doc" to rebuild -->
# Dependency Injection

@@ -14,3 +14,3 @@ ## Dependency registration/management and injection support.

## Declaration
The [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L29) and [@InjectableFactory](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L71) decorators provide the registration of dependencies. Dependency declaration revolves around exposing `class`es and subtypes thereof to provide necessary functionality. Additionally, the framework will utilize dependencies to satisfy contracts with various implementations (e.g. [MongoModelService](https://github.com/travetto/travetto/tree/master/module/model-mongo/src/service.ts#L78) provides itself as an injectable candidate for [ModelCrudSupport](https://github.com/travetto/travetto/tree/master/module/model/src/service/crud.ts).
The [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L30) and [@InjectableFactory](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L72) decorators provide the registration of dependencies. Dependency declaration revolves around exposing `class`es and subtypes thereof to provide necessary functionality. Additionally, the framework will utilize dependencies to satisfy contracts with various implementations (e.g. [MongoModelService](https://github.com/travetto/travetto/tree/master/module/model-mongo/src/service.ts#L45) provides itself as an injectable candidate for [ModelCrudSupport](https://github.com/travetto/travetto/tree/master/module/model/src/service/crud.ts).

@@ -76,3 +76,3 @@ **Code: Example Injectable**

In this scenario, `SpecificService` is a valid candidate for `BaseService` due to the abstract inheritance. Sometimes, you may want to provide a slight variation to a dependency without extending a class. To this end, the [@InjectableFactory](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L71) decorator denotes a `static` class method that produces an [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L29).
In this scenario, `SpecificService` is a valid candidate for `BaseService` due to the abstract inheritance. Sometimes, you may want to provide a slight variation to a dependency without extending a class. To this end, the [@InjectableFactory](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L72) decorator denotes a `static` class method that produces an [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L30).

@@ -98,11 +98,11 @@ **Code: Example InjectableFactory**

**Note**: Other modules are able to provide aliases to [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L29) that also provide additional functionality. For example, the [@Config](https://github.com/travetto/travetto/tree/master/module/config/src/decorator.ts#L10) or the [@Controller](https://github.com/travetto/travetto/tree/master/module/rest/src/decorator/controller.ts#L9) decorator registers the associated class as an injectable element.
**Note**: Other modules are able to provide aliases to [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L30) that also provide additional functionality. For example, the [@Config](https://github.com/travetto/travetto/tree/master/module/config/src/decorator.ts#L10) or the [@Controller](https://github.com/travetto/travetto/tree/master/module/rest/src/decorator/controller.ts#L9) decorator registers the associated class as an injectable element.
## Injection
Once all of your necessary dependencies are defined, now is the time to provide those [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L29) instances to your code. There are three primary methods for injection:
Once all of your necessary dependencies are defined, now is the time to provide those [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L30) instances to your code. There are three primary methods for injection:
The [@Inject](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L29) decorator, which denotes a desire to inject a value directly. These will be set post construction.
The [@Inject](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L30) decorator, which denotes a desire to inject a value directly. These will be set post construction.
**Code: Example Injectable with dependencies as [@Inject](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L29) fields**
**Code: Example Injectable with dependencies as [@Inject](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L30) fields**
```typescript

@@ -123,3 +123,3 @@ import { Injectable, Inject } from '@travetto/di';

The [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L29) constructor params, which will be provided as the instance is being constructed.
The [@Injectable](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L30) constructor params, which will be provided as the instance is being constructed.

@@ -141,3 +141,3 @@ **Code: Example Injectable with dependencies in constructor**

Via [@InjectableFactory](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L71) params, which are comparable to constructor params
Via [@InjectableFactory](https://github.com/travetto/travetto/tree/master/module/di/src/decorator.ts#L72) params, which are comparable to constructor params

@@ -218,2 +218,1 @@ **Code: Example InjectableFactory with parameters as dependencies**

```
import { Class, ClassInstance } from '@travetto/base';
import { MethodDescriptor } from '@travetto/base/src/internal/types';

@@ -39,3 +40,3 @@ import { InjectableFactoryConfig, InjectableConfig, Dependency } from './types';

export type InjectConfig = { qualifier?: symbol, optional?: boolean };
export type InjectConfig = { qualifier?: symbol, optional?: boolean, resolution?: 'loose' | 'strict' };

@@ -73,3 +74,3 @@ export function InjectArgs(configs?: InjectConfig[][]) {

export function InjectableFactory(first?: Partial<InjectableFactoryConfig> | symbol, ...args: (Partial<InjectableFactoryConfig> | undefined)[]) {
return <T extends Class>(target: T, property: string | symbol, descriptor: TypedPropertyDescriptor<any>) => {
return <T extends Class>(target: T, property: string | symbol, descriptor: MethodDescriptor) => {
const config: InjectableFactoryConfig = collapseConfig(first, ...args);

@@ -79,3 +80,3 @@ DependencyRegistry.registerFactory({

dependencies: config.dependencies?.map(x => Array.isArray(x) ? collapseConfig(...x) : collapseConfig(x)),
fn: descriptor.value,
fn: descriptor.value!,
id: `${target.ᚕid}#${property.toString()}`

@@ -82,0 +83,0 @@ });

@@ -10,2 +10,4 @@ import { Class, ClassInstance, ConcreteClass } from '@travetto/base';

type ClassId = string;
type Resolution = 'strict' | 'loose';
type Resolved<T> = { config: InjectableConfig<T>, qualifier: symbol, id: string };

@@ -49,3 +51,3 @@ const PrimaryCandidateSym = Symbol.for('@trv:di/primary');

*/
protected resolveTarget<T>(target: ClassTarget<T>, qualifier?: symbol) {
protected resolveTarget<T>(target: ClassTarget<T>, qualifier?: symbol, resolution?: Resolution): Resolved<T> {
const qualifiers = this.targetToClass.get(target.ᚕid) ?? new Map<symbol, string>();

@@ -60,5 +62,7 @@

if (!qualifier) {
// If primary found
if (qualifiers.has(PrimaryCandidateSym)) {
qualifier = PrimaryCandidateSym;
} else {
// If there is only one default symbol
const filtered = resolved.filter(x => !!x).filter(x => this.defaultSymbols.has(x));

@@ -68,3 +72,9 @@ if (filtered.length === 1) {

} else if (filtered.length > 1) {
throw new InjectionError('Dependency has multiple candidates', target, filtered);
// If dealing with sub types, prioritize exact matches
const exact = this.getCandidateTypes(target as Class).filter(x => x.class === target);
if (exact.length === 1) {
qualifier = exact[0].qualifier;
} else {
throw new InjectionError('Dependency has multiple candidates', target, filtered);
}
}

@@ -77,2 +87,6 @@ }

} else if (!qualifiers.has(qualifier)) {
if (!this.defaultSymbols.has(qualifier) && resolution === 'loose') {
console.debug('Unable to find specific dependency, falling back to general instance', { qualifier, target: target.ᚕid });
return this.resolveTarget(target);
}
throw new InjectionError('Dependency not found', target, [qualifier]);

@@ -102,6 +116,5 @@ } else {

try {
return await this.getInstance(x.target, x.qualifier);
return await this.getInstance(x.target, x.qualifier, x.resolution);
} catch (e) {
if (x.optional && e instanceof InjectionError && e.category === 'notfound') {
return undefined;

@@ -121,3 +134,6 @@ } else {

*/
protected async resolveFieldDependencies<T>(keys: string[], config: InjectableConfig<T>, instance: T) {
protected async resolveFieldDependencies<T>(config: InjectableConfig<T>, instance: T) {
const keys = Object.keys(config.dependencies.fields ?? {})
.filter(k => instance[k as keyof T] === undefined); // Filter out already set ones
// And auto-wire

@@ -146,8 +162,4 @@ if (keys.length) {

// Compute fields to be auto-wired
const fieldKeys = Object.keys(managed.dependencies.fields!)
.filter(x => inst[x as keyof typeof inst] === undefined); // Only apply fields that have not been set
// And auto-wire fields
await this.resolveFieldDependencies(fieldKeys, managed, inst);
await this.resolveFieldDependencies(managed, inst);

@@ -159,4 +171,3 @@ // If factory with field properties on the sub class

if (resolved) {
const subKeys = Object.keys(resolved.dependencies.fields).filter(x => !managed.dependencies.fields[x]);
await this.resolveFieldDependencies(subKeys, resolved, inst);
await this.resolveFieldDependencies(resolved, inst);
}

@@ -209,2 +220,3 @@ }

this.defaultSymbols.delete(qualifier);
this.instances.get(classId)!.delete(qualifier);

@@ -252,6 +264,6 @@ this.instancePromises.get(classId)!.delete(qualifier);

*/
async getInstance<T>(target: ClassTarget<T>, qual?: symbol): Promise<T> {
async getInstance<T>(target: ClassTarget<T>, qual?: symbol, resolution?: Resolution): Promise<T> {
this.verifyInitialized();
const { id: classId, qualifier } = this.resolveTarget(target, qual);
const { id: classId, qualifier } = this.resolveTarget(target, qual, resolution);
if (!this.instances.has(classId) || !this.instances.get(classId)!.has(qualifier)) {

@@ -437,2 +449,6 @@ await this.createInstance(target, qualifier); // Wait for proxy

this.classToTarget.get(classId)!.set(Symbol.for(el.ᚕid), el.ᚕid);
if (config.primary && (classId === targetId || config.factory)) {
this.targetToClass.get(el.ᚕid)!.set(PrimaryCandidateSym, classId);
}
}

@@ -505,4 +521,13 @@

}
/**
* Inject fields into instance
*/
async injectFields<T extends { constructor: Class<T> }>(o: T, cls = o.constructor as Class<T>) {
this.verifyInitialized();
// Compute fields to be auto-wired
return await this.resolveFieldDependencies(this.get(cls), o);
}
}
export const DependencyRegistry = new $DependencyRegistry();

@@ -27,2 +27,8 @@ import { Class } from '@travetto/base';

optional?: boolean;
/**
* Whether or not resolution of dependency should be flexible,
* or should be strict. Default is strict.
*/
resolution?: 'loose' | 'strict';
}

@@ -29,0 +35,0 @@

@@ -1,8 +0,8 @@

import { CliUtil } from '@travetto/cli/src/util';
import { EnvInit } from '@travetto/base/bin/init';
export async function invoke(...[mod, cls, method, qualifier]: (string | undefined)[]) {
CliUtil.initEnv({});
await (await import('@travetto/base')).PhaseManager.init();
EnvInit.init({});
await (await import('@travetto/base')).PhaseManager.run('init');
const inst = await (await import('../src/registry')).DependencyRegistry
.getInstance(require(mod!)[cls!], qualifier ? Symbol.for(qualifier) : qualifier as undefined);
.getInstance((await import(mod!))[cls!], qualifier ? Symbol.for(qualifier) : qualifier as undefined);
return await (inst as Record<string, () => Promise<unknown>>)[method!]();

@@ -9,0 +9,0 @@ }

@@ -16,3 +16,3 @@ import { RetargettingProxy } from '@travetto/watch';

const Cls = class extends $DependencyRegistry {
private proxies = new Map<string, Map<symbol | undefined, RetargettingProxy<unknown>>>();
#proxies = new Map<string, Map<symbol | undefined, RetargettingProxy<unknown>>>();

@@ -24,14 +24,14 @@ /**

const { qualifier, id: classId } = this.resolveTarget(target, qual);
let proxy: RetargettingProxy<T>;
let proxy: RetargettingProxy<unknown>;
if (!this.proxies.has(classId)) {
this.proxies.set(classId, new Map());
if (!this.#proxies.has(classId)) {
this.#proxies.set(classId, new Map());
}
if (!this.proxies.get(classId)!.has(qualifier)) {
proxy = new RetargettingProxy(instance);
this.proxies.get(classId)!.set(qualifier, proxy);
if (!this.#proxies.get(classId)!.has(qualifier)) {
proxy = new RetargettingProxy<unknown>(instance);
this.#proxies.get(classId)!.set(qualifier, proxy);
console.debug('Registering proxy', { id: target.ᚕid, qualifier: qualifier.toString() });
} else {
proxy = this.proxies.get(classId)!.get(qualifier)! as RetargettingProxy<T>;
proxy = this.#proxies.get(classId)!.get(qualifier)! as RetargettingProxy<unknown>;
proxy.setTarget(instance);

@@ -43,3 +43,3 @@ console.debug('Updating target', {

return proxy.get();
return proxy.get() as T;
}

@@ -69,4 +69,4 @@

!cls.ᚕabstract &&
this.proxies.has(classId) &&
this.proxies.get(classId)!.has(config.qualifier)
this.#proxies.has(classId) &&
this.#proxies.get(classId)!.has(config.qualifier)
) {

@@ -83,3 +83,3 @@ console.debug('Reloading on next tick');

const classId = cls.ᚕid;
const proxy = this.proxies.get(classId)!.get(qualifier);
const proxy = this.#proxies.get(classId)!.get(qualifier);
super.destroyInstance(cls, qualifier);

@@ -93,3 +93,3 @@ if (proxy) {

super.reset();
this.proxies.clear();
this.#proxies.clear();
}

@@ -96,0 +96,0 @@ };

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