Skip to content

Commit

Permalink
feat: precedence config option
Browse files Browse the repository at this point in the history
closes #81
  • Loading branch information
Jack Ellis committed Aug 27, 2020
1 parent 7aa641f commit 0fe2f0e
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Change Log
- you can now pass an `opts` parameter when resolving i.e. `.resolve<A>({ optional: true })`
- `resolveWith` now has a nicer syntax for ts inference: `.resolveWith<Foo, Dep1, Dep2>([ 'val1', 'val2' ])`. The original syntax i.e. `.resolveWith({ dep1: 'val1' })` is still valid.
- removed the built-in dependency `$options`. You can no longer do `.resolve({ foo: 'someValue' })`
- `precedence` option lets you determine if a factory should overwrite an existing factory or not

#### 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
Expand Down
1 change: 1 addition & 0 deletions src/Jpex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Jpex implements IJpex {
this.$$parent = parent;
this.$$config = {
lifecycle: (inherit ? parent?.$$config.lifecycle : void 0) ?? 'class',
precedence: 'active',
globals: true,
nodeModules: true,
optional: false,
Expand Down
100 changes: 100 additions & 0 deletions src/__tests__/precedence.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import anyTest, { TestInterface } from 'ava';
import { jpex as base, JpexInstance } from '..';

const test: TestInterface<{
jpex: JpexInstance,
jpex2: JpexInstance,
}> = anyTest;

test.beforeEach((t) => {
const jpex = base.extend();
const jpex2 = jpex.extend();

t.context = {
jpex,
jpex2,
};
});

test('active overwrites an existing factory', (t) => {
const { jpex } = t.context;

type A = string;
jpex.factory<A>(() => 'a');
jpex.factory<A>(() => 'A', { precedence: 'active' });

const result = jpex.resolve<A>();

t.is(result, 'A');
});

test('active overwrites an inherited factory', (t) => {
const { jpex, jpex2 } = t.context;

type A = string;
jpex.factory<A>(() => 'a');
jpex2.factory<A>(() => 'A', { precedence: 'active' });

const result = jpex2.resolve<A>();

t.is(result, 'A');
});

test('defaults to active', (t) => {
const { jpex } = t.context;

type A = string;
jpex.factory<A>(() => 'a');
jpex.factory<A>(() => 'A');

const result = jpex.resolve<A>();

t.is(result, 'A');
});

test('passive is ignored over an existing factory', (t) => {
const { jpex } = t.context;

type A = string;
jpex.factory<A>(() => 'a');
jpex.factory<A>(() => 'A', { precedence: 'passive' });

const result = jpex.resolve<A>();

t.is(result, 'a');
});

test('passive is ignored over an inherited factory', (t) => {
const { jpex, jpex2 } = t.context;

type A = string;
jpex.factory<A>(() => 'a');
jpex2.factory<A>(() => 'A', { precedence: 'passive' });

const result = jpex2.resolve<A>();

t.is(result, 'a');
});

test('passive is used if it does not exist', (t) => {
const { jpex2 } = t.context;

type A = string;
jpex2.factory<A>(() => 'A', { precedence: 'passive' });

const result = jpex2.resolve<A>();

t.is(result, 'A');
});

test('inherits passive from config', (t) => {
const { jpex: base } = t.context;
const jpex = base.extend({ precedence: 'passive' });
type A = string;
jpex.factory<A>(() => 'a');
jpex.factory<A>(() => 'A');

const result = jpex.resolve<A>();

t.is(result, 'a');
});
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
NamedParameters,
Resolve,
Lifecycle,
Precedence,
} from './types';

const jpex = new Jpex() as JpexInstance;
Expand All @@ -22,6 +23,7 @@ export type {
SetupConfig,
NamedParameters,
Resolve,
Precedence,
};

export default jpex;
6 changes: 6 additions & 0 deletions src/registers/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ function factory <T>(
dependencies = null;
}

const precedence = opts?.precedence ?? jpex.$$config.precedence;

if (precedence === 'passive' && jpex.$$factories[name]) {
return;
}

const f: Factory = {
fn,
dependencies,
Expand Down
13 changes: 12 additions & 1 deletion src/types/JpexInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@ import {
AnyFunction,
Dependency,
AnyConstructor,
SetupConfig,
Factory,
Precedence,
} from './';
import { NamedParameters } from './BuiltIns';

export interface SetupConfig {
inherit?: boolean,
lifecycle?: Lifecycle,
precedence?: Precedence,
optional?: boolean,
nodeModules?: boolean,
globals?: boolean,
}

export interface FactoryOpts {
lifecycle?: Lifecycle,
precedence?: Precedence,
}
export interface ServiceOpts extends FactoryOpts {
bindToInstance?: boolean,
Expand Down Expand Up @@ -72,6 +82,7 @@ export interface JpexInstance {
},
$$config: {
lifecycle: Lifecycle,
precedence: Precedence,
optional: boolean,
nodeModules: boolean,
globals: boolean,
Expand Down
10 changes: 2 additions & 8 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,13 @@ export * from './BuiltIns';

export type Lifecycle = 'application' | 'class' | 'instance' | 'none';

export type Precedence = 'active' | 'passive';

export type AnyFunction<R = any> = (...args: any[]) => R;
export interface AnyConstructor<T = any> {
new (...args: any[]): T
}

export interface SetupConfig {
inherit?: boolean,
lifecycle?: Lifecycle,
optional?: boolean,
nodeModules?: boolean,
globals?: boolean,
}

export type Dependency = string;

export interface Definition {
Expand Down

0 comments on commit 0fe2f0e

Please sign in to comment.