diff --git a/lib/config/configTypes.ts b/lib/config/configTypes.ts index b64df92..333ee3e 100644 --- a/lib/config/configTypes.ts +++ b/lib/config/configTypes.ts @@ -1,41 +1,161 @@ -import * as C from "./configTypesRaw"; - -export type ValueType = C.ValueType; - -export type RequiredDeep = A extends {} - ? { [K in keyof A]-?: RequiredDeep } - : Required; - -export type InputSpec = Record>; - -export type ValueSpec = RequiredDeep; - +export type InputSpec = Record; +export type ValueType = + | "string" + | "textarea" + | "number" + | "boolean" + | "select" + | "multiselect" + | "list" + | "object" + | "file" + | "union"; +export type ValueSpec = ValueSpecOf; /** core spec types. These types provide the metadata for performing validations */ -export type ValueSpecOf = RequiredDeep>; - -export type ValueSpecString = RequiredDeep; -export type ValueSpecTextarea = RequiredDeep; -export type ValueSpecNumber = RequiredDeep; -export type ValueSpecSelect = RequiredDeep; -export type ValueSpecMultiselect = RequiredDeep; -export type ValueSpecBoolean = RequiredDeep; -export type ValueSpecUnion = RequiredDeep; -export type ValueSpecFile = RequiredDeep; -export type ValueSpecObject = RequiredDeep; -export type WithStandalone = RequiredDeep; -export type SelectBase = RequiredDeep; -export type ListValueSpecType = RequiredDeep; +export type ValueSpecOf = 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: 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; +} +export type ListValueSpecType = "string" | "number" | "object"; /** represents a spec for the values of a list */ -export type ListValueSpecOf = RequiredDeep< - C.ListValueSpecOf ->; - +export type ListValueSpecOf = T extends "string" + ? ListValueSpecString + : T extends "number" + ? ListValueSpecNumber + : T extends "object" + ? ListValueSpecObject + : never; /** represents a spec for a list */ -export type ValueSpecList = RequiredDeep; -export type ValueSpecListOf = RequiredDeep< - C.ValueSpecListOf ->; +export type ValueSpecList = ValueSpecListOf; +export interface ValueSpecListOf + extends WithStandalone { + type: "list"; + spec: ListValueSpecOf; + range: string; + default: + | string[] + | number[] + | DefaultString[] + | Record[] + | readonly string[] + | readonly number[] + | readonly DefaultString[] + | readonly Record[]; +} +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 export function isValueSpecListOf( @@ -44,12 +164,6 @@ export function isValueSpecListOf( ): t is ValueSpecListOf & { spec: ListValueSpecOf } { return t.spec.type === s; } -export type ListValueSpecString = RequiredDeep; -export type ListValueSpecNumber = RequiredDeep; -export type ListValueSpecObject = RequiredDeep; -export type UniqueBy = RequiredDeep; -export type DefaultString = RequiredDeep; - export const unionSelectKey = "unionSelectKey" as const; export type UnionSelectKey = typeof unionSelectKey; diff --git a/lib/config/configTypesRaw.ts b/lib/config/configTypesRaw.ts deleted file mode 100644 index 46a1be8..0000000 --- a/lib/config/configTypesRaw.ts +++ /dev/null @@ -1,172 +0,0 @@ -export { - InputSpec, - UnionSelectKey, - UnionValueKey, - unionSelectKey, - unionValueKey, -} from "./configTypes"; - -export type InputSpecRaw = Record; -export type ValueType = - | "string" - | "textarea" - | "number" - | "boolean" - | "select" - | "multiselect" - | "list" - | "object" - | "file" - | "union"; -export type ValueSpec = ValueSpecOf; -/** core spec types. These types provide the metadata for performing validations */ -export type ValueSpecOf = 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; -} -export type ListValueSpecType = "string" | "number" | "object"; -/** represents a spec for the values of a list */ -export type ListValueSpecOf = T extends "string" - ? ListValueSpecString - : T extends "number" - ? ListValueSpecNumber - : T extends "object" - ? ListValueSpecObject - : never; -/** represents a spec for a list */ -export type ValueSpecList = ValueSpecListOf; -export interface ValueSpecListOf - extends WithStandalone { - type: "list"; - spec: ListValueSpecOf; - range?: string; - default?: - | string[] - | number[] - | DefaultString[] - | Record[] - | readonly string[] - | readonly number[] - | readonly DefaultString[] - | readonly Record[]; -} -export declare function isValueSpecListOf( - t: ValueSpecListOf, - s: S -): t is ValueSpecListOf & { - spec: ListValueSpecOf; -}; -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; - }; diff --git a/lib/config/specToBuilder.ts b/lib/config/specToBuilder.ts index 8004e0d..a3b470a 100644 --- a/lib/config/specToBuilder.ts +++ b/lib/config/specToBuilder.ts @@ -1,11 +1,11 @@ import camelCase from "lodash/camelCase"; import * as fs from "fs"; -import { InputSpecRaw } from "./configTypesRaw"; -import * as C from "./configTypesRaw"; +import { InputSpec } from "./configTypes"; +import * as C from "./configTypes"; export async function specToBuilderFile( file: string, - inputData: Promise | InputSpecRaw, + inputData: Promise | InputSpec, options: Parameters[1] ) { await fs.writeFile(file, await specToBuilder(inputData, options), (err) => @@ -13,7 +13,7 @@ export async function specToBuilderFile( ); } export async function specToBuilder( - inputData: Promise | InputSpecRaw, + inputData: Promise | InputSpec, { startSdk = "start-sdk" } = {} ) { const outputLines: string[] = []; @@ -39,7 +39,7 @@ export async function specToBuilder( outputLines.push(`export const ${variableName} = ${data};`); return variableName; } - function convertInputSpec(data: C.InputSpecRaw) { + function convertInputSpec(data: C.InputSpec) { let answer = "Config.of({"; for (const [key, value] of Object.entries(data)) { const variableName = newConst(key, convertValueSpec(value)); @@ -153,7 +153,7 @@ export async function specToBuilder( string, { name: string; - spec: C.InputSpecRaw; + spec: C.InputSpec; } > ): string { diff --git a/lib/properties/Properties.ts b/lib/properties/Properties.ts deleted file mode 100644 index f2dca18..0000000 --- a/lib/properties/Properties.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { - PackagePropertiesV2, - PackagePropertyObject, - PackagePropertyString, - Properties as P, -} from "../types"; -import { PropertyObject } from "./PropertyObject"; -import { PropertyString } from "./PropertyString"; - -export class Properties { - constructor(readonly data: X) {} - - static of< - X extends Record< - string, - | PropertyObject - | PropertyString - > - >(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; - } -} diff --git a/lib/properties/PropertyGroup.ts b/lib/properties/PropertyGroup.ts new file mode 100644 index 0000000..a9df920 --- /dev/null +++ b/lib/properties/PropertyGroup.ts @@ -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), + }); + } +} diff --git a/lib/properties/PropertyObject.ts b/lib/properties/PropertyObject.ts deleted file mode 100644 index ac0c72d..0000000 --- a/lib/properties/PropertyObject.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { PackagePropertiesV2, PackagePropertyObject } from "../types"; -import { Properties } from "./Properties"; - -export class PropertyObject { - private constructor(readonly data: X) {} - static of>( - description: string, - value: X - ) { - return new PropertyObject({ - type: "object", - description, - value: value.data, - }); - } -} diff --git a/lib/properties/PropertyString.ts b/lib/properties/PropertyString.ts index 691f4a2..465b515 100644 --- a/lib/properties/PropertyString.ts +++ b/lib/properties/PropertyString.ts @@ -1,17 +1,8 @@ import { PackagePropertyString } from "../types"; -export class PropertyString { - private constructor(readonly data: X) {} - static of(value: { - 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; - }) { +export class PropertyString { + private constructor(readonly data: PackagePropertyString) {} + static of(value: Omit) { return new PropertyString({ ...value, type: "string", diff --git a/lib/properties/index.ts b/lib/properties/index.ts index 33ad3af..395bdd3 100644 --- a/lib/properties/index.ts +++ b/lib/properties/index.ts @@ -1,11 +1,12 @@ -import { ExpectedExports, PackagePropertiesV2 } from "../types"; +import { ExpectedExports, Properties } from "../types"; import "../util/extensions"; -import { Properties } from "./Properties"; -export { Properties } from "./Properties"; -export { PropertyObject } from "./PropertyObject"; +import { PropertyGroup } from "./PropertyGroup"; +import { PropertyString } from "./PropertyString"; +export { PropertyGroup } from "./PropertyGroup"; export { PropertyString } from "./PropertyString"; export const test = ""; + export type UnionToIntersection = ((x: T) => any) extends (x: infer R) => any ? R : never; @@ -20,12 +21,13 @@ export type UnionToIntersection = ((x: T) => any) extends (x: infer R) => any export function setupPropertiesExport( fn: ( ...args: Parameters - ) => void | Promise | Promise> + ) => void | Promise | Promise<(PropertyGroup | PropertyString)[]> ): ExpectedExports.properties { - return async (...args: Parameters) => { + return (async (...args) => { const result = await fn(...args); if (result) { - return result.build(); + const answer: Properties = result.map((x) => x.data); + return answer; } - }; + }) as ExpectedExports.properties; } diff --git a/lib/types.ts b/lib/types.ts index 1cd18f3..f21cf93 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -25,8 +25,8 @@ export namespace ExpectedExports { effects: Effects; }) => Promise; /** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */ - export type properties = (options: { - effects: Effects; + export type properties = (options: { + wrapperData: WrapperData; }) => Promise; // /** 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 */ - getWrapperData(options?: { + getWrapperData(options: { /** If there is no packageId it is assumed the current package */ packageId?: string; /** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */ @@ -265,7 +265,7 @@ export type Effects = { }): Promise; /** 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/) */ path?: string; value: unknown; @@ -469,35 +469,27 @@ export type KnownError = "error-code": [number, string] | readonly [number, string]; }; -export type PackagePropertiesV2 = { - [name: string]: PackagePropertyObject | PackagePropertyString; -}; +export type PackageProperties = PackagePropertyGroup | PackagePropertyString; export type PackagePropertyString = { type: "string"; - description?: string; + name: string; + description: string | null; value: string; /** Let's the ui make this copyable button */ - copyable?: boolean; + copyable: boolean; /** Let the ui create a qr for this field */ - qr?: boolean; + qr: boolean; /** Hiding the value unless toggled off for field */ - masked?: boolean; - - watch?: { - packageId?: string; - path: string; - }; + masked: boolean; }; -export type PackagePropertyObject = { - value: PackagePropertiesV2; +export type PackagePropertyGroup = { + value: PackageProperties[]; type: "object"; + name: string; description: string; }; -export type Properties = { - version: 2; - data: PackagePropertiesV2; -}; +export type Properties = PackageProperties[]; export type Dependency = { id: PackageId; diff --git a/lib/util/propertiesMatcher.ts b/lib/util/propertiesMatcher.ts index 2246b13..0779d6c 100644 --- a/lib/util/propertiesMatcher.ts +++ b/lib/util/propertiesMatcher.ts @@ -4,8 +4,8 @@ import { UnionSelectKey, UnionValueKey, ValueSpec as ValueSpecAny, -} from "../config/configTypesRaw"; -import { InputSpecRaw } from "../config/configTypesRaw"; + InputSpec, +} from "../config/configTypes"; const { string, @@ -333,7 +333,7 @@ export function guardAll( * @param valueDictionary * @returns */ -export function typeFromProps( +export function typeFromProps( valueDictionary: A ): Parser> { if (!recordString.test(valueDictionary)) return unknown as any; diff --git a/package-lock.json b/package-lock.json index 17616da..e938c0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "start-sdk", - "version": "0.4.0-lib0.charlie26", + "version": "0.4.0-lib0.charlie29", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "start-sdk", - "version": "0.4.0-lib0.charlie26", + "version": "0.4.0-lib0.charlie29", "license": "MIT", "dependencies": { "@iarna/toml": "^2.2.5", diff --git a/package.json b/package.json index 3ab5382..d6d382d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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.", "main": "./lib/index.js", "types": "./lib/index.d.ts",