mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-30 04:11:57 +00:00
chore: Update the builder.
This commit is contained in:
@@ -3,10 +3,16 @@ describe("test", () => {
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
});
|
||||
import { values } from "lodash";
|
||||
import { Validator } from "ts-matches";
|
||||
import { testOutput } from "../../test/output.test";
|
||||
import { Config } from "./config";
|
||||
import { List } from "./list";
|
||||
import { Value } from "./value";
|
||||
import { Variants } from "./variants";
|
||||
describe("builder tests", () => {
|
||||
test("String", () => {
|
||||
console.log("BLUJ->");
|
||||
const bitcoinPropertiesBuilt: {
|
||||
"peer-tor-address": {
|
||||
name: string;
|
||||
@@ -19,7 +25,7 @@ describe("builder tests", () => {
|
||||
default: "",
|
||||
description: "The Tor address of the peer interface",
|
||||
warning: null,
|
||||
nullable: false,
|
||||
required: true,
|
||||
masked: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
@@ -30,15 +36,16 @@ describe("builder tests", () => {
|
||||
/*json*/ `{
|
||||
"peer-tor-address": {
|
||||
"type": "string",
|
||||
"name": "Peer tor address",
|
||||
"default": "",
|
||||
"description": "The Tor address of the peer interface",
|
||||
"warning": null,
|
||||
"nullable": false,
|
||||
"masked": true,
|
||||
"placeholder": null,
|
||||
"pattern": null,
|
||||
"patternDescription": null
|
||||
"patternDescription": null,
|
||||
"inputmode":"text",
|
||||
"name": "Peer tor address",
|
||||
"required": true
|
||||
}}`
|
||||
.replaceAll("\n", " ")
|
||||
.replaceAll(/\s{2,}/g, "")
|
||||
@@ -46,3 +53,115 @@ describe("builder tests", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("values", () => {
|
||||
test("boolean", () => {
|
||||
const value = Value.boolean({
|
||||
name: "Testing",
|
||||
});
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast(false);
|
||||
testOutput<typeof validator._TYPE, boolean>()(null);
|
||||
});
|
||||
test("string", () => {
|
||||
const value = Value.string({
|
||||
name: "Testing",
|
||||
required: false,
|
||||
});
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast("test text");
|
||||
testOutput<typeof validator._TYPE, string>()(null);
|
||||
});
|
||||
test("textarea", () => {
|
||||
const value = Value.textarea({
|
||||
name: "Testing",
|
||||
required: false,
|
||||
});
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast("test text");
|
||||
testOutput<typeof validator._TYPE, string>()(null);
|
||||
});
|
||||
test("number", () => {
|
||||
const value = Value.number({
|
||||
name: "Testing",
|
||||
required: false,
|
||||
integral: false,
|
||||
});
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast(2);
|
||||
testOutput<typeof validator._TYPE, number>()(null);
|
||||
});
|
||||
test("select", () => {
|
||||
const value = Value.select({
|
||||
name: "Testing",
|
||||
required: false,
|
||||
values: {
|
||||
a: "A",
|
||||
b: "B",
|
||||
},
|
||||
});
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast("a");
|
||||
validator.unsafeCast("b");
|
||||
testOutput<typeof validator._TYPE, "a" | "b">()(null);
|
||||
});
|
||||
test("multiselect", () => {
|
||||
const value = Value.multiselect({
|
||||
name: "Testing",
|
||||
values: {
|
||||
a: "A",
|
||||
b: "B",
|
||||
},
|
||||
});
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast([]);
|
||||
validator.unsafeCast(["a", "b"]);
|
||||
testOutput<typeof validator._TYPE, Array<"a" | "b">>()(null);
|
||||
});
|
||||
test("object", () => {
|
||||
const value = Value.object({
|
||||
name: "Testing",
|
||||
spec: Config.of({
|
||||
a: Value.boolean({
|
||||
name: "test",
|
||||
}),
|
||||
}),
|
||||
});
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast({ a: true });
|
||||
testOutput<typeof validator._TYPE, { a: boolean }>()(null);
|
||||
});
|
||||
test("union", () => {
|
||||
const value = Value.union(
|
||||
{
|
||||
name: "Testing",
|
||||
required: true,
|
||||
},
|
||||
Variants.of({
|
||||
a: {
|
||||
name: "a",
|
||||
spec: Config.of({ b: Value.boolean({ name: "b" }) }),
|
||||
},
|
||||
})
|
||||
);
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast({ unionSelectKey: "a", b: false });
|
||||
type Test = typeof validator._TYPE;
|
||||
testOutput<Test, { unionSelectKey: "a" } & { b: boolean }>()(null);
|
||||
});
|
||||
test("list", () => {
|
||||
const value = Value.list(
|
||||
List.number(
|
||||
{
|
||||
name: "test",
|
||||
},
|
||||
{
|
||||
integral: false,
|
||||
}
|
||||
)
|
||||
);
|
||||
const validator = value.validator();
|
||||
validator.unsafeCast([1, 2, 3]);
|
||||
testOutput<typeof validator._TYPE, number[]>()(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { BuilderExtract, IBuilder } from "./builder";
|
||||
import { Config } from "./config";
|
||||
import { InputSpec, UniqueBy, ValueSpecList } from "../config-types";
|
||||
import { InputSpec, ListValueSpecNumber, ListValueSpecString, UniqueBy, ValueSpecList } from "../config-types";
|
||||
import { guardAll } from "../../util";
|
||||
import { range } from "lodash";
|
||||
|
||||
/**
|
||||
* Used as a subtype of Value.list
|
||||
@@ -26,76 +27,115 @@ import { guardAll } from "../../util";
|
||||
```
|
||||
*/
|
||||
export class List<A extends ValueSpecList> extends IBuilder<A> {
|
||||
static string<
|
||||
A extends {
|
||||
static string(
|
||||
a: {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
default: string[];
|
||||
range: string;
|
||||
spec: {
|
||||
masked: boolean;
|
||||
placeholder: string | null;
|
||||
pattern: string | null;
|
||||
patternDescription: string | null;
|
||||
};
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
/** Default = [] */
|
||||
default?: string[];
|
||||
/** Default = "(\*,\*)" */
|
||||
range?: string;
|
||||
},
|
||||
aSpec: {
|
||||
/** Default = false */
|
||||
masked?: boolean;
|
||||
placeholder?: string | null;
|
||||
pattern?: string | null;
|
||||
patternDescription?: string | null;
|
||||
/** Default = "text" */
|
||||
inputmode?: ListValueSpecString["inputmode"];
|
||||
}
|
||||
>(a: A) {
|
||||
) {
|
||||
const spec = {
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
patternDescription: null,
|
||||
masked: false,
|
||||
inputmode: "text" as const,
|
||||
...aSpec,
|
||||
};
|
||||
return new List({
|
||||
description: null,
|
||||
warning: null,
|
||||
default: [],
|
||||
type: "list" as const,
|
||||
subtype: "string" as const,
|
||||
range: "(*,*)",
|
||||
...a,
|
||||
spec,
|
||||
});
|
||||
}
|
||||
static number<
|
||||
A extends {
|
||||
static number(
|
||||
a: {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
default: string[];
|
||||
range: string;
|
||||
spec: {
|
||||
range: string;
|
||||
integral: boolean;
|
||||
units: string | null;
|
||||
placeholder: string | null;
|
||||
};
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
/** Default = [] */
|
||||
default?: string[];
|
||||
/** Default = "(\*,\*)" */
|
||||
range?: string;
|
||||
},
|
||||
aSpec: {
|
||||
integral: boolean;
|
||||
/** Default = "(\*,\*)" */
|
||||
range?: string;
|
||||
units?: string | null;
|
||||
placeholder?: string | null;
|
||||
/** Default = "decimal" */
|
||||
inputmode?: ListValueSpecNumber["inputmode"];
|
||||
}
|
||||
>(a: A) {
|
||||
) {
|
||||
const spec = {
|
||||
placeholder: null,
|
||||
inputmode: "decimal" as const,
|
||||
range: "(*,*)",
|
||||
units: null,
|
||||
...aSpec,
|
||||
};
|
||||
return new List({
|
||||
description: null,
|
||||
warning: null,
|
||||
units: null,
|
||||
range: "(*,*)",
|
||||
default: [],
|
||||
type: "list" as const,
|
||||
subtype: "number" as const,
|
||||
...a,
|
||||
spec,
|
||||
});
|
||||
}
|
||||
static obj<
|
||||
A extends {
|
||||
static obj<Spec extends Config<InputSpec>>(
|
||||
a: {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
default: Record<string, unknown>[];
|
||||
range: string;
|
||||
spec: {
|
||||
spec: Config<InputSpec>;
|
||||
displayAs: null | string;
|
||||
uniqueBy: null | UniqueBy;
|
||||
};
|
||||
/** Default = "(\*,\*)" */
|
||||
range?: string;
|
||||
},
|
||||
aSpec: {
|
||||
spec: Spec;
|
||||
displayAs?: null | string;
|
||||
uniqueBy?: null | UniqueBy;
|
||||
}
|
||||
>(a: A) {
|
||||
const { spec: previousSpec, ...rest } = a;
|
||||
const { spec: previousSpecSpec, ...restSpec } = previousSpec;
|
||||
const specSpec = previousSpecSpec.build() as BuilderExtract<
|
||||
A["spec"]["spec"]
|
||||
>;
|
||||
) {
|
||||
const { spec: previousSpecSpec, ...restSpec } = aSpec;
|
||||
const specSpec = previousSpecSpec.build() as BuilderExtract<Spec>;
|
||||
const spec = {
|
||||
displayAs: null,
|
||||
uniqueBy: null,
|
||||
...restSpec,
|
||||
spec: specSpec,
|
||||
};
|
||||
const value = {
|
||||
spec,
|
||||
...rest,
|
||||
...a,
|
||||
};
|
||||
return new List({
|
||||
description: null,
|
||||
warning: null,
|
||||
range: "(*,*)",
|
||||
type: "list" as const,
|
||||
subtype: "object" as const,
|
||||
...value,
|
||||
|
||||
@@ -4,6 +4,8 @@ import { List } from "./list";
|
||||
import { Variants } from "./variants";
|
||||
import {
|
||||
InputSpec,
|
||||
ListValueSpecNumber,
|
||||
ListValueSpecString,
|
||||
ValueSpec,
|
||||
ValueSpecList,
|
||||
ValueSpecNumber,
|
||||
@@ -11,14 +13,7 @@ import {
|
||||
ValueSpecTextarea,
|
||||
} from "../config-types";
|
||||
import { guardAll } from "../../util";
|
||||
|
||||
export type DefaultString =
|
||||
| string
|
||||
| {
|
||||
charset: string | null | undefined;
|
||||
len: number;
|
||||
};
|
||||
|
||||
import { DefaultString } from "../config-types";
|
||||
/**
|
||||
* A value is going to be part of the form in the FE of the OS.
|
||||
* Something like a boolean, a string, a number, etc.
|
||||
@@ -43,132 +38,152 @@ export type DefaultString =
|
||||
```
|
||||
*/
|
||||
export class Value<A extends ValueSpec> extends IBuilder<A> {
|
||||
static boolean<
|
||||
A extends {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
default: boolean | null;
|
||||
}
|
||||
>(a: A) {
|
||||
static boolean(a: { name: string; description?: string | null; warning?: string | null; default?: boolean | null }) {
|
||||
return new Value({
|
||||
description: null,
|
||||
warning: null,
|
||||
default: null,
|
||||
type: "boolean" as const,
|
||||
...a,
|
||||
});
|
||||
}
|
||||
static string<
|
||||
A extends {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
nullable: boolean;
|
||||
default: DefaultString | null;
|
||||
masked: boolean | null;
|
||||
placeholder: string | null;
|
||||
pattern: string | null;
|
||||
patternDescription: string | null;
|
||||
}
|
||||
>(a: A) {
|
||||
static string(a: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
required: boolean;
|
||||
default?: DefaultString | null;
|
||||
/** Default = false */
|
||||
masked?: boolean;
|
||||
placeholder?: string | null;
|
||||
pattern?: string | null;
|
||||
patternDescription?: string | null;
|
||||
/** Default = 'text' */
|
||||
inputmode?: ListValueSpecString["inputmode"];
|
||||
}) {
|
||||
return new Value({
|
||||
type: "string" as const,
|
||||
default: null,
|
||||
description: null,
|
||||
warning: null,
|
||||
masked: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
patternDescription: null,
|
||||
inputmode: "text",
|
||||
...a,
|
||||
} as ValueSpecString);
|
||||
});
|
||||
}
|
||||
static textarea<
|
||||
A extends {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
nullable: boolean;
|
||||
placeholder: string | null;
|
||||
}
|
||||
>(a: A) {
|
||||
static textarea(a: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
required: boolean;
|
||||
placeholder?: string | null;
|
||||
}) {
|
||||
return new Value({
|
||||
description: null,
|
||||
warning: null,
|
||||
placeholder: null,
|
||||
type: "textarea" as const,
|
||||
...a,
|
||||
} as ValueSpecTextarea);
|
||||
}
|
||||
static number<
|
||||
A extends {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
nullable: boolean;
|
||||
default: number | null;
|
||||
range: string;
|
||||
integral: boolean;
|
||||
units: string | null;
|
||||
placeholder: string | null;
|
||||
}
|
||||
>(a: A) {
|
||||
static number(a: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
required: boolean;
|
||||
default?: number | null;
|
||||
/** default = "(\*,\*)" */
|
||||
range?: string;
|
||||
integral: boolean;
|
||||
units?: string | null;
|
||||
placeholder?: string | null;
|
||||
/** Default = 'decimal' */
|
||||
inputmode?: ListValueSpecNumber["inputmode"];
|
||||
}) {
|
||||
return new Value({
|
||||
type: "number" as const,
|
||||
inputmode: "decimal",
|
||||
description: null,
|
||||
warning: null,
|
||||
default: null,
|
||||
range: "(*,*)",
|
||||
units: null,
|
||||
placeholder: null,
|
||||
...a,
|
||||
} as ValueSpecNumber);
|
||||
}
|
||||
static select<
|
||||
A extends {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
nullable: boolean;
|
||||
default: string | null;
|
||||
values: B;
|
||||
},
|
||||
B extends Record<string, string>
|
||||
>(a: A) {
|
||||
static select<B extends Record<string, string>>(a: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
required: boolean;
|
||||
default?: string | null;
|
||||
values: B;
|
||||
}) {
|
||||
return new Value({
|
||||
description: null,
|
||||
warning: null,
|
||||
default: null,
|
||||
type: "select" as const,
|
||||
...a,
|
||||
});
|
||||
}
|
||||
static multiselect<
|
||||
A extends {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
default: string[];
|
||||
values: Record<string, string>;
|
||||
range: string;
|
||||
}
|
||||
>(a: A) {
|
||||
static multiselect<Values extends Record<string, string>>(a: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
default?: string[];
|
||||
values: Values;
|
||||
/** default = "(\*,\*)" */
|
||||
range?: string;
|
||||
}) {
|
||||
return new Value({
|
||||
type: "multiselect" as const,
|
||||
range: "(*,*)",
|
||||
warning: null,
|
||||
default: [],
|
||||
description: null,
|
||||
...a,
|
||||
});
|
||||
}
|
||||
static object<
|
||||
A extends {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
default: null | { [k: string]: unknown };
|
||||
spec: Config<InputSpec>;
|
||||
}
|
||||
>(a: A) {
|
||||
static object<Spec extends Config<InputSpec>>(a: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
default?: null | { [k: string]: unknown };
|
||||
spec: Spec;
|
||||
}) {
|
||||
const { spec: previousSpec, ...rest } = a;
|
||||
const spec = previousSpec.build() as BuilderExtract<A["spec"]>;
|
||||
const spec = previousSpec.build() as BuilderExtract<Spec>;
|
||||
return new Value({
|
||||
type: "object" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
default: null,
|
||||
...rest,
|
||||
spec,
|
||||
});
|
||||
}
|
||||
static union<
|
||||
A extends {
|
||||
static union<V extends Variants<{ [key: string]: { name: string; spec: InputSpec } }>>(
|
||||
a: {
|
||||
name: string;
|
||||
description: string | null;
|
||||
warning: string | null;
|
||||
variants: Variants<{ [key: string]: { name: string; spec: InputSpec } }>;
|
||||
nullable: boolean;
|
||||
default: string | null;
|
||||
}
|
||||
>(a: A) {
|
||||
const { variants: previousVariants, ...rest } = a;
|
||||
const variants = previousVariants.build() as BuilderExtract<A["variants"]>;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
required: boolean;
|
||||
default?: string | null;
|
||||
},
|
||||
aVariants: V
|
||||
) {
|
||||
const variants = aVariants.build() as BuilderExtract<V>;
|
||||
return new Value({
|
||||
type: "union" as const,
|
||||
...rest,
|
||||
description: null,
|
||||
warning: null,
|
||||
default: null,
|
||||
...a,
|
||||
variants,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,10 +67,7 @@ export class Variants<
|
||||
static empty() {
|
||||
return Variants.of({});
|
||||
}
|
||||
static withVariant<K extends string, B extends InputSpec>(
|
||||
key: K,
|
||||
value: Config<B>
|
||||
) {
|
||||
static withVariant<K extends string, B extends InputSpec>(key: K, value: Config<B>) {
|
||||
return Variants.empty().withVariant(key, value);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user