mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-04-04 22:39:47 +00:00
chore: something about fixing the builder
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import camelCase from "lodash/camelCase";
|
import camelCase from "lodash/camelCase";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import { string } from "ts-matches";
|
||||||
|
|
||||||
export async function writeConvertedFile(
|
export async function writeConvertedFile(
|
||||||
file: string,
|
file: string,
|
||||||
@@ -97,14 +98,22 @@ export default async function makeFileContent(
|
|||||||
)})`;
|
)})`;
|
||||||
}
|
}
|
||||||
case "enum": {
|
case "enum": {
|
||||||
|
const allValueNames = new Set(
|
||||||
|
...value?.spec?.["values"] || [],
|
||||||
|
...Object.keys(value?.spec?.["value-names"] || {})
|
||||||
|
);
|
||||||
|
const values = Object.fromEntries(
|
||||||
|
Array.from(allValueNames)
|
||||||
|
.filter(string.test)
|
||||||
|
.map(key => [key, value?.spec?.["value-names"]?.[key] || key])
|
||||||
|
)
|
||||||
return `Value.select(${JSON.stringify(
|
return `Value.select(${JSON.stringify(
|
||||||
{
|
{
|
||||||
name: value.name || null,
|
name: value.name || null,
|
||||||
description: value.description || null,
|
description: value.description || null,
|
||||||
warning: value.warning || null,
|
warning: value.warning || null,
|
||||||
default: value.default || null,
|
default: value.default || null,
|
||||||
values: value.values || null,
|
values,
|
||||||
valueNames: value["value-names"] || null,
|
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
2
|
2
|
||||||
@@ -205,15 +214,23 @@ export default async function makeFileContent(
|
|||||||
)})`;
|
)})`;
|
||||||
}
|
}
|
||||||
case "enum": {
|
case "enum": {
|
||||||
|
const allValueNames = new Set(
|
||||||
|
...value?.spec?.["values"] || [],
|
||||||
|
...Object.keys(value?.spec?.["value-names"] || {})
|
||||||
|
);
|
||||||
|
const values = Object.fromEntries(
|
||||||
|
Array.from(allValueNames)
|
||||||
|
.filter(string.test)
|
||||||
|
.map(key => [key, value?.spec?.["value-names"]?.[key] || key])
|
||||||
|
)
|
||||||
return `Value.multiselect(${JSON.stringify(
|
return `Value.multiselect(${JSON.stringify(
|
||||||
{
|
{
|
||||||
name: value.name || null,
|
name: value.name || null,
|
||||||
range: value.range || null,
|
range: value.range || null,
|
||||||
values: value?.spec?.["values"] || null,
|
|
||||||
valueNames: value?.spec?.["value-names"] || {},
|
|
||||||
default: value.default || null,
|
default: value.default || null,
|
||||||
description: value.description || null,
|
description: value.description || null,
|
||||||
warning: value.warning || null,
|
warning: value.warning || null,
|
||||||
|
values,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
2
|
2
|
||||||
@@ -249,21 +266,7 @@ export default async function makeFileContent(
|
|||||||
name:${JSON.stringify(value.name || null)},
|
name:${JSON.stringify(value.name || null)},
|
||||||
range:${JSON.stringify(value.range || null)},
|
range:${JSON.stringify(value.range || null)},
|
||||||
spec: {
|
spec: {
|
||||||
tag: {
|
|
||||||
"id":${JSON.stringify(value?.spec?.tag?.["id"] || null)},
|
|
||||||
"name": ${JSON.stringify(
|
|
||||||
value?.spec?.tag?.name || null
|
|
||||||
)},
|
|
||||||
"description": ${JSON.stringify(
|
|
||||||
value?.spec?.tag?.description || null
|
|
||||||
)},
|
|
||||||
"warning": ${JSON.stringify(
|
|
||||||
value?.spec?.tag?.warning || null
|
|
||||||
)},
|
|
||||||
variantNames: ${JSON.stringify(
|
|
||||||
value?.spec?.tag?.["variant-names"] || {}
|
|
||||||
)},
|
|
||||||
},
|
|
||||||
variants: ${variants},
|
variants: ${variants},
|
||||||
displayAs: ${JSON.stringify(
|
displayAs: ${JSON.stringify(
|
||||||
value?.spec?.["display-as"] || null
|
value?.spec?.["display-as"] || null
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export interface ValueSpecNumber extends ListValueSpecNumber, WithStandalone {
|
|||||||
export interface ValueSpecSelect extends SelectBase, WithStandalone {
|
export interface ValueSpecSelect extends SelectBase, WithStandalone {
|
||||||
type: "select";
|
type: "select";
|
||||||
default: string;
|
default: string;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ValueSpecMultiselect extends SelectBase, WithStandalone {
|
export interface ValueSpecMultiselect extends SelectBase, WithStandalone {
|
||||||
|
|||||||
@@ -54,11 +54,7 @@ export const serialversion = Value.select({
|
|||||||
"description": "Return raw transaction or block hex with Segwit or non-SegWit serialization.",
|
"description": "Return raw transaction or block hex with Segwit or non-SegWit serialization.",
|
||||||
"warning": null,
|
"warning": null,
|
||||||
"default": "segwit",
|
"default": "segwit",
|
||||||
"values": [
|
"values": {}
|
||||||
"non-segwit",
|
|
||||||
"segwit"
|
|
||||||
],
|
|
||||||
"valueNames": {}
|
|
||||||
});
|
});
|
||||||
export const servertimeout = Value.number({
|
export const servertimeout = Value.number({
|
||||||
"name": "Rpc Server Timeout",
|
"name": "Rpc Server Timeout",
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import * as matches from "ts-matches";
|
import * as matches from "ts-matches";
|
||||||
|
import { Parser } from "ts-matches";
|
||||||
import { InputSpec, ValueSpec as ValueSpecAny } from "../types/config-types";
|
import { InputSpec, ValueSpec as ValueSpecAny } from "../types/config-types";
|
||||||
|
|
||||||
|
const { string, some, object, arrayOf, dictionary, unknown, number, literals, boolean, array } = matches
|
||||||
|
|
||||||
type TypeBoolean = "boolean";
|
type TypeBoolean = "boolean";
|
||||||
type TypeString = "string";
|
type TypeString = "string";
|
||||||
type TypeNumber = "number";
|
type TypeNumber = "number";
|
||||||
@@ -8,7 +11,6 @@ type TypeObject = "object";
|
|||||||
type TypeList = "list";
|
type TypeList = "list";
|
||||||
type TypeSelect = "select";
|
type TypeSelect = "select";
|
||||||
type TypeMultiselect = "multiselect";
|
type TypeMultiselect = "multiselect";
|
||||||
type TypePointer = "pointer";
|
|
||||||
type TypeUnion = "union";
|
type TypeUnion = "union";
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@@ -46,20 +48,22 @@ export type GuardList<A> =
|
|||||||
A extends { readonly type: TypeList, readonly subtype: infer B, spec?: {} } ? ReadonlyArray<GuardAll<Omit<A, "type"> & ({ type: B })>> :
|
A extends { readonly type: TypeList, readonly subtype: infer B, spec?: {} } ? ReadonlyArray<GuardAll<Omit<A, "type"> & ({ type: B })>> :
|
||||||
unknown
|
unknown
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
type GuardPointer<A> =
|
|
||||||
A extends { readonly type: TypePointer } ? (string | null) :
|
|
||||||
unknown
|
|
||||||
// prettier-ignore
|
|
||||||
type GuardSelect<A> =
|
type GuardSelect<A> =
|
||||||
A extends { readonly type: TypeSelect, readonly values: ArrayLike<infer B> } ? GuardDefaultNullable<A, B> :
|
A extends { readonly type: TypeSelect, variants: { [key in infer B & string]: string } } ? B :
|
||||||
unknown
|
unknown
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
type GuardMultiselect<A> =
|
type GuardMultiselect<A> =
|
||||||
A extends { readonly type: TypeMultiselect, readonly values: ArrayLike<infer B> } ? GuardDefaultNullable<A, B> :
|
A extends { readonly type: TypeMultiselect, variants: { [key in infer B & string]: string } } ? B[] :
|
||||||
unknown
|
unknown
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
type VariantValue<A> =
|
||||||
|
A extends { name: string, spec: infer B } ? { name: A['name'], spec: TypeFromProps<B> } :
|
||||||
|
never
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
type GuardUnion<A> =
|
type GuardUnion<A> =
|
||||||
A extends { readonly type: TypeUnion, readonly tag: { id: infer Id & string }, variants: infer Variants & Record<string, unknown> } ? { [K in keyof Variants]: { [keyType in Id & string]: K } & TypeFromProps<Variants[K]> }[keyof Variants] :
|
A extends { readonly type: TypeUnion, variants: infer Variants & Record<string, unknown> } ?
|
||||||
|
{ [K in keyof Variants]: { [key in K]: VariantValue<Variants[K]>['spec'] } }[keyof Variants] :
|
||||||
unknown
|
unknown
|
||||||
|
|
||||||
type _<T> = T;
|
type _<T> = T;
|
||||||
@@ -68,7 +72,6 @@ export type GuardAll<A> = GuardNumber<A> &
|
|||||||
GuardBoolean<A> &
|
GuardBoolean<A> &
|
||||||
GuardObject<A> &
|
GuardObject<A> &
|
||||||
GuardList<A> &
|
GuardList<A> &
|
||||||
GuardPointer<A> &
|
|
||||||
GuardUnion<A> &
|
GuardUnion<A> &
|
||||||
GuardSelect<A> &
|
GuardSelect<A> &
|
||||||
GuardMultiselect<A>;
|
GuardMultiselect<A>;
|
||||||
@@ -77,22 +80,25 @@ export type TypeFromProps<A> =
|
|||||||
A extends Record<string, unknown> ? { readonly [K in keyof A & string]: _<GuardAll<A[K]>> } :
|
A extends Record<string, unknown> ? { readonly [K in keyof A & string]: _<GuardAll<A[K]>> } :
|
||||||
unknown;
|
unknown;
|
||||||
|
|
||||||
const isType = matches.shape({ type: matches.string });
|
const isType = object({ type: string });
|
||||||
const recordString = matches.dictionary([matches.string, matches.unknown]);
|
const matchVariant = object({
|
||||||
const matchDefault = matches.shape({ default: matches.unknown });
|
name: string,
|
||||||
const matchNullable = matches.shape({ nullable: matches.literal(true) });
|
spec: unknown
|
||||||
const matchPattern = matches.shape({ pattern: matches.string });
|
})
|
||||||
|
const recordString = dictionary([string, unknown]);
|
||||||
|
const matchDefault = object({ default: unknown });
|
||||||
|
const matchNullable = object({ nullable: literals(true) });
|
||||||
|
const matchPattern = object({ pattern: string });
|
||||||
const rangeRegex = /(\[|\()(\*|(\d|\.)+),(\*|(\d|\.)+)(\]|\))/;
|
const rangeRegex = /(\[|\()(\*|(\d|\.)+),(\*|(\d|\.)+)(\]|\))/;
|
||||||
const matchRange = matches.shape({ range: matches.regex(rangeRegex) });
|
const matchRange = object({ range: string });
|
||||||
const matchIntegral = matches.shape({ integral: matches.literal(true) });
|
const matchIntegral = object({ integral: literals(true) });
|
||||||
const matchSpec = matches.shape({ spec: recordString });
|
const matchSpec = object({ spec: recordString });
|
||||||
const matchSubType = matches.shape({ subtype: matches.string });
|
const matchSubType = object({ subtype: string });
|
||||||
const matchUnion = matches.shape({
|
const matchUnion = object({
|
||||||
tag: matches.shape({ id: matches.string }),
|
variants: dictionary([string, matchVariant]),
|
||||||
variants: recordString,
|
|
||||||
});
|
});
|
||||||
const matchValues = matches.shape({
|
const matchValues = object({
|
||||||
values: matches.arrayOf(matches.string),
|
values: dictionary([string, string]),
|
||||||
});
|
});
|
||||||
|
|
||||||
function charRange(value = "") {
|
function charRange(value = "") {
|
||||||
@@ -142,15 +148,11 @@ export function generateDefault(
|
|||||||
return answer.join("");
|
return answer.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function withPattern<A>(value: unknown) {
|
|
||||||
if (matchPattern.test(value)) return matches.regex(RegExp(value.pattern));
|
|
||||||
return matches.string;
|
|
||||||
}
|
|
||||||
export function matchNumberWithRange(range: string) {
|
export function matchNumberWithRange(range: string) {
|
||||||
const matched = rangeRegex.exec(range);
|
const matched = rangeRegex.exec(range);
|
||||||
if (!matched) return matches.number;
|
if (!matched) return number;
|
||||||
const [, left, leftValue, , rightValue, , right] = matched;
|
const [, left, leftValue, , rightValue, , right] = matched;
|
||||||
return matches.number
|
return number
|
||||||
.validate(
|
.validate(
|
||||||
leftValue === "*"
|
leftValue === "*"
|
||||||
? (_) => true
|
? (_) => true
|
||||||
@@ -174,7 +176,7 @@ export function matchNumberWithRange(range: string) {
|
|||||||
`lessThan${rightValue}`
|
`lessThan${rightValue}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function withIntegral(parser: matches.Parser<unknown, number>, value: unknown) {
|
function withIntegral(parser: Parser<unknown, number>, value: unknown) {
|
||||||
if (matchIntegral.test(value)) {
|
if (matchIntegral.test(value)) {
|
||||||
return parser.validate(Number.isInteger, "isIntegral");
|
return parser.validate(Number.isInteger, "isIntegral");
|
||||||
}
|
}
|
||||||
@@ -184,14 +186,14 @@ function withRange(value: unknown) {
|
|||||||
if (matchRange.test(value)) {
|
if (matchRange.test(value)) {
|
||||||
return matchNumberWithRange(value.range);
|
return matchNumberWithRange(value.range);
|
||||||
}
|
}
|
||||||
return matches.number;
|
return number;
|
||||||
}
|
}
|
||||||
const isGenerator = matches.shape({
|
const isGenerator = object({
|
||||||
charset: matches.string,
|
charset: string,
|
||||||
len: matches.number,
|
len: number,
|
||||||
}).test;
|
}).test;
|
||||||
function defaultNullable<A>(
|
function defaultNullable<A>(
|
||||||
parser: matches.Parser<unknown, A>,
|
parser: Parser<unknown, A>,
|
||||||
value: unknown
|
value: unknown
|
||||||
) {
|
) {
|
||||||
if (matchDefault.test(value)) {
|
if (matchDefault.test(value)) {
|
||||||
@@ -216,16 +218,16 @@ function defaultNullable<A>(
|
|||||||
*/
|
*/
|
||||||
export function guardAll<A extends ValueSpecAny>(
|
export function guardAll<A extends ValueSpecAny>(
|
||||||
value: A
|
value: A
|
||||||
): matches.Parser<unknown, GuardAll<A>> {
|
): Parser<unknown, GuardAll<A>> {
|
||||||
if (!isType.test(value)) {
|
if (!isType.test(value)) {
|
||||||
return matches.unknown as any;
|
return unknown as any;
|
||||||
}
|
}
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case "boolean":
|
case "boolean":
|
||||||
return defaultNullable(matches.boolean, value) as any;
|
return defaultNullable(boolean, value) as any;
|
||||||
|
|
||||||
case "string":
|
case "string":
|
||||||
return defaultNullable(withPattern(value), value) as any;
|
return defaultNullable(string, value) as any;
|
||||||
|
|
||||||
case "number":
|
case "number":
|
||||||
return defaultNullable(
|
return defaultNullable(
|
||||||
@@ -237,7 +239,7 @@ export function guardAll<A extends ValueSpecAny>(
|
|||||||
if (matchSpec.test(value)) {
|
if (matchSpec.test(value)) {
|
||||||
return defaultNullable(typeFromProps(value.spec), value) as any;
|
return defaultNullable(typeFromProps(value.spec), value) as any;
|
||||||
}
|
}
|
||||||
return matches.unknown as any;
|
return unknown as any;
|
||||||
|
|
||||||
case "list": {
|
case "list": {
|
||||||
const spec = (matchSpec.test(value) && value.spec) || {};
|
const spec = (matchSpec.test(value) && value.spec) || {};
|
||||||
@@ -255,40 +257,40 @@ export function guardAll<A extends ValueSpecAny>(
|
|||||||
}
|
}
|
||||||
case "select":
|
case "select":
|
||||||
if (matchValues.test(value)) {
|
if (matchValues.test(value)) {
|
||||||
|
const valueKeys = Object.keys(value.values)
|
||||||
return defaultNullable(
|
return defaultNullable(
|
||||||
matches.literals(value.values[0], ...value.values),
|
literals(valueKeys[0], ...valueKeys),
|
||||||
value
|
value
|
||||||
) as any;
|
) as any;
|
||||||
}
|
}
|
||||||
return matches.unknown as any;
|
return unknown as any;
|
||||||
case "multiselect":
|
case "multiselect":
|
||||||
if (matchValues.test(value)) {
|
if (matchValues.test(value)) {
|
||||||
const rangeValidate =
|
const rangeValidate =
|
||||||
(matchRange.test(value) && matchNumberWithRange(value.range).test) ||
|
(matchRange.test(value) && matchNumberWithRange(value.range).test) ||
|
||||||
(() => true);
|
(() => true);
|
||||||
|
|
||||||
|
const valueKeys = Object.keys(value.values)
|
||||||
return defaultNullable(
|
return defaultNullable(
|
||||||
matches
|
matches
|
||||||
.literals(value.values[0], ...value.values)
|
.literals(valueKeys[0], ...valueKeys)
|
||||||
.validate((x) => rangeValidate(x.length), "valid length"),
|
.validate((x) => rangeValidate(x.length), "valid length"),
|
||||||
value
|
value
|
||||||
) as any;
|
) as any;
|
||||||
}
|
}
|
||||||
return matches.unknown as any;
|
return unknown as any;
|
||||||
case "union":
|
case "union":
|
||||||
if (matchUnion.test(value)) {
|
if (matchUnion.test(value)) {
|
||||||
return matches.some(
|
return some(
|
||||||
...Object.entries(value.variants).map(([variant, spec]) =>
|
...Object.entries(value.variants).map(([_, { spec }]) =>
|
||||||
matches
|
typeFromProps(spec)
|
||||||
.shape({ [value.tag.id]: matches.literal(variant) })
|
|
||||||
.concat(typeFromProps(spec))
|
|
||||||
)
|
)
|
||||||
) as any;
|
) as any;
|
||||||
}
|
}
|
||||||
return matches.unknown as any;
|
return unknown as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches.unknown as any;
|
return unknown as any;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* InputSpec: Tells the UI how to ask for information, verification, and will send the service a config in a shape via the spec.
|
* InputSpec: Tells the UI how to ask for information, verification, and will send the service a config in a shape via the spec.
|
||||||
@@ -300,9 +302,9 @@ export function guardAll<A extends ValueSpecAny>(
|
|||||||
*/
|
*/
|
||||||
export function typeFromProps<A extends InputSpec>(
|
export function typeFromProps<A extends InputSpec>(
|
||||||
valueDictionary: A
|
valueDictionary: A
|
||||||
): matches.Parser<unknown, TypeFromProps<A>> {
|
): Parser<unknown, TypeFromProps<A>> {
|
||||||
if (!recordString.test(valueDictionary)) return matches.unknown as any;
|
if (!recordString.test(valueDictionary)) return unknown as any;
|
||||||
return matches.shape(
|
return object(
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
Object.entries(valueDictionary).map(([key, value]) => [
|
Object.entries(valueDictionary).map(([key, value]) => [
|
||||||
key,
|
key,
|
||||||
|
|||||||
Reference in New Issue
Block a user