chore: Update the types for autoconfig

This commit is contained in:
BluJ
2023-04-24 13:24:57 -06:00
parent 0e3bf38ed4
commit 0be8d9d5bc
6 changed files with 49 additions and 31 deletions

View File

@@ -1,30 +1,36 @@
import { AutoConfigure, Effects, ExpectedExports } from "../types"; import { AutoConfigure, Effects, ExpectedExports } from "../types";
import { deepEqual, deepMerge } from "../util"; import { Utils, deepEqual, deepMerge, utils } from "../util";
export type AutoConfigFrom = { export type AutoConfigFrom<WD, Input> = {
[key: string]: (options: { [key: string]: (options: {
effects: Effects; effects: Effects;
localConfig: unknown; localConfig: Input;
remoteConfig: unknown; remoteConfig: unknown;
utils: Utils<WD>;
}) => Promise<void | Record<string, unknown>>; }) => Promise<void | Record<string, unknown>>;
}; };
export class AutoConfig { export class AutoConfig<WD, Input> {
constructor( constructor(
readonly configs: AutoConfigFrom, readonly configs: AutoConfigFrom<WD, Input>,
readonly path: keyof AutoConfigFrom, readonly path: keyof AutoConfigFrom<WD, Input>,
) {} ) {}
async check( async check(
options: Parameters<AutoConfigure["check"]>[0], options: Parameters<AutoConfigure["check"]>[0],
): ReturnType<AutoConfigure["check"]> { ): ReturnType<AutoConfigure["check"]> {
const origConfig = JSON.parse(JSON.stringify(options.localConfig)); const origConfig = JSON.parse(JSON.stringify(options.localConfig));
const newOptions = {
...options,
utils: utils<WD>(options.effects),
localConfig: options.localConfig as Input,
};
if ( if (
!deepEqual( !deepEqual(
origConfig, origConfig,
deepMerge( deepMerge(
{}, {},
options.localConfig, options.localConfig,
await this.configs[this.path](options), await this.configs[this.path](newOptions),
), ),
) )
) )
@@ -33,10 +39,15 @@ export class AutoConfig {
async autoConfigure( async autoConfigure(
options: Parameters<AutoConfigure["autoConfigure"]>[0], options: Parameters<AutoConfigure["autoConfigure"]>[0],
): ReturnType<AutoConfigure["autoConfigure"]> { ): ReturnType<AutoConfigure["autoConfigure"]> {
const newOptions = {
...options,
utils: utils<WD>(options.effects),
localConfig: options.localConfig as Input,
};
return deepMerge( return deepMerge(
{}, {},
options.localConfig, options.localConfig,
await this.configs[this.path](options), await this.configs[this.path](newOptions),
); );
} }
} }

View File

@@ -1,9 +1,12 @@
import { AutoConfig, AutoConfigFrom } from "./AutoConfig"; import { AutoConfig, AutoConfigFrom } from "./AutoConfig";
export function setupAutoConfig<C extends AutoConfigFrom>(configs: C) { export function setupAutoConfig<WD, Input>(configs: AutoConfigFrom<WD, Input>) {
const answer = { ...configs } as unknown as { [k in keyof C]: AutoConfig }; type C = typeof configs;
const answer = { ...configs } as unknown as {
[k in keyof C]: AutoConfig<WD, Input>;
};
for (const key in configs) { for (const key in configs) {
answer[key] = new AutoConfig(configs, key); answer[key] = new AutoConfig<WD, Input>(configs, key);
} }
return answer; return answer;
} }

View File

@@ -1,5 +1,5 @@
export * as configBuilder from "./builder"; export * as configBuilder from "./builder";
export { setupConfig as setupConfigExports } from "./setupConfig"; export { setupConfig } from "./setupConfig";
export { specToBuilder, specToBuilderFile } from "./specToBuilder"; export { specToBuilder, specToBuilderFile } from "./specToBuilder";
export * as dependencies from "./dependencies"; export * as dependencies from "./dependencies";

View File

@@ -1,20 +1,23 @@
import { Config } from "./builder"; import { Config } from "./builder";
import { DeepPartial, Dependencies, Effects, ExpectedExports } from "../types"; import { DeepPartial, Dependencies, Effects, ExpectedExports } from "../types";
import { InputSpec } from "./configTypes"; import { InputSpec } from "./configTypes";
import { nullIfEmpty } from "../util"; import { Utils, nullIfEmpty, utils } from "../util";
import { TypeFromProps } from "../util/propertiesMatcher"; import { TypeFromProps } from "../util/propertiesMatcher";
export type Write<A> = (options: { declare const dependencyProof: unique symbol;
export type DependenciesReceipt = void & {
[dependencyProof]: never;
};
export type Save<WD, A> = (options: {
effects: Effects; effects: Effects;
input: TypeFromProps<A>; input: A;
}) => Promise<void>; utils: Utils<WD>;
export type Read<A> = (options: { }) => Promise<DependenciesReceipt>;
export type Read<WD, A> = (options: {
effects: Effects; effects: Effects;
}) => Promise<null | DeepPartial<TypeFromProps<A>>>; utils: Utils<WD>;
export type DependenciesFn<A> = (options: { }) => Promise<null | DeepPartial<A>>;
effects: Effects;
input: TypeFromProps<A>;
}) => Promise<Dependencies | void>;
/** /**
* We want to setup a config export with a get and set, this * We want to setup a config export with a get and set, this
* is going to be the default helper to setup config, because it will help * is going to be the default helper to setup config, because it will help
@@ -22,11 +25,10 @@ export type DependenciesFn<A> = (options: {
* @param options * @param options
* @returns * @returns
*/ */
export function setupConfig<A extends InputSpec>( export function setupConfig<WD, A extends Config<InputSpec>>(
spec: Config<A>, spec: A,
write: Write<A>, write: Save<WD, TypeFromProps<A>>,
read: Read<A>, read: Read<WD, TypeFromProps<A>>,
dependencies: DependenciesFn<A>,
) { ) {
const validator = spec.validator(); const validator = spec.validator();
return { return {
@@ -38,14 +40,13 @@ export function setupConfig<A extends InputSpec>(
await write({ await write({
input: JSON.parse(JSON.stringify(input)), input: JSON.parse(JSON.stringify(input)),
effects, effects,
utils: utils<WD>(effects),
}); });
const dependenciesToSet = (await dependencies({ effects, input })) || [];
await effects.setDependencies(dependenciesToSet);
}) as ExpectedExports.setConfig, }) as ExpectedExports.setConfig,
getConfig: (async ({ effects, config }) => { getConfig: (async ({ effects, config }) => {
return { return {
spec: spec.build(), spec: spec.build(),
config: nullIfEmpty(await read({ effects })), config: nullIfEmpty(await read({ effects, utils: utils<WD>(effects) })),
}; };
}) as ExpectedExports.getConfig, }) as ExpectedExports.getConfig,
}; };

View File

@@ -1,5 +1,6 @@
export * as configTypes from "./config/configTypes"; export * as configTypes from "./config/configTypes";
import { InputSpec } from "./config/configTypes"; import { InputSpec } from "./config/configTypes";
import { DependenciesReceipt } from "./config/setupConfig";
import { ActionReceipt } from "./init"; import { ActionReceipt } from "./init";
export type ExportedAction = (options: { export type ExportedAction = (options: {
@@ -382,7 +383,7 @@ export type Effects = {
}): Promise<void>; }): Promise<void>;
/** Set the dependencies of what the service needs, usually ran during the set config as a best practice */ /** Set the dependencies of what the service needs, usually ran during the set config as a best practice */
setDependencies(dependencies: Dependencies): Promise<void>; setDependencies(dependencies: Dependencies): Promise<DependenciesReceipt>;
/** Exists could be useful during the runtime to know if some service exists, option dep */ /** Exists could be useful during the runtime to know if some service exists, option dep */
exists(packageId: PackageId): Promise<boolean>; exists(packageId: PackageId): Promise<boolean>;
/** Exists could be useful during the runtime to know if some service is running, option dep */ /** Exists could be useful during the runtime to know if some service is running, option dep */

View File

@@ -6,6 +6,7 @@ import {
ValueSpec as ValueSpecAny, ValueSpec as ValueSpecAny,
InputSpec, InputSpec,
} from "../config/configTypes"; } from "../config/configTypes";
import { Config } from "../config/builder/config";
const { const {
string, string,
@@ -110,6 +111,7 @@ export type GuardAll<A> = GuardNumber<A> &
GuardDatetime<A>; GuardDatetime<A>;
// prettier-ignore // prettier-ignore
export type TypeFromProps<A> = export type TypeFromProps<A> =
A extends Config<infer B> ? TypeFromProps<B> :
A extends Record<string, unknown> ? { [K in keyof A & string]: _<GuardAll<A[K]>> } : A extends Record<string, unknown> ? { [K in keyof A & string]: _<GuardAll<A[K]>> } :
unknown; unknown;