From 16fed45f4b9fb469527723d50e36d92139114369 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Sat, 25 Mar 2023 12:49:58 -0600 Subject: [PATCH 1/2] rename enum and add multiselect --- lib/config/builder/config.ts | 4 ++-- lib/config/builder/list.ts | 18 ----------------- lib/config/builder/value.ts | 4 ++-- lib/config/builder/variants.ts | 6 +++--- lib/scripts/oldSpecToBuilder.ts | 10 ++++------ lib/types/config-types.ts | 34 +++++++++++++++++++------------- lib/util/artifacts/makeOutput.ts | 3 +-- lib/util/artifacts/output.ts | 2 +- lib/util/propertiesMatcher.ts | 30 +++++++++++++++++++++++----- 9 files changed, 58 insertions(+), 53 deletions(-) diff --git a/lib/config/builder/config.ts b/lib/config/builder/config.ts index d76d10d..c2eda1f 100644 --- a/lib/config/builder/config.ts +++ b/lib/config/builder/config.ts @@ -19,7 +19,7 @@ import { Value } from "./value"; The idea of a config is that now the form is going to ask for Test: [ ] and the value is going to be checked as a boolean. - There are more complex values like enums, lists, and objects. See {@link Value} + There are more complex values like selects, lists, and objects. See {@link Value} Also, there is the ability to get a validator/parser from this config spec. ```ts @@ -81,7 +81,7 @@ import { Value } from "./value"; "warning": null, }); export const auth = Value.list(authorizationList); - export const serialversion = Value.enum({ + export const serialversion = Value.select({ "name": "Serialization Version", "description": "Return raw transaction or block hex with Segwit or non-SegWit serialization.", diff --git a/lib/config/builder/list.ts b/lib/config/builder/list.ts index 84c47ea..b52ad98 100644 --- a/lib/config/builder/list.ts +++ b/lib/config/builder/list.ts @@ -59,24 +59,6 @@ export class List extends IBuilder { ...a, }); } - static enum< - A extends Description & - Default & { - range: string; - spec: { - values: string[]; - "value-names": { - [key: string]: string; - }; - }; - } - >(a: A) { - return new List({ - type: "list" as const, - subtype: "enum" as const, - ...a, - }); - } static obj< A extends Description & Default[]> & { diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index cde5804..aeed549 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -95,7 +95,7 @@ export class Value extends IBuilder { ...a, } as ValueSpecNumber); } - static enum< + static select< A extends Description & Default & { values: readonly string[] | string[]; @@ -103,7 +103,7 @@ export class Value extends IBuilder { } >(a: A) { return new Value({ - type: "enum" as const, + type: "select" as const, ...a, }); } diff --git a/lib/config/builder/variants.ts b/lib/config/builder/variants.ts index c689b2e..9e01bb7 100644 --- a/lib/config/builder/variants.ts +++ b/lib/config/builder/variants.ts @@ -3,9 +3,9 @@ import { BuilderExtract, IBuilder } from "./builder"; import { Config } from "."; /** - * Used in the the Value.enum { @link './value.ts' } - * to indicate the type of enums variants that are available. The key for the record passed in will be the - * key to the tag.id in the Value.enum + * Used in the the Value.select { @link './value.ts' } + * to indicate the type of select variants that are available. The key for the record passed in will be the + * key to the tag.id in the Value.select ```ts export const pruningSettingsVariants = Variants.of({ "disabled": disabled, diff --git a/lib/scripts/oldSpecToBuilder.ts b/lib/scripts/oldSpecToBuilder.ts index 75e31f0..a5e0992 100644 --- a/lib/scripts/oldSpecToBuilder.ts +++ b/lib/scripts/oldSpecToBuilder.ts @@ -97,7 +97,7 @@ export default async function makeFileContent( )})`; } case "enum": { - return `Value.enum(${JSON.stringify( + return `Value.select(${JSON.stringify( { name: value.name || null, description: value.description || null, @@ -205,14 +205,12 @@ export default async function makeFileContent( )})`; } case "enum": { - return `List.enum(${JSON.stringify( + return `Value.multiselect(${JSON.stringify( { name: value.name || null, range: value.range || null, - spec: { - values: value?.spec?.["values"] || null, - "value-names": value?.spec?.["value-names"] || {}, - }, + values: value?.spec?.["values"] || null, + "value-names": value?.spec?.["value-names"] || {}, default: value.default || null, description: value.description || null, warning: value.warning || null, diff --git a/lib/types/config-types.ts b/lib/types/config-types.ts index 8b69d3c..b57a521 100644 --- a/lib/types/config-types.ts +++ b/lib/types/config-types.ts @@ -4,7 +4,8 @@ export type ValueType = | "string" | "number" | "boolean" - | "enum" + | "select" + | "multiselect" | "list" | "object" | "file" @@ -18,8 +19,10 @@ export type ValueSpecOf = T extends "string" ? ValueSpecNumber : T extends "boolean" ? ValueSpecBoolean - : T extends "enum" - ? ValueSpecEnum + : T extends "select" + ? ValueSpecSelect + : T extends "multiselect" + ? ValueSpecMultiselect : T extends "list" ? ValueSpecList : T extends "object" @@ -43,11 +46,17 @@ export interface ValueSpecNumber extends ListValueSpecNumber, WithStandalone { default: null | number; } -export interface ValueSpecEnum extends ListValueSpecEnum, WithStandalone { - type: "enum"; +export interface ValueSpecSelect extends SelectBase, WithStandalone { + type: "select"; default: string; } +export interface ValueSpecMultiselect extends SelectBase, WithStandalone { + type: "multiselect"; + range: string; // '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules + default: string[]; +} + export interface ValueSpecBoolean extends WithStandalone { type: "boolean"; default: boolean; @@ -78,11 +87,15 @@ export interface WithStandalone { warning: null | string; } +export interface SelectBase { + values: string[] | readonly string[]; + "value-names": { [value: string]: string }; +} + // no lists of booleans, lists export type ListValueSpecType = | "string" | "number" - | "enum" | "object" | "union"; @@ -91,8 +104,6 @@ export type ListValueSpecOf = T extends "string" ? ListValueSpecString : T extends "number" ? ListValueSpecNumber - : T extends "enum" - ? ListValueSpecEnum : T extends "object" ? ListValueSpecObject : T extends "union" @@ -134,17 +145,12 @@ export interface ListValueSpecString { } export interface ListValueSpecNumber { - range: string; + range: string; // '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules integral: boolean; units: null | string; placeholder: null | string; } -export interface ListValueSpecEnum { - values: string[] | readonly string[]; - "value-names": { [value: string]: string }; -} - export interface ListValueSpecObject { spec: InputSpec; // this is a mapped type of the config object at this level, replacing the object's values with specs on those values "unique-by": UniqueBy; // indicates whether duplicates can be permitted in the list diff --git a/lib/util/artifacts/makeOutput.ts b/lib/util/artifacts/makeOutput.ts index 8fa33a0..9bf8cc8 100644 --- a/lib/util/artifacts/makeOutput.ts +++ b/lib/util/artifacts/makeOutput.ts @@ -1,5 +1,4 @@ import { writeConvertedFile } from "../../scripts/oldSpecToBuilder"; -import { writeFileSync, readFileSync } from "fs"; writeConvertedFile( "./lib/util/artifacts/output.ts", @@ -66,7 +65,7 @@ writeConvertedFile( name: "Serialization Version", description: "Return raw transaction or block hex with Segwit or non-SegWit serialization.", - type: "enum", + type: "select", values: ["non-segwit", "segwit"], "value-names": {}, default: "segwit", diff --git a/lib/util/artifacts/output.ts b/lib/util/artifacts/output.ts index de40e99..427ac4b 100644 --- a/lib/util/artifacts/output.ts +++ b/lib/util/artifacts/output.ts @@ -51,7 +51,7 @@ export const authorizationList = List.string({ warning: null, }); export const auth = Value.list(authorizationList); -export const serialversion = Value.enum({ +export const serialversion = Value.select({ name: "Serialization Version", description: "Return raw transaction or block hex with Segwit or non-SegWit serialization.", diff --git a/lib/util/propertiesMatcher.ts b/lib/util/propertiesMatcher.ts index 40e9cdf..6dd7ee8 100644 --- a/lib/util/propertiesMatcher.ts +++ b/lib/util/propertiesMatcher.ts @@ -6,7 +6,8 @@ type TypeString = "string"; type TypeNumber = "number"; type TypeObject = "object"; type TypeList = "list"; -type TypeEnum = "enum"; +type TypeSelect = "select"; +type TypeMultiselect = "multiselect"; type TypePointer = "pointer"; type TypeUnion = "union"; @@ -49,8 +50,12 @@ type GuardPointer = A extends {readonly type:TypePointer} ? (string | null) : unknown // prettier-ignore -type GuardEnum = - A extends {readonly type:TypeEnum, readonly values: ArrayLike} ? GuardDefaultNullable : +type GuardSelect = + A extends {readonly type:TypeSelect, readonly values: ArrayLike} ? GuardDefaultNullable : + unknown +// prettier-ignore +type GuardMultiselect = + A extends {readonly type:TypeMultiselect, readonly values: ArrayLike} ? GuardDefaultNullable : unknown // prettier-ignore type GuardUnion = @@ -65,7 +70,8 @@ export type GuardAll = GuardNumber & GuardList & GuardPointer & GuardUnion & - GuardEnum; + GuardSelect & + GuardMultiselect; // prettier-ignore export type TypeFromProps = A extends Record ? {readonly [K in keyof A & string]: _>} : @@ -247,7 +253,7 @@ export function guardAll( value ) as any; } - case "enum": + case "select": if (matchValues.test(value)) { return defaultNullable( matches.literals(value.values[0], ...value.values), @@ -255,6 +261,20 @@ export function guardAll( ) as any; } return matches.unknown as any; + case "multiselect": + if (matchValues.test(value)) { + const rangeValidate = + (matchRange.test(value) && matchNumberWithRange(value.range).test) || + (() => true); + + return defaultNullable( + matches + .literals(value.values[0], ...value.values) + .validate((x) => rangeValidate(x.length), "valid length"), + value + ) as any; + } + return matches.unknown as any; case "union": if (matchUnion.test(value)) { return matches.some( From fa2d9367c684f90d00b84accc4757b142eeb882f Mon Sep 17 00:00:00 2001 From: BluJ Date: Sat, 25 Mar 2023 18:35:14 -0600 Subject: [PATCH 2/2] chore: Update to docstrings --- lib/types/config-types.ts | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/types/config-types.ts b/lib/types/config-types.ts index b57a521..c75d8ed 100644 --- a/lib/types/config-types.ts +++ b/lib/types/config-types.ts @@ -12,7 +12,7 @@ export type ValueType = | "union"; export type ValueSpec = ValueSpecOf; -// core spec types. These types provide the metadata for performing validations +/** core spec types. These types provide the metadata for performing validations */ export type ValueSpecOf = T extends "string" ? ValueSpecString : T extends "number" @@ -53,7 +53,8 @@ export interface ValueSpecSelect extends SelectBase, WithStandalone { export interface ValueSpecMultiselect extends SelectBase, WithStandalone { type: "multiselect"; - range: string; // '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules + /**'[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules */ + range: string; default: string[]; } @@ -70,7 +71,7 @@ export interface ValueSpecUnion { } export interface ValueSpecFile extends WithStandalone { - type: 'file'; + type: "file"; placeholder: null | string; nullable: boolean; extensions: string[]; @@ -92,14 +93,10 @@ export interface SelectBase { "value-names": { [value: string]: string }; } -// no lists of booleans, lists -export type ListValueSpecType = - | "string" - | "number" - | "object" - | "union"; +/** no lists of booleans, lists*/ +export type ListValueSpecType = "string" | "number" | "object" | "union"; -// represents a spec for the values of a list +/** represents a spec for the values of a list */ export type ListValueSpecOf = T extends "string" ? ListValueSpecString : T extends "number" @@ -110,10 +107,9 @@ export type ListValueSpecOf = T extends "string" ? ListValueSpecUnion : never; -// represents a spec for a list +/** represents a spec for a list */ export type ValueSpecList = ValueSpecListOf; -export interface ValueSpecListOf - extends WithStandalone { +export interface ValueSpecListOf extends WithStandalone { type: "list"; subtype: T; spec: ListValueSpecOf; @@ -130,10 +126,7 @@ export interface ValueSpecListOf } // sometimes the type checker needs just a little bit of help -export function isValueSpecListOf( - t: ValueSpecList, - s: S -): t is ValueSpecListOf { +export function isValueSpecListOf(t: ValueSpecList, s: S): t is ValueSpecListOf { return t.subtype === s; } @@ -145,16 +138,20 @@ export interface ListValueSpecString { } export interface ListValueSpecNumber { - range: string; // '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules + /** '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules */ + range: string; integral: boolean; units: null | string; placeholder: null | string; } export interface ListValueSpecObject { - spec: InputSpec; // this is a mapped type of the config object at this level, replacing the object's values with specs on those values - "unique-by": UniqueBy; // indicates whether duplicates can be permitted in the list - "display-as": null | string; // this should be a handlebars template which can make use of the entire config which corresponds to 'spec' + /** this is a mapped type of the config object at this level, replacing the object's values with specs on those values */ + spec: InputSpec; + /** indicates whether duplicates can be permitted in the list */ + "unique-by": UniqueBy; + /** this should be a handlebars template which can make use of the entire config which corresponds to 'spec' */ + "display-as": null | string; } export type UniqueBy = @@ -167,15 +164,18 @@ export type UniqueBy = export interface ListValueSpecUnion { tag: UnionTagSpec; variants: { [key: string]: InputSpec }; - "display-as": null | string; // this may be a handlebars template which can conditionally (on tag.id) make use of each union's entries, or if left blank will display as tag.id + /** this may be a handlebars template which can conditionally (on tag.id) make use of each union's entries, or if left blank will display as tag.id*/ + "display-as": null | string; "unique-by": UniqueBy; - default: string; // this should be the variantName which one prefers a user to start with by default when creating a new union instance in a list + /** this should be the variantName which one prefers a user to start with by default when creating a new union instance in a list*/ + default: string; } export interface UnionTagSpec { - id: string; // The name of the field containing one of the union variants + /** The name of the field containing one of the union variants*/ + id: string; "variant-names": { - // the name of each variant + /** the name of each variant*/ [variant: string]: string; }; name: string;