chore: Update the builder.

This commit is contained in:
BluJ
2023-03-31 09:30:11 -06:00
parent 0aab08585d
commit 26f544718b
10 changed files with 429 additions and 374 deletions

View File

@@ -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);
});
});

View File

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

View File

@@ -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,
});
}

View File

@@ -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);
}