From 333bddf3451d09d006ccc4063d48110967297f20 Mon Sep 17 00:00:00 2001 From: BluJ Date: Thu, 27 Apr 2023 08:19:14 -0600 Subject: [PATCH] wip: Working with a nested nullable + default --- lib/config/builder/value.ts | 65 ++++++++++++++++++++++++---------- lib/test/configBuilder.test.ts | 12 +++---- lib/test/makeOutput.ts | 2 +- lib/test/output.test.ts | 13 ++++--- scripts/oldSpecToBuilder.ts | 8 +++-- 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index 3172ac7..9df7191 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -18,8 +18,28 @@ import { guardAll } from "../../util"; import { DefaultString } from "../configTypes"; import { _ } from "../../util"; -function flatten(a: A): _ { - return a as _; +type RequiredLike = + | false + | true + | { default: A } + | { defaultWithRequired: A }; + +function requiredLikeToAbove>( + requiredLike: Input, +) { + // prettier-ignore + return { + default: + (typeof requiredLike === "object" ? ( + 'default' in requiredLike ? requiredLike.default : requiredLike.defaultWithRequired + ) : + null) as Input extends { default: infer T } | {defaultWithRequired: infer T} ? T : null, + required: (requiredLike === true ? true : false) as ( + Input extends true ? true : + Input extends { defaultWithRequired: unknown } ? true : + false + ), + }; } /** * A value is going to be part of the form in the FE of the OS. @@ -55,26 +75,33 @@ export class Value extends IBuilder { ...a, }); } - static text< - A extends { - name: string; - description: string | null; - warning: string | null; - required: boolean; - default: DefaultString | null; - /** Default = false */ - masked: boolean; - placeholder: string | null; - minLength: number | null; - maxLength: number | null; - patterns: Pattern[]; - /** Default = 'text' */ - inputmode: ValueSpecText["inputmode"]; - }, - >(a: A) { + + static text>(a: { + name: string; + description?: string | null; + warning?: string | null; + required: Required; + /** Default = false */ + masked?: boolean; + placeholder?: string | null; + minLength?: number | null; + maxLength?: number | null; + patterns?: Pattern[]; + /** Default = 'text' */ + inputmode?: ValueSpecText["inputmode"]; + }) { return new Value({ type: "text" as const, + description: null, + warning: null, + masked: false, + placeholder: null, + minLength: null, + maxLength: null, + patterns: [], + inputmode: "text", ...a, + ...requiredLikeToAbove(a.required), }); } static textarea(a: { diff --git a/lib/test/configBuilder.test.ts b/lib/test/configBuilder.test.ts index efe2ef7..e2c6cdd 100644 --- a/lib/test/configBuilder.test.ts +++ b/lib/test/configBuilder.test.ts @@ -15,7 +15,6 @@ describe("builder tests", () => { } = Config.of({ "peer-tor-address": Value.text({ name: "Peer tor address", - default: null, description: "The Tor address of the peer interface", warning: null, required: true, @@ -31,17 +30,17 @@ describe("builder tests", () => { /*json*/ `{ "peer-tor-address": { "type": "text", - "name": "Peer tor address", - "default": null, "description": "The Tor address of the peer interface", "warning": null, - "required": true, "masked": true, "placeholder": null, "minLength": null, "maxLength": null, "patterns": [], - "inputmode":"text" + "inputmode":"text", + "name": "Peer tor address", + "required": true, + "default": null }}` .replaceAll("\n", " ") .replaceAll(/\s{2,}/g, "") @@ -68,7 +67,6 @@ describe("values", () => { required: false, description: null, warning: null, - default: null, masked: false, placeholder: null, minLength: null, @@ -86,7 +84,6 @@ describe("values", () => { required: true, description: null, warning: null, - default: null, masked: false, placeholder: null, minLength: null, @@ -340,7 +337,6 @@ describe("Nested nullable values", () => { description: "If no name is provided, the name from config will be used", required: false, - default: null, warning: null, masked: false, placeholder: null, diff --git a/lib/test/makeOutput.ts b/lib/test/makeOutput.ts index 7895985..212e107 100644 --- a/lib/test/makeOutput.ts +++ b/lib/test/makeOutput.ts @@ -281,7 +281,7 @@ writeConvertedFileFromOld( spec: { hostname: { type: "string", - nullable: false, + nullable: true, name: "Hostname", description: "Domain or IP address of bitcoin peer", pattern: diff --git a/lib/test/output.test.ts b/lib/test/output.test.ts index f061ec0..6e5ad78 100644 --- a/lib/test/output.test.ts +++ b/lib/test/output.test.ts @@ -18,8 +18,7 @@ export function testOutput(): (c: IfEquals) => null { /// Testing the types of the input spec testOutput()(null); -// @ts-expect-error Because enable should be a boolean -testOutput()(null); +testOutput()(null); testOutput()(null); testOutput()(null); @@ -28,9 +27,10 @@ testOutput< "segwit" | "non-segwit" >()(null); testOutput()(null); -testOutput()( - null, -); +testOutput< + InputSpec["advanced"]["peers"]["addnode"][0]["hostname"], + string | null | undefined +>()(null); testOutput< InputSpec["testListUnion"][0]["union"][UnionValueKey]["name"], string @@ -38,6 +38,9 @@ testOutput< testOutput()( null, ); + +// @ts-expect-error Because enable should be a boolean +testOutput()(null); // prettier-ignore // @ts-expect-error Expect that the string is the one above testOutput()(null); diff --git a/scripts/oldSpecToBuilder.ts b/scripts/oldSpecToBuilder.ts index 3cfc492..1bc9c0c 100644 --- a/scripts/oldSpecToBuilder.ts +++ b/scripts/oldSpecToBuilder.ts @@ -77,10 +77,14 @@ export default async function makeFileContentFromOld( return `${rangeToTodoComment(value?.range)}Value.text(${JSON.stringify( { name: value.name || null, - default: value.default || null, + // prettier-ignore + required: ( + value.default != null && !value.nullable ? {default: value.default} : + value.default != null && value.nullable ? {defaultWithRequired: value.default} : + !value.nullable + ), description: value.description || null, warning: value.warning || null, - required: !(value.nullable || false), masked: value.masked || false, placeholder: value.placeholder || null, inputmode: "text",