Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix injection of optional properties #1308

Merged
merged 9 commits into from
Apr 17, 2021
Merged
4 changes: 4 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ jobs:
strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 15.x]
ts-project: [src/tsconfig.json, src/tsconfig-es6.json]

env:
TS_NODE_PROJECT: ${{ matrix.ts-project }}

steps:
- uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ dts
lib
temp
es
es6
amd

type_definitions/inversify/*.js
Expand Down
17 changes: 7 additions & 10 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,18 @@
"name": "Mocha Tests",
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"args": [
"-r",
"ts-node/register",
"--require",
"reflect-metadata",
"-u",
"tdd",
"--timeout",
"999999",
"--colors",
"${workspaceRoot}/test/**/*.test.js"
"${workspaceRoot}/test/**/*.test.ts"
],
"sourceMaps": true,
"outFiles": [
"${workspaceRoot}/test",
"${workspaceRoot}/src"
],
"internalConsoleOptions": "openOnSessionStart"
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"protocol": "inspector"
Comment on lines +13 to +24
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

},
{
"type": "node",
Expand All @@ -49,4 +46,4 @@
"console": "internalConsole",
}
]
}
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Fix `Target.isTagged()` to exclude `optional` from tag injections #1190.
- Update `toConstructor`, `toFactory`, `toFunction`, `toAutoFactory`, `toProvider` and `toConstantValue` to have singleton scope #1297.
- Fix injection on optional properties when targeting ES6 #928

## [5.0.1] - 2018-10-17
### Added
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
"jsnext:main": "es/inversify.js",
"types": "lib/inversify.d.ts",
"scripts": {
"build": "npm run build:lib && npm run build:amd && npm run build:es",
"build": "npm run build:lib && npm run build:amd && npm run build:es && npm run build:es6",
"build:lib": "tsc -p src/tsconfig.json",
"build:amd": "tsc -p src/tsconfig-amd.json",
"build:es": "tsc -p src/tsconfig-es.json",
"build:es6": "tsc -p src/tsconfig-es6.json",
"clean": "rm -r amd es lib",
"pretest": "tslint --project .",
"test": "nyc --require ts-node/register mocha test/**/*.test.ts --reporter spec --retries 3 --require 'node_modules/reflect-metadata/Reflect.js' --exit",
Expand Down
4 changes: 3 additions & 1 deletion src/planning/reflection_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ function getTargets(

const keys = Object.keys(constructorArgsMetadata);
const hasUserDeclaredUnknownInjections = (func.length === 0 && keys.length > 0);
const iterations = (hasUserDeclaredUnknownInjections) ? keys.length : func.length;
const hasOptionalParameters = keys.length > func.length;

const iterations = (hasUserDeclaredUnknownInjections || hasOptionalParameters) ? keys.length : func.length;

// Target instances that represent constructor arguments to be injected
const constructorTargets = getConstructorArgsAsTargets(
Expand Down
10 changes: 10 additions & 0 deletions src/tsconfig-es6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"include": [
"./**/*.ts"
],
"extends": "../tsconfig.json",
"compilerOptions": {
"target": "es6",
"outDir": "../es6"
},
}
41 changes: 23 additions & 18 deletions test/bugs/issue_543.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,44 @@ describe("Issue 543", () => {
Root: Symbol.for("Root")
};

interface IIrrelevant {}
interface ICircular{}
interface IChild {}
interface IChild2 {}

@injectable()
class Irrelevant {}
class Irrelevant implements IIrrelevant {}

@injectable()
class Child2 {
public circ: Circular;
class Child2 implements IChild2 {
public circ: ICircular;
public constructor(
@inject(TYPE.Circular) circ: Circular
@inject(TYPE.Circular) circ: ICircular
) {
this.circ = circ;
}
}

@injectable()
class Child {
public irrelevant: Irrelevant;
public child2: Child2;
class Child implements IChild {
public irrelevant: IIrrelevant;
public child2: IChild2;
public constructor(
@inject(TYPE.Irrelevant) irrelevant: Irrelevant,
@inject(TYPE.Child2) child2: Child2
@inject(TYPE.Irrelevant) irrelevant: IIrrelevant,
@inject(TYPE.Child2) child2: IChild2
) {
this.irrelevant = irrelevant;
this.child2 = child2;
}
}

@injectable()
class Circular {
public irrelevant: Irrelevant;
public child: Child;
class Circular implements Circular {
public irrelevant: IIrrelevant;
public child: IChild;
public constructor(
@inject(TYPE.Irrelevant) irrelevant: Irrelevant,
@inject(TYPE.Child) child: Child
@inject(TYPE.Irrelevant) irrelevant: IIrrelevant,
@inject(TYPE.Child) child: IChild
) {
this.irrelevant = irrelevant;
this.child = child;
Expand All @@ -55,11 +60,11 @@ describe("Issue 543", () => {

@injectable()
class Root {
public irrelevant: Irrelevant;
public circ: Circular;
public irrelevant: IIrrelevant;
public circ: ICircular;
public constructor(
@inject(TYPE.Irrelevant) irrelevant1: Irrelevant,
@inject(TYPE.Circular) circ: Circular
@inject(TYPE.Irrelevant) irrelevant1: IIrrelevant,
@inject(TYPE.Circular) circ: ICircular
) {
this.irrelevant = irrelevant1;
this.circ = circ;
Expand Down
11 changes: 7 additions & 4 deletions test/bugs/issue_549.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,24 @@ describe("Issue 549", () => {
BDynamicValue: Symbol.for("BDynamicValue")
};

interface IA {}
interface IB {}

@injectable()
class A {
public b: B;
public b: IB;
public constructor(
@inject(TYPE.BDynamicValue) b: B
@inject(TYPE.BDynamicValue) b: IB
) {
this.b = b;
}
}

@injectable()
class B {
public a: A;
public a: IA;
public constructor(
@inject(TYPE.ADynamicValue) a: A
@inject(TYPE.ADynamicValue) a: IA
) {
this.a = a;
}
Expand Down
42 changes: 42 additions & 0 deletions test/bugs/issue_928.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { expect } from "chai";
import { Container, inject, injectable, optional } from "../../src/inversify";


describe("Issue 928", () => {

it('should inject the right instances', () => {

let injectedA: unknown;
let injectedB: unknown;
let injectedC: unknown;

// some dependencies
@injectable() class DepA { a = 1 }
@injectable() class DepB { b = 1 }
@injectable() class DepC { c = 1 }

@injectable() abstract class AbstractCls {
constructor(@inject(DepA) a: DepA, @inject(DepB) @optional() b: DepB = {b: 0}) {
injectedA = a;
injectedB = b;
}
}

@injectable() class Cls extends AbstractCls {
constructor(@inject(DepC) c: DepC, @inject(DepB) @optional() b: DepB = { b: 0 }, @inject(DepA) a: DepA) {
super(a, b);

injectedC = c;
}
}

const container = new Container();
[DepA, DepB, DepC, Cls].forEach(i => container.bind(i).toSelf().inSingletonScope());

container.get(Cls);

expect(injectedA).to.deep.eq(new DepA());
expect(injectedB).to.deep.eq(new DepB());
expect(injectedC).to.deep.eq(new DepC());
});
});
32 changes: 16 additions & 16 deletions test/node/exceptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,39 @@ describe("Node", () => {

it("Should throw if circular dependencies found", () => {

interface A {}
interface B {}
interface C {}
interface D {}
interface IA {}
interface IB {}
interface IC {}
interface ID {}

@injectable()
class A implements A {
public b: B;
public c: C;
class A implements IA {
public b: IB;
public c: IC;
public constructor(
@inject("B") b: B,
@inject("C") c: C
@inject("B") b: IB,
@inject("C") c: IC,
) {
this.b = b;
this.c = c;
}
}

@injectable()
class B implements B {}
class B implements IB {}

@injectable()
class C implements C {
public d: D;
public constructor(@inject("D") d: D) {
class C implements IC {
public d: ID;
public constructor(@inject("D") d: ID) {
this.d = d;
}
}

@injectable()
class D implements D {
public a: A;
public constructor(@inject("A") a: A) {
class D implements ID {
public a: IA;
public constructor(@inject("A") a: IA) {
this.a = a;
}
}
Expand Down
40 changes: 20 additions & 20 deletions test/planning/planner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,41 +120,41 @@ describe("Planner", () => {

it("Should throw when circular dependencies found", () => {

interface A { }
interface B { }
interface C { }
interface D { }
interface IA { }
interface IB { }
interface IC { }
interface ID { }

@injectable()
class D implements D {
public a: A;
class D implements ID {
public a: IA;
public constructor(
@inject("A") a: A
@inject("A") a: IA
) { // circular dependency
this.a = a;
}
}

@injectable()
class C implements C {
public d: D;
class C implements IC {
public d: ID;
public constructor(
@inject("D") d: D
@inject("D") d: ID
) {
this.d = d;
}
}

@injectable()
class B implements B { }
class B implements IB { }

@injectable()
class A implements A {
public b: B;
public c: C;
class A implements IA {
public b: IB;
public c: IC;
public constructor(
@inject("B") b: B,
@inject("C") c: C
@inject("B") b: IB,
@inject("C") c: IC
) {
this.b = b;
this.c = c;
Expand All @@ -167,10 +167,10 @@ describe("Planner", () => {
const dId = "D";

const container = new Container();
container.bind<A>(aId).to(A);
container.bind<B>(bId).to(B);
container.bind<C>(cId).to(C);
container.bind<D>(dId).to(D);
container.bind<IA>(aId).to(A);
container.bind<IB>(bId).to(B);
container.bind<IC>(cId).to(C);
container.bind<ID>(dId).to(D);

const throwErrorFunction = () => {
container.get(aId);
Expand Down