chore: INput config to remove the transformer

This commit is contained in:
BluJ
2023-04-18 13:38:43 -06:00
parent af1f9b22bd
commit 397401e259
12 changed files with 211 additions and 318 deletions

View File

@@ -1,41 +1,161 @@
import * as C from "./configTypesRaw"; export type InputSpec = Record<string, ValueSpec>;
export type ValueType =
export type ValueType = C.ValueType; | "string"
| "textarea"
export type RequiredDeep<A> = A extends {} | "number"
? { [K in keyof A]-?: RequiredDeep<A[K]> } | "boolean"
: Required<A>; | "select"
| "multiselect"
export type InputSpec = Record<string, RequiredDeep<C.ValueSpec>>; | "list"
| "object"
export type ValueSpec = RequiredDeep<C.ValueSpec>; | "file"
| "union";
export type ValueSpec = ValueSpecOf<ValueType>;
/** core spec types. These types provide the metadata for performing validations */ /** core spec types. These types provide the metadata for performing validations */
export type ValueSpecOf<T extends ValueType> = RequiredDeep<C.ValueSpecOf<T>>; export type ValueSpecOf<T extends ValueType> = T extends "string"
? ValueSpecString
export type ValueSpecString = RequiredDeep<C.ValueSpecString>; : T extends "number"
export type ValueSpecTextarea = RequiredDeep<C.ValueSpecTextarea>; ? ValueSpecTextarea
export type ValueSpecNumber = RequiredDeep<C.ValueSpecNumber>; : T extends "textarea"
export type ValueSpecSelect = RequiredDeep<C.ValueSpecSelect>; ? ValueSpecNumber
export type ValueSpecMultiselect = RequiredDeep<C.ValueSpecMultiselect>; : T extends "boolean"
export type ValueSpecBoolean = RequiredDeep<C.ValueSpecBoolean>; ? ValueSpecBoolean
export type ValueSpecUnion = RequiredDeep<C.ValueSpecUnion>; : T extends "select"
export type ValueSpecFile = RequiredDeep<C.ValueSpecFile>; ? ValueSpecSelect
export type ValueSpecObject = RequiredDeep<C.ValueSpecObject>; : T extends "multiselect"
export type WithStandalone = RequiredDeep<C.WithStandalone>; ? ValueSpecMultiselect
export type SelectBase = RequiredDeep<C.SelectBase>; : T extends "list"
export type ListValueSpecType = RequiredDeep<C.ListValueSpecType>; ? ValueSpecList
: T extends "object"
? ValueSpecObject
: T extends "file"
? ValueSpecFile
: T extends "union"
? ValueSpecUnion
: never;
export interface ValueSpecString extends ListValueSpecString, WithStandalone {
required: boolean;
default: DefaultString | null;
}
export interface ValueSpecTextarea extends WithStandalone {
type: "textarea";
placeholder: string | null;
required: boolean;
}
export interface ValueSpecNumber extends ListValueSpecNumber, WithStandalone {
required: boolean;
default: number | null;
}
export interface ValueSpecSelect extends SelectBase, WithStandalone {
type: "select";
required: boolean;
default: string | null;
}
export interface ValueSpecMultiselect extends SelectBase, WithStandalone {
type: "multiselect";
/**'[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules */
range: string;
default: string[];
}
export interface ValueSpecBoolean extends WithStandalone {
type: "boolean";
default: boolean | null;
}
export interface ValueSpecUnion extends WithStandalone {
type: "union";
variants: Record<
string,
{
name: string;
spec: InputSpec;
}
>;
required: boolean;
default: string | null;
}
export interface ValueSpecFile extends WithStandalone {
type: "file";
extensions: string[];
required: boolean;
}
export interface ValueSpecObject extends WithStandalone {
type: "object";
spec: InputSpec;
}
export interface WithStandalone {
name: string;
description: string | null;
warning: string | null;
}
export interface SelectBase {
values: Record<string, string>;
}
export type ListValueSpecType = "string" | "number" | "object";
/** represents a spec for the values of a list */ /** represents a spec for the values of a list */
export type ListValueSpecOf<T extends ListValueSpecType> = RequiredDeep< export type ListValueSpecOf<T extends ListValueSpecType> = T extends "string"
C.ListValueSpecOf<T> ? ListValueSpecString
>; : T extends "number"
? ListValueSpecNumber
: T extends "object"
? ListValueSpecObject
: never;
/** represents a spec for a list */ /** represents a spec for a list */
export type ValueSpecList = RequiredDeep<C.ValueSpecList>; export type ValueSpecList = ValueSpecListOf<ListValueSpecType>;
export type ValueSpecListOf<T extends ListValueSpecType> = RequiredDeep< export interface ValueSpecListOf<T extends ListValueSpecType>
C.ValueSpecListOf<T> extends WithStandalone {
>; type: "list";
spec: ListValueSpecOf<T>;
range: string;
default:
| string[]
| number[]
| DefaultString[]
| Record<string, unknown>[]
| readonly string[]
| readonly number[]
| readonly DefaultString[]
| readonly Record<string, unknown>[];
}
export interface ListValueSpecString {
type: "string";
pattern: string | null;
patternDescription: string | null;
masked: boolean;
inputmode: "text" | "email" | "tel" | "url";
placeholder: string | null;
}
export interface ListValueSpecNumber {
type: "number";
range: string;
integral: boolean;
units: string | null;
placeholder: string | null;
}
export interface ListValueSpecObject {
type: "object";
/** this is a mapped type of the config object at this level, replacing the object's values with specs on those values */
spec: InputSpec;
/** indicates whether duplicates can be permitted in the list */
uniqueBy: UniqueBy;
/** this should be a handlebars template which can make use of the entire config which corresponds to 'spec' */
displayAs: string | null;
}
export type UniqueBy =
| null
| string
| {
any: readonly UniqueBy[] | UniqueBy[];
}
| {
all: readonly UniqueBy[] | UniqueBy[];
};
export type DefaultString =
| string
| {
charset: string;
len: number;
};
// sometimes the type checker needs just a little bit of help // sometimes the type checker needs just a little bit of help
export function isValueSpecListOf<S extends ListValueSpecType>( export function isValueSpecListOf<S extends ListValueSpecType>(
@@ -44,12 +164,6 @@ export function isValueSpecListOf<S extends ListValueSpecType>(
): t is ValueSpecListOf<S> & { spec: ListValueSpecOf<S> } { ): t is ValueSpecListOf<S> & { spec: ListValueSpecOf<S> } {
return t.spec.type === s; return t.spec.type === s;
} }
export type ListValueSpecString = RequiredDeep<C.ListValueSpecString>;
export type ListValueSpecNumber = RequiredDeep<C.ListValueSpecNumber>;
export type ListValueSpecObject = RequiredDeep<C.ListValueSpecObject>;
export type UniqueBy = RequiredDeep<C.UniqueBy>;
export type DefaultString = RequiredDeep<C.DefaultString>;
export const unionSelectKey = "unionSelectKey" as const; export const unionSelectKey = "unionSelectKey" as const;
export type UnionSelectKey = typeof unionSelectKey; export type UnionSelectKey = typeof unionSelectKey;

View File

@@ -1,172 +0,0 @@
export {
InputSpec,
UnionSelectKey,
UnionValueKey,
unionSelectKey,
unionValueKey,
} from "./configTypes";
export type InputSpecRaw = Record<string, ValueSpec>;
export type ValueType =
| "string"
| "textarea"
| "number"
| "boolean"
| "select"
| "multiselect"
| "list"
| "object"
| "file"
| "union";
export type ValueSpec = ValueSpecOf<ValueType>;
/** core spec types. These types provide the metadata for performing validations */
export type ValueSpecOf<T extends ValueType> = T extends "string"
? ValueSpecString
: T extends "number"
? ValueSpecTextarea
: T extends "textarea"
? ValueSpecNumber
: T extends "boolean"
? ValueSpecBoolean
: T extends "select"
? ValueSpecSelect
: T extends "multiselect"
? ValueSpecMultiselect
: T extends "list"
? ValueSpecList
: T extends "object"
? ValueSpecObject
: T extends "file"
? ValueSpecFile
: T extends "union"
? ValueSpecUnion
: never;
export interface ValueSpecString extends ListValueSpecString, WithStandalone {
required: boolean;
default?: DefaultString | null;
}
export interface ValueSpecTextarea extends WithStandalone {
type: "textarea";
placeholder?: string | null;
required: boolean;
}
export interface ValueSpecNumber extends ListValueSpecNumber, WithStandalone {
required: boolean;
default?: number | null;
}
export interface ValueSpecSelect extends SelectBase, WithStandalone {
type: "select";
required: boolean;
default?: string | null;
}
export interface ValueSpecMultiselect extends SelectBase, WithStandalone {
type: "multiselect";
/**'[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules */
range?: string;
default?: string[];
}
export interface ValueSpecBoolean extends WithStandalone {
type: "boolean";
default?: boolean | null;
}
export interface ValueSpecUnion extends WithStandalone {
type: "union";
variants: Record<
string,
{
name: string;
spec: InputSpecRaw;
}
>;
required: boolean;
default?: string | null;
}
export interface ValueSpecFile extends WithStandalone {
type: "file";
extensions: string[];
required: boolean;
}
export interface ValueSpecObject extends WithStandalone {
type: "object";
spec: InputSpecRaw;
}
export interface WithStandalone {
name: string;
description?: string | null;
warning?: string | null;
}
export interface SelectBase {
values: Record<string, string>;
}
export type ListValueSpecType = "string" | "number" | "object";
/** represents a spec for the values of a list */
export type ListValueSpecOf<T extends ListValueSpecType> = T extends "string"
? ListValueSpecString
: T extends "number"
? ListValueSpecNumber
: T extends "object"
? ListValueSpecObject
: never;
/** represents a spec for a list */
export type ValueSpecList = ValueSpecListOf<ListValueSpecType>;
export interface ValueSpecListOf<T extends ListValueSpecType>
extends WithStandalone {
type: "list";
spec: ListValueSpecOf<T>;
range?: string;
default?:
| string[]
| number[]
| DefaultString[]
| Record<string, unknown>[]
| readonly string[]
| readonly number[]
| readonly DefaultString[]
| readonly Record<string, unknown>[];
}
export declare function isValueSpecListOf<S extends ListValueSpecType>(
t: ValueSpecListOf<ListValueSpecType>,
s: S
): t is ValueSpecListOf<S> & {
spec: ListValueSpecOf<S>;
};
export interface ListValueSpecString {
type: "string";
pattern?: string | null;
patternDescription?: string | null;
masked?: boolean;
inputmode?: "text" | "email" | "tel" | "url";
placeholder?: string | null;
}
export interface ListValueSpecNumber {
type: "number";
range?: string;
integral: boolean;
units?: string | null;
placeholder?: string | null;
}
export interface ListValueSpecObject {
type: "object";
/** this is a mapped type of the config object at this level, replacing the object's values with specs on those values */
spec: InputSpecRaw;
/** indicates whether duplicates can be permitted in the list */
uniqueBy: UniqueBy;
/** this should be a handlebars template which can make use of the entire config which corresponds to 'spec' */
displayAs?: string | null;
}
export type UniqueBy =
| null
| string
| {
any: readonly UniqueBy[] | UniqueBy[];
}
| {
all: readonly UniqueBy[] | UniqueBy[];
};
export type DefaultString =
| string
| {
charset: string;
len: number;
};

View File

@@ -1,11 +1,11 @@
import camelCase from "lodash/camelCase"; import camelCase from "lodash/camelCase";
import * as fs from "fs"; import * as fs from "fs";
import { InputSpecRaw } from "./configTypesRaw"; import { InputSpec } from "./configTypes";
import * as C from "./configTypesRaw"; import * as C from "./configTypes";
export async function specToBuilderFile( export async function specToBuilderFile(
file: string, file: string,
inputData: Promise<InputSpecRaw> | InputSpecRaw, inputData: Promise<InputSpec> | InputSpec,
options: Parameters<typeof specToBuilder>[1] options: Parameters<typeof specToBuilder>[1]
) { ) {
await fs.writeFile(file, await specToBuilder(inputData, options), (err) => await fs.writeFile(file, await specToBuilder(inputData, options), (err) =>
@@ -13,7 +13,7 @@ export async function specToBuilderFile(
); );
} }
export async function specToBuilder( export async function specToBuilder(
inputData: Promise<InputSpecRaw> | InputSpecRaw, inputData: Promise<InputSpec> | InputSpec,
{ startSdk = "start-sdk" } = {} { startSdk = "start-sdk" } = {}
) { ) {
const outputLines: string[] = []; const outputLines: string[] = [];
@@ -39,7 +39,7 @@ export async function specToBuilder(
outputLines.push(`export const ${variableName} = ${data};`); outputLines.push(`export const ${variableName} = ${data};`);
return variableName; return variableName;
} }
function convertInputSpec(data: C.InputSpecRaw) { function convertInputSpec(data: C.InputSpec) {
let answer = "Config.of({"; let answer = "Config.of({";
for (const [key, value] of Object.entries(data)) { for (const [key, value] of Object.entries(data)) {
const variableName = newConst(key, convertValueSpec(value)); const variableName = newConst(key, convertValueSpec(value));
@@ -153,7 +153,7 @@ export async function specToBuilder(
string, string,
{ {
name: string; name: string;
spec: C.InputSpecRaw; spec: C.InputSpec;
} }
> >
): string { ): string {

View File

@@ -1,36 +0,0 @@
import {
PackagePropertiesV2,
PackagePropertyObject,
PackagePropertyString,
Properties as P,
} from "../types";
import { PropertyObject } from "./PropertyObject";
import { PropertyString } from "./PropertyString";
export class Properties<X extends PackagePropertiesV2> {
constructor(readonly data: X) {}
static of<
X extends Record<
string,
| PropertyObject<PackagePropertyObject>
| PropertyString<PackagePropertyString>
>
>(x: X) {
const answer = {} as {
[key in keyof X]: X[key]["data"];
};
for (const [key, value] of x.entries()) {
answer[key] = value.data;
}
return new Properties(answer);
}
build() {
return {
version: 2,
data: this.data,
} satisfies P;
}
}

View File

@@ -0,0 +1,18 @@
import { PackagePropertyGroup } from "../types";
import { PropertyString } from "./PropertyString";
export class PropertyGroup {
private constructor(readonly data: PackagePropertyGroup) {}
static of(options: {
description: string;
value: (PropertyGroup | PropertyString)[];
name: string;
}) {
return new PropertyGroup({
type: "object",
name: options.name,
description: options.description,
value: options.value.map((x) => x.data),
});
}
}

View File

@@ -1,16 +0,0 @@
import { PackagePropertiesV2, PackagePropertyObject } from "../types";
import { Properties } from "./Properties";
export class PropertyObject<X extends PackagePropertyObject> {
private constructor(readonly data: X) {}
static of<X extends Properties<PackagePropertiesV2>>(
description: string,
value: X
) {
return new PropertyObject({
type: "object",
description,
value: value.data,
});
}
}

View File

@@ -1,17 +1,8 @@
import { PackagePropertyString } from "../types"; import { PackagePropertyString } from "../types";
export class PropertyString<X extends PackagePropertyString> { export class PropertyString {
private constructor(readonly data: X) {} private constructor(readonly data: PackagePropertyString) {}
static of(value: { static of(value: Omit<PackagePropertyString, "type" | "watch">) {
description?: string;
value: string;
/** Let's the ui make this copyable button */
copyable?: boolean;
/** Let the ui create a qr for this field */
qr?: boolean;
/** Hiding the value unless toggled off for field */
masked?: boolean;
}) {
return new PropertyString({ return new PropertyString({
...value, ...value,
type: "string", type: "string",

View File

@@ -1,11 +1,12 @@
import { ExpectedExports, PackagePropertiesV2 } from "../types"; import { ExpectedExports, Properties } from "../types";
import "../util/extensions"; import "../util/extensions";
import { Properties } from "./Properties"; import { PropertyGroup } from "./PropertyGroup";
export { Properties } from "./Properties"; import { PropertyString } from "./PropertyString";
export { PropertyObject } from "./PropertyObject"; export { PropertyGroup } from "./PropertyGroup";
export { PropertyString } from "./PropertyString"; export { PropertyString } from "./PropertyString";
export const test = ""; export const test = "";
export type UnionToIntersection<T> = ((x: T) => any) extends (x: infer R) => any export type UnionToIntersection<T> = ((x: T) => any) extends (x: infer R) => any
? R ? R
: never; : never;
@@ -20,12 +21,13 @@ export type UnionToIntersection<T> = ((x: T) => any) extends (x: infer R) => any
export function setupPropertiesExport( export function setupPropertiesExport(
fn: ( fn: (
...args: Parameters<ExpectedExports.properties> ...args: Parameters<ExpectedExports.properties>
) => void | Promise<void> | Promise<Properties<PackagePropertiesV2>> ) => void | Promise<void> | Promise<(PropertyGroup | PropertyString)[]>
): ExpectedExports.properties { ): ExpectedExports.properties {
return async (...args: Parameters<ExpectedExports.properties>) => { return (async (...args) => {
const result = await fn(...args); const result = await fn(...args);
if (result) { if (result) {
return result.build(); const answer: Properties = result.map((x) => x.data);
return answer;
} }
}; }) as ExpectedExports.properties;
} }

View File

@@ -25,8 +25,8 @@ export namespace ExpectedExports {
effects: Effects; effects: Effects;
}) => Promise<unknown>; }) => Promise<unknown>;
/** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */ /** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */
export type properties = (options: { export type properties = <WrapperData>(options: {
effects: Effects; wrapperData: WrapperData;
}) => Promise<Properties | null | undefined | void>; }) => Promise<Properties | null | undefined | void>;
// /** Health checks are used to determine if the service is working properly after starting // /** Health checks are used to determine if the service is working properly after starting
@@ -256,7 +256,7 @@ export type Effects = {
}; };
/** Get a value in a json like data, can be observed and subscribed */ /** Get a value in a json like data, can be observed and subscribed */
getWrapperData(options?: { getWrapperData(options: {
/** If there is no packageId it is assumed the current package */ /** If there is no packageId it is assumed the current package */
packageId?: string; packageId?: string;
/** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */ /** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */
@@ -265,7 +265,7 @@ export type Effects = {
}): Promise<unknown>; }): Promise<unknown>;
/** Used to store values that can be accessed and subscribed to */ /** Used to store values that can be accessed and subscribed to */
setWrapperData(options?: { setWrapperData(options: {
/** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */ /** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */
path?: string; path?: string;
value: unknown; value: unknown;
@@ -469,35 +469,27 @@ export type KnownError =
"error-code": [number, string] | readonly [number, string]; "error-code": [number, string] | readonly [number, string];
}; };
export type PackagePropertiesV2 = { export type PackageProperties = PackagePropertyGroup | PackagePropertyString;
[name: string]: PackagePropertyObject | PackagePropertyString;
};
export type PackagePropertyString = { export type PackagePropertyString = {
type: "string"; type: "string";
description?: string; name: string;
description: string | null;
value: string; value: string;
/** Let's the ui make this copyable button */ /** Let's the ui make this copyable button */
copyable?: boolean; copyable: boolean;
/** Let the ui create a qr for this field */ /** Let the ui create a qr for this field */
qr?: boolean; qr: boolean;
/** Hiding the value unless toggled off for field */ /** Hiding the value unless toggled off for field */
masked?: boolean; masked: boolean;
watch?: {
packageId?: string;
path: string;
};
}; };
export type PackagePropertyObject = { export type PackagePropertyGroup = {
value: PackagePropertiesV2; value: PackageProperties[];
type: "object"; type: "object";
name: string;
description: string; description: string;
}; };
export type Properties = { export type Properties = PackageProperties[];
version: 2;
data: PackagePropertiesV2;
};
export type Dependency = { export type Dependency = {
id: PackageId; id: PackageId;

View File

@@ -4,8 +4,8 @@ import {
UnionSelectKey, UnionSelectKey,
UnionValueKey, UnionValueKey,
ValueSpec as ValueSpecAny, ValueSpec as ValueSpecAny,
} from "../config/configTypesRaw"; InputSpec,
import { InputSpecRaw } from "../config/configTypesRaw"; } from "../config/configTypes";
const { const {
string, string,
@@ -333,7 +333,7 @@ export function guardAll<A extends ValueSpecAny>(
* @param valueDictionary * @param valueDictionary
* @returns * @returns
*/ */
export function typeFromProps<A extends InputSpecRaw>( export function typeFromProps<A extends InputSpec>(
valueDictionary: A valueDictionary: A
): Parser<unknown, TypeFromProps<A>> { ): Parser<unknown, TypeFromProps<A>> {
if (!recordString.test(valueDictionary)) return unknown as any; if (!recordString.test(valueDictionary)) return unknown as any;

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "start-sdk", "name": "start-sdk",
"version": "0.4.0-lib0.charlie26", "version": "0.4.0-lib0.charlie29",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "start-sdk", "name": "start-sdk",
"version": "0.4.0-lib0.charlie26", "version": "0.4.0-lib0.charlie29",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",

View File

@@ -1,6 +1,6 @@
{ {
"name": "start-sdk", "name": "start-sdk",
"version": "0.4.0-lib0.charlie26", "version": "0.4.0-lib0.charlie29",
"description": "For making the patterns that are wanted in making services for the startOS.", "description": "For making the patterns that are wanted in making services for the startOS.",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",