mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 02:11:56 +00:00
Merge pull request #2 from Start9Labs/feat/multiselect
Rename enum and add multiselect (replaces list of enums)
This commit is contained in:
@@ -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.",
|
||||
|
||||
@@ -59,24 +59,6 @@ export class List<A extends ValueSpecList> extends IBuilder<A> {
|
||||
...a,
|
||||
});
|
||||
}
|
||||
static enum<
|
||||
A extends Description &
|
||||
Default<string[]> & {
|
||||
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<Record<string, unknown>[]> & {
|
||||
|
||||
@@ -95,7 +95,7 @@ export class Value<A extends ValueSpec> extends IBuilder<A> {
|
||||
...a,
|
||||
} as ValueSpecNumber);
|
||||
}
|
||||
static enum<
|
||||
static select<
|
||||
A extends Description &
|
||||
Default<string> & {
|
||||
values: readonly string[] | string[];
|
||||
@@ -103,7 +103,7 @@ export class Value<A extends ValueSpec> extends IBuilder<A> {
|
||||
}
|
||||
>(a: A) {
|
||||
return new Value({
|
||||
type: "enum" as const,
|
||||
type: "select" as const,
|
||||
...a,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -4,22 +4,25 @@ export type ValueType =
|
||||
| "string"
|
||||
| "number"
|
||||
| "boolean"
|
||||
| "enum"
|
||||
| "select"
|
||||
| "multiselect"
|
||||
| "list"
|
||||
| "object"
|
||||
| "file"
|
||||
| "union";
|
||||
export type ValueSpec = ValueSpecOf<ValueType>;
|
||||
|
||||
// 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 ValueType> = T extends "string"
|
||||
? ValueSpecString
|
||||
: T extends "number"
|
||||
? 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,18 @@ 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";
|
||||
/**'[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules */
|
||||
range: string;
|
||||
default: string[];
|
||||
}
|
||||
|
||||
export interface ValueSpecBoolean extends WithStandalone {
|
||||
type: "boolean";
|
||||
default: boolean;
|
||||
@@ -61,7 +71,7 @@ export interface ValueSpecUnion {
|
||||
}
|
||||
|
||||
export interface ValueSpecFile extends WithStandalone {
|
||||
type: 'file';
|
||||
type: "file";
|
||||
placeholder: null | string;
|
||||
nullable: boolean;
|
||||
extensions: string[];
|
||||
@@ -78,31 +88,28 @@ export interface WithStandalone {
|
||||
warning: null | string;
|
||||
}
|
||||
|
||||
// no lists of booleans, lists
|
||||
export type ListValueSpecType =
|
||||
| "string"
|
||||
| "number"
|
||||
| "enum"
|
||||
| "object"
|
||||
| "union";
|
||||
export interface SelectBase {
|
||||
values: string[] | readonly string[];
|
||||
"value-names": { [value: string]: string };
|
||||
}
|
||||
|
||||
// represents a spec for the values of a list
|
||||
/** no lists of booleans, lists*/
|
||||
export type ListValueSpecType = "string" | "number" | "object" | "union";
|
||||
|
||||
/** represents a spec for the values of a list */
|
||||
export type ListValueSpecOf<T extends ListValueSpecType> = T extends "string"
|
||||
? ListValueSpecString
|
||||
: T extends "number"
|
||||
? ListValueSpecNumber
|
||||
: T extends "enum"
|
||||
? ListValueSpecEnum
|
||||
: T extends "object"
|
||||
? ListValueSpecObject
|
||||
: T extends "union"
|
||||
? ListValueSpecUnion
|
||||
: never;
|
||||
|
||||
// represents a spec for a list
|
||||
/** represents a spec for a list */
|
||||
export type ValueSpecList = ValueSpecListOf<ListValueSpecType>;
|
||||
export interface ValueSpecListOf<T extends ListValueSpecType>
|
||||
extends WithStandalone {
|
||||
export interface ValueSpecListOf<T extends ListValueSpecType> extends WithStandalone {
|
||||
type: "list";
|
||||
subtype: T;
|
||||
spec: ListValueSpecOf<T>;
|
||||
@@ -119,10 +126,7 @@ export interface ValueSpecListOf<T extends ListValueSpecType>
|
||||
}
|
||||
|
||||
// sometimes the type checker needs just a little bit of help
|
||||
export function isValueSpecListOf<S extends ListValueSpecType>(
|
||||
t: ValueSpecList,
|
||||
s: S
|
||||
): t is ValueSpecListOf<S> {
|
||||
export function isValueSpecListOf<S extends ListValueSpecType>(t: ValueSpecList, s: S): t is ValueSpecListOf<S> {
|
||||
return t.subtype === s;
|
||||
}
|
||||
|
||||
@@ -134,21 +138,20 @@ export interface ListValueSpecString {
|
||||
}
|
||||
|
||||
export interface ListValueSpecNumber {
|
||||
/** '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules */
|
||||
range: string;
|
||||
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
|
||||
"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 =
|
||||
@@ -161,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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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> =
|
||||
A extends {readonly type:TypePointer} ? (string | null) :
|
||||
unknown
|
||||
// prettier-ignore
|
||||
type GuardEnum<A> =
|
||||
A extends {readonly type:TypeEnum, readonly values: ArrayLike<infer B>} ? GuardDefaultNullable<A, B> :
|
||||
type GuardSelect<A> =
|
||||
A extends {readonly type:TypeSelect, readonly values: ArrayLike<infer B>} ? GuardDefaultNullable<A, B> :
|
||||
unknown
|
||||
// prettier-ignore
|
||||
type GuardMultiselect<A> =
|
||||
A extends {readonly type:TypeMultiselect, readonly values: ArrayLike<infer B>} ? GuardDefaultNullable<A, B> :
|
||||
unknown
|
||||
// prettier-ignore
|
||||
type GuardUnion<A> =
|
||||
@@ -65,7 +70,8 @@ export type GuardAll<A> = GuardNumber<A> &
|
||||
GuardList<A> &
|
||||
GuardPointer<A> &
|
||||
GuardUnion<A> &
|
||||
GuardEnum<A>;
|
||||
GuardSelect<A> &
|
||||
GuardMultiselect<A>;
|
||||
// prettier-ignore
|
||||
export type TypeFromProps<A> =
|
||||
A extends Record<string, unknown> ? {readonly [K in keyof A & string]: _<GuardAll<A[K]>>} :
|
||||
@@ -247,7 +253,7 @@ export function guardAll<A extends ValueSpecAny>(
|
||||
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<A extends ValueSpecAny>(
|
||||
) 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(
|
||||
|
||||
Reference in New Issue
Block a user