Skip to content

Commit 9bc9739

Browse files
committed
refactor: reach the process-wide injector through getInjector()
Internal code no longer reads global.$injector: the two cycle-bound sites (the deprecation tracer's logger fallback and @hook's last-resort lookup) go through a getInjector() accessor required at call time. The global property remains write-only from the CLI's side - it exists as the published surface for extensions and hooks.
1 parent 55a507e commit 9bc9739

5 files changed

Lines changed: 37 additions & 27 deletions

File tree

lib/common/deprecation.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,13 @@ function getDeprecationStage(): DeprecationStage {
8080

8181
function tryResolveGlobalLogger(): IDeprecationLogger | null {
8282
try {
83-
const globalInjector = (<any>global).$injector;
84-
if (!globalInjector) {
83+
// Required at call time: yok imports this module, so a static import
84+
// would be a cycle. Every reporting site already runs with yok loaded.
85+
const injector = require("./yok").getInjector();
86+
if (!injector) {
8587
return null;
8688
}
87-
return globalInjector.resolve("logger");
89+
return injector.resolve("logger");
8890
} catch (err) {
8991
return null;
9092
}

lib/common/helpers.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,10 +567,11 @@ export function hook(commandName: string) {
567567
function getHooksService(self: any): IHooksService {
568568
let hooksService: IHooksService = self.$hooksService;
569569
if (!hooksService) {
570-
// The global injector must stay the LAST resort: tests stub
570+
// The process-wide injector must stay the LAST resort: tests stub
571571
// self.$hooksService / self.$injector, and a class migrated off
572-
// property injection has neither — only then may the global be used.
573-
const injector = self.$injector || (<any>global).$injector;
572+
// property injection has neither — only then may it be used. It is
573+
// required at call time because yok imports this module (cycle).
574+
const injector = self.$injector || require("./yok").getInjector();
574575
if (!injector) {
575576
throw Error(
576577
"Type with hooks needs to have either $hooksService or $injector injected.",

lib/common/yok.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,17 @@ if (!(<any>global).$injector) {
589589
injector = (<any>global).$injector;
590590
}
591591

592+
/**
593+
* Accessor for the process-wide facade, for code that cannot receive the
594+
* injector through DI or a static import (import cycles, decorator bodies).
595+
* Prefer inject(Injector) in an injection context; prefer a constructor
596+
* dependency in services. Never read global.$injector directly — the global
597+
* exists only as the published legacy surface for extensions and hooks.
598+
*/
599+
export function getInjector(): IInjector {
600+
return injector;
601+
}
602+
592603
/**
593604
* @deprecated Global-singleton wiring for the legacy facade; new code receives
594605
* the container via inject(Injector) instead of a process-wide global.

test/compat/legacy-hooks.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { assert } from "chai";
22
import * as fs from "fs";
33
import * as os from "os";
44
import * as path from "path";
5-
import { Yok } from "../../lib/common/yok";
5+
import { Yok, getInjector, setGlobalInjector } from "../../lib/common/yok";
66
import { HooksService } from "../../lib/common/services/hooks-service";
77
import { hook } from "../../lib/common/helpers";
88
import { IInjector } from "../../lib/common/definitions/yok";
@@ -301,15 +301,14 @@ describe("legacy hook contract", () => {
301301
}
302302
}
303303

304-
const globalAny = <any>global;
305-
const previousInjector = globalAny.$injector;
306-
globalAny.$injector = testInjector;
304+
const previousInjector = getInjector();
305+
setGlobalInjector(testInjector);
307306
try {
308307
const result = await new Subject().doWork();
309308
assert.equal(result, "ok");
310309
assert.isTrue(capture.ran);
311310
} finally {
312-
globalAny.$injector = previousInjector;
311+
setGlobalInjector(previousInjector);
313312
}
314313
});
315314

@@ -329,19 +328,18 @@ describe("legacy hook contract", () => {
329328
}
330329
}
331330

332-
const globalAny = <any>global;
333-
const previousInjector = globalAny.$injector;
334-
globalAny.$injector = {
331+
const previousInjector = getInjector();
332+
setGlobalInjector(<any>{
335333
resolve: () => {
336-
throw new Error("global injector must be the last resort");
334+
throw new Error("the process-wide injector must be the last resort");
337335
},
338-
};
336+
});
339337
try {
340338
const result = await new Subject().doWork();
341339
assert.equal(result, "ok");
342340
assert.isTrue(capture.ran);
343341
} finally {
344-
globalAny.$injector = previousInjector;
342+
setGlobalInjector(previousInjector);
345343
}
346344
});
347345
});

test/deprecation.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { assert } from "chai";
2-
import { Yok } from "../lib/common/yok";
2+
import { Yok, getInjector, setGlobalInjector } from "../lib/common/yok";
33
import {
44
reportDeprecation,
55
clearReportedDeprecations,
@@ -59,31 +59,29 @@ describe("deprecation tracer", () => {
5959
);
6060
});
6161

62-
it("falls back to the global injector's logger when none is passed", () => {
63-
const globalAny = <any>global;
64-
const previousInjector = globalAny.$injector;
62+
it("falls back to the process-wide injector's logger when none is passed", () => {
63+
const previousInjector = getInjector();
6564
const freshInjector = new Yok();
6665
const freshLogger = new LoggerStub();
6766
freshInjector.register("logger", freshLogger);
68-
globalAny.$injector = freshInjector;
67+
setGlobalInjector(freshInjector);
6968

7069
try {
7170
reportDeprecation({ api: "test.global-logger" });
7271
assert.include(freshLogger.traceOutput, "test.global-logger");
7372
} finally {
74-
globalAny.$injector = previousInjector;
73+
setGlobalInjector(previousInjector);
7574
}
7675
});
7776

7877
it("drops the report silently when no logger is resolvable", () => {
79-
const globalAny = <any>global;
80-
const previousInjector = globalAny.$injector;
81-
globalAny.$injector = undefined;
78+
const previousInjector = getInjector();
79+
setGlobalInjector(new Yok());
8280

8381
try {
8482
assert.doesNotThrow(() => reportDeprecation({ api: "test.no-logger" }));
8583
} finally {
86-
globalAny.$injector = previousInjector;
84+
setGlobalInjector(previousInjector);
8785
}
8886
});
8987
});

0 commit comments

Comments
 (0)