diff --git a/src/helpers/config-file-loader.mts b/src/helpers/config-file-loader.mts index d6c242d..b509c02 100644 --- a/src/helpers/config-file-loader.mts +++ b/src/helpers/config-file-loader.mts @@ -45,9 +45,10 @@ export function configFilePaths(name: string): string[] { export async function configLoaderFile< S extends ServiceMap = ServiceMap, C extends ModuleConfiguration = ModuleConfiguration, ->({ application, logger }: ConfigLoaderParams): ConfigLoaderReturn { +>({ application, logger, internal }: ConfigLoaderParams): ConfigLoaderReturn { const CLI_SWITCHES = minimist(process.argv); - const configFile = CLI_SWITCHES.config; + const configFile = + CLI_SWITCHES.config ?? internal?.boot?.options?.configuration?.boilerplate?.CONFIG; let files: string[]; if (is.boolean(configFile)) { logger.fatal({ argv: process.argv }, "system failed to parse argv"); diff --git a/src/services/wiring.service.mts b/src/services/wiring.service.mts index 593d9b2..838976f 100644 --- a/src/services/wiring.service.mts +++ b/src/services/wiring.service.mts @@ -62,7 +62,7 @@ function createBoilerplate() { return CreateLibrary({ configuration: { /** - * Only usable by **cli switch**. + * Only usable by **cli switch** / application bootstrap. * Pass path to a config file for loader * * ```bash diff --git a/testing/configuration.spec.mts b/testing/configuration.spec.mts index a1332a2..004547d 100644 --- a/testing/configuration.spec.mts +++ b/testing/configuration.spec.mts @@ -884,6 +884,87 @@ describe("Configuration", () => { expect(readSpy).toHaveBeenCalledWith("./config_file", "utf8"); }); + + it("uses bootstrap-provided CONFIG when no CLI switch", async () => { + vi.spyOn(fs, "existsSync").mockImplementation(() => true); + + const readSpy = vi.spyOn(fs, "readFileSync").mockImplementation(() => ``); + const logger = createMockLogger(); + process.argv = [""]; + await configLoaderFile({ + // @ts-expect-error not needed for test + application: {}, + internal: { + boot: { + options: { + configuration: { + boilerplate: { + CONFIG: "./bootstrap_config.yaml", + }, + }, + }, + }, + } as InternalDefinition, + logger, + }); + + expect(readSpy).toHaveBeenCalledWith("./bootstrap_config.yaml", "utf8"); + }); + + it("CLI switch takes precedence over bootstrap-provided CONFIG", async () => { + vi.spyOn(fs, "existsSync").mockImplementation(() => true); + + const readSpy = vi.spyOn(fs, "readFileSync").mockImplementation(() => ``); + const logger = createMockLogger(); + process.argv = ["", "--config=./cli_config.yaml"]; + await configLoaderFile({ + // @ts-expect-error not needed for test + application: {}, + internal: { + boot: { + options: { + configuration: { + boilerplate: { + CONFIG: "./bootstrap_config.yaml", + }, + }, + }, + }, + } as InternalDefinition, + logger, + }); + + expect(readSpy).toHaveBeenCalledWith("./cli_config.yaml", "utf8"); + }); + + it("bootstrap CONFIG overrides auto-discovery", async () => { + vi.spyOn(fs, "existsSync").mockImplementation(() => true); + // @ts-expect-error rest isn't needed + vi.spyOn(fs, "statSync").mockImplementation(() => ({ isFile: () => true })); + + const readSpy = vi.spyOn(fs, "readFileSync").mockImplementation(() => ``); + const logger = createMockLogger(); + process.argv = [""]; + await configLoaderFile({ + // @ts-expect-error not needed for test + application: { name: "test-app" }, + internal: { + boot: { + options: { + configuration: { + boilerplate: { + CONFIG: "./explicit_config.yaml", + }, + }, + }, + }, + } as InternalDefinition, + logger, + }); + + expect(readSpy).toHaveBeenCalledWith("./explicit_config.yaml", "utf8"); + expect(readSpy).not.toHaveBeenCalledWith(expect.stringContaining(".test-app"), "utf8"); + }); }); // #MARK: loadConfigFromFile