chore: something about fixing the builder

This commit is contained in:
BluJ
2023-03-27 14:10:36 -06:00
parent 56c775e9a4
commit 736395d25e
4 changed files with 201 additions and 199 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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,