From d2ec9b292d3dee2a9b6aa967c24260c02596e341 Mon Sep 17 00:00:00 2001 From: Jack Ellis Date: Sun, 23 Aug 2020 06:44:55 +0100 Subject: [PATCH] feat: nicer syntax for resolveWith closes #78 --- CHANGELOG.md | 1 + package.json | 6 +-- plugin/resolveWith.ts | 26 +++++++++++ src/__tests__/resolve.test.ts | 6 ++- src/__tests__/resolveWith.test.ts | 78 +++++++++++++++++++++++++++++++ src/types/JpexInstance.ts | 10 +++- 6 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 src/__tests__/resolveWith.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6837b37..398f92b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Change Log - changed format of `.factory` `.service` and `.resolve` - you can now pass an `opts` parameter when registering a factory i.e. `.factory(fn, { lifecycle: 'none' })` - you can now pass an `opts` parameter when resolving i.e. `.resolve({ optional: true })` +- `resolveWith` now has a nicer syntax for ts inference: `.resolveWith([ 'val1', 'val2' ])`. The original syntax i.e. `.resolveWith({ dep1: 'val1' })` is still valid. #### Breaking Changes - if you attempt to resolve a global like `Window` without registering it first, rather than throw an error, you will now get the global variable diff --git a/package.json b/package.json index 239fbaf..e0cbb70 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,9 @@ "module": "dist/es/jpex.js", "types": "dist/es/index.d.ts", "scripts": { - "test": "ava", - "test:debug": "ava debug", - "coverage": "nyc ava", + "test": "BABEL_DISABLE_CACHE=1 ava", + "test:debug": "BABEL_DISABLE_CACHE=1 ava debug", + "coverage": "BABEL_DISABLE_CACHE=1 nyc ava", "lint": "eslint './src/**/*.ts' && eslint './plugin/**/*.ts' && tsc --noEmit", "build:prepare": "rm -rf dist", "build:js": "rollup --config ./rollup.config.js", diff --git a/plugin/resolveWith.ts b/plugin/resolveWith.ts index 2479074..de74f3e 100644 --- a/plugin/resolveWith.ts +++ b/plugin/resolveWith.ts @@ -27,7 +27,33 @@ const resolveWith = ( args.unshift(t.stringLiteral(name)); } else if (t.isTSTypeLiteral(type) || t.isTSFunctionType(type)) { throw new Error('Currently resolving with a literal type is not supported'); + } else { + return; + } + + if (!t.isArrayExpression(args[1])) { + return; } + + const namedDependencies: t.ObjectProperty[] = []; + let i = 1; + let namedType = getTypeParameter(path, i); + while (namedType) { + const name = getConcreteTypeName(namedType, filename, publicPath, programPath); + if (name != null) { + const value = args[1].elements[i - 1]; + const key = t.stringLiteral(name); + // @ts-ignore + const prop = t.objectProperty(key, value); + namedDependencies.push(prop); + } else if (t.isTSTypeLiteral(type) || t.isTSFunctionType(type)) { + throw new Error('Currently resolving with a literal type is not supported'); + } + // eslint-disable-next-line no-plusplus + namedType = getTypeParameter(path, ++i); + } + + args.splice(1, 1, t.objectExpression(namedDependencies)); }; export default resolveWith; diff --git a/src/__tests__/resolve.test.ts b/src/__tests__/resolve.test.ts index dab6fcf..2cabf63 100644 --- a/src/__tests__/resolve.test.ts +++ b/src/__tests__/resolve.test.ts @@ -54,8 +54,10 @@ test('resolves named dependencies', (t) => { type Named = string; jpex.factory((named: Named) => named); - const result = jpex.resolveWith({ - [jpex.infer()]: 'pop', + const result = jpex.resolve({ + with: { + [jpex.infer()]: 'pop', + }, }); t.is(result, 'pop'); diff --git a/src/__tests__/resolveWith.test.ts b/src/__tests__/resolveWith.test.ts new file mode 100644 index 0000000..41e7c3e --- /dev/null +++ b/src/__tests__/resolveWith.test.ts @@ -0,0 +1,78 @@ +import anyTest, { TestInterface } from 'ava'; +import base, { JpexInstance } from '..'; + +const test: TestInterface<{ + jpex: JpexInstance, +}> = anyTest; + +test.beforeEach((t) => { + const jpex = base.extend(); + + t.context = { + jpex, + }; +}); + +test('it resolves with given values (js)', (t) => { + const { jpex } = t.context; + + jpex.factory('A', [ 'B', 'C', 'D' ], (b, c, d) => { + return b + c + d; + }); + + const result = jpex.resolveWith('A', { + B: 'b', + C: 'c', + D: 'd', + }); + + t.is(result, 'bcd'); +}); + +test('it resolves with given values (ts)', (t) => { + const { jpex } = t.context; + + type A = string; + type B = string; + type C = string; + type D = string; + + jpex.factory((b: B, c: C, d: D) => b + c + d); + + const result = jpex.resolveWith({ + [jpex.infer()]: 'b', + [jpex.infer()]: 'c', + [jpex.infer()]: 'd', + }); + + t.is(result, 'bcd'); +}); + +test('it resolves using type inference (1)', (t) => { + const { jpex } = t.context; + type A = string; + type B = string; + + jpex.factory((b: B) => `a${b}`); + + const result = jpex.resolveWith([ 'b' ]); + + t.is(result, 'ab'); +}); + +test('it resolves with type inference (6)', (t) => { + const { jpex } = t.context; + type A = string; + type B = string; + type C = string; + type D = string; + type E = string; + type F = string; + type G = string; + + jpex.factory((b: B, c: C, d: D, e: E, f: F, g: G) => `a${b}${c}${d}${e}${f}${g}`); + + const result = jpex.resolveWith([ 'b', 'c', 'd', 'e', 'f', 'g' ]); + + t.is(result, 'abcdefg'); +}); diff --git a/src/types/JpexInstance.ts b/src/types/JpexInstance.ts index d6dcf69..46c9e62 100644 --- a/src/types/JpexInstance.ts +++ b/src/types/JpexInstance.ts @@ -36,8 +36,14 @@ export interface JpexInstance { resolve(name: Dependency, opts?: ResolveOpts): any, resolve(opts?: ResolveOpts): T, - resolveWith(name: Dependency, namedParameters: NamedParameters): any - resolveWith(namedParameters: NamedParameters): T, + resolveWith(name: Dependency, namedParameters: NamedParameters, opts?: ResolveOpts): any + resolveWith(namedParameters: NamedParameters, opts?: ResolveOpts): T, + resolveWith(args: [ A ], opts?: ResolveOpts): T, + resolveWith(args: [ A, B ], opts?: ResolveOpts): T, + resolveWith(args: [ A, B, C ], opts?: ResolveOpts): T, + resolveWith(args: [ A, B, C, D ], opts?: ResolveOpts): T, + resolveWith(args: [ A, B, C, D, E ], opts?: ResolveOpts): T, + resolveWith(args: [ A, B, C, D, E, F ], opts?: ResolveOpts): T, encase>( dependencies: Dependency[],