xtaskjs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +44 -0
- package/app.ts +7 -0
- package/babel.config.js +4 -0
- package/dist/packages/common/index.js +17 -0
- package/dist/packages/common/src/decorators/core/server/applicationrunner.js +11 -0
- package/dist/packages/common/src/decorators/core/server/commandlinerunner.js +11 -0
- package/dist/packages/common/src/decorators/core/server/constants.js +5 -0
- package/dist/packages/common/src/decorators/core/server/index.js +20 -0
- package/dist/packages/common/src/decorators/core/server/onevent.js +11 -0
- package/dist/packages/common/src/index.js +24 -0
- package/dist/packages/common/src/logger/index.js +17 -0
- package/dist/packages/common/src/logger/logger.js +40 -0
- package/dist/packages/common/src/types/eventhandlermeta.js +2 -0
- package/dist/packages/common/src/types/index.js +19 -0
- package/dist/packages/common/src/types/lifecycle-events.js +2 -0
- package/dist/packages/common/src/types/runnermeta.js +2 -0
- package/dist/packages/common/test/logger/logger.test.js +12 -0
- package/dist/packages/core/index.js +17 -0
- package/dist/packages/core/src/bootstrap.js +13 -0
- package/dist/packages/core/src/di/autowired.js +41 -0
- package/dist/packages/core/src/di/component.js +19 -0
- package/dist/packages/core/src/di/container.js +225 -0
- package/dist/packages/core/src/di/index.js +27 -0
- package/dist/packages/core/src/di/lifecycle.js +27 -0
- package/dist/packages/core/src/di/managedinstance.js +2 -0
- package/dist/packages/core/src/di/qualifier.js +26 -0
- package/dist/packages/core/src/di/stereotypes.js +10 -0
- package/dist/packages/core/src/index.js +21 -0
- package/dist/packages/core/src/kernel/index.js +18 -0
- package/dist/packages/core/src/kernel/kernel.js +26 -0
- package/dist/packages/core/src/kernel/kernellisteners.js +72 -0
- package/dist/packages/core/src/server/application-lifecycle.js +103 -0
- package/dist/packages/core/src/server/index.js +19 -0
- package/dist/packages/core/src/server/registereventhandlers.js +15 -0
- package/dist/packages/core/test/di/autowired.test.js +92 -0
- package/dist/packages/core/test/di/container.test.js +43 -0
- package/dist/packages/core/test/di/qualifier.test.js +71 -0
- package/dist/packages/core/test/logger/logger.test.js +12 -0
- package/dist/packages/core/test/server/applicationlifecycle.test.js +28 -0
- package/jest.config.js +9 -0
- package/package.json +36 -0
- package/packages/common/README.md +21 -0
- package/packages/common/babel.config.js +3 -0
- package/packages/common/index.ts +1 -0
- package/packages/common/jest.config.js +11 -0
- package/packages/common/package.json +50 -0
- package/packages/common/src/decorators/core/server/applicationrunner.ts +10 -0
- package/packages/common/src/decorators/core/server/commandlinerunner.ts +10 -0
- package/packages/common/src/decorators/core/server/constants.ts +2 -0
- package/packages/common/src/decorators/core/server/index.ts +4 -0
- package/packages/common/src/decorators/core/server/onevent.ts +10 -0
- package/packages/common/src/index.ts +5 -0
- package/packages/common/src/logger/index.ts +1 -0
- package/packages/common/src/logger/logger.ts +26 -0
- package/packages/common/src/types/eventhandlermeta.ts +7 -0
- package/packages/common/src/types/index.ts +3 -0
- package/packages/common/src/types/lifecycle-events.ts +10 -0
- package/packages/common/src/types/runnermeta.ts +5 -0
- package/packages/common/test/logger/logger.test.ts +11 -0
- package/packages/common/tsconfig.json +13 -0
- package/packages/core/README.md +21 -0
- package/packages/core/babel.config.js +3 -0
- package/packages/core/index.ts +1 -0
- package/packages/core/jest.config.js +15 -0
- package/packages/core/package.json +51 -0
- package/packages/core/src/bootstrap.ts +11 -0
- package/packages/core/src/di/autowired.ts +56 -0
- package/packages/core/src/di/component.ts +34 -0
- package/packages/core/src/di/container.ts +216 -0
- package/packages/core/src/di/index.ts +8 -0
- package/packages/core/src/di/lifecycle.ts +25 -0
- package/packages/core/src/di/managedinstance.ts +4 -0
- package/packages/core/src/di/qualifier.ts +25 -0
- package/packages/core/src/di/stereotypes.ts +10 -0
- package/packages/core/src/index.ts +5 -0
- package/packages/core/src/kernel/index.ts +2 -0
- package/packages/core/src/kernel/kernel.ts +31 -0
- package/packages/core/src/kernel/kernellisteners.ts +36 -0
- package/packages/core/src/server/application-lifecycle.ts +85 -0
- package/packages/core/src/server/index.ts +3 -0
- package/packages/core/src/server/registereventhandlers.ts +18 -0
- package/packages/core/test/di/autowired.test.ts +83 -0
- package/packages/core/test/di/container.test.ts +49 -0
- package/packages/core/test/di/qualifier.test.ts +60 -0
- package/packages/core/test/logger/logger.test.ts +11 -0
- package/packages/core/test/server/applicationlifecycle.test.ts +13 -0
- package/packages/core/tsconfig.json +19 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
|
|
3
|
+
const QUALIFIER_KEY = Symbol("xtaskjs:qualifier");
|
|
4
|
+
|
|
5
|
+
export function Qualifier(name: string) {
|
|
6
|
+
return function (target: any, propertyKey: string | symbol | undefined, parameterIndex?: number) {
|
|
7
|
+
if(parameterIndex !== undefined){
|
|
8
|
+
// Parameter decorator
|
|
9
|
+
const existingQualifiers = Reflect.getMetadata(QUALIFIER_KEY, target) || {};
|
|
10
|
+
existingQualifiers[parameterIndex] = name;
|
|
11
|
+
Reflect.defineMetadata(QUALIFIER_KEY, existingQualifiers, target);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getQualifier(target: any, propertyKey?: string | symbol): string | undefined {
|
|
17
|
+
if(propertyKey){
|
|
18
|
+
return Reflect.getMetadata(QUALIFIER_KEY, target, propertyKey);
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getConstructorQualifiers(target: any):Record<number,string>| undefined {
|
|
24
|
+
return Reflect.getMetadata(QUALIFIER_KEY, target);
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Component, ComponentOptions } from "./component";
|
|
2
|
+
|
|
3
|
+
export const Service = (options: Omit<ComponentOptions, "type"> = {}) =>
|
|
4
|
+
Component({ ...options, type: "service" });
|
|
5
|
+
|
|
6
|
+
export const Controller = (options: Omit<ComponentOptions, "type"> = {}) =>
|
|
7
|
+
Component({ ...options, type: "controller" });
|
|
8
|
+
|
|
9
|
+
export const Repository = (options: Omit<ComponentOptions, "type"> = {}) =>
|
|
10
|
+
Component({ ...options, type: "repository" });
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { Container } from "@xtaskjs/core";
|
|
3
|
+
import { Logger } from "@xtaskjs/common";
|
|
4
|
+
|
|
5
|
+
export class Kernel {
|
|
6
|
+
|
|
7
|
+
private container:Container;
|
|
8
|
+
private logger:Logger;
|
|
9
|
+
|
|
10
|
+
constructor(){
|
|
11
|
+
}
|
|
12
|
+
async boot(): Promise<void> {
|
|
13
|
+
// Bootstrapping logic here
|
|
14
|
+
this.container = new Container();
|
|
15
|
+
// Autoload components from the "packages" directory
|
|
16
|
+
await this.container.autoload("packages");
|
|
17
|
+
|
|
18
|
+
this.logger = await this.container.get(Logger);
|
|
19
|
+
// Simulate some async operation
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
21
|
+
this.logger.info("🚀 Kernel started successfully.");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async getContainer(): Promise<Container> {
|
|
25
|
+
return this.container;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { OnEvent , ApplicationRunner, CommandLineRunner } from "@xtaskjs/common";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// Clase que escucha eventos del ciclo de vida
|
|
6
|
+
export class KernelListeners {
|
|
7
|
+
@OnEvent("starting")
|
|
8
|
+
onStarting() {
|
|
9
|
+
console.log("[Lifecycle] Starting...");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@OnEvent("ready")
|
|
13
|
+
onReady() {
|
|
14
|
+
console.log("[Lifecycle] Application ready!");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@ApplicationRunner(5)
|
|
18
|
+
async afterStart() {
|
|
19
|
+
console.log("[Runner] ApplicationRunner ejecutado después de arrancar Kernel");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@CommandLineRunner(0)
|
|
23
|
+
async cli(args: string[]) {
|
|
24
|
+
console.log("[Runner] CommandLineRunner con args:", args);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@OnEvent("memoryReport")
|
|
28
|
+
memory(mem: NodeJS.MemoryUsage) {
|
|
29
|
+
console.log("[Metrics] Heap MB:", (mem.heapUsed / 1024 / 1024).toFixed(2));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@OnEvent("cpuReport")
|
|
33
|
+
cpu(calc: NodeJS.CpuUsage){
|
|
34
|
+
console.log("CPU", (calc));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { LifeCyclePhase } from "@xtaskjs/common";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import * as process from "process";
|
|
4
|
+
|
|
5
|
+
interface Listener{
|
|
6
|
+
fn: (...args: any[]) => any | Promise<any>;
|
|
7
|
+
priority:number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class ApplicationLifeCycle {
|
|
11
|
+
private listeners: Map<LifeCyclePhase, Listener[]> = new Map();
|
|
12
|
+
private metricsInterval?: NodeJS.Timeout;
|
|
13
|
+
private runners : { type: "ApplicationRunner" | "CommandLineRunner"; priority:number; fn:(args?:string[]) => any }[] = [];
|
|
14
|
+
|
|
15
|
+
constructor() {}
|
|
16
|
+
|
|
17
|
+
public on(event: LifeCyclePhase, Listener: (...args: any[]) => any | Promise<any>, priority = 0) {
|
|
18
|
+
const list = this.listeners.get(event) || [];
|
|
19
|
+
list.push({ fn: Listener, priority });
|
|
20
|
+
this.listeners.set(event, list.sort((a, b) => b.priority - a.priority));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public registerRunner(fn: (args?:string[]) => any, type: "ApplicationRunner" | "CommandLineRunner" = "ApplicationRunner", priority = 0) {
|
|
24
|
+
this.runners.push({ fn, type, priority});
|
|
25
|
+
this.runners.sort((a,b) => b.priority - a.priority);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public async emit(event: LifeCyclePhase, payload?:any) {
|
|
29
|
+
const list = this.listeners.get(event) || [];
|
|
30
|
+
for (const { fn, priority } of list) {
|
|
31
|
+
try {
|
|
32
|
+
await Promise.resolve(fn(payload));
|
|
33
|
+
} catch(error) {
|
|
34
|
+
console.error(`Error in lifecycle handler for phase ${event} (priority ${priority}):`, error);
|
|
35
|
+
if (event !="error"){
|
|
36
|
+
await this.emit("error", error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async runRunners(type: "ApplicationRunner" | "CommandLineRunner") {
|
|
43
|
+
for (const runner of this.runners.filter(r => r.type === type)) {
|
|
44
|
+
await Promise.resolve(runner.fn(process.argv.slice(2)));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async boot(startFn: () => Promise<void>) {
|
|
49
|
+
try{
|
|
50
|
+
await this.emit("starting");
|
|
51
|
+
await this.emit("environmentPrepared", { env: process.env, args: process.argv });
|
|
52
|
+
await this.emit("contextPrepared");
|
|
53
|
+
|
|
54
|
+
await this.emit("serverStarting");
|
|
55
|
+
|
|
56
|
+
await startFn();
|
|
57
|
+
|
|
58
|
+
await this.emit("serverStarted");
|
|
59
|
+
|
|
60
|
+
this.metricsInterval = setInterval(async() => {
|
|
61
|
+
await this.emit("memoryReport", process.memoryUsage());
|
|
62
|
+
await this.emit("cpuReport",{
|
|
63
|
+
loadavg:os.loadavg(),
|
|
64
|
+
usage: process.cpuUsage()
|
|
65
|
+
});
|
|
66
|
+
}, 5000); //every minute
|
|
67
|
+
|
|
68
|
+
await this.runRunners("ApplicationRunner");
|
|
69
|
+
await this.emit("ready");
|
|
70
|
+
await this.runRunners("CommandLineRunner");
|
|
71
|
+
} catch (error){
|
|
72
|
+
await this.emit("error", error);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public async stop() {
|
|
79
|
+
if(this.metricsInterval){
|
|
80
|
+
clearInterval(this.metricsInterval);
|
|
81
|
+
this.metricsInterval = undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { ApplicationLifeCycle } from "./application-lifecycle";
|
|
3
|
+
import { EventHandlerMeta } from "@xtaskjs/common";
|
|
4
|
+
import { RunnerMeta } from "../../../common/src/types/runnermeta";
|
|
5
|
+
import { HANDLERS_KEY, RUNNERS_KEY } from "@xtaskjs/common";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export function registerEventHandlers(instance: any, app:ApplicationLifeCycle) {
|
|
9
|
+
const handlers: EventHandlerMeta[] = Reflect.getMetadata(HANDLERS_KEY, instance.constructor) || [];
|
|
10
|
+
for (const { phase, method, priority } of handlers.sort((a, b) => b.priority - a.priority)) {
|
|
11
|
+
app.on(phase, async (...args) => (instance as any)[method](...args), priority);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const runners: RunnerMeta[] = Reflect.getMetadata(RUNNERS_KEY, instance.constructor) || [];
|
|
15
|
+
for (const { type, method, priority } of runners.sort((a, b) => b.priority - a.priority)) {
|
|
16
|
+
app.registerRunner((args) => (instance as any)[method](...args), type, priority);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Container, Service, AutoWired } from "../../src/di/index";
|
|
2
|
+
|
|
3
|
+
@Service()
|
|
4
|
+
class Logger {
|
|
5
|
+
log(message: string):string {
|
|
6
|
+
return `Log: ${message}`;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@Service()
|
|
11
|
+
class Database {
|
|
12
|
+
query(sql: string):string {
|
|
13
|
+
return `Result of "${sql}"`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@Service()
|
|
18
|
+
class UserService {
|
|
19
|
+
@AutoWired()
|
|
20
|
+
logger!: Logger;
|
|
21
|
+
|
|
22
|
+
@AutoWired()
|
|
23
|
+
database!: Database;
|
|
24
|
+
|
|
25
|
+
getUser(id: number):string {
|
|
26
|
+
this.logger.log(`Fetching user with id: ${id}`);
|
|
27
|
+
return this.database.query(`SELECT * FROM users WHERE id = ${id}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Service()
|
|
32
|
+
class OptionalDependencyService {
|
|
33
|
+
@AutoWired({ required: false })
|
|
34
|
+
optionalLogger?: Logger;
|
|
35
|
+
|
|
36
|
+
hasLogger(): boolean {
|
|
37
|
+
return this.optionalLogger !==undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe("AutoWired Decorator", () => {
|
|
42
|
+
let container:Container;
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
container = new Container();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should inject dependencies into UserService", () => {
|
|
49
|
+
container.register(Logger, { scope: "singleton" });
|
|
50
|
+
container.register(Database, { scope: "singleton" });
|
|
51
|
+
container.register(UserService, { scope: "singleton" });
|
|
52
|
+
|
|
53
|
+
const userService = container.get(UserService);
|
|
54
|
+
expect(userService).toBeInstanceOf(UserService);
|
|
55
|
+
// expect(userService.getUser(1)).toBe('Result of "SELECT * FROM users WHERE id = 1"');
|
|
56
|
+
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should handle optional dependencies", () => {
|
|
60
|
+
container.register(OptionalDependencyService, { scope: "singleton" });
|
|
61
|
+
|
|
62
|
+
const optionalService = container.get(OptionalDependencyService);
|
|
63
|
+
expect(optionalService).toBeInstanceOf(OptionalDependencyService);
|
|
64
|
+
expect(optionalService.hasLogger()).toBe(false); // Logger is not registered, should be undefined
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should throw error for missing required dependencies", () => {
|
|
68
|
+
container.register(UserService, { scope: "singleton" });
|
|
69
|
+
|
|
70
|
+
expect(() => container.get(UserService)).toThrow();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should inject dependencies into constructor and field dependencies", () => {
|
|
74
|
+
container.register(Logger, { scope: "singleton" });
|
|
75
|
+
container.register(Database, { scope: "singleton" });
|
|
76
|
+
container.register(UserService, { scope: "singleton" });
|
|
77
|
+
|
|
78
|
+
const userService = container.get(UserService);
|
|
79
|
+
expect(userService).toBeDefined();
|
|
80
|
+
expect(userService.getUser(1)).toBeDefined();
|
|
81
|
+
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Container, Service, AutoWired } from "../../src/di/index";
|
|
2
|
+
|
|
3
|
+
@Service()
|
|
4
|
+
class TestService{
|
|
5
|
+
getValue():number {
|
|
6
|
+
return 42;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
describe("Container", () => {
|
|
13
|
+
let container : Container
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
container = new Container();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should register and resolve a singleton service", () => {
|
|
20
|
+
container.register(TestService, { scope: "singleton" });
|
|
21
|
+
const resolved = container.get(TestService);
|
|
22
|
+
expect(resolved.getValue()).toBe(42);
|
|
23
|
+
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should return singleton instances y default ", () => {
|
|
27
|
+
container.register(TestService, { scope: "singleton" });
|
|
28
|
+
|
|
29
|
+
const instance1 = container.get(TestService);
|
|
30
|
+
|
|
31
|
+
const instance2 = container.get(TestService);
|
|
32
|
+
|
|
33
|
+
expect(instance1).toBe(instance2); // Same instance
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should return new instances for transient scope", () => {
|
|
37
|
+
container.register(TestService, { scope: "transient" });
|
|
38
|
+
|
|
39
|
+
const instance1 = container.get(TestService);
|
|
40
|
+
|
|
41
|
+
const instance2 = container.get(TestService);
|
|
42
|
+
|
|
43
|
+
expect(instance1).not.toBe(instance2); // Different instances
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it ("should throw error for unregistered services", () =>{
|
|
47
|
+
expect(() => container.get(TestService)).toThrow("No provider found for TestService");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Container, Service, AutoWired, Qualifier } from "../../src/di/index";
|
|
2
|
+
|
|
3
|
+
interface INotificiationService{
|
|
4
|
+
send(message:string):string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@Service({name: "emailNotificer"})
|
|
8
|
+
class EmailNotificationService implements INotificiationService{
|
|
9
|
+
send(message: string):string {
|
|
10
|
+
return `Email sent: ${message}`;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Service({name: "smsNotificer"})
|
|
15
|
+
class SMSNotificationService implements INotificiationService{
|
|
16
|
+
send(message: string):string {
|
|
17
|
+
return `SMS sent: ${message}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Service()
|
|
22
|
+
class OrderService {
|
|
23
|
+
constructor(
|
|
24
|
+
@Qualifier("emailNotificer") public emailService: INotificiationService,
|
|
25
|
+
@Qualifier("smsNotificer") public smsService: INotificiationService
|
|
26
|
+
){}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe ("Qualifier Decorator", () => {
|
|
30
|
+
let container:Container;
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
container = new Container();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should inject beans by qualifier name", () => {
|
|
37
|
+
container.registerWithName(EmailNotificationService,{ scope: "singleton"}, "emailNotificer");
|
|
38
|
+
container.registerWithName(SMSNotificationService,{ scope: "singleton"}, "smsNotificer");
|
|
39
|
+
container.register(OrderService, { scope: "singleton" });
|
|
40
|
+
|
|
41
|
+
const orderService = container.get(OrderService);
|
|
42
|
+
expect(orderService).toBeInstanceOf(OrderService);
|
|
43
|
+
expect(orderService['emailService']).toBeInstanceOf(EmailNotificationService);
|
|
44
|
+
expect(orderService['smsService']).toBeInstanceOf(SMSNotificationService);
|
|
45
|
+
expect(orderService.emailService.send("Hello")).toBe("Email sent: Hello");
|
|
46
|
+
expect(orderService.smsService.send("Hello")).toBe("SMS sent: Hello");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it ("should retrieve beans by name from container", () =>{
|
|
50
|
+
container.registerWithName(EmailNotificationService,{ scope: "singleton"}, "emailNotificer");
|
|
51
|
+
|
|
52
|
+
const notifier = container.getByName<EmailNotificationService>("emailNotificer");
|
|
53
|
+
expect(notifier).toBeInstanceOf(EmailNotificationService);
|
|
54
|
+
expect(notifier.send("Test")).toBe("Email sent: Test");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it ("should throw error for unknown qualifier names", () =>{
|
|
58
|
+
expect(() => container.getByName("unknownService")).toThrow("No component found with name: unknownService");
|
|
59
|
+
});
|
|
60
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Logger } from "@xtaskjs/common";
|
|
2
|
+
|
|
3
|
+
describe("Logger", ()=> {
|
|
4
|
+
it ("Should print logs", () =>{
|
|
5
|
+
const logger = new Logger();
|
|
6
|
+
const spy = jest.spyOn(console, "log").mockImplementation();
|
|
7
|
+
logger.info("hello");
|
|
8
|
+
expect(spy).toHaveBeenCalledWith(expect.stringContaining("hello"));
|
|
9
|
+
spy.mockRestore();
|
|
10
|
+
})
|
|
11
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { OnEvent } from "@xtaskjs/common";
|
|
2
|
+
import { Service } from "packages/core/src";
|
|
3
|
+
|
|
4
|
+
@Service()
|
|
5
|
+
class TestLifeCycleListener {
|
|
6
|
+
public events: string []=[];
|
|
7
|
+
|
|
8
|
+
@OnEvent('starting', 10)
|
|
9
|
+
async onStarting(){
|
|
10
|
+
this.events.push("starting");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2021",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"emitDecoratorMetadata": true,
|
|
10
|
+
"baseUrl": ".",
|
|
11
|
+
"paths":{
|
|
12
|
+
"@xtaskjs/common": ["../../dist/packages/common"],
|
|
13
|
+
"@xtaskjs/common/*": ["../../dist/packages/common/*"]
|
|
14
|
+
},
|
|
15
|
+
"declaration": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["packages/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"rootDir": "./",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"emitDecoratorMetadata": true,
|
|
10
|
+
"baseUrl": "./",
|
|
11
|
+
"paths": {
|
|
12
|
+
"@xtaskjs/common": ["packages/common"],
|
|
13
|
+
"@xtaskjs/core": ["packages/core"]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"include": ["packages/**/*","packages/**/**/*","packages/**/**/**/*"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|