mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 02:11:56 +00:00
wip
This commit is contained in:
@@ -105,7 +105,8 @@ export type ListValueSpecOf<T extends ListValueSpecType> = T extends "string"
|
||||
|
||||
/** 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>;
|
||||
@@ -122,7 +123,10 @@ export interface ValueSpecListOf<T extends ListValueSpecType> extends WithStanda
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ writeConvertedFile(
|
||||
tag: {
|
||||
id: "type",
|
||||
name: "Type",
|
||||
description: "- LND: Lightning Network Daemon from Lightning Labs\n- CLN: Core Lightning from Blockstream\n",
|
||||
description:
|
||||
"- LND: Lightning Network Daemon from Lightning Labs\n- CLN: Core Lightning from Blockstream\n",
|
||||
"variant-names": {
|
||||
lnd: "Lightning Network Daemon (LND)",
|
||||
"c-lightning": "Core Lightning (CLN)",
|
||||
@@ -57,7 +58,8 @@ writeConvertedFile(
|
||||
default: "bitcoin",
|
||||
masked: true,
|
||||
pattern: "^[a-zA-Z0-9_]+$",
|
||||
"pattern-description": "Must be alphanumeric (can contain underscore).",
|
||||
"pattern-description":
|
||||
"Must be alphanumeric (can contain underscore).",
|
||||
},
|
||||
password: {
|
||||
type: "string",
|
||||
@@ -69,7 +71,8 @@ writeConvertedFile(
|
||||
len: 20,
|
||||
},
|
||||
pattern: '^[^\\n"]*$',
|
||||
"pattern-description": "Must not contain newline or quote characters.",
|
||||
"pattern-description":
|
||||
"Must not contain newline or quote characters.",
|
||||
copyable: true,
|
||||
masked: true,
|
||||
},
|
||||
@@ -86,15 +89,18 @@ writeConvertedFile(
|
||||
subtype: "string",
|
||||
default: [],
|
||||
spec: {
|
||||
pattern: "^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$",
|
||||
"pattern-description": 'Each item must be of the form "<USERNAME>:<SALT>$<HASH>".',
|
||||
pattern:
|
||||
"^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$",
|
||||
"pattern-description":
|
||||
'Each item must be of the form "<USERNAME>:<SALT>$<HASH>".',
|
||||
masked: false,
|
||||
},
|
||||
range: "[0,*)",
|
||||
},
|
||||
serialversion: {
|
||||
name: "Serialization Version",
|
||||
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.",
|
||||
type: "enum",
|
||||
values: ["non-segwit", "segwit"],
|
||||
"value-names": {},
|
||||
@@ -102,7 +108,8 @@ writeConvertedFile(
|
||||
},
|
||||
servertimeout: {
|
||||
name: "Rpc Server Timeout",
|
||||
description: "Number of seconds after which an uncompleted RPC call will time out.",
|
||||
description:
|
||||
"Number of seconds after which an uncompleted RPC call will time out.",
|
||||
type: "number",
|
||||
nullable: false,
|
||||
range: "[5,300]",
|
||||
@@ -205,7 +212,8 @@ writeConvertedFile(
|
||||
type: "number",
|
||||
nullable: false,
|
||||
name: "Max Mempool Size",
|
||||
description: "Keep the transaction memory pool below <n> megabytes.",
|
||||
description:
|
||||
"Keep the transaction memory pool below <n> megabytes.",
|
||||
range: "[1,*)",
|
||||
integral: true,
|
||||
units: "MiB",
|
||||
@@ -215,7 +223,8 @@ writeConvertedFile(
|
||||
type: "number",
|
||||
nullable: false,
|
||||
name: "Mempool Expiration",
|
||||
description: "Do not keep transactions in the mempool longer than <n> hours.",
|
||||
description:
|
||||
"Do not keep transactions in the mempool longer than <n> hours.",
|
||||
range: "[1,*)",
|
||||
integral: true,
|
||||
units: "Hr",
|
||||
@@ -231,7 +240,8 @@ writeConvertedFile(
|
||||
listen: {
|
||||
type: "boolean",
|
||||
name: "Make Public",
|
||||
description: "Allow other nodes to find your server on the network.",
|
||||
description:
|
||||
"Allow other nodes to find your server on the network.",
|
||||
default: true,
|
||||
},
|
||||
onlyconnect: {
|
||||
@@ -271,7 +281,8 @@ writeConvertedFile(
|
||||
type: "number",
|
||||
nullable: true,
|
||||
name: "Port",
|
||||
description: "Port that peer is listening on for inbound p2p connections",
|
||||
description:
|
||||
"Port that peer is listening on for inbound p2p connections",
|
||||
range: "[0,65535]",
|
||||
integral: true,
|
||||
},
|
||||
@@ -295,7 +306,8 @@ writeConvertedFile(
|
||||
pruning: {
|
||||
type: "union",
|
||||
name: "Pruning Settings",
|
||||
description: "Blockchain Pruning Options\nReduce the blockchain size on disk\n",
|
||||
description:
|
||||
"Blockchain Pruning Options\nReduce the blockchain size on disk\n",
|
||||
warning:
|
||||
"If you set pruning to Manual and your disk is smaller than the total size of the blockchain, you MUST have something running that prunes these blocks or you may overfill your disk!\nDisabling pruning will convert your node into a full archival node. This requires a resync of the entire blockchain, a process that may take several days. Make sure you have enough free disk space or you may fill up your disk.\n",
|
||||
tag: {
|
||||
@@ -317,7 +329,8 @@ writeConvertedFile(
|
||||
nullable: false,
|
||||
name: "Max Chain Size",
|
||||
description: "Limit of blockchain size on disk.",
|
||||
warning: "Increasing this value will require re-syncing your node.",
|
||||
warning:
|
||||
"Increasing this value will require re-syncing your node.",
|
||||
default: 550,
|
||||
range: "[550,1000000)",
|
||||
integral: true,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { UnionSelectKey, unionSelectKey } from "../config/config-types";
|
||||
import { InputSpec, matchInputSpec, threads } from "./output";
|
||||
|
||||
type IfEquals<T, U, Y = unknown, N = never> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2
|
||||
type IfEquals<T, U, Y = unknown, N = never> = (<G>() => G extends T
|
||||
? 1
|
||||
: 2) extends <G>() => G extends U ? 1 : 2
|
||||
? Y
|
||||
: N;
|
||||
function testOutput<A, B>(): (c: IfEquals<A, B>) => null {
|
||||
@@ -11,7 +13,11 @@ function testOutput<A, B>(): (c: IfEquals<A, B>) => null {
|
||||
function isObject(item: unknown): item is object {
|
||||
return !!(item && typeof item === "object" && !Array.isArray(item));
|
||||
}
|
||||
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;
|
||||
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (
|
||||
x: infer R
|
||||
) => any
|
||||
? R
|
||||
: never;
|
||||
export function mergeDeep<A extends unknown[]>(...sources: A) {
|
||||
return _mergeDeep({}, ...sources);
|
||||
}
|
||||
@@ -43,12 +49,22 @@ testOutput<InputSpec["rpc"]["enable"], boolean>()(null);
|
||||
testOutput<InputSpec["rpc"]["username"], string>()(null);
|
||||
|
||||
testOutput<InputSpec["rpc"]["advanced"]["auth"], string[]>()(null);
|
||||
testOutput<InputSpec["rpc"]["advanced"]["serialversion"], "segwit" | "non-segwit">()(null);
|
||||
testOutput<
|
||||
InputSpec["rpc"]["advanced"]["serialversion"],
|
||||
"segwit" | "non-segwit"
|
||||
>()(null);
|
||||
testOutput<InputSpec["rpc"]["advanced"]["servertimeout"], number>()(null);
|
||||
testOutput<InputSpec["advanced"]["peers"]["addnode"][0]["hostname"], string>()(null);
|
||||
testOutput<InputSpec["testListUnion"][0][UnionSelectKey]["name"], string>()(null);
|
||||
testOutput<InputSpec["testListUnion"][0][UnionSelectKey][UnionSelectKey], "lnd">()(null);
|
||||
|
||||
testOutput<InputSpec["advanced"]["peers"]["addnode"][0]["hostname"], string>()(
|
||||
null
|
||||
);
|
||||
testOutput<InputSpec["testListUnion"][0][UnionSelectKey]["name"], string>()(
|
||||
null
|
||||
);
|
||||
testOutput<
|
||||
InputSpec["testListUnion"][0][UnionSelectKey][UnionSelectKey],
|
||||
"lnd"
|
||||
>()(null);
|
||||
// prettier-ignore
|
||||
// @ts-expect-error Expect that the string is the one above
|
||||
testOutput<InputSpec["testListUnion"][0][UnionSelectKey][UnionSelectKey], "unionSelectKey">()(null);
|
||||
|
||||
@@ -110,12 +126,20 @@ describe("Inputs", () => {
|
||||
});
|
||||
test("test errors", () => {
|
||||
expect(() =>
|
||||
matchInputSpec.unsafeCast(mergeDeep(validInput, { rpc: { advanced: { threads: 0 } } }))
|
||||
matchInputSpec.unsafeCast(
|
||||
mergeDeep(validInput, { rpc: { advanced: { threads: 0 } } })
|
||||
)
|
||||
).toThrowError();
|
||||
expect(() =>
|
||||
matchInputSpec.unsafeCast(mergeDeep(validInput, { rpc: { enable: 2 } }))
|
||||
).toThrowError();
|
||||
expect(() => matchInputSpec.unsafeCast(mergeDeep(validInput, { rpc: { enable: 2 } }))).toThrowError();
|
||||
|
||||
expect(() =>
|
||||
matchInputSpec.unsafeCast(mergeDeep(validInput, { rpc: { advanced: { serialversion: "testing" } } }))
|
||||
matchInputSpec.unsafeCast(
|
||||
mergeDeep(validInput, {
|
||||
rpc: { advanced: { serialversion: "testing" } },
|
||||
})
|
||||
)
|
||||
).toThrowError();
|
||||
matchInputSpec.unsafeCast(validInput);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import * as matches from "ts-matches";
|
||||
import { Parser } from "ts-matches";
|
||||
import { InputSpec, unionSelectKey, ValueSpec as ValueSpecAny } from "../config/config-types";
|
||||
import {
|
||||
InputSpec,
|
||||
unionSelectKey,
|
||||
ValueSpec as ValueSpecAny,
|
||||
} from "../config/config-types";
|
||||
|
||||
const { string, some, object, dictionary, unknown, number, literals, boolean } = matches;
|
||||
const { string, some, object, dictionary, unknown, number, literals, boolean } =
|
||||
matches;
|
||||
|
||||
type TypeBoolean = "boolean";
|
||||
type TypeString = "string";
|
||||
@@ -118,18 +123,28 @@ function charRange(value = "") {
|
||||
* @param param1
|
||||
* @returns
|
||||
*/
|
||||
export function generateDefault(generate: { charset: string; len: number }, { random = () => Math.random() } = {}) {
|
||||
const validCharSets: number[][] = generate.charset.split(",").map(charRange).filter(Array.isArray);
|
||||
export function generateDefault(
|
||||
generate: { charset: string; len: number },
|
||||
{ random = () => Math.random() } = {}
|
||||
) {
|
||||
const validCharSets: number[][] = generate.charset
|
||||
.split(",")
|
||||
.map(charRange)
|
||||
.filter(Array.isArray);
|
||||
if (validCharSets.length === 0) {
|
||||
throw new Error("Expecing that we have a valid charset");
|
||||
}
|
||||
const max = validCharSets.reduce((acc, x) => x.reduce((x, y) => Math.max(x, y), acc), 0);
|
||||
const max = validCharSets.reduce(
|
||||
(acc, x) => x.reduce((x, y) => Math.max(x, y), acc),
|
||||
0
|
||||
);
|
||||
let i = 0;
|
||||
const answer: string[] = Array(generate.len);
|
||||
while (i < generate.len) {
|
||||
const nextValue = Math.round(random() * max);
|
||||
const inRange = validCharSets.reduce(
|
||||
(acc, [lower, upper]) => acc || (nextValue >= lower && nextValue <= upper),
|
||||
(acc, [lower, upper]) =>
|
||||
acc || (nextValue >= lower && nextValue <= upper),
|
||||
false
|
||||
);
|
||||
if (!inRange) continue;
|
||||
@@ -145,8 +160,16 @@ export function matchNumberWithRange(range: string) {
|
||||
const [, left, leftValue, , rightValue, , right] = matched;
|
||||
return number
|
||||
.validate(
|
||||
leftValue === "*" ? (_) => true : left === "[" ? (x) => x >= Number(leftValue) : (x) => x > Number(leftValue),
|
||||
leftValue === "*" ? "any" : left === "[" ? `greaterThanOrEqualTo${leftValue}` : `greaterThan${leftValue}`
|
||||
leftValue === "*"
|
||||
? (_) => true
|
||||
: left === "["
|
||||
? (x) => x >= Number(leftValue)
|
||||
: (x) => x > Number(leftValue),
|
||||
leftValue === "*"
|
||||
? "any"
|
||||
: left === "["
|
||||
? `greaterThanOrEqualTo${leftValue}`
|
||||
: `greaterThan${leftValue}`
|
||||
)
|
||||
.validate(
|
||||
// prettier-ignore
|
||||
@@ -178,7 +201,9 @@ const isGenerator = object({
|
||||
function defaultNullable<A>(parser: Parser<unknown, A>, value: unknown) {
|
||||
if (matchDefault.test(value)) {
|
||||
if (isGenerator(value.default)) {
|
||||
return parser.defaultTo(parser.unsafeCast(generateDefault(value.default)));
|
||||
return parser.defaultTo(
|
||||
parser.unsafeCast(generateDefault(value.default))
|
||||
);
|
||||
}
|
||||
return parser.defaultTo(value.default);
|
||||
}
|
||||
@@ -194,7 +219,9 @@ function defaultNullable<A>(parser: Parser<unknown, A>, value: unknown) {
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
export function guardAll<A extends ValueSpecAny>(value: A): Parser<unknown, GuardAll<A>> {
|
||||
export function guardAll<A extends ValueSpecAny>(
|
||||
value: A
|
||||
): Parser<unknown, GuardAll<A>> {
|
||||
if (!isType.test(value)) {
|
||||
return unknown as any;
|
||||
}
|
||||
@@ -206,7 +233,10 @@ export function guardAll<A extends ValueSpecAny>(value: A): Parser<unknown, Guar
|
||||
return defaultNullable(string, value) as any;
|
||||
|
||||
case "number":
|
||||
return defaultNullable(withIntegral(withRange(value), value), value) as any;
|
||||
return defaultNullable(
|
||||
withIntegral(withRange(value), value),
|
||||
value
|
||||
) as any;
|
||||
|
||||
case "object":
|
||||
if (matchSpec.test(value)) {
|
||||
@@ -216,7 +246,9 @@ export function guardAll<A extends ValueSpecAny>(value: A): Parser<unknown, Guar
|
||||
|
||||
case "list": {
|
||||
const spec = (matchSpec.test(value) && value.spec) || {};
|
||||
const rangeValidate = (matchRange.test(value) && matchNumberWithRange(value.range).test) || (() => true);
|
||||
const rangeValidate =
|
||||
(matchRange.test(value) && matchNumberWithRange(value.range).test) ||
|
||||
(() => true);
|
||||
|
||||
const subtype = matchSubType.unsafeCast(value).subtype;
|
||||
return defaultNullable(
|
||||
@@ -229,23 +261,34 @@ export function guardAll<A extends ValueSpecAny>(value: A): Parser<unknown, Guar
|
||||
case "select":
|
||||
if (matchValues.test(value)) {
|
||||
const valueKeys = Object.keys(value.values);
|
||||
return defaultNullable(literals(valueKeys[0], ...valueKeys), value) as any;
|
||||
return defaultNullable(
|
||||
literals(valueKeys[0], ...valueKeys),
|
||||
value
|
||||
) as any;
|
||||
}
|
||||
return unknown as any;
|
||||
case "multiselect":
|
||||
if (matchValues.test(value)) {
|
||||
const rangeValidate = (matchRange.test(value) && matchNumberWithRange(value.range).test) || (() => true);
|
||||
const rangeValidate =
|
||||
(matchRange.test(value) && matchNumberWithRange(value.range).test) ||
|
||||
(() => true);
|
||||
|
||||
const valueKeys = Object.keys(value.values);
|
||||
return defaultNullable(
|
||||
matches.literals(valueKeys[0], ...valueKeys).validate((x) => rangeValidate(x.length), "valid length"),
|
||||
matches
|
||||
.literals(valueKeys[0], ...valueKeys)
|
||||
.validate((x) => rangeValidate(x.length), "valid length"),
|
||||
value
|
||||
) as any;
|
||||
}
|
||||
return unknown as any;
|
||||
case "union":
|
||||
if (matchUnion.test(value)) {
|
||||
return some(...Object.entries(value.variants).map(([_, { spec }]) => typeFromProps(spec))) as any;
|
||||
return some(
|
||||
...Object.entries(value.variants).map(([_, { spec }]) =>
|
||||
typeFromProps(spec)
|
||||
)
|
||||
) as any;
|
||||
}
|
||||
return unknown as any;
|
||||
}
|
||||
@@ -260,9 +303,16 @@ export function guardAll<A extends ValueSpecAny>(value: A): Parser<unknown, Guar
|
||||
* @param valueDictionary
|
||||
* @returns
|
||||
*/
|
||||
export function typeFromProps<A extends InputSpec>(valueDictionary: A): Parser<unknown, TypeFromProps<A>> {
|
||||
export function typeFromProps<A extends InputSpec>(
|
||||
valueDictionary: A
|
||||
): Parser<unknown, TypeFromProps<A>> {
|
||||
if (!recordString.test(valueDictionary)) return unknown as any;
|
||||
return object(
|
||||
Object.fromEntries(Object.entries(valueDictionary).map(([key, value]) => [key, guardAll(value)]))
|
||||
Object.fromEntries(
|
||||
Object.entries(valueDictionary).map(([key, value]) => [
|
||||
key,
|
||||
guardAll(value),
|
||||
])
|
||||
)
|
||||
) as any;
|
||||
}
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "start-sdk",
|
||||
"version": "0.4.0-lib0.beta3",
|
||||
"version": "0.4.0-lib0.beta4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "start-sdk",
|
||||
"version": "0.4.0-lib0.beta3",
|
||||
"version": "0.4.0-lib0.beta4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "start-sdk",
|
||||
"version": "0.4.0-lib0.beta3",
|
||||
"version": "0.4.0-lib0.beta4",
|
||||
"description": "For making the patterns that are wanted in making services for the startOS.",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
|
||||
@@ -8,10 +8,15 @@ export async function writeConvertedFile(
|
||||
inputData: Promise<any> | any,
|
||||
options: Parameters<typeof makeFileContent>[1]
|
||||
) {
|
||||
await fs.writeFile(file, await makeFileContent(inputData, options), (err) => console.error(err));
|
||||
await fs.writeFile(file, await makeFileContent(inputData, options), (err) =>
|
||||
console.error(err)
|
||||
);
|
||||
}
|
||||
|
||||
export default async function makeFileContent(inputData: Promise<any> | any, { startSdk = "start-sdk" } = {}) {
|
||||
export default async function makeFileContent(
|
||||
inputData: Promise<any> | any,
|
||||
{ startSdk = "start-sdk" } = {}
|
||||
) {
|
||||
const outputLines: string[] = [];
|
||||
outputLines.push(`
|
||||
import {Config, Value, List, Variants} from '${startSdk}/config/builder';
|
||||
@@ -20,8 +25,13 @@ export default async function makeFileContent(inputData: Promise<any> | any, { s
|
||||
|
||||
const namedConsts = new Set(["Config", "Value", "List"]);
|
||||
const configName = newConst("InputSpec", convertInputSpec(data));
|
||||
const configMatcherName = newConst("matchInputSpec", `${configName}.validator()`);
|
||||
outputLines.push(`export type InputSpec = typeof ${configMatcherName}._TYPE;`);
|
||||
const configMatcherName = newConst(
|
||||
"matchInputSpec",
|
||||
`${configName}.validator()`
|
||||
);
|
||||
outputLines.push(
|
||||
`export type InputSpec = typeof ${configMatcherName}._TYPE;`
|
||||
);
|
||||
|
||||
return outputLines.join("\n");
|
||||
|
||||
@@ -89,7 +99,10 @@ export default async function makeFileContent(inputData: Promise<any> | any, { s
|
||||
)})`;
|
||||
}
|
||||
case "enum": {
|
||||
const allValueNames = new Set([...(value?.["values"] || []), ...Object.keys(value?.["value-names"] || {})]);
|
||||
const allValueNames = new Set([
|
||||
...(value?.["values"] || []),
|
||||
...Object.keys(value?.["value-names"] || {}),
|
||||
]);
|
||||
const values = Object.fromEntries(
|
||||
Array.from(allValueNames)
|
||||
.filter(string.test)
|
||||
@@ -109,7 +122,10 @@ export default async function makeFileContent(inputData: Promise<any> | any, { s
|
||||
)} as const)`;
|
||||
}
|
||||
case "object": {
|
||||
const specName = newConst(value.name + "_spec", convertInputSpec(value.spec));
|
||||
const specName = newConst(
|
||||
value.name + "_spec",
|
||||
convertInputSpec(value.spec)
|
||||
);
|
||||
return `Value.object({
|
||||
name: ${JSON.stringify(value.name || null)},
|
||||
description: ${JSON.stringify(value.description || null)},
|
||||
@@ -209,7 +225,10 @@ export default async function makeFileContent(inputData: Promise<any> | any, { s
|
||||
)})`;
|
||||
}
|
||||
case "object": {
|
||||
const specName = newConst(value.name + "_spec", convertInputSpec(value.spec.spec));
|
||||
const specName = newConst(
|
||||
value.name + "_spec",
|
||||
convertInputSpec(value.spec.spec)
|
||||
);
|
||||
return `List.obj({
|
||||
name: ${JSON.stringify(value.name || null)},
|
||||
range: ${JSON.stringify(value.range || null)},
|
||||
@@ -226,14 +245,19 @@ export default async function makeFileContent(inputData: Promise<any> | any, { s
|
||||
case "union": {
|
||||
const variants = newConst(
|
||||
value.name + "_variants",
|
||||
convertVariants(value.spec.variants, value.spec["variant-names"] || {})
|
||||
convertVariants(
|
||||
value.spec.variants,
|
||||
value.spec["variant-names"] || {}
|
||||
)
|
||||
);
|
||||
const unionValueName = newConst(
|
||||
value.name + "_union",
|
||||
`
|
||||
Value.union({
|
||||
name: ${JSON.stringify(value?.spec?.tag?.name || null)},
|
||||
description: ${JSON.stringify(value?.spec?.tag?.description || null)},
|
||||
description: ${JSON.stringify(
|
||||
value?.spec?.tag?.description || null
|
||||
)},
|
||||
warning: ${JSON.stringify(value?.spec?.tag?.warning || null)},
|
||||
variants: ${variants},
|
||||
nullable: ${JSON.stringify(value?.spec?.tag?.nullable || false)},
|
||||
@@ -267,11 +291,16 @@ export default async function makeFileContent(inputData: Promise<any> | any, { s
|
||||
throw new Error(`Unknown subtype "${value.subtype}"`);
|
||||
}
|
||||
|
||||
function convertVariants(variants: Record<string, unknown>, variantNames: Record<string, string>): string {
|
||||
function convertVariants(
|
||||
variants: Record<string, unknown>,
|
||||
variantNames: Record<string, string>
|
||||
): string {
|
||||
let answer = "Variants.of({";
|
||||
for (const [key, value] of Object.entries(variants)) {
|
||||
const variantSpec = newConst(key, convertInputSpec(value));
|
||||
answer += `"${key}": {name: "${variantNames[key] || key}", spec: ${variantSpec}},`;
|
||||
answer += `"${key}": {name: "${
|
||||
variantNames[key] || key
|
||||
}", spec: ${variantSpec}},`;
|
||||
}
|
||||
return `${answer}})`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user