From fc83606c2084adce9503d0be1e989abf127730ae Mon Sep 17 00:00:00 2001 From: Chau Tran Date: Sun, 10 Sep 2023 21:41:32 -0500 Subject: [PATCH] feat(assert-injector): add `assertInjector` closes #15 This PR adds a utility function `assertInjector` that abstracts `assertInInjectionContext` and guarantees an `Injector` after the utility is invoked ```ts function injectDummy(injector?: Injector) { injector = assertInjector(injectDummy, injector); // ^ injector is guaranteed to be an Injector runInInjectionContext(injector, () => { // always run in a particular Injector's context }) } ``` --- libs/ngxtension/assert-injector/README.md | 3 ++ .../assert-injector/ng-package.json | 5 +++ .../src/assert-injector.spec.ts | 39 +++++++++++++++++++ .../assert-injector/src/assert-injector.ts | 9 +++++ libs/ngxtension/assert-injector/src/index.ts | 1 + libs/ngxtension/project.json | 4 +- tsconfig.base.json | 3 ++ 7 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 libs/ngxtension/assert-injector/README.md create mode 100644 libs/ngxtension/assert-injector/ng-package.json create mode 100644 libs/ngxtension/assert-injector/src/assert-injector.spec.ts create mode 100644 libs/ngxtension/assert-injector/src/assert-injector.ts create mode 100644 libs/ngxtension/assert-injector/src/index.ts diff --git a/libs/ngxtension/assert-injector/README.md b/libs/ngxtension/assert-injector/README.md new file mode 100644 index 000000000..2c1bc6641 --- /dev/null +++ b/libs/ngxtension/assert-injector/README.md @@ -0,0 +1,3 @@ +# ngxtension/assert-injector + +Secondary entry point of `ngxtension`. It can be used by importing from `ngxtension/assert-injector`. diff --git a/libs/ngxtension/assert-injector/ng-package.json b/libs/ngxtension/assert-injector/ng-package.json new file mode 100644 index 000000000..b3e53d699 --- /dev/null +++ b/libs/ngxtension/assert-injector/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/libs/ngxtension/assert-injector/src/assert-injector.spec.ts b/libs/ngxtension/assert-injector/src/assert-injector.spec.ts new file mode 100644 index 000000000..6956b440d --- /dev/null +++ b/libs/ngxtension/assert-injector/src/assert-injector.spec.ts @@ -0,0 +1,39 @@ +import { Injector, runInInjectionContext } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { createInjectionToken } from 'libs/ngxtension/create-injection-token/src/create-injection-token'; +import { assertInjector } from './assert-injector'; + +describe(assertInjector.name, () => { + const [injectNumber, provideNumber] = createInjectionToken(() => 1); + + function injectDummy(injector?: Injector) { + injector = assertInjector(injectDummy, injector); + return runInInjectionContext(injector, () => injectNumber()); + } + + it('given no custom injector, when run in injection context, then return value', () => { + TestBed.runInInjectionContext(() => { + const value = injectDummy(); + expect(value).toEqual(1); + }); + }); + + it('given no custom injector, when run outside injection context, then throw', () => { + expect(() => injectDummy()).toThrowError( + /injectDummy\(\) can only be used within an injection context/i + ); + }); + + it('given a custom injector, when run in that injector context without providing number, then throw', () => { + expect(() => injectDummy(Injector.create({ providers: [] }))).toThrowError( + /No provider for InjectionToken/i + ); + }); + + it('given a custom injector, when run in that injector context and providing number, then return value', () => { + const value = injectDummy( + Injector.create({ providers: [provideNumber(2)] }) + ); + expect(value).toEqual(2); + }); +}); diff --git a/libs/ngxtension/assert-injector/src/assert-injector.ts b/libs/ngxtension/assert-injector/src/assert-injector.ts new file mode 100644 index 000000000..15b77cd89 --- /dev/null +++ b/libs/ngxtension/assert-injector/src/assert-injector.ts @@ -0,0 +1,9 @@ +import { Injector, assertInInjectionContext, inject } from '@angular/core'; + +export function assertInjector( + fn: Function, + injector: Injector | undefined | null +): Injector { + !injector && assertInInjectionContext(fn); + return injector ?? inject(Injector); +} diff --git a/libs/ngxtension/assert-injector/src/index.ts b/libs/ngxtension/assert-injector/src/index.ts new file mode 100644 index 000000000..59d806d6b --- /dev/null +++ b/libs/ngxtension/assert-injector/src/index.ts @@ -0,0 +1 @@ +export const greeting = 'Hello World!'; diff --git a/libs/ngxtension/project.json b/libs/ngxtension/project.json index 37e109793..821bc4897 100644 --- a/libs/ngxtension/project.json +++ b/libs/ngxtension/project.json @@ -47,7 +47,9 @@ "libs/ngxtension/resize/**/*.ts", "libs/ngxtension/resize/**/*.html", "libs/ngxtension/create-injection-token/**/*.ts", - "libs/ngxtension/create-injection-token/**/*.html" + "libs/ngxtension/create-injection-token/**/*.html", + "libs/ngxtension/assert-injector/**/*.ts", + "libs/ngxtension/assert-injector/**/*.html" ] } }, diff --git a/tsconfig.base.json b/tsconfig.base.json index 98115e152..0f127ab13 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -16,6 +16,9 @@ "baseUrl": ".", "paths": { "ngxtension": ["libs/ngxtension/src/index.ts"], + "ngxtension/assert-injector": [ + "libs/ngxtension/assert-injector/src/index.ts" + ], "ngxtension/create-injection-token": [ "libs/ngxtension/create-injection-token/src/index.ts" ],