Skip to content

Commit

Permalink
Circular service params (#113)
Browse files Browse the repository at this point in the history
  • Loading branch information
zoe-codez authored Nov 11, 2024
1 parent 172feb9 commit e7391d3
Show file tree
Hide file tree
Showing 16 changed files with 450 additions and 314 deletions.
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,40 +54,40 @@
"js-yaml": "^4.1.0",
"minimist": "^1.2.8",
"node-cron": "^3.0.3",
"uuid": "^11.0.2"
"uuid": "^11.0.3"
},
"devDependencies": {
"@cspell/eslint-plugin": "^8.15.4",
"@cspell/eslint-plugin": "^8.16.0",
"@eslint/compat": "^1.2.2",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.13.0",
"@faker-js/faker": "^9.1.0",
"@eslint/js": "^9.14.0",
"@faker-js/faker": "^9.2.0",
"@jest/globals": "^29.7.0",
"@types/dotenv": "^8.2.3",
"@types/ini": "^4.1.1",
"@types/jest": "^29.5.14",
"@types/js-yaml": "^4.0.9",
"@types/minimist": "^1.2.5",
"@types/node": "^22.8.1",
"@types/node": "^22.9.0",
"@types/node-cron": "^3.0.11",
"@types/sinonjs__fake-timers": "^8.1.5",
"@typescript-eslint/eslint-plugin": "8.12.0",
"@typescript-eslint/parser": "8.12.0",
"@typescript-eslint/eslint-plugin": "8.13.0",
"@typescript-eslint/parser": "8.13.0",
"chalk": "^5.3.0",
"dayjs": "^1.11.13",
"dotenv": "^16.4.5",
"eslint": "9.13.0",
"eslint": "9.14.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsonc": "^2.16.0",
"eslint-plugin-jsonc": "^2.18.1",
"eslint-plugin-no-unsanitized": "^4.1.2",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-security": "^3.0.1",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-sonarjs": "^2.0.4",
"eslint-plugin-sort-keys-fix": "^1.1.2",
"eslint-plugin-unicorn": "^56.0.0",
"globals": "^15.11.0",
"globals": "^15.12.0",
"ini": "^5.0.0",
"jest": "^29.7.0",
"jest-environment-node": "^29.7.0",
Expand All @@ -96,11 +96,11 @@
"node-cron": "^3.0.3",
"prettier": "^3.3.3",
"ts-jest": "^29.2.5",
"tslib": "^2.8.0",
"tslib": "^2.8.1",
"tsx": "^4.19.2",
"type-fest": "^4.26.1",
"typescript": "^5.6.3",
"uuid": "^11.0.2"
"uuid": "^11.0.3"
},
"jest": {
"extensionsToTreatAsEsm": [
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/extend.helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { is } from "../services/is.extension";
import { is } from "../services/is.service";

function isSpecificValue(value: unknown) {
return value instanceof Date || value instanceof RegExp;
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/utilities.helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { is } from "../services/is.extension";
import { is } from "../services/is.service";

/* eslint-disable @typescript-eslint/no-magic-numbers */
export const EVEN = 2;
Expand Down
6 changes: 6 additions & 0 deletions src/helpers/wiring.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ export type TServiceParams = {
* make sure to use with/after the `onPostConfig` lifecycle event in order to receive user configuration values
*/
config: TInjectedConfig;
/**
* reference to self
*
* useful if you want to pass the entire block of params into something deeper
*/
params: TServiceParams;
} & {
[K in ExternalLoadedModules]: GetApis<LoadedModules[K]>;
};
Expand Down
File renamed without changes.
File renamed without changes.
14 changes: 7 additions & 7 deletions src/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from "./als.extension";
export * from "./configuration.extension";
export * from "./internal.extension";
export * from "./is.extension";
export * from "./logger.extension";
export * from "./scheduler.extension";
export * from "./wiring.extension";
export * from "./als.service";
export * from "./configuration.service";
export * from "./internal.service";
export * from "./is.service";
export * from "./logger.service";
export * from "./scheduler.service";
export * from "./wiring.service";
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ import {
TResolvedModuleMappings,
YEAR,
} from "..";
import { CreateLifecycle } from "./lifecycle.extension";
import { CreateLifecycle } from "./lifecycle.service";

const EVERYTHING_ELSE = 1;
const MONTHS = 12;

type inputFormats = Date | string | number | Dayjs;
export type RemoveCallback = { remove: () => void; (): void };

// TODO: probably should make this configurable
const formatter = new Intl.RelativeTimeFormat("en", {
Expand Down Expand Up @@ -240,6 +241,23 @@ export class InternalDefinition {
};
public utils = new InternalUtils();

/**
*
* ```typescript
* // Is it
* const remove = doThing();
* // or
* const { remove } = doThing();
* ```
*
* Now it's both! Inconsistency is the now supported
*/
public removeFn(remove: () => TBlackHole): RemoveCallback {
const out = remove as RemoveCallback;
out.remove = remove;
return out;
}

// #MARK: safeExec
public async safeExec<T>(options: (() => TBlackHole) | SafeExecOptions): Promise<T> {
const logger = this.boilerplate.logger.systemLogger;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
TLifecycleBase,
UP,
} from "../helpers";
import { is } from "./is.extension";
import { is } from "./is.service";

type EventMapObject = {
callback: LifecycleCallback;
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ import {
INITIALIZE,
INJECTED_DEFINITIONS,
LOAD_PROJECT,
} from "./configuration.extension";
import { CreateLifecycle } from "./lifecycle.extension";
import { Logger } from "./logger.extension";
import { Scheduler } from "./scheduler.extension";
} from "./configuration.service";
import { CreateLifecycle } from "./lifecycle.service";
import { Logger } from "./logger.service";
import { Scheduler } from "./scheduler.service";

export interface DeclaredEnvironments {
prod: true;
Expand Down Expand Up @@ -329,7 +329,7 @@ async function wireService(
]),
);

loaded[service] = (await definition({
const serviceParams = {
...inject,
als: boilerplate.als,
config: boilerplate?.configuration?.[INJECTED_DEFINITIONS],
Expand All @@ -339,7 +339,10 @@ async function wireService(
lifecycle,
logger,
scheduler: boilerplate?.scheduler?.(context),
})) as TServiceReturn;
} as TServiceParams;
serviceParams.params = serviceParams;

loaded[service] = (await definition(serviceParams)) as TServiceReturn;

return loaded[service];
} catch (error) {
Expand Down
57 changes: 52 additions & 5 deletions testing/internal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { BootstrapOptions, CreateApplication, TestRunner } from "../src";
import {
BootstrapOptions,
CreateApplication,
InternalDefinition,
TBlackHole,
TestRunner,
} from "../src";

export const BASIC_BOOT = {
configuration: { boilerplate: { LOG_LEVEL: "silent" } },
Expand All @@ -11,10 +17,10 @@ export const BASIC_BOOT = {

describe("Fetch Extension", () => {
beforeAll(async () => {
jest.spyOn(global.console, "error").mockImplementation(() => {});
jest.spyOn(global.console, "warn").mockImplementation(() => {});
jest.spyOn(global.console, "debug").mockImplementation(() => {});
jest.spyOn(global.console, "log").mockImplementation(() => {});
jest.spyOn(globalThis.console, "error").mockImplementation(() => {});
jest.spyOn(globalThis.console, "warn").mockImplementation(() => {});
jest.spyOn(globalThis.console, "debug").mockImplementation(() => {});
jest.spyOn(globalThis.console, "log").mockImplementation(() => {});
const preload = CreateApplication({
// @ts-expect-error testing
name: "testing",
Expand All @@ -27,6 +33,47 @@ describe("Fetch Extension", () => {
jest.restoreAllMocks();
});

describe("removeFn", () => {
const internal = new InternalDefinition();

it("should return a function with a remove property", () => {
const mockRemove: () => TBlackHole = jest.fn(() => ({}) as TBlackHole);
const result = internal.removeFn(mockRemove);

expect(typeof result).toBe("function");
expect(result.remove).toBe(mockRemove);
});

it("should correctly call the remove function", () => {
const mockRemove: () => TBlackHole = jest.fn(() => ({}) as TBlackHole);
const result = internal.removeFn(mockRemove);

result(); // Call the function
expect(mockRemove).toHaveBeenCalledTimes(1);
});

it("should allow calling remove via the returned function", () => {
const mockRemove: () => TBlackHole = jest.fn(() => ({}) as TBlackHole);
const result = internal.removeFn(mockRemove);

result.remove!(); // Call remove
expect(mockRemove).toHaveBeenCalledTimes(1);
});

it("should support both destructured and non-destructured usage", () => {
const mockRemove: () => TBlackHole = jest.fn(() => ({}) as TBlackHole);
// Destructured case
const { remove } = internal.removeFn(mockRemove);
remove!(); // Call remove
expect(mockRemove).toHaveBeenCalledTimes(1);

// Non-destructured case
const result = internal.removeFn(mockRemove);
result(); // Call the function
expect(mockRemove).toHaveBeenCalledTimes(2); // Called once more
});
});

describe("relativeDate", () => {
describe("relativeDate", () => {
it("should return the correct relative time for a valid past date", async () => {
Expand Down
19 changes: 13 additions & 6 deletions testing/wiring.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ describe("Wiring", () => {
it("should exit if service constructor throws error", async () => {
expect.assertions(1);
const spy = jest.spyOn(process, "exit").mockImplementation(() => undefined as never);
jest.spyOn(global.console, "error").mockImplementation(() => undefined);
jest.spyOn(globalThis.console, "error").mockImplementation(() => undefined);

await TestRunner().run(() => {
throw new Error("boom");
Expand Down Expand Up @@ -743,7 +743,7 @@ describe("Wiring", () => {

it("shouldn't process double teardown", async () => {
expect.assertions(1);
const spy = jest.spyOn(global.console, "error").mockImplementation(() => undefined);
const spy = jest.spyOn(globalThis.console, "error").mockImplementation(() => undefined);
const app = await TestRunner().run(({ lifecycle }) => {
lifecycle.onPreShutdown(() => {
throw new Error("test");
Expand Down Expand Up @@ -834,6 +834,13 @@ describe("Wiring", () => {

// #MARK: Wiring
describe("Wiring", () => {
it("has recursive service params", async () => {
expect.assertions(2);
await TestRunner().run(({ params }) => {
expect(params).toBeDefined();
expect(params.params).toBe(params);
});
});
it("should allow 2 separate apps to boot", async () => {
expect.assertions(1);
await expect(async () => {
Expand Down Expand Up @@ -1100,10 +1107,10 @@ describe("Wiring", () => {
const other_a = CreateLibrary({ name: "A", services: {} });

let hit = false;
jest.spyOn(global.console, "log").mockImplementation(() => {});
jest.spyOn(global.console, "error").mockImplementation(() => {});
jest.spyOn(global.console, "debug").mockImplementation(() => {});
jest.spyOn(global.console, "warn").mockImplementation((text: string) => {
jest.spyOn(globalThis.console, "log").mockImplementation(() => {});
jest.spyOn(globalThis.console, "error").mockImplementation(() => {});
jest.spyOn(globalThis.console, "debug").mockImplementation(() => {});
jest.spyOn(globalThis.console, "warn").mockImplementation((text: string) => {
hit ||= text?.includes("depends different version");
});
const customLogger = createMockLogger();
Expand Down
Loading

0 comments on commit e7391d3

Please sign in to comment.