From 867d760e41e195dc809388eb8b89c428e9d3094e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vlatkovi=C4=87?= <390700+ivandotv@users.noreply.github.com> Date: Mon, 1 Jul 2024 21:23:02 +0200 Subject: [PATCH] remove transform utility function --- .changeset/small-windows-teach.md | 5 + README.md | 50 --- .../transform/dependency-transform.test.ts | 290 ------------------ src/index.ts | 4 +- src/pumpit.ts | 12 +- src/utils.ts | 27 +- 6 files changed, 10 insertions(+), 378 deletions(-) create mode 100644 .changeset/small-windows-teach.md delete mode 100644 src/__tests__/transform/dependency-transform.test.ts diff --git a/.changeset/small-windows-teach.md b/.changeset/small-windows-teach.md new file mode 100644 index 0000000..0b62154 --- /dev/null +++ b/.changeset/small-windows-teach.md @@ -0,0 +1,5 @@ +--- +"pumpit": major +--- + +remove `transform` utility function. Another anti-pattern. diff --git a/README.md b/README.md index ff081fd..a2e4b41 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ It supports different injection scopes, child containers, hooks etc... - [Optional injections](#optional-injections) - [~~Circular dependencies~~](#circular-dependencies) - [~~Injecting arrays~~](#injecting-arrays) - * [Transforming injected dependencies](#transforming-injected-dependencies) * [Post construct method](#post-construct-method) - [Removing values from the container](#removing-values-from-the-container) * [Calling the dispose method](#calling-the-dispose-method) @@ -315,9 +314,6 @@ const container = new PumpIt() const resolveCtx = { foo: 'bar' } container.resolve('some_key', resolveCtx) ``` - -> Read about [transforming dependencies](#transforming-dependencies) to see how context is passed to the callbacks. - ## Injection tokens Injection tokens are the values by which the injection container knows how to resolve registered data. They can be `string`, `Symbol`, or any object. @@ -536,52 +532,6 @@ instanceA.b // undefined > NOTE: Injecting array as a dependency has been removed in version 6. > If you want to use this feature you can use [version 5](https://github.com/ivandotv/pumpit/tree/v5.0.0) -### Transforming injected dependencies - -Injected dependencies can also be manipulated just before they are injected. For this, we use the `transform()` helper function. - -`transform` function wraps the injected dependencies, and accepts a callback which will receive all the resolved dependencies that need to be injected, and it should return an array of dependencies. whatever is returned from the callback, will be injected. - -```ts -import { transform, PumpIt } from 'pumpit' - -const container = new PumpIt() - -const keyA = Symbol() -const keyB = Symbol() -const keyC = Symbol() - -const valueA = { name: 'a' } -const valueB = { name: 'b' } -const valueC = { name: 'c' } - -const resolveCtx = { hello: 'world' } - -class TestA { - static inject = transform( - [keyA, keyB, keyC], - ( - { container, ctx }, - a: typeof valueA, - b: typeof valueB, - c: typeof valueC - ) => { - container === pumpIt // instance of PumpIt - ctx === resolveCtx // context data - - a === valueA - b === valueB - c === valueC - - //default implementation, return the same dependencies in the same order - return [a, b, c] - } - ) - - constructor(a: typeof valueA, b: typeof valueB, c: typeof valueC) {} -} -``` - ### Post construct method If the class that is being constructed (resolved) has a "postConstruct" method defined it will be called automatically when the class instance is created, in the case of singleton instances it will be called only once. One more important thing about `postConstruct` method is that it will be called in the reverse order of the resolution chain. [Please refer to this test for a concrete example](src/__tests__/instance/post-construct.test.ts#L22) diff --git a/src/__tests__/transform/dependency-transform.test.ts b/src/__tests__/transform/dependency-transform.test.ts deleted file mode 100644 index 9abed9b..0000000 --- a/src/__tests__/transform/dependency-transform.test.ts +++ /dev/null @@ -1,290 +0,0 @@ -import { describe, expect, test, vi } from "vitest" -import { PumpIt } from "../../pumpit" -import { get, transform } from "../../utils" - -describe("Transform dependencies", () => { - describe("Class", () => { - test("transform function receives resolved dependencies", () => { - const pumpIt = new PumpIt() - const classKey = Symbol() - const keyA = Symbol() - const keyB = Symbol() - const keyC = Symbol() - - const resolveCtx = { hello: "world" } - - const valueA = { name: "a" } - const valueB = { name: "b" } - const valueC = { name: "c" } - - const transformFn = vi.fn().mockReturnValue([valueA, valueB, valueC]) - - class TestA { - static inject = transform([keyA, keyB, keyC], transformFn) - } - - pumpIt - .bindClass(classKey, TestA) - .bindValue(keyA, valueA) - .bindValue(keyB, valueB) - .bindValue(keyC, valueC) - .resolve(classKey, resolveCtx) - - expect(transformFn).toHaveBeenCalledWith( - { - container: pumpIt, - ctx: resolveCtx, - }, - valueA, - valueB, - valueC, - ) - }) - - test("transform function can be applied on object registration", () => { - const pumpIt = new PumpIt() - const classKey = Symbol() - const keyA = Symbol() - const keyB = Symbol() - const keyC = Symbol() - - const valueA = { name: "a" } - const valueB = { name: "b" } - const valueC = { name: "c" } - - const transformFn = vi.fn().mockReturnValue([valueA, valueB, valueC]) - - class TestA { - constructor( - public a: any, - public b: any, - public c: any, - ) {} - } - - pumpIt - .bindClass(classKey, { - value: TestA, - inject: transform([keyA, keyB, keyC], transformFn), - }) - .bindValue(keyA, valueA) - .bindValue(keyB, valueB) - .bindValue(keyC, valueC) - - const instance = pumpIt.resolve(classKey) - - expect(transformFn).toHaveBeenCalledWith( - { - container: pumpIt, - ctx: undefined, - }, - valueA, - valueB, - valueC, - ) - - expect(instance.a).toBe(valueA) - expect(instance.b).toBe(valueB) - expect(instance.c).toBe(valueC) - }) - - test("transform function receives resolved dependency as an array", () => { - const pumpIt = new PumpIt() - const classKey = Symbol() - const keyA = Symbol() - const keyB = Symbol() - const keyC = Symbol() - - const valueA = { a: "a" } - const valueB = { b: "b" } - const valueC = { c: "c" } - - const transformFn = vi.fn().mockReturnValue([valueA, valueB, valueC]) - - class TestA { - static inject = transform([keyA, keyB, keyC], transformFn) - } - - pumpIt - .bindClass(classKey, TestA) - .bindValue(keyA, valueA) - .bindValue(keyB, valueB) - .bindValue(keyC, valueC) - .resolve(classKey) - - expect(transformFn).toHaveBeenCalledWith( - { container: pumpIt, ctx: undefined }, - valueA, - valueB, - valueC, - ) - }) - - test("transform function can replace dependencies", () => { - const pumpIt = new PumpIt() - const classKey = Symbol() - const keyA = Symbol() - const keyB = Symbol() - const keyC = Symbol() - - const valueA = {} - const valueB = {} - const valueC = {} - - const transformedA = {} - const transformedB = {} - const transformedC = {} - - const injectTransform = vi - .fn() - .mockReturnValue([transformedA, transformedB, transformedC]) - - class TestA { - static inject = transform([keyA, keyB, keyC], injectTransform) - - constructor( - public keyA: any, - public keyB: any, - public keyC: any, - ) {} - } - - pumpIt - .bindClass(classKey, TestA) - .bindValue(keyA, valueA) - .bindValue(keyB, valueB) - .bindValue(keyC, valueC) - - const instance = pumpIt.resolve(classKey) - - expect(injectTransform).toHaveBeenCalledWith( - { - container: pumpIt, - ctx: undefined, - }, - valueA, - valueB, - valueC, - ) - expect(instance.keyA).toBe(transformedA) - expect(instance.keyB).toBe(transformedB) - expect(instance.keyC).toBe(transformedC) - }) - - test('transform function receives "undefined" for non existent dependency', () => { - const pumpIt = new PumpIt() - const keyA = Symbol() - const keyC = Symbol() - - const valueA = {} - const valueC = {} - - const injectTransform = vi.fn().mockReturnValue([]) - - class TestA { - static inject = transform( - [keyA, get("not_found", { optional: true }), keyC], - injectTransform, - ) - - constructor( - public keyA: any, - public keyB: any, - public keyC: any, - ) {} - } - - pumpIt - .bindClass(TestA, TestA) - .bindValue(keyA, valueA) - .bindValue(keyC, valueC) - .resolve(TestA) - - expect(injectTransform).toHaveBeenCalledWith( - { - container: pumpIt, - ctx: undefined, - }, - valueA, - undefined, - valueC, - ) - }) - }) - - describe("Factory", () => { - test("transform function receives resolved dependencies", () => { - const pumpIt = new PumpIt() - const factoryKey = Symbol() - const keyA = Symbol() - const keyB = Symbol() - const keyC = Symbol() - const requestData = { foo: "bar" } - - const valueA = {} - const valueB = {} - const valueC = {} - - const injectTransform = vi.fn().mockReturnValue([valueA, valueB, valueC]) - - const factory = () => {} - factory.inject = transform([keyA, keyB, keyC], injectTransform) - - pumpIt - .bindFactory(factoryKey, factory) - .bindValue(keyA, valueA) - .bindValue(keyB, valueB) - .bindValue(keyC, valueC) - .resolve>(factoryKey, { data: requestData }) - - expect(injectTransform).toHaveBeenCalledWith( - { - container: pumpIt, - ctx: { - data: requestData, - }, - }, - valueA, - valueB, - valueC, - ) - }) - - test("transform function can replace dependencies", () => { - const pumpIt = new PumpIt() - const factoryKey = Symbol() - const keyA = Symbol() - const keyB = Symbol() - const keyC = Symbol() - - const valueA = {} - const valueB = {} - const valueC = {} - - const transformedA = {} - const transformedB = {} - const transformedC = {} - - const factory = vi.fn() - // @ts-expect-error - there is no inject on vi.fn - factory.inject = transform([keyA, keyB, keyC], () => [ - transformedA, - transformedB, - transformedC, - ]) - - pumpIt - .bindFactory(factoryKey, factory) - .bindValue(keyA, valueA) - .bindValue(keyB, valueB) - .bindValue(keyC, valueC) - .resolve(factoryKey) - - expect(factory).toHaveBeenCalledWith( - transformedA, - transformedB, - transformedC, - ) - }) - }) -}) diff --git a/src/index.ts b/src/index.ts index ad67df4..feb9702 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,6 @@ export * from "./pumpit.js" export * from "./types.js" export * from "./pumpit-error.js" -import { INJECT_KEY, get, registerInjections, transform } from "./utils.js" +import { INJECT_KEY, get, registerInjections } from "./utils.js" -export { get, transform, INJECT_KEY, registerInjections } +export { get, INJECT_KEY, registerInjections } diff --git a/src/pumpit.ts b/src/pumpit.ts index 8cae6c1..0a36fa9 100644 --- a/src/pumpit.ts +++ b/src/pumpit.ts @@ -375,17 +375,7 @@ export class PumpIt { let resolvedDeps: any[] = [] if (injectionData) { - if (Array.isArray(injectionData)) { - resolvedDeps = this.resolveDeps(injectionData, ctx) - } else { - resolvedDeps = injectionData.fn( - { - container: this, - ctx: ctx.ctx, - }, - ...this.resolveDeps(injectionData.deps, ctx), - ) - } + resolvedDeps = this.resolveDeps(injectionData, ctx) } // @ts-expect-error - type narrow const result = value(...resolvedDeps) diff --git a/src/utils.ts b/src/utils.ts index 0fe13ff..82ce779 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,8 +1,4 @@ -import type { PumpIt } from "./pumpit" -import type { BindKey, ResolveCtx } from "./types" - -//detect transfom action function -export const TRANSFORM_DEPS = Symbol() +import type { BindKey } from "./types" //detect injection function const INJECTION_FN = Symbol() @@ -22,9 +18,7 @@ export type ParsedInjectionData = export type Injection = BindKey | ReturnType -export type InjectionData = - | Injection[] - | { action: symbol; fn: (...args: any) => any; deps: Injection[] } +export type InjectionData = Injection[] /** * get dependency by key @@ -67,23 +61,6 @@ export function parseInjectionData(key: Injection): ParsedInjectionData { return { key, options: { optional: false } } } -/** - * Wrapper function for registering dependencies that can be manipulated before being injected - * It gets an array of dependencies in injection order, and it should return an array - * @param deps - array of dependencies that need to be satisfied see: {@link BindKey | BindKey} {@link get | get()} - * @param fn - function that will be called with the resolved dependencies - */ -export function transform( - deps: (BindKey | typeof get)[], - fn: (data: { container: PumpIt; ctx: ResolveCtx }, ...deps: any[]) => any[], -) { - return { - action: TRANSFORM_DEPS, - fn: fn, - deps, - } -} - export function keyToString(key: BindKey) { // @ts-expect-error name does not exist on string or symbol return key.name || key.toString()