chore: Make the expanded types extended, so that way we know we are outputing the correct type.

This commit is contained in:
BluJ
2023-02-13 10:36:11 -07:00
parent 894084db5b
commit c685e9e169
5 changed files with 68 additions and 53 deletions

View File

@@ -1,17 +1,18 @@
import { ConfigSpec, ValueSpecAny } from "../types.ts";
import { BuilderExtract, IBuilder } from "./builder.ts"; import { BuilderExtract, IBuilder } from "./builder.ts";
import { Value } from "./value.ts"; import { Value } from "./value.ts";
export class Config<A> extends IBuilder<A> { export class Config<A extends ConfigSpec> extends IBuilder<A> {
static empty() { static empty() {
return new Config({}); return new Config({});
} }
static withValue<K extends string, B>(key: K, value: Value<B>) { static withValue<K extends string, B extends ValueSpecAny>(key: K, value: Value<B>) {
return new Config({ return new Config({
[key]: value.build(), [key]: value.build(),
} as { [key in K]: B }); } as { [key in K]: B });
} }
static of<B extends { [key: string]: Value<unknown> }>(spec: B) { static of<B extends { [key: string]: Value<C> }, C extends ValueSpecAny>(spec: B) {
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
const answer: { [K in keyof B]: BuilderExtract<B[K]> } = {} as any; const answer: { [K in keyof B]: BuilderExtract<B[K]> } = {} as any;
for (const key in spec) { for (const key in spec) {
@@ -20,7 +21,7 @@ export class Config<A> extends IBuilder<A> {
} }
return new Config(answer); return new Config(answer);
} }
addValue<K extends string, B>(key: K, value: Value<B>) { addValue<K extends string, B extends ValueSpecAny>(key: K, value: Value<B>) {
return new Config({ return new Config({
...this.a, ...this.a,
[key]: value.build(), [key]: value.build(),

View File

@@ -1,28 +1,32 @@
import { UniqueBy } from "../types.ts"; import { ConfigSpec, Tag, UniqueBy, ValueSpecList } from "../types.ts";
import { BuilderExtract, IBuilder } from "./builder.ts"; import { BuilderExtract, IBuilder } from "./builder.ts";
import { Config } from "./config.ts"; import { Config } from "./config.ts";
import { Default, NullableDefault, NumberSpec, StringSpec } from "./value.ts"; import { Default, NullableDefault, NumberSpec, StringSpec } from "./value.ts";
import { Description } from "./value.ts"; import { Description } from "./value.ts";
import * as T from "../types.ts";
export class List<A> extends IBuilder<A> { export class List<A extends Tag<"list", ValueSpecList>> extends IBuilder<A> {
// deno-lint-ignore ban-types // deno-lint-ignore ban-types
static boolean<A extends Description & Default<boolean[]> & { range: string; spec: {} }>(a: A) { static boolean<A extends Description & Default<boolean[]> & { range: string; spec: {} }>(a: A) {
return new List({ return new List({
type: "list" as const,
subtype: "boolean" as const, subtype: "boolean" as const,
...a, ...a,
}); });
} }
static string< static string<
A extends Description & Default<string[] & { range: string; spec: null | { range: string; spec: StringSpec } }> A extends Description & Default<string[]> & { range: string; spec: { range: string; spec: StringSpec } }
>(a: A) { >(a: A) {
return new List({ return new List({
type: "list" as const,
subtype: "string" as const, subtype: "string" as const,
...a, ...a,
}); } as T.Tag<"list", T.Subtype<"string", T.WithDescription<T.WithDefault<T.ListSpec<T.ValueSpecString>, string[]>>>>);
} }
static number<A extends Description & Default<number[]> & { range: string; spec: NumberSpec }>(a: A) { static number<A extends Description & Default<number[]> & { range: string; spec: NumberSpec }>(a: A) {
return new List({ return new List({
type: "list" as const,
subtype: "number" as const, subtype: "number" as const,
...a, ...a,
}); });
@@ -40,6 +44,7 @@ export class List<A> extends IBuilder<A> {
} }
>(a: A) { >(a: A) {
return new List({ return new List({
type: "list" as const,
subtype: "enum" as const, subtype: "enum" as const,
...a, ...a,
}); });
@@ -54,7 +59,7 @@ export class List<A> extends IBuilder<A> {
"unique-by": null | UniqueBy; "unique-by": null | UniqueBy;
}; };
}, },
B B extends ConfigSpec
>(a: A) { >(a: A) {
const { spec: previousSpec, ...rest } = a; const { spec: previousSpec, ...rest } = a;
const { spec: previousSpecSpec, ...restSpec } = previousSpec; const { spec: previousSpecSpec, ...restSpec } = previousSpec;
@@ -68,9 +73,10 @@ export class List<A> extends IBuilder<A> {
...rest, ...rest,
}; };
return new List({ return new List({
type: "list" as const,
subtype: "object" as const, subtype: "object" as const,
...value, ...value,
}); } as T.Tag<"list", T.Subtype<"object", T.WithDescription<T.WithNullableDefault<T.ListSpec<T.ValueSpecObject>, Record<string, unknown>[]>>>>);
} }
static union< static union<
A extends Description & A extends Description &
@@ -90,7 +96,8 @@ export class List<A> extends IBuilder<A> {
"unique-by": null | UniqueBy | undefined; "unique-by": null | UniqueBy | undefined;
}; };
}, },
Variants extends { [key: string]: Config<unknown> } Variants extends { [key: string]: Config<ConfigSpec> },
B extends ConfigSpec
>(a: A) { >(a: A) {
const { spec: previousSpec, ...rest } = a; const { spec: previousSpec, ...rest } = a;
const { variants: previousVariants, ...restSpec } = previousSpec; const { variants: previousVariants, ...restSpec } = previousSpec;
@@ -109,6 +116,7 @@ export class List<A> extends IBuilder<A> {
...rest, ...rest,
}; };
return new List({ return new List({
type: "list" as const,
subtype: "union" as const, subtype: "union" as const,
...value, ...value,
}); });

View File

@@ -1,7 +1,8 @@
import { ValueSpecAny } from "../types.ts";
import { IBuilder } from "./builder.ts"; import { IBuilder } from "./builder.ts";
import { Description } from "./value.ts"; import { Description } from "./value.ts";
export class Pointer<A> extends IBuilder<A> { export class Pointer<A extends ValueSpecAny> extends IBuilder<A> {
static packageTorKey<A extends Description & { "package-id": string; interface: string }>(a: A) { static packageTorKey<A extends Description & { "package-id": string; interface: string }>(a: A) {
return new Pointer({ return new Pointer({
type: "pointer" as const, type: "pointer" as const,

View File

@@ -1,8 +1,16 @@
import { ConfigSpec, Tag, ValueSpecAny, ValueSpecList } from "../types.ts";
import * as T from "../types.ts";
import { BuilderExtract, IBuilder } from "./builder.ts"; import { BuilderExtract, IBuilder } from "./builder.ts";
import { Config } from "./config.ts"; import { Config } from "./config.ts";
import { List } from "./list.ts"; import { List } from "./list.ts";
import { Pointer } from "./pointer.ts"; import { Pointer } from "./pointer.ts";
export type DefaultString =
| string
| {
charset: string | null | undefined;
len: number;
};
export type Description = { export type Description = {
name: string; name: string;
description: string | null; description: string | null;
@@ -12,7 +20,7 @@ export type Default<A> = {
default: A; default: A;
}; };
export type NullableDefault<A> = { export type NullableDefault<A> = {
default: A | null; default?: A;
}; };
export type StringSpec = { export type StringSpec = {
@@ -38,30 +46,29 @@ export type Nullable = {
}; };
type _UniqueBy = type _UniqueBy =
| null
| string | string
| { | {
any: string; any: _UniqueBy[];
}; };
export class Value<A> extends IBuilder<A> { export class Value<A extends ValueSpecAny> extends IBuilder<A> {
static boolean<A extends Description & Default<boolean>>(a: A) { static boolean<A extends Description & Default<boolean>>(a: A) {
return new Value({ return new Value({
type: "boolean" as const, type: "boolean" as const,
...a, ...a,
}); });
} }
static string<A extends Description & NullableDefault<string> & Nullable & StringSpec>(a: A) { static string<A extends Description & NullableDefault<DefaultString> & Nullable & StringSpec>(a: A) {
return new Value({ return new Value({
type: "string" as const, type: "string" as const,
...a, ...a,
}); } as Tag<"string", T.WithDescription<T.WithNullableDefault<T.WithNullable<T.ValueSpecString>, DefaultString>>>);
} }
static number<A extends Description & NullableDefault<number> & Nullable & NumberSpec>(a: A) { static number<A extends Description & NullableDefault<number> & Nullable & NumberSpec>(a: A) {
return new Value({ return new Value({
type: "number" as const, type: "number" as const,
...a, ...a,
}); } as Tag<"number", T.WithDescription<T.WithNullableDefault<T.WithNullable<T.ValueSpecNumber>, number>>>);
} }
static enum< static enum<
A extends Description & A extends Description &
@@ -74,20 +81,20 @@ export class Value<A> extends IBuilder<A> {
} }
static object< static object<
A extends Description & A extends Description &
NullableDefault<Config<B>> & { values: readonly string[] | string[]; "value-names": Record<string, string> }, NullableDefault<{ [k: string]: unknown }> & {
B "display-as": null | string;
"unique-by": null | string;
spec: Config<B>;
"value-names": Record<string, string>;
},
B extends ConfigSpec
>(a: A) { >(a: A) {
const { default: previousDefault, ...rest } = a; const { spec: previousSpec, ...rest } = a;
if (previousDefault == null) { const spec = previousSpec.build();
return new Value({
type: "object" as const,
...rest,
});
}
return new Value({ return new Value({
type: "object" as const, type: "object" as const,
...rest, ...rest,
default: previousDefault.build(), spec,
}); });
} }
static union< static union<
@@ -106,8 +113,9 @@ export class Value<A> extends IBuilder<A> {
"unique-by": _UniqueBy | null; "unique-by": _UniqueBy | null;
}, },
Variants extends { Variants extends {
[key: string]: Config<unknown>; [key: string]: Config<B>;
} },
B extends ConfigSpec
>(a: A) { >(a: A) {
const { variants: previousVariants, ...rest } = a; const { variants: previousVariants, ...rest } = a;
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
@@ -123,13 +131,10 @@ export class Value<A> extends IBuilder<A> {
}); });
} }
static pointer<A>(a: Pointer<A>) { static pointer<A extends ValueSpecAny>(a: Pointer<A>) {
return new Value(a.build()); return new Value(a.build());
} }
static list<A extends List<B>, B>(a: A) { static list<A extends List<B>, B extends Tag<"list", ValueSpecList>>(a: A) {
return new Value({ return new Value(a.build());
type: "list" as const,
...a.build(),
});
} }
} }

View File

@@ -176,9 +176,9 @@ export type WithNullableDefault<T, Default> = T & {
}; };
export type WithDescription<T> = T & { export type WithDescription<T> = T & {
description?: string; description?: null | string;
name: string; name: string;
warning?: string; warning?: null | string;
}; };
export type ListSpec<T> = { export type ListSpec<T> = {
@@ -212,7 +212,7 @@ export type DefaultString =
| string | string
| { | {
/** The chars available for the randome generation */ /** The chars available for the randome generation */
charset?: string; charset?: null | string;
/** Length that we generate to */ /** Length that we generate to */
len: number; len: number;
}; };
@@ -225,17 +225,17 @@ export type ValueSpecString = (
"pattern-description": string; "pattern-description": string;
} }
) & { ) & {
copyable?: boolean; copyable?: null | boolean;
masked?: boolean; masked?: null | boolean;
placeholder?: string; placeholder?: null | string;
}; };
export type ValueSpecNumber = { export type ValueSpecNumber = {
/** Something like [3,6] or [0, *) */ /** Something like [3,6] or [0, *) */
range?: string; range?: null | string;
integral?: boolean; integral?: null | boolean;
/** Used a description of the units */ /** Used a description of the units */
units?: string; units?: null | string;
placeholder?: number; placeholder?: null | number;
}; };
export type ValueSpecBoolean = Record<string, unknown>; export type ValueSpecBoolean = Record<string, unknown>;
export type ValueSpecAny = export type ValueSpecAny =
@@ -301,8 +301,8 @@ export type ValueSpecUnion = {
/** What tag for the specification, for tag unions */ /** What tag for the specification, for tag unions */
tag: { tag: {
id: string; id: string;
name?: string; name?: null | string;
description?: string; description?: null | string;
"variant-names": { "variant-names": {
[key: string]: string; [key: string]: string;
}; };
@@ -311,13 +311,13 @@ export type ValueSpecUnion = {
variants: { variants: {
[key: string]: ConfigSpec; [key: string]: ConfigSpec;
}; };
"display-as"?: string; "display-as"?: null | string;
"unique-by"?: UniqueBy; "unique-by"?: null | UniqueBy;
}; };
export type ValueSpecObject = { export type ValueSpecObject = {
spec: ConfigSpec; spec: ConfigSpec;
"display-as"?: string; "display-as"?: null | string;
"unique-by"?: UniqueBy; "unique-by"?: null | UniqueBy;
}; };
export type ValueSpecList = export type ValueSpecList =
| Subtype<"boolean", WithDescription<WithDefault<ListSpec<ValueSpecBoolean>, boolean[]>>> | Subtype<"boolean", WithDescription<WithDefault<ListSpec<ValueSpecBoolean>, boolean[]>>>