From 2a9ded772e3d49cdcb53f29fe8eb655d71c3552d Mon Sep 17 00:00:00 2001 From: nitowa Date: Sun, 16 Oct 2022 03:45:21 +0200 Subject: [PATCH] 0.0.7 init order fix, add proper README --- README.md | 144 +++++++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- src/Injector.ts | 2 +- 3 files changed, 145 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5e1c309..ac6f0b4 100644 --- a/README.md +++ b/README.md @@ -1 +1,143 @@ -Hello World \ No newline at end of file +# Overview + +[![Build Status](https://drone.nitowa.xyz/api/badges/npm-packages/depents/status.svg)](https://drone.nitowa.xyz/npm-packages/depents) +[![Current Version](https://img.shields.io/npm/v/depents.svg)](https://www.npmjs.com/package/depents) +[![Weekly Downloads](https://img.shields.io/npm/dw/depents?color=important)](https://www.npmjs.com/package/depents) +[![License Type](https://img.shields.io/npm/l/depents?color=blueviolet)](https://gitea.nitowa.xyz/docs/depents/src/branch/master/LICENSE.md) + +depents is a typescript dependency injection framework + +# How to install +``` +npm i depents +``` + +# Quickstart (TL;DR) +```typescript +import {Singleton, Inject, Injector} from 'dependjs' + + +@Singleton() +class AClass{ + private A = 'a' + + getA () { + return this.A + } +} + +@Singleton() +class BClass{ + + @Inject(AClass) + private a: AClass + + getA(){ + return this.a.getA() + } +} + + +console.log(Injector.resolve(BClass).getA()) //"a" + +``` + +# Working with interfaces as non-default injection tokens +As interfaces are not a runtime construct in javascript, classes have to be used in their place in order to work with injection resolution. + +Consider this quick example: + + +File `MyModule/Interface.ts` +```typescript +export abstract class IComponent{ + get: () => string +} +``` + +File `MyModule/Implementation.ts` +```typescript +import {IComponent} from 'Interface.ts' + +@Singleton({ + interface: IComponentB, +}) +export class ComponentB implements IComponent{ + get(): string { + return "Hello!" + } +} +``` + +File `Main.ts` +```typescript +import {IComponent} from 'MyModule/Interface.ts' +import {ComponentB} from 'Module/Implementation.ts' +ComponentB; //see Tree shaking pitfall below + +Injector.resolve(IComponent).get() +``` + +# Tree shaking pitfall +TSC will attempt to exclude unused code in order to keep the compiled JS minimal. In the above example neither `Main.ts` nor `MyModule/Interface.ts` ever reference `MyModule/Implementation.ts` and it is therefore considered unused code. This will lead to the compilation output not containing the `ComponentB` class. To forcibly include `ComponentB`, it has to be referenced at least once - even if it is a senseless operation like in the above example. + +# Initialization +This version of depents will simply call all constructors of classes marked as `Singleton` without arguments and it is therefore recommended that the user does not place initialization logic there. Alternatively, you may provide a function named `initialize` which will be called during Singleton creation. + +An example: + +```typescript +@Singleton() +export class Component{ + private value: string + + get(): string { + return this.value + } + + initialize():void { //Called during object creation + this.value = "Hello!" + } +} +``` + +If your code requires objects to be initialized in a particular order, you may pass an optional `initializationPriority` parameter to `@Singleton`. The respective initialize operations will be called in order of `initializationPriority` from **lowest to highest**. If omitted, the default value is 0. + +```typescript +@Singleton({ + initializationPriority: 0 +}) +export class InitializedFirst{ + private value: number + + get(): number { + return this.value + } + + initialize():void { + this.value = 1 + } +} + +@Singleton({ + initializationPriority: 1 +}) +export class InitializedSecond{ + @Inject(InitializedFirst) + private otherSingleton: InitializedFirst + + private value: number + + get(): number { + return this.value + } + + initialize():void { + this.value = 1 + this.otherSingleton.get() + } +} + +console.log(Injector.resolve(InitializedSecond).get()) //2 +``` + +# [Full documentation](https://gitea.nitowa.xyz/docs/depents) diff --git a/package.json b/package.json index 3c69905..14e730e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "depents", - "version": "0.0.6", + "version": "0.0.7", "description": "depents is a typescript dependency injector", "main": "./js/Index.js", "repository": { diff --git a/src/Injector.ts b/src/Injector.ts index f31b27c..4114121 100644 --- a/src/Injector.ts +++ b/src/Injector.ts @@ -71,7 +71,7 @@ class _Injector { private initializeSingletons = () => { this.singletonDefinitions - .sort((a, b) => (b.initializationPriority ?? 0) - (a.initializationPriority ?? 0)) + .sort((a, b) => (a.initializationPriority ?? 0) - (b.initializationPriority ?? 0)) .map(def => this.singletonObjects[def.ctor.name]) .forEach(obj => obj.initialize ? obj.initialize() : undefined) }