From 31c2131ca990072361751ca961b816c43c21e5e9 Mon Sep 17 00:00:00 2001 From: BluJ Date: Wed, 3 May 2023 07:47:21 -0600 Subject: [PATCH] chore: Update the types of config --- lib/actions/createAction.ts | 5 +- lib/config/builder/config.ts | 43 +++++++---- lib/config/builder/list.ts | 14 ++-- lib/config/builder/value.ts | 136 +++++++++++++++++++-------------- lib/config/builder/variants.ts | 48 +++++++----- lib/config/constants.ts | 16 +--- lib/config/setupConfig.ts | 19 +++-- lib/test/configBuilder.test.ts | 29 +++---- lib/test/configTypes.test.ts | 2 +- lib/types.ts | 2 +- scripts/oldSpecToBuilder.ts | 9 +-- 11 files changed, 185 insertions(+), 138 deletions(-) diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index 9aea2f3..d3e36ec 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -4,7 +4,10 @@ import { Utils, utils } from "../util" export class CreatedAction< WrapperData, - ConfigType extends Record | Config, + ConfigType extends + | Record + | Config + | Config, Type extends Record = ExtractConfigType, > { private constructor( diff --git a/lib/config/builder/config.ts b/lib/config/builder/config.ts index 2b55b0a..5671176 100644 --- a/lib/config/builder/config.ts +++ b/lib/config/builder/config.ts @@ -14,10 +14,14 @@ export type LazyBuild = ( ) => Promise | ExpectedOut // prettier-ignore -export type ExtractConfigType | Config, any>> = - A extends Config ? B : +export type ExtractConfigType | Config, any> | Config, never>> = + A extends Config | Config ? B : A +export type TypeAsConfigOf, WD> = { + [K in keyof A]: Value +} + export type MaybeLazyValues = LazyBuild | A /** * Configs are the specs that are used by the os configuration form for this service. @@ -92,19 +96,28 @@ export class Config, WD> { return answer } - static of() { - return >(spec: { - [K in keyof Type]: Value - }) => { - const validatorObj = {} as { - [K in keyof Type]: Parser - } - for (const key in spec) { - validatorObj[key] = spec[key].validator - } - const validator = object(validatorObj) - return new Config(spec, validator) + static of | Value>>( + spec: Spec, + ) { + const validatorObj = {} as { + [K in keyof Spec]: Parser } + for (const key in spec) { + validatorObj[key] = spec[key].validator + } + const validator = object(validatorObj) + return new Config< + { + [K in keyof Spec]: Spec[K] extends + | Value + | Value + ? T + : never + }, + { + [K in keyof Spec]: Spec[K] extends Value ? WD : never + }[keyof Spec] + >(spec as any, validator as any) } /** @@ -121,7 +134,7 @@ export class Config, WD> { }) ``` */ - withWrapperData() { + withWrapperData() { return this as any as Config } } diff --git a/lib/config/builder/list.ts b/lib/config/builder/list.ts index 3f07e97..95ba9e0 100644 --- a/lib/config/builder/list.ts +++ b/lib/config/builder/list.ts @@ -26,7 +26,7 @@ export class List { public build: LazyBuild, public validator: Parser, ) {} - static text( + static text( a: { name: string description?: string | null @@ -47,7 +47,7 @@ export class List { inputmode?: ListValueSpecText["inputmode"] }, ) { - return new List(() => { + return new List(() => { const spec = { type: "text" as const, placeholder: null, @@ -70,7 +70,7 @@ export class List { } satisfies ValueSpecListOf<"text"> }, arrayOf(string)) } - static dynamicText( + static dynamicText( getA: LazyBuild< WD, { @@ -119,7 +119,7 @@ export class List { } satisfies ValueSpecListOf<"text"> }, arrayOf(string)) } - static number( + static number( a: { name: string description?: string | null @@ -138,7 +138,7 @@ export class List { placeholder?: string | null }, ) { - return new List(() => { + return new List(() => { const spec = { type: "number" as const, placeholder: null, @@ -161,7 +161,7 @@ export class List { } satisfies ValueSpecListOf<"number"> }, arrayOf(number)) } - static dynamicNumber( + static dynamicNumber( getA: LazyBuild< WD, { @@ -265,7 +265,7 @@ export class List { }) ``` */ - withWrapperData() { + withWrapperData() { return this as any as List } } diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index c28caad..ca1118f 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -98,7 +98,7 @@ export class Value { public build: LazyBuild, public validator: Parser, ) {} - static toggle(a: { + static toggle(a: { name: string description?: string | null warning?: string | null @@ -107,7 +107,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value( + return new Value( async () => ({ description: null, warning: null, @@ -120,7 +120,7 @@ export class Value { boolean, ) } - static dynamicToggle( + static dynamicToggle( a: LazyBuild< WD, { @@ -145,7 +145,7 @@ export class Value { boolean, ) } - static text, WD>(a: { + static text>(a: { name: string description?: string | null warning?: string | null @@ -163,7 +163,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, WD>( + return new Value, never>( async () => ({ type: "text" as const, description: null, @@ -182,7 +182,7 @@ export class Value { asRequiredParser(string, a), ) } - static dynamicText( + static dynamicText( getA: LazyBuild< WD, { @@ -221,7 +221,7 @@ export class Value { } }, string.optional()) } - static textarea(a: { + static textarea(a: { name: string description?: string | null warning?: string | null @@ -233,7 +233,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value( + return new Value( async () => ({ description: null, @@ -249,7 +249,7 @@ export class Value { string, ) } - static dynamicTextarea( + static dynamicTextarea( getA: LazyBuild< WD, { @@ -279,7 +279,7 @@ export class Value { } }, string) } - static number, WD>(a: { + static number>(a: { name: string description?: string | null warning?: string | null @@ -295,7 +295,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, WD>( + return new Value, never>( () => ({ type: "number" as const, description: null, @@ -313,7 +313,7 @@ export class Value { asRequiredParser(number, a), ) } - static dynamicNumber( + static dynamicNumber( getA: LazyBuild< WD, { @@ -350,7 +350,7 @@ export class Value { } }, number.optional()) } - static color, WD>(a: { + static color>(a: { name: string description?: string | null warning?: string | null @@ -359,7 +359,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, WD>( + return new Value, never>( () => ({ type: "color" as const, description: null, @@ -374,7 +374,7 @@ export class Value { ) } - static dynamicColor( + static dynamicColor( getA: LazyBuild< WD, { @@ -400,7 +400,7 @@ export class Value { } }, string.optional()) } - static datetime, WD>(a: { + static datetime>(a: { name: string description?: string | null warning?: string | null @@ -414,7 +414,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, WD>( + return new Value, never>( () => ({ type: "datetime" as const, description: null, @@ -431,7 +431,7 @@ export class Value { asRequiredParser(string, a), ) } - static dynamicDatetime( + static dynamicDatetime( getA: LazyBuild< WD, { @@ -468,7 +468,6 @@ export class Value { static select< Required extends RequiredDefault, B extends Record, - WD, >(a: { name: string description?: string | null @@ -479,7 +478,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, WD>( + return new Value, never>( () => ({ description: null, warning: null, @@ -497,7 +496,7 @@ export class Value { ) as any, ) } - static dynamicSelect( + static dynamicSelect( getA: LazyBuild< WD, { @@ -523,7 +522,7 @@ export class Value { } }, string.optional()) } - static multiselect, WD>(a: { + static multiselect>(a: { name: string description?: string | null warning?: string | null @@ -535,7 +534,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value<(keyof Values)[], WD>( + return new Value<(keyof Values)[], never>( () => ({ type: "multiselect" as const, minLength: null, @@ -551,7 +550,7 @@ export class Value { ), ) } - static dynamicMultiselect( + static dynamicMultiselect( getA: LazyBuild< WD, { @@ -625,41 +624,36 @@ export class Value { asRequiredParser(aVariants.validator, a), ) } - static filteredUnion< - Required extends RequiredDefault, - Type, - WrapperData, - >( - a: { - name: string - description?: string | null - warning?: string | null - required: Required - default?: string | null - }, - aVariants: Variants, - getDisabledFn: LazyBuild< - WrapperData, - Array - >, + static filteredUnion( + getDisabledFn: LazyBuild, ) { - return new Value( - async (options) => ({ - type: "union" as const, - description: null, - warning: null, - ...a, - variants: await aVariants.build(options as any), - ...requiredLikeToAbove(a.required), - disabled: (await getDisabledFn(options)) || [], - immutable: false, - }), - aVariants.validator.optional(), - ) + return >( + a: { + name: string + description?: string | null + warning?: string | null + required: RequiredDefault + default?: string | null + }, + aVariants: Variants | Variants, + ) => { + return new Value( + async (options) => ({ + type: "union" as const, + description: null, + warning: null, + ...a, + variants: await aVariants.build(options as any), + ...requiredLikeToAbove(a.required), + disabled: (await getDisabledFn(options)) || [], + immutable: false, + }), + aVariants.validator.optional(), + ) + } } static list(a: List) { - /// TODO return new Value( (options) => a.build(options), a.validator, @@ -680,7 +674,37 @@ export class Value { }) ``` */ - withWrapperData() { + withWrapperData() { return this as any as Value } } + +type Wrapper = { test: 1 | "5" } +const valueA = Value.dynamicText(() => ({ + name: "a", + required: false, +})) +const variantForC = Variants.of({ + lnd: { + name: "lnd Name", + spec: Config.of({ + name: Value.text({ + name: "Node Name", + required: false, + }), + }), + }, +}) +const valueC = Value.filteredUnion(() => [])( + { name: "a", required: false }, + variantForC, +) +const valueB = Value.text({ + name: "a", + required: false, +}) +const test = Config.of({ + a: valueA, + b: valueB, + c: valueC, +}) diff --git a/lib/config/builder/variants.ts b/lib/config/builder/variants.ts index 0b6e8d0..b30b3f1 100644 --- a/lib/config/builder/variants.ts +++ b/lib/config/builder/variants.ts @@ -63,20 +63,13 @@ export class Variants { // } // }, static of< - TypeMap extends Record>, - WrapperData, - TypeOut = { - [K in keyof TypeMap & string]: { - unionSelectKey: K - unionValueKey: TypeMap[K] + VariantValues extends { + [K in string]: { + name: string + spec: Config | Config } - }[keyof TypeMap & string], - >(a: { - [K in keyof TypeMap]: { - name: string - spec: Config - } - }) { + }, + >(a: VariantValues) { const validator = anyOf( ...Object.entries(a).map(([name, { spec }]) => object({ @@ -84,17 +77,36 @@ export class Variants { unionValueKey: spec.validator, }), ), - ) as Parser + ) as Parser - return new Variants(async (options) => { + return new Variants< + { + [K in keyof VariantValues]: { + unionSelectKey: K + unionValueKey: VariantValues[K]["spec"] extends + | Config + | Config + ? B + : never + } + }[keyof VariantValues], + { + [K in keyof VariantValues]: VariantValues[K] extends Config< + any, + infer C + > + ? C + : never + }[keyof VariantValues] + >(async (options) => { const variants = {} as { - [K in keyof TypeMap]: { name: string; spec: InputSpec } + [K in keyof VariantValues]: { name: string; spec: InputSpec } } for (const key in a) { const value = a[key] variants[key] = { name: value.name, - spec: await value.spec.build(options), + spec: await value.spec.build(options as any), } } return variants @@ -114,7 +126,7 @@ export class Variants { }) ``` */ - withWrapperData() { + withWrapperData() { return this as any as Variants } } diff --git a/lib/config/constants.ts b/lib/config/constants.ts index cabc916..f287811 100644 --- a/lib/config/constants.ts +++ b/lib/config/constants.ts @@ -1,5 +1,5 @@ import { SmtpValue } from "../types" -import { Config } from "./builder/config" +import { Config, TypeAsConfigOf } from "./builder/config" import { Value } from "./builder/value" import { Variants } from "./builder/variants" @@ -10,11 +10,11 @@ export const smtpConfig = Value.union( required: { default: "disabled" }, }, Variants.of({ - disabled: { name: "Disabled", spec: Config.of()({}) }, - system: { name: "System Credentials", spec: Config.of()({}) }, + disabled: { name: "Disabled", spec: Config.of({}) }, + system: { name: "System Credentials", spec: Config.of({}) }, custom: { name: "Custom Credentials", - spec: Config.of()({ + spec: Config.of>({ server: Value.text({ name: "SMTP Server", required: { @@ -56,11 +56,3 @@ export const smtpConfig = Value.union( }, }), ) - -export function getConst() { - return { - get smtp() { - return smtpConfig.withWrapperData() - }, - } -} diff --git a/lib/config/setupConfig.ts b/lib/config/setupConfig.ts index a72ade3..34442a4 100644 --- a/lib/config/setupConfig.ts +++ b/lib/config/setupConfig.ts @@ -13,7 +13,10 @@ export type DependenciesReceipt = void & { export type Save< WD, - A extends Record | Config, any>, + A extends + | Record + | Config, any> + | Config, never>, Manifest extends SDKManifest, > = (options: { effects: Effects @@ -26,7 +29,10 @@ export type Save< }> export type Read< WD, - A extends Record | Config, any>, + A extends + | Record + | Config, any> + | Config, never>, > = (options: { effects: Effects utils: Utils @@ -40,11 +46,14 @@ export type Read< */ export function setupConfig< WD, - ConfigType extends Record | Config, + ConfigType extends + | Record + | Config + | Config, Manifest extends SDKManifest, Type extends Record = ExtractConfigType, >( - spec: Config, + spec: Config | Config, write: Save, read: Read, ) { @@ -73,7 +82,7 @@ export function setupConfig< return { spec: await spec.build({ effects, - utils: myUtils, + utils: myUtils as any, }), config: configValue, } diff --git a/lib/test/configBuilder.test.ts b/lib/test/configBuilder.test.ts index 2e57b44..5798eca 100644 --- a/lib/test/configBuilder.test.ts +++ b/lib/test/configBuilder.test.ts @@ -11,7 +11,7 @@ describe("builder tests", () => { test("text", async () => { const bitcoinPropertiesBuilt: { "peer-tor-address": ValueSpec - } = await Config.of()({ + } = await Config.of({ "peer-tor-address": Value.text({ name: "Peer tor address", description: "The Tor address of the peer interface", @@ -234,7 +234,7 @@ describe("values", () => { description: null, warning: null, }, - Config.of()({ + Config.of({ a: Value.toggle({ name: "test", description: null, @@ -259,7 +259,7 @@ describe("values", () => { Variants.of({ a: { name: "a", - spec: Config.of()({ + spec: Config.of({ b: Value.toggle({ name: "b", description: null, @@ -501,7 +501,7 @@ describe("values", () => { }) describe("filtering", () => { test("union", async () => { - const value = Value.filteredUnion( + const value = Value.filteredUnion(() => ["a", "c"])( { name: "Testing", required: { default: null }, @@ -512,7 +512,7 @@ describe("values", () => { Variants.of({ a: { name: "a", - spec: Config.of()({ + spec: Config.of({ b: Value.toggle({ name: "b", description: null, @@ -523,7 +523,7 @@ describe("values", () => { }, b: { name: "b", - spec: Config.of()({ + spec: Config.of({ b: Value.toggle({ name: "b", description: null, @@ -533,11 +533,6 @@ describe("values", () => { }), }, }), - () => [ - "a", - // @ts-expect-error - "c", - ], ) const validator = value.validator validator.unsafeCast({ unionSelectKey: "a", unionValueKey: { b: false } }) @@ -584,7 +579,7 @@ describe("Builder List", () => { name: "test", }, { - spec: Config.of()({ + spec: Config.of({ test: Value.toggle({ name: "test", description: null, @@ -655,7 +650,7 @@ describe("Builder List", () => { describe("Nested nullable values", () => { test("Testing text", async () => { - const value = Config.of()({ + const value = Config.of({ a: Value.text({ name: "Temp Name", description: @@ -670,7 +665,7 @@ describe("Nested nullable values", () => { testOutput()(null) }) test("Testing number", async () => { - const value = Config.of()({ + const value = Config.of({ a: Value.number({ name: "Temp Name", description: @@ -692,7 +687,7 @@ describe("Nested nullable values", () => { testOutput()(null) }) test("Testing color", async () => { - const value = Config.of()({ + const value = Config.of({ a: Value.color({ name: "Temp Name", description: @@ -708,7 +703,7 @@ describe("Nested nullable values", () => { testOutput()(null) }) test("Testing select", async () => { - const value = Config.of()({ + const value = Config.of({ a: Value.select({ name: "Temp Name", description: @@ -737,7 +732,7 @@ describe("Nested nullable values", () => { testOutput()(null) }) test("Testing multiselect", async () => { - const value = Config.of()({ + const value = Config.of({ a: Value.multiselect({ name: "Temp Name", description: diff --git a/lib/test/configTypes.test.ts b/lib/test/configTypes.test.ts index aab6a90..a50ec6c 100644 --- a/lib/test/configTypes.test.ts +++ b/lib/test/configTypes.test.ts @@ -9,7 +9,7 @@ describe("Config Types", () => { for (const option of options) { const test = (option as any)( {} as any, - { spec: Config.of()({}) } as any, + { spec: Config.of({}) } as any, ) as any const someList = await Value.list(test).build({} as any) if (isValueSpecListOf(someList, "text")) { diff --git a/lib/types.ts b/lib/types.ts index 4f827f5..413789a 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -436,7 +436,7 @@ export type ExtractWrapperData = // prettier-ignore type _EnsureWrapperDataPath = Path extends`/${infer A }/${infer Rest}` ? (WrapperData extends {[K in A & string]: infer NextWrapperData} ? _EnsureWrapperDataPath : never) : - Path extends `/${infer A }` ? (WrapperData extends {[K in A]: any} ? Origin : never) : + Path extends `/${infer A }` ? (WrapperData extends {[K in A]: infer B} ? Origin : never) : Path extends '' ? Origin : never // prettier-ignore diff --git a/scripts/oldSpecToBuilder.ts b/scripts/oldSpecToBuilder.ts index 9f8dac3..73a7e6c 100644 --- a/scripts/oldSpecToBuilder.ts +++ b/scripts/oldSpecToBuilder.ts @@ -43,7 +43,6 @@ import { Variants } from "${startSdk}/lib/config/builder/variants" import {WrapperData} from '${wrapperData}' `) const data = await inputData - const hammerWrapperData = !nested ? ".withWrapperData()" : "" const namedConsts = new Set(["Config", "Value", "List"]) const configName = newConst("configSpec", convertInputSpec(data)) @@ -73,13 +72,13 @@ import { Variants } from "${startSdk}/lib/config/builder/variants" for (const [key, value] of Object.entries(data)) { const variableName = maybeNewConst(key, convertValueSpec(value)) - answer += `${JSON.stringify(key)}: ${variableName}${hammerWrapperData},` + answer += `${JSON.stringify(key)}: ${variableName},` } return `${answer}}` } function convertInputSpec(data: any) { - return `Config.of()(${convertInputSpecInner(data)})` + return `Config.of(${convertInputSpecInner(data)})` } function convertValueSpec(value: any): string { switch (value.type) { @@ -363,8 +362,8 @@ import { Variants } from "${startSdk}/lib/config/builder/variants" const listConfig = maybeNewConst( value.name + "_list_config", ` - Config.of()({ - "union": ${unionValueName}${hammerWrapperData} + Config.of({ + "union": ${unionValueName} }) `, )