From c7d38fc7ce15545a1b796b99b685f89a3cd1aa6e Mon Sep 17 00:00:00 2001 From: BluJ Date: Thu, 27 Apr 2023 11:22:42 -0600 Subject: [PATCH] feat: Utils to do bindLan and have ipv4 and ipv6 if need be --- lib/actions/createAction.ts | 43 +- lib/actions/index.ts | 4 +- lib/actions/setupActions.ts | 14 +- lib/autoconfig/AutoConfig.ts | 26 +- lib/autoconfig/index.ts | 8 +- lib/autoconfig/setupAutoConfig.ts | 16 +- lib/backup/Backups.ts | 72 ++-- lib/backup/index.ts | 4 +- lib/backup/setupBackups.ts | 16 +- lib/config/builder/builder.ts | 6 +- lib/config/builder/config.ts | 28 +- lib/config/builder/index.ts | 10 +- lib/config/builder/list.ts | 94 ++--- lib/config/builder/value.ts | 206 +++++----- lib/config/builder/variants.ts | 30 +- lib/config/configTypes.ts | 172 ++++---- lib/config/dependencies.ts | 16 +- lib/config/index.ts | 6 +- lib/config/setupConfig.ts | 50 +-- lib/emverLite/mod.ts | 158 ++++---- lib/health/HealthCheck.ts | 44 +- lib/health/HealthReceipt.ts | 6 +- lib/health/checkFns/CheckResult.ts | 8 +- lib/health/checkFns/checkPortListening.ts | 14 +- lib/health/checkFns/checkWebUrl.ts | 18 +- lib/health/checkFns/index.ts | 12 +- lib/health/checkFns/runHealthScript.ts | 20 +- lib/health/index.ts | 10 +- lib/health/trigger/TriggerInput.ts | 6 +- lib/health/trigger/changeOnFirstSuccess.ts | 28 +- lib/health/trigger/cooldownTrigger.ts | 6 +- lib/health/trigger/defaultTrigger.ts | 6 +- lib/health/trigger/index.ts | 8 +- lib/index.ts | 36 +- lib/inits/index.ts | 6 +- lib/inits/migrations/Migration.ts | 24 +- lib/inits/migrations/setupMigrations.ts | 36 +- lib/inits/setupInit.ts | 22 +- lib/inits/setupInstall.ts | 16 +- lib/inits/setupUninstall.ts | 16 +- lib/mainFn/AddressReceipt.ts | 6 +- lib/mainFn/Daemons.ts | 80 ++-- lib/mainFn/LocalBinding.ts | 28 +- lib/mainFn/LocalPort.ts | 21 +- lib/mainFn/NetworkBuilder.ts | 13 +- lib/mainFn/NetworkInterfaceBuilder.ts | 30 +- lib/mainFn/Origin.ts | 6 +- lib/mainFn/ReadyProof.ts | 6 +- lib/mainFn/RunningMainRet.ts | 10 +- lib/mainFn/TorBinding.ts | 4 +- lib/mainFn/TorHostname.ts | 10 +- lib/mainFn/exportInterfaces.ts | 8 +- lib/mainFn/index.ts | 38 +- lib/mainFn/interfaceReceipt.ts | 6 +- lib/manifest/ManifestTypes.ts | 88 ++-- lib/manifest/index.ts | 4 +- lib/manifest/setupManifest.ts | 12 +- lib/properties/PropertyGroup.ts | 12 +- lib/properties/PropertyString.ts | 4 +- lib/properties/index.ts | 26 +- lib/test/configBuilder.test.ts | 351 ++++++++-------- lib/test/configTypes.test.ts | 26 +- lib/test/emverList.test.ts | 322 +++++++-------- lib/test/health.readyCheck.test.ts | 12 +- lib/test/makeOutput.ts | 4 +- lib/test/output.test.ts | 52 +-- lib/test/util.deepMerge.test.ts | 20 +- lib/test/wrapperData.test.ts | 60 ++- lib/types.ts | 448 +++++++++++---------- lib/util/deepEqual.ts | 20 +- lib/util/deepMerge.ts | 20 +- lib/util/fileHelper.ts | 44 +- lib/util/getWrapperData.ts | 26 +- lib/util/index.ts | 92 ++--- lib/util/nullIfEmpty.ts | 4 +- lib/util/once.ts | 8 +- lib/util/propertiesMatcher.ts | 110 ++--- package.json | 2 +- scripts/oldSpecToBuilder.ts | 144 +++---- 79 files changed, 1754 insertions(+), 1744 deletions(-) diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index f6e139c..fc64eef 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -1,42 +1,37 @@ -import { Parser } from "ts-matches"; -import { Config } from "../config/builder"; -import { - ActionMetaData, - ActionResult, - Effects, - ExportedAction, -} from "../types"; -import { Utils, once, utils } from "../util"; -import { TypeFromProps } from "../util/propertiesMatcher"; -import { InputSpec } from "../config/configTypes"; +import { Parser } from "ts-matches" +import { Config } from "../config/builder" +import { ActionMetaData, ActionResult, Effects, ExportedAction } from "../types" +import { Utils, once, utils } from "../util" +import { TypeFromProps } from "../util/propertiesMatcher" +import { InputSpec } from "../config/configTypes" export class CreatedAction> { private constructor( private myMetaData: Omit & { input: Input }, readonly fn: (options: { - effects: Effects; - utils: Utils; - input: TypeFromProps; + effects: Effects + utils: Utils + input: TypeFromProps }) => Promise, ) {} private validator = this.myMetaData.input.validator() as Parser< unknown, TypeFromProps - >; + > metaData = { ...this.myMetaData, input: this.myMetaData.input.build(), - }; + } static of>( metaData: Omit & { input: Input }, fn: (options: { - effects: Effects; - utils: Utils; - input: TypeFromProps; + effects: Effects + utils: Utils + input: TypeFromProps }) => Promise, ) { - return new CreatedAction(metaData, fn); + return new CreatedAction(metaData, fn) } exportedAction: ExportedAction = ({ effects, input }) => { @@ -44,12 +39,12 @@ export class CreatedAction> { effects, utils: utils(effects), input: this.validator.unsafeCast(input), - }); - }; + }) + } async exportAction(effects: Effects) { - await effects.exportAction(this.metaData); + await effects.exportAction(this.metaData) } } -export const createAction = CreatedAction.of; +export const createAction = CreatedAction.of diff --git a/lib/actions/index.ts b/lib/actions/index.ts index f2ce18d..1b32d34 100644 --- a/lib/actions/index.ts +++ b/lib/actions/index.ts @@ -1,3 +1,3 @@ -export { CreatedAction, createAction } from "./createAction"; +export { CreatedAction, createAction } from "./createAction" -export { setupActions } from "./setupActions"; +export { setupActions } from "./setupActions" diff --git a/lib/actions/setupActions.ts b/lib/actions/setupActions.ts index cd198af..21cbe64 100644 --- a/lib/actions/setupActions.ts +++ b/lib/actions/setupActions.ts @@ -1,16 +1,16 @@ -import { Effects, ExpectedExports, ExportedAction } from "../types"; -import { ActionMetaData } from "../types"; -import { CreatedAction } from "./createAction"; +import { Effects, ExpectedExports, ExportedAction } from "../types" +import { ActionMetaData } from "../types" +import { CreatedAction } from "./createAction" export function setupActions(...createdActions: CreatedAction[]) { - const actions: Record = {}; + const actions: Record = {} for (const action of createdActions) { - actions[action.metaData.id] = action.exportedAction; + actions[action.metaData.id] = action.exportedAction } - const actionsMetadata = createdActions.map((x) => x.metaData); + const actionsMetadata = createdActions.map((x) => x.metaData) return { actions, actionsMetadata, - }; + } } diff --git a/lib/autoconfig/AutoConfig.ts b/lib/autoconfig/AutoConfig.ts index 465feb5..477b360 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/autoconfig/AutoConfig.ts @@ -1,14 +1,14 @@ -import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types"; -import { Utils, deepEqual, deepMerge, utils } from "../util"; +import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types" +import { Utils, deepEqual, deepMerge, utils } from "../util" export type AutoConfigFrom = { [key in keyof NestedConfigs & string]: (options: { - effects: Effects; - localConfig: Input; - remoteConfig: NestedConfigs[key]; - utils: Utils; - }) => Promise>; -}; + effects: Effects + localConfig: Input + remoteConfig: NestedConfigs[key] + utils: Utils + }) => Promise> +} export class AutoConfig { constructor( readonly configs: AutoConfigFrom, @@ -18,13 +18,13 @@ export class AutoConfig { async check( options: Parameters[0], ): ReturnType { - const origConfig = JSON.parse(JSON.stringify(options.localConfig)); + const origConfig = JSON.parse(JSON.stringify(options.localConfig)) const newOptions = { ...options, utils: utils(options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, - }; + } if ( !deepEqual( origConfig, @@ -35,7 +35,7 @@ export class AutoConfig { ), ) ) - throw new Error(`Check failed for ${this.path}`); + throw new Error(`Check failed for ${this.path}`) } async autoConfigure( options: Parameters[0], @@ -45,11 +45,11 @@ export class AutoConfig { utils: utils(options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, - }; + } return deepMerge( {}, options.localConfig, await this.configs[this.path](newOptions), - ); + ) } } diff --git a/lib/autoconfig/index.ts b/lib/autoconfig/index.ts index df6fc2c..2f6deda 100644 --- a/lib/autoconfig/index.ts +++ b/lib/autoconfig/index.ts @@ -2,8 +2,8 @@ export type ReadonlyDeep = A extends Function ? A : A extends {} ? { readonly [K in keyof A]: ReadonlyDeep } : A; -export type MaybePromise = Promise | A; -export type Message = string; +export type MaybePromise = Promise | A +export type Message = string -export { AutoConfig } from "./AutoConfig"; -export { setupAutoConfig } from "./setupAutoConfig"; +export { AutoConfig } from "./AutoConfig" +export { setupAutoConfig } from "./setupAutoConfig" diff --git a/lib/autoconfig/setupAutoConfig.ts b/lib/autoconfig/setupAutoConfig.ts index ade5059..0c7f072 100644 --- a/lib/autoconfig/setupAutoConfig.ts +++ b/lib/autoconfig/setupAutoConfig.ts @@ -1,24 +1,24 @@ -import { GenericManifest } from "../manifest/ManifestTypes"; -import { AutoConfig, AutoConfigFrom } from "./AutoConfig"; +import { GenericManifest } from "../manifest/ManifestTypes" +import { AutoConfig, AutoConfigFrom } from "./AutoConfig" export function setupAutoConfig< WD, Input, Manifest extends GenericManifest, NestedConfigs extends { - [key in keyof Manifest["dependencies"]]: unknown; + [key in keyof Manifest["dependencies"]]: unknown }, >(configs: AutoConfigFrom) { - type C = typeof configs; + type C = typeof configs const answer = { ...configs } as unknown as { - [k in keyof C]: AutoConfig; - }; + [k in keyof C]: AutoConfig + } for (const key in configs) { answer[key as keyof typeof configs] = new AutoConfig< WD, Input, NestedConfigs - >(configs, key as keyof typeof configs); + >(configs, key as keyof typeof configs) } - return answer; + return answer } diff --git a/lib/backup/Backups.ts b/lib/backup/Backups.ts index b5e84e1..0a6eecc 100644 --- a/lib/backup/Backups.ts +++ b/lib/backup/Backups.ts @@ -1,20 +1,20 @@ -import { GenericManifest } from "../manifest/ManifestTypes"; -import * as T from "../types"; +import { GenericManifest } from "../manifest/ManifestTypes" +import * as T from "../types" -export type BACKUP = "BACKUP"; +export type BACKUP = "BACKUP" export const DEFAULT_OPTIONS: T.BackupOptions = { delete: true, force: true, ignoreExisting: false, exclude: [], -}; +} type BackupSet = { - srcPath: string; - srcVolume: Volumes | BACKUP; - dstPath: string; - dstVolume: Volumes | BACKUP; - options?: Partial; -}; + srcPath: string + srcVolume: Volumes | BACKUP + dstPath: string + dstVolume: Volumes | BACKUP + options?: Partial +} /** * This utility simplifies the volume backup process. * ```ts @@ -38,7 +38,7 @@ type BackupSet = { * ``` */ export class Backups { - static BACKUP: BACKUP = "BACKUP"; + static BACKUP: BACKUP = "BACKUP" constructor( private options = DEFAULT_OPTIONS, @@ -54,24 +54,24 @@ export class Backups { dstPath: `./${srcVolume}/`, dstVolume: Backups.BACKUP, })), - ); + ) } static addSets( ...options: BackupSet[] ) { - return new Backups().addSets(...options); + return new Backups().addSets(...options) } static with_options( options?: Partial, ) { - return new Backups({ ...DEFAULT_OPTIONS, ...options }); + return new Backups({ ...DEFAULT_OPTIONS, ...options }) } set_options(options?: Partial) { this.options = { ...this.options, ...options, - }; - return this; + } + return this } volumes(...volumeNames: Array) { return this.addSets( @@ -81,13 +81,13 @@ export class Backups { dstPath: `./${srcVolume}/`, dstVolume: Backups.BACKUP, })), - ); + ) } addSets(...options: BackupSet[]) { options.forEach((x) => this.backupSet.push({ ...x, options: { ...this.options, ...x.options } }), - ); - return this; + ) + return this } build() { const createBackup: T.ExpectedExports.createBackup = async ({ @@ -100,16 +100,16 @@ export class Backups { path: ".", }) .catch(() => []) - ).map((x) => `${x}`); + ).map((x) => `${x}`) const backupPaths = this.backupSet .filter((x) => x.dstVolume === Backups.BACKUP) .map((x) => x.dstPath) - .map((x) => x.replace(/\.\/([^]*)\//, "$1")); + .map((x) => x.replace(/\.\/([^]*)\//, "$1")) const filteredItems = previousItems.filter( (x) => backupPaths.indexOf(x) === -1, - ); + ) for (const itemToRemove of filteredItems) { - effects.error(`Trying to remove ${itemToRemove}`); + effects.console.error(`Trying to remove ${itemToRemove}`) await effects .removeDir({ volumeId: Backups.BACKUP, @@ -122,15 +122,17 @@ export class Backups { }), ) .catch(() => { - effects.warn(`Failed to remove ${itemToRemove} from backup volume`); - }); + effects.console.warn( + `Failed to remove ${itemToRemove} from backup volume`, + ) + }) } for (const item of this.backupSet) { if (notEmptyPath(item.dstPath)) { await effects.createDir({ volumeId: item.dstVolume, path: item.dstPath, - }); + }) } await effects .runRsync({ @@ -140,10 +142,10 @@ export class Backups { ...item.options, }, }) - .wait(); + .wait() } - return; - }; + return + } const restoreBackup: T.ExpectedExports.restoreBackup = async ({ effects, }) => { @@ -152,7 +154,7 @@ export class Backups { await effects.createDir({ volumeId: item.srcVolume, path: item.srcPath, - }); + }) } await effects .runRsync({ @@ -165,13 +167,13 @@ export class Backups { srcPath: item.dstPath, dstPath: item.srcPath, }) - .wait(); + .wait() } - return; - }; - return { createBackup, restoreBackup }; + return + } + return { createBackup, restoreBackup } } } function notEmptyPath(file: string) { - return ["", ".", "./"].indexOf(file) === -1; + return ["", ".", "./"].indexOf(file) === -1 } diff --git a/lib/backup/index.ts b/lib/backup/index.ts index a2f1d57..b56fc0e 100644 --- a/lib/backup/index.ts +++ b/lib/backup/index.ts @@ -1,3 +1,3 @@ -export { Backups } from "./Backups"; +export { Backups } from "./Backups" -export { setupBackups } from "./setupBackups"; +export { setupBackups } from "./setupBackups" diff --git a/lib/backup/setupBackups.ts b/lib/backup/setupBackups.ts index f9d4189..a32acec 100644 --- a/lib/backup/setupBackups.ts +++ b/lib/backup/setupBackups.ts @@ -1,17 +1,17 @@ -import { string } from "ts-matches"; -import { Backups } from "."; -import { GenericManifest } from "../manifest/ManifestTypes"; -import { BackupOptions } from "../types"; -import { _ } from "../util"; +import { string } from "ts-matches" +import { Backups } from "." +import { GenericManifest } from "../manifest/ManifestTypes" +import { BackupOptions } from "../types" +import { _ } from "../util" export type SetupBackupsParams = Array< keyof M["volumes"] & string ->; +> export function setupBackups( ...args: _> ) { - return Backups.volumes(...args).build(); + return Backups.volumes(...args).build() } export function setupBackupsOptions( @@ -20,5 +20,5 @@ export function setupBackupsOptions( ) { return Backups.with_options(options) .volumes(...args) - .build(); + .build() } diff --git a/lib/config/builder/builder.ts b/lib/config/builder/builder.ts index 86045b8..33805de 100644 --- a/lib/config/builder/builder.ts +++ b/lib/config/builder/builder.ts @@ -1,10 +1,10 @@ -import { _ } from "../../util"; +import { _ } from "../../util" export class IBuilder { protected constructor(readonly a: A) {} public build(): A { - return this.a; + return this.a } } -export type BuilderExtract = A extends IBuilder ? B : never; +export type BuilderExtract = A extends IBuilder ? B : never diff --git a/lib/config/builder/config.ts b/lib/config/builder/config.ts index 7c12ab7..2f2bfb3 100644 --- a/lib/config/builder/config.ts +++ b/lib/config/builder/config.ts @@ -1,8 +1,8 @@ -import { InputSpec, ValueSpec } from "../configTypes"; -import { typeFromProps } from "../../util"; -import { BuilderExtract, IBuilder } from "./builder"; -import { Value } from "./value"; -import { _ } from "../../util"; +import { InputSpec, ValueSpec } from "../configTypes" +import { typeFromProps } from "../../util" +import { BuilderExtract, IBuilder } from "./builder" +import { Value } from "./value" +import { _ } from "../../util" /** * Configs are the specs that are used by the os configuration form for this service. @@ -62,42 +62,42 @@ export const addNodesSpec = Config.of({ hostname: hostname, port: port }); */ export class Config extends IBuilder { static empty() { - return new Config({}); + return new Config({}) } static withValue( key: K, value: Value, ) { - return Config.empty().withValue(key, value); + return Config.empty().withValue(key, value) } static addValue( key: K, value: Value, ) { - return Config.empty().withValue(key, value); + return Config.empty().withValue(key, value) } static of }>(spec: B) { - const answer: { [K in keyof B]: BuilderExtract } = {} as any; + const answer: { [K in keyof B]: BuilderExtract } = {} as any for (const key in spec) { - answer[key] = spec[key].build() as any; + answer[key] = spec[key].build() as any } - return new Config(answer); + return new Config(answer) } withValue(key: K, value: Value) { return new Config({ ...this.a, [key]: value.build(), - } as A & { [key in K]: B }); + } as A & { [key in K]: B }) } addValue(key: K, value: Value) { return new Config({ ...this.a, [key]: value.build(), - } as A & { [key in K]: B }); + } as A & { [key in K]: B }) } public validator() { - return typeFromProps(this.a); + return typeFromProps(this.a) } } diff --git a/lib/config/builder/index.ts b/lib/config/builder/index.ts index c0c9b1e..84b807f 100644 --- a/lib/config/builder/index.ts +++ b/lib/config/builder/index.ts @@ -1,7 +1,7 @@ -import { Config } from "./config"; -import { List } from "./list"; -import { Value } from "./value"; -import { Variants } from "./variants"; +import { Config } from "./config" +import { List } from "./list" +import { Value } from "./value" +import { Variants } from "./variants" export { /** @typedef { import("./config").Config } Pet @@ -10,4 +10,4 @@ export { List, Value, Variants, -}; +} diff --git a/lib/config/builder/list.ts b/lib/config/builder/list.ts index 9f4d179..2e4ee8f 100644 --- a/lib/config/builder/list.ts +++ b/lib/config/builder/list.ts @@ -1,13 +1,13 @@ -import { BuilderExtract, IBuilder } from "./builder"; -import { Config } from "./config"; +import { BuilderExtract, IBuilder } from "./builder" +import { Config } from "./config" import { InputSpec, ListValueSpecText, Pattern, UniqueBy, ValueSpecList, -} from "../configTypes"; -import { guardAll } from "../../util"; +} from "../configTypes" +import { guardAll } from "../../util" /** * Used as a subtype of Value.list ```ts @@ -24,23 +24,23 @@ export const auth = Value.list(authorizationList); export class List extends IBuilder { static text( a: { - name: string; - description?: string | null; - warning?: string | null; + name: string + description?: string | null + warning?: string | null /** Default = [] */ - default?: string[]; - minLength?: number | null; - maxLength?: number | null; + default?: string[] + minLength?: number | null + maxLength?: number | null }, aSpec: { /** Default = false */ - masked?: boolean; - placeholder?: string | null; - minLength?: number | null; - maxLength?: number | null; - patterns: Pattern[]; + masked?: boolean + placeholder?: string | null + minLength?: number | null + maxLength?: number | null + patterns: Pattern[] /** Default = "text" */ - inputmode?: ListValueSpecText["inputmode"]; + inputmode?: ListValueSpecText["inputmode"] }, ) { const spec = { @@ -51,7 +51,7 @@ export class List extends IBuilder { masked: false, inputmode: "text" as const, ...aSpec, - }; + } return new List({ description: null, warning: null, @@ -61,25 +61,25 @@ export class List extends IBuilder { maxLength: null, ...a, spec, - }); + }) } static number( a: { - name: string; - description?: string | null; - warning?: string | null; + name: string + description?: string | null + warning?: string | null /** Default = [] */ - default?: string[]; - minLength?: number | null; - maxLength?: number | null; + default?: string[] + minLength?: number | null + maxLength?: number | null }, aSpec: { - integer: boolean; - min?: number | null; - max?: number | null; - step?: string | null; - units?: string | null; - placeholder?: string | null; + integer: boolean + min?: number | null + max?: number | null + step?: string | null + units?: string | null + placeholder?: string | null }, ) { const spec = { @@ -90,7 +90,7 @@ export class List extends IBuilder { step: null, units: null, ...aSpec, - }; + } return new List({ description: null, warning: null, @@ -100,38 +100,38 @@ export class List extends IBuilder { type: "list" as const, ...a, spec, - }); + }) } static obj>( a: { - name: string; - description?: string | null; - warning?: string | null; + name: string + description?: string | null + warning?: string | null /** Default [] */ - default?: []; - minLength?: number | null; - maxLength?: number | null; + default?: [] + minLength?: number | null + maxLength?: number | null }, aSpec: { - spec: Spec; - displayAs?: null | string; - uniqueBy?: null | UniqueBy; + spec: Spec + displayAs?: null | string + uniqueBy?: null | UniqueBy }, ) { - const { spec: previousSpecSpec, ...restSpec } = aSpec; - const specSpec = previousSpecSpec.build() as BuilderExtract; + const { spec: previousSpecSpec, ...restSpec } = aSpec + const specSpec = previousSpecSpec.build() as BuilderExtract const spec = { type: "object" as const, displayAs: null, uniqueBy: null, ...restSpec, spec: specSpec, - }; + } const value = { spec, default: [], ...a, - }; + } return new List({ description: null, warning: null, @@ -139,10 +139,10 @@ export class List extends IBuilder { maxLength: null, type: "list" as const, ...value, - }); + }) } public validator() { - return guardAll(this.a); + return guardAll(this.a) } } diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index 7e7b9ac..d1dd1c6 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -1,7 +1,7 @@ -import { BuilderExtract, IBuilder } from "./builder"; -import { Config } from "./config"; -import { List } from "./list"; -import { Variants } from "./variants"; +import { BuilderExtract, IBuilder } from "./builder" +import { Config } from "./config" +import { List } from "./list" +import { Variants } from "./variants" import { InputSpec, Pattern, @@ -13,32 +13,31 @@ import { ValueSpecSelect, ValueSpecText, ValueSpecTextarea, -} from "../configTypes"; -import { guardAll } from "../../util"; -import { DefaultString } from "../configTypes"; -import { _ } from "../../util"; +} from "../configTypes" +import { guardAll } from "../../util" +import { DefaultString } from "../configTypes" +import { _ } from "../../util" -type RequiredLike = +type RequiredDefault = | false - | true - | { default: A } - | { defaultWithRequired: A }; + | { + default: A | null + } -function requiredLikeToAbove>( +function requiredLikeToAbove, A>( requiredLike: Input, ) { // prettier-ignore return { - default: - (typeof requiredLike === "object" ? ( - 'default' in requiredLike ? requiredLike.default : requiredLike.defaultWithRequired - ) : - null) as Input extends { default: infer T } | {defaultWithRequired: infer T} ? T : null, - required: (requiredLike === true ? true : false) as ( + required: (typeof requiredLike === 'object' ? true : requiredLike) as ( + Input extends { default: unknown} ? true: Input extends true ? true : - Input extends { defaultWithRequired: unknown } ? true : false ), + default:(typeof requiredLike === 'object' ? requiredLike.default : null) as ( + Input extends { default: infer Default } ? Default : + null + ) }; } /** @@ -65,10 +64,10 @@ const username = Value.string({ */ export class Value extends IBuilder { static toggle(a: { - name: string; - description?: string | null; - warning?: string | null; - default?: boolean | null; + name: string + description?: string | null + warning?: string | null + default?: boolean | null }) { return new Value({ description: null, @@ -76,21 +75,22 @@ export class Value extends IBuilder { default: null, type: "toggle" as const, ...a, - }); + }) } - static text>(a: { - name: string; - description?: string | null; - warning?: string | null; - required: Required; + static text>(a: { + name: string + description?: string | null + warning?: string | null + required: Required + /** Default = false */ - masked?: boolean; - placeholder?: string | null; - minLength?: number | null; - maxLength?: number | null; - patterns?: Pattern[]; + masked?: boolean + placeholder?: string | null + minLength?: number | null + maxLength?: number | null + patterns?: Pattern[] /** Default = 'text' */ - inputmode?: ValueSpecText["inputmode"]; + inputmode?: ValueSpecText["inputmode"] }) { return new Value({ type: "text" as const, @@ -104,16 +104,16 @@ export class Value extends IBuilder { inputmode: "text", ...a, ...requiredLikeToAbove(a.required), - }); + }) } static textarea(a: { - name: string; - description?: string | null; - warning?: string | null; - required: boolean; - minLength?: number | null; - maxLength?: number | null; - placeholder?: string | null; + name: string + description?: string | null + warning?: string | null + required: boolean + minLength?: number | null + maxLength?: number | null + placeholder?: string | null }) { return new Value({ description: null, @@ -123,20 +123,20 @@ export class Value extends IBuilder { placeholder: null, type: "textarea" as const, ...a, - } as ValueSpecTextarea); + } as ValueSpecTextarea) } - static number>(a: { - name: string; - description?: string | null; - warning?: string | null; - required: Required; - min?: number | null; - max?: number | null; + static number>(a: { + name: string + description?: string | null + warning?: string | null + required: Required + min?: number | null + max?: number | null /** Default = '1' */ - step?: string | null; - integer: boolean; - units?: string | null; - placeholder?: string | null; + step?: string | null + integer: boolean + units?: string | null + placeholder?: string | null }) { return new Value({ type: "number" as const, @@ -149,13 +149,13 @@ export class Value extends IBuilder { placeholder: null, ...a, ...requiredLikeToAbove(a.required), - }); + }) } - static color>(a: { - name: string; - description?: string | null; - warning?: string | null; - required: Required; + static color>(a: { + name: string + description?: string | null + warning?: string | null + required: Required }) { return new Value({ type: "color" as const, @@ -163,18 +163,18 @@ export class Value extends IBuilder { warning: null, ...a, ...requiredLikeToAbove(a.required), - }); + }) } - static datetime>(a: { - name: string; - description?: string | null; - warning?: string | null; - required: Required; + static datetime>(a: { + name: string + description?: string | null + warning?: string | null + required: Required /** Default = 'datetime-local' */ - inputmode?: ValueSpecDatetime["inputmode"]; - min?: string | null; - max?: string | null; - step?: string | null; + inputmode?: ValueSpecDatetime["inputmode"] + min?: string | null + max?: string | null + step?: string | null }) { return new Value({ type: "datetime" as const, @@ -186,17 +186,17 @@ export class Value extends IBuilder { step: null, ...a, ...requiredLikeToAbove(a.required), - }); + }) } static select< - Required extends RequiredLike, + Required extends RequiredDefault, B extends Record, >(a: { - name: string; - description?: string | null; - warning?: string | null; - required: Required; - values: B; + name: string + description?: string | null + warning?: string | null + required: Required + values: B }) { return new Value({ description: null, @@ -204,16 +204,16 @@ export class Value extends IBuilder { type: "select" as const, ...a, ...requiredLikeToAbove(a.required), - }); + }) } static multiselect>(a: { - name: string; - description?: string | null; - warning?: string | null; - default: string[]; - values: Values; - minLength?: number | null; - maxLength?: number | null; + name: string + description?: string | null + warning?: string | null + default: string[] + values: Values + minLength?: number | null + maxLength?: number | null }) { return new Value({ type: "multiselect" as const, @@ -222,39 +222,39 @@ export class Value extends IBuilder { warning: null, description: null, ...a, - }); + }) } static object>( a: { - name: string; - description?: string | null; - warning?: string | null; + name: string + description?: string | null + warning?: string | null }, previousSpec: Spec, ) { - const spec = previousSpec.build() as BuilderExtract; + const spec = previousSpec.build() as BuilderExtract return new Value({ type: "object" as const, description: null, warning: null, ...a, spec, - }); + }) } static union< - Required extends RequiredLike, + Required extends RequiredDefault, V extends Variants<{ [key: string]: { name: string; spec: InputSpec } }>, >( a: { - name: string; - description?: string | null; - warning?: string | null; - required: Required; - default?: string | null; + name: string + description?: string | null + warning?: string | null + required: Required + default?: string | null }, aVariants: V, ) { - const variants = aVariants.build() as BuilderExtract; + const variants = aVariants.build() as BuilderExtract return new Value({ type: "union" as const, description: null, @@ -262,13 +262,13 @@ export class Value extends IBuilder { ...a, variants, ...requiredLikeToAbove(a.required), - }); + }) } static list(a: List) { - return new Value(a.build()); + return new Value(a.build()) } public validator() { - return guardAll(this.a); + return guardAll(this.a) } } diff --git a/lib/config/builder/variants.ts b/lib/config/builder/variants.ts index 99eb515..5d9c7c0 100644 --- a/lib/config/builder/variants.ts +++ b/lib/config/builder/variants.ts @@ -1,6 +1,6 @@ -import { InputSpec } from "../configTypes"; -import { BuilderExtract, IBuilder } from "./builder"; -import { Config } from "."; +import { InputSpec } from "../configTypes" +import { BuilderExtract, IBuilder } from "./builder" +import { Config } from "." /** * Used in the the Value.select { @link './value.ts' } @@ -54,43 +54,43 @@ export const pruning = Value.union( export class Variants< A extends { [key: string]: { - name: string; - spec: InputSpec; - }; + name: string + spec: InputSpec + } }, > extends IBuilder { static of< A extends { - [key: string]: { name: string; spec: Config }; + [key: string]: { name: string; spec: Config } }, >(a: A) { const variants: { - [K in keyof A]: { name: string; spec: BuilderExtract }; - } = {} as any; + [K in keyof A]: { name: string; spec: BuilderExtract } + } = {} as any for (const key in a) { - const value = a[key]; + const value = a[key] variants[key] = { name: value.name, spec: value.spec.build() as any, - }; + } } - return new Variants(variants); + return new Variants(variants) } static empty() { - return Variants.of({}); + return Variants.of({}) } static withVariant( key: K, value: Config, ) { - return Variants.empty().withVariant(key, value); + return Variants.empty().withVariant(key, value) } withVariant(key: K, value: Config) { return new Variants({ ...this.a, [key]: value.build(), - } as A & { [key in K]: B }); + } as A & { [key in K]: B }) } } diff --git a/lib/config/configTypes.ts b/lib/config/configTypes.ts index 4b080d6..d9928e8 100644 --- a/lib/config/configTypes.ts +++ b/lib/config/configTypes.ts @@ -1,4 +1,4 @@ -export type InputSpec = Record; +export type InputSpec = Record export type ValueType = | "text" | "textarea" @@ -11,8 +11,8 @@ export type ValueType = | "list" | "object" | "file" - | "union"; -export type ValueSpec = ValueSpecOf; + | "union" +export type ValueSpec = ValueSpecOf /** core spec types. These types provide the metadata for performing validations */ export type ValueSpecOf = T extends "text" ? ValueSpecText @@ -38,82 +38,82 @@ export type ValueSpecOf = T extends "text" ? ValueSpecFile : T extends "union" ? ValueSpecUnion - : never; + : never export interface ValueSpecText extends ListValueSpecText, WithStandalone { - required: boolean; - default: DefaultString | null; + required: boolean + default: DefaultString | null } export interface ValueSpecTextarea extends WithStandalone { - type: "textarea"; - placeholder: string | null; - minLength: number | null; - maxLength: number | null; - required: boolean; + type: "textarea" + placeholder: string | null + minLength: number | null + maxLength: number | null + required: boolean } export interface ValueSpecNumber extends ListValueSpecNumber, WithStandalone { - required: boolean; - default: number | null; + required: boolean + default: number | null } export interface ValueSpecColor extends WithStandalone { - type: "color"; - required: boolean; - default: string | null; + type: "color" + required: boolean + default: string | null } export interface ValueSpecDatetime extends WithStandalone { - type: "datetime"; - required: boolean; - inputmode: "date" | "time" | "datetime-local"; - min: string | null; - max: string | null; - step: string | null; - default: string | null; + type: "datetime" + required: boolean + inputmode: "date" | "time" | "datetime-local" + min: string | null + max: string | null + step: string | null + default: string | null } export interface ValueSpecSelect extends SelectBase, WithStandalone { - type: "select"; - required: boolean; - default: string | null; + type: "select" + required: boolean + default: string | null } export interface ValueSpecMultiselect extends SelectBase, WithStandalone { - type: "multiselect"; - minLength: number | null; - maxLength: number | null; - default: string[]; + type: "multiselect" + minLength: number | null + maxLength: number | null + default: string[] } export interface ValueSpecToggle extends WithStandalone { - type: "toggle"; - default: boolean | null; + type: "toggle" + default: boolean | null } export interface ValueSpecUnion extends WithStandalone { - type: "union"; + type: "union" variants: Record< string, { - name: string; - spec: InputSpec; + name: string + spec: InputSpec } - >; - required: boolean; - default: string | null; + > + required: boolean + default: string | null } export interface ValueSpecFile extends WithStandalone { - type: "file"; - extensions: string[]; - required: boolean; + type: "file" + extensions: string[] + required: boolean } export interface ValueSpecObject extends WithStandalone { - type: "object"; - spec: InputSpec; + type: "object" + spec: InputSpec } export interface WithStandalone { - name: string; - description: string | null; - warning: string | null; + name: string + description: string | null + warning: string | null } export interface SelectBase { - values: Record; + values: Record } -export type ListValueSpecType = "text" | "number" | "object"; +export type ListValueSpecType = "text" | "number" | "object" /** represents a spec for the values of a list */ export type ListValueSpecOf = T extends "text" ? ListValueSpecText @@ -121,15 +121,15 @@ export type ListValueSpecOf = T extends "text" ? ListValueSpecNumber : T extends "object" ? ListValueSpecObject - : never; + : never /** represents a spec for a list */ -export type ValueSpecList = ValueSpecListOf; +export type ValueSpecList = ValueSpecListOf export interface ValueSpecListOf extends WithStandalone { - type: "list"; - spec: ListValueSpecOf; - minLength: number | null; - maxLength: number | null; + type: "list" + spec: ListValueSpecOf + minLength: number | null + maxLength: number | null default: | string[] | number[] @@ -138,64 +138,64 @@ export interface ValueSpecListOf | readonly string[] | readonly number[] | readonly DefaultString[] - | readonly Record[]; + | readonly Record[] } export interface Pattern { - regex: string; - description: string; + regex: string + description: string } export interface ListValueSpecText { - type: "text"; - patterns: Pattern[]; - minLength: number | null; - maxLength: number | null; - masked: boolean; - inputmode: "text" | "email" | "tel" | "url"; - placeholder: string | null; + type: "text" + patterns: Pattern[] + minLength: number | null + maxLength: number | null + masked: boolean + inputmode: "text" | "email" | "tel" | "url" + placeholder: string | null } export interface ListValueSpecNumber { - type: "number"; - min: number | null; - max: number | null; - integer: boolean; - step: string | null; - units: string | null; - placeholder: string | null; + type: "number" + min: number | null + max: number | null + integer: boolean + step: string | null + units: string | null + placeholder: string | null } export interface ListValueSpecObject { - type: "object"; + 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; + spec: InputSpec /** indicates whether duplicates can be permitted in the list */ - uniqueBy: UniqueBy; + uniqueBy: UniqueBy /** this should be a handlebars template which can make use of the entire config which corresponds to 'spec' */ - displayAs: string | null; + displayAs: string | null } export type UniqueBy = | null | string | { - any: readonly UniqueBy[] | UniqueBy[]; + any: readonly UniqueBy[] | UniqueBy[] } | { - all: readonly UniqueBy[] | UniqueBy[]; - }; + all: readonly UniqueBy[] | UniqueBy[] + } export type DefaultString = | string | { - charset: string; - len: number; - }; + charset: string + len: number + } // sometimes the type checker needs just a little bit of help export function isValueSpecListOf( t: ValueSpecListOf, s: S, ): t is ValueSpecListOf & { spec: ListValueSpecOf } { - return t.spec.type === s; + return t.spec.type === s } -export const unionSelectKey = "unionSelectKey" as const; -export type UnionSelectKey = typeof unionSelectKey; +export const unionSelectKey = "unionSelectKey" as const +export type UnionSelectKey = typeof unionSelectKey -export const unionValueKey = "unionValueKey" as const; -export type UnionValueKey = typeof unionValueKey; +export const unionValueKey = "unionValueKey" as const +export type UnionValueKey = typeof unionValueKey diff --git a/lib/config/dependencies.ts b/lib/config/dependencies.ts index d4d46bf..80c7843 100644 --- a/lib/config/dependencies.ts +++ b/lib/config/dependencies.ts @@ -1,10 +1,10 @@ -import { GenericManifest } from "../manifest/ManifestTypes"; -import { Dependency, PackageId } from "../types"; +import { GenericManifest } from "../manifest/ManifestTypes" +import { Dependency, PackageId } from "../types" export type Dependencies = { - exists(id: keyof T["dependencies"]): Dependency; - running(id: keyof T["dependencies"]): Dependency; -}; + exists(id: keyof T["dependencies"]): Dependency + running(id: keyof T["dependencies"]): Dependency +} export const dependenciesSet = < T extends GenericManifest, @@ -13,13 +13,13 @@ export const dependenciesSet = < return { id, kind: "exists", - } as Dependency; + } as Dependency }, running(id: keyof T["dependencies"]) { return { id, kind: "running", - } as Dependency; + } as Dependency }, -}); +}) diff --git a/lib/config/index.ts b/lib/config/index.ts index 8d08c94..ff4b602 100644 --- a/lib/config/index.ts +++ b/lib/config/index.ts @@ -1,4 +1,4 @@ -export * as configBuilder from "./builder"; +export * as configBuilder from "./builder" -export { setupConfig } from "./setupConfig"; -export * as dependencies from "./dependencies"; +export { setupConfig } from "./setupConfig" +export * as dependencies from "./dependencies" diff --git a/lib/config/setupConfig.ts b/lib/config/setupConfig.ts index 26f2221..755be5e 100644 --- a/lib/config/setupConfig.ts +++ b/lib/config/setupConfig.ts @@ -1,26 +1,26 @@ -import { Config } from "./builder"; -import { DeepPartial, Dependencies, Effects, ExpectedExports } from "../types"; -import { InputSpec } from "./configTypes"; -import { Utils, nullIfEmpty, once, utils } from "../util"; -import { TypeFromProps } from "../util/propertiesMatcher"; -import { GenericManifest } from "../manifest/ManifestTypes"; -import * as D from "./dependencies"; +import { Config } from "./builder" +import { DeepPartial, Dependencies, Effects, ExpectedExports } from "../types" +import { InputSpec } from "./configTypes" +import { Utils, nullIfEmpty, once, utils } from "../util" +import { TypeFromProps } from "../util/propertiesMatcher" +import { GenericManifest } from "../manifest/ManifestTypes" +import * as D from "./dependencies" -declare const dependencyProof: unique symbol; +declare const dependencyProof: unique symbol export type DependenciesReceipt = void & { - [dependencyProof]: never; -}; + [dependencyProof]: never +} export type Save = (options: { - effects: Effects; - input: A; - utils: Utils; - dependencies: D.Dependencies; -}) => Promise; + effects: Effects + input: A + utils: Utils + dependencies: D.Dependencies +}) => Promise export type Read = (options: { - effects: Effects; - utils: Utils; -}) => Promise>; + effects: Effects + utils: Utils +}) => Promise> /** * We want to setup a config export with a get and set, this * is going to be the default helper to setup config, because it will help @@ -37,19 +37,19 @@ export function setupConfig< write: Save, Manifest>, read: Read>, ) { - const validator = once(() => spec.validator()); + const validator = once(() => spec.validator()) return { setConfig: (async ({ effects, input }) => { if (!validator().test(input)) { - await effects.error(String(validator().errorMessage(input))); - return { error: "Set config type error for config" }; + await effects.console.error(String(validator().errorMessage(input))) + return { error: "Set config type error for config" } } await write({ input: JSON.parse(JSON.stringify(input)), effects, utils: utils(effects), dependencies: D.dependenciesSet(), - }); + }) }) as ExpectedExports.setConfig, getConfig: (async ({ effects, config }) => { return { @@ -57,9 +57,9 @@ export function setupConfig< config: nullIfEmpty( (await read({ effects, utils: utils(effects) })) || null, ), - }; + } }) as ExpectedExports.getConfig, - }; + } } -export default setupConfig; +export default setupConfig diff --git a/lib/emverLite/mod.ts b/lib/emverLite/mod.ts index c892cc8..db1e983 100644 --- a/lib/emverLite/mod.ts +++ b/lib/emverLite/mod.ts @@ -1,13 +1,13 @@ -import * as matches from "ts-matches"; +import * as matches from "ts-matches" -const starSub = /((\d+\.)*\d+)\.\*/; +const starSub = /((\d+\.)*\d+)\.\*/ // prettier-ignore export type ValidEmVer = `${number | '*'}${`.${number | '*'}` | ""}${`.${number | '*'}` | ""}${`-${string}` | ""}`; function incrementLastNumber(list: number[]) { - const newList = [...list]; - newList[newList.length - 1]++; - return newList; + const newList = [...list] + newList[newList.length - 1]++ + return newList } /** * Will take in a range, like `>1.2` or `<1.2.3.4` or `=1.2` or `1.*` @@ -16,7 +16,7 @@ function incrementLastNumber(list: number[]) { * @returns */ export function rangeOf(range: string | Checker): Checker { - return Checker.parse(range); + return Checker.parse(range) } /** @@ -26,10 +26,10 @@ export function rangeOf(range: string | Checker): Checker { */ export function rangeAnd(...ranges: (string | Checker)[]): Checker { if (ranges.length === 0) { - throw new Error("No ranges given"); + throw new Error("No ranges given") } - const [firstCheck, ...rest] = ranges; - return Checker.parse(firstCheck).and(...rest); + const [firstCheck, ...rest] = ranges + return Checker.parse(firstCheck).and(...rest) } /** @@ -39,10 +39,10 @@ export function rangeAnd(...ranges: (string | Checker)[]): Checker { */ export function rangeOr(...ranges: (string | Checker)[]): Checker { if (ranges.length === 0) { - throw new Error("No ranges given"); + throw new Error("No ranges given") } - const [firstCheck, ...rest] = ranges; - return Checker.parse(firstCheck).or(...rest); + const [firstCheck, ...rest] = ranges + return Checker.parse(firstCheck).or(...rest) } /** @@ -51,7 +51,7 @@ export function rangeOr(...ranges: (string | Checker)[]): Checker { * @returns */ export function notRange(range: string | Checker): Checker { - return rangeOf(range).not(); + return rangeOf(range).not() } /** @@ -65,23 +65,23 @@ export class EmVer { */ static from(range: ValidEmVer | EmVer): EmVer { if (range instanceof EmVer) { - return range; + return range } - return EmVer.parse(range); + return EmVer.parse(range) } /** * Convert the range, should be 1.2.* or * into a emver * IsUnsafe */ static parse(rangeExtra: string): EmVer { - const [range, extra] = rangeExtra.split("-"); - const values = range.split(".").map((x) => parseInt(x)); + const [range, extra] = rangeExtra.split("-") + const values = range.split(".").map((x) => parseInt(x)) for (const value of values) { if (isNaN(value)) { - throw new Error(`Couldn't parse range: ${range}`); + throw new Error(`Couldn't parse range: ${range}`) } } - return new EmVer(values, extra); + return new EmVer(values, extra) } private constructor( public readonly values: number[], @@ -92,44 +92,44 @@ export class EmVer { * Used when we need a new emver that has the last number incremented, used in the 1.* like things */ public withLastIncremented() { - return new EmVer(incrementLastNumber(this.values), null); + return new EmVer(incrementLastNumber(this.values), null) } public greaterThan(other: EmVer): boolean { for (const i in this.values) { if (other.values[i] == null) { - return true; + return true } if (this.values[i] > other.values[i]) { - return true; + return true } if (this.values[i] < other.values[i]) { - return false; + return false } } - return false; + return false } public equals(other: EmVer): boolean { if (other.values.length !== this.values.length) { - return false; + return false } for (const i in this.values) { if (this.values[i] !== other.values[i]) { - return false; + return false } } - return true; + return true } public greaterThanOrEqual(other: EmVer): boolean { - return this.greaterThan(other) || this.equals(other); + return this.greaterThan(other) || this.equals(other) } public lessThanOrEqual(other: EmVer): boolean { - return !this.greaterThan(other); + return !this.greaterThan(other) } public lessThan(other: EmVer): boolean { - return !this.greaterThanOrEqual(other); + return !this.greaterThanOrEqual(other) } /** * Return a enum string that describes (used for switching/iffs) @@ -139,11 +139,11 @@ export class EmVer { */ public compare(other: EmVer) { if (this.equals(other)) { - return "equal" as const; + return "equal" as const } else if (this.greaterThan(other)) { - return "greater" as const; + return "greater" as const } else { - return "less" as const; + return "less" as const } } /** @@ -157,11 +157,11 @@ export class EmVer { .when("equal", () => 0 as const) .when("greater", () => 1 as const) .when("less", () => -1 as const) - .unwrap(); + .unwrap() } toString() { - return `${this.values.join(".")}${this.extra ? `-${this.extra}` : ""}`; + return `${this.values.join(".")}${this.extra ? `-${this.extra}` : ""}` } } @@ -178,80 +178,80 @@ export class Checker { */ static parse(range: string | Checker): Checker { if (range instanceof Checker) { - return range; + return range } - range = range.trim(); + range = range.trim() if (range.indexOf("||") !== -1) { - return rangeOr(...range.split("||").map((x) => Checker.parse(x))); + return rangeOr(...range.split("||").map((x) => Checker.parse(x))) } if (range.indexOf("&&") !== -1) { - return rangeAnd(...range.split("&&").map((x) => Checker.parse(x))); + return rangeAnd(...range.split("&&").map((x) => Checker.parse(x))) } if (range === "*") { return new Checker((version) => { - EmVer.from(version); - return true; - }); + EmVer.from(version) + return true + }) } if (range.startsWith("!")) { - return Checker.parse(range.substring(1)).not(); + return Checker.parse(range.substring(1)).not() } - const starSubMatches = starSub.exec(range); + const starSubMatches = starSub.exec(range) if (starSubMatches != null) { - const emVarLower = EmVer.parse(starSubMatches[1]); - const emVarUpper = emVarLower.withLastIncremented(); + const emVarLower = EmVer.parse(starSubMatches[1]) + const emVarUpper = emVarLower.withLastIncremented() return new Checker((version) => { - const v = EmVer.from(version); + const v = EmVer.from(version) return ( (v.greaterThan(emVarLower) || v.equals(emVarLower)) && !v.greaterThan(emVarUpper) && !v.equals(emVarUpper) - ); - }); + ) + }) } switch (range.substring(0, 2)) { case ">=": { - const emVar = EmVer.parse(range.substring(2)); + const emVar = EmVer.parse(range.substring(2)) return new Checker((version) => { - const v = EmVer.from(version); - return v.greaterThanOrEqual(emVar); - }); + const v = EmVer.from(version) + return v.greaterThanOrEqual(emVar) + }) } case "<=": { - const emVar = EmVer.parse(range.substring(2)); + const emVar = EmVer.parse(range.substring(2)) return new Checker((version) => { - const v = EmVer.from(version); - return v.lessThanOrEqual(emVar); - }); + const v = EmVer.from(version) + return v.lessThanOrEqual(emVar) + }) } } switch (range.substring(0, 1)) { case ">": { - const emVar = EmVer.parse(range.substring(1)); + const emVar = EmVer.parse(range.substring(1)) return new Checker((version) => { - const v = EmVer.from(version); - return v.greaterThan(emVar); - }); + const v = EmVer.from(version) + return v.greaterThan(emVar) + }) } case "<": { - const emVar = EmVer.parse(range.substring(1)); + const emVar = EmVer.parse(range.substring(1)) return new Checker((version) => { - const v = EmVer.from(version); - return v.lessThan(emVar); - }); + const v = EmVer.from(version) + return v.lessThan(emVar) + }) } case "=": { - const emVar = EmVer.parse(range.substring(1)); + const emVar = EmVer.parse(range.substring(1)) return new Checker((version) => { - const v = EmVer.from(version); - return v.equals(emVar); - }); + const v = EmVer.from(version) + return v.equals(emVar) + }) } } - throw new Error("Couldn't parse range: " + range); + throw new Error("Couldn't parse range: " + range) } constructor( /** @@ -267,15 +267,15 @@ export class Checker { public and(...others: (Checker | string)[]): Checker { return new Checker((value) => { if (!this.check(value)) { - return false; + return false } for (const other of others) { if (!Checker.parse(other).check(value)) { - return false; + return false } } - return true; - }); + return true + }) } /** @@ -284,15 +284,15 @@ export class Checker { public or(...others: (Checker | string)[]): Checker { return new Checker((value) => { if (this.check(value)) { - return true; + return true } for (const other of others) { if (Checker.parse(other).check(value)) { - return true; + return true } } - return false; - }); + return false + }) } /** @@ -300,6 +300,6 @@ export class Checker { * @returns */ public not(): Checker { - return new Checker((value) => !this.check(value)); + return new Checker((value) => !this.check(value)) } } diff --git a/lib/health/HealthCheck.ts b/lib/health/HealthCheck.ts index 53578eb..67c2245 100644 --- a/lib/health/HealthCheck.ts +++ b/lib/health/HealthCheck.ts @@ -1,43 +1,43 @@ -import { InterfaceReceipt } from "../mainFn/interfaceReceipt"; -import { Daemon, Effects } from "../types"; -import { CheckResult } from "./checkFns/CheckResult"; -import { HealthReceipt } from "./HealthReceipt"; -import { Trigger } from "./trigger"; -import { TriggerInput } from "./trigger/TriggerInput"; -import { defaultTrigger } from "./trigger/defaultTrigger"; +import { InterfaceReceipt } from "../mainFn/interfaceReceipt" +import { Daemon, Effects } from "../types" +import { CheckResult } from "./checkFns/CheckResult" +import { HealthReceipt } from "./HealthReceipt" +import { Trigger } from "./trigger" +import { TriggerInput } from "./trigger/TriggerInput" +import { defaultTrigger } from "./trigger/defaultTrigger" export function healthCheck(o: { - effects: Effects; - name: string; - trigger?: Trigger; - fn(): Promise | CheckResult; - onFirstSuccess?: () => () => Promise | unknown; + effects: Effects + name: string + trigger?: Trigger + fn(): Promise | CheckResult + onFirstSuccess?: () => () => Promise | unknown }) { new Promise(async () => { let currentValue: TriggerInput = { lastResult: null, hadSuccess: false, - }; - const getCurrentValue = () => currentValue; - const trigger = (o.trigger ?? defaultTrigger)(getCurrentValue); + } + const getCurrentValue = () => currentValue + const trigger = (o.trigger ?? defaultTrigger)(getCurrentValue) for ( let res = await trigger.next(); !res.done; res = await trigger.next() ) { try { - const { status, message } = await o.fn(); + const { status, message } = await o.fn() await o.effects.setHealth({ name: o.name, status, message, - }); - currentValue.hadSuccess = true; - currentValue.lastResult = "success"; + }) + currentValue.hadSuccess = true + currentValue.lastResult = "success" } catch (_) { - currentValue.lastResult = "failure"; + currentValue.lastResult = "failure" } } - }); - return {} as HealthReceipt; + }) + return {} as HealthReceipt } diff --git a/lib/health/HealthReceipt.ts b/lib/health/HealthReceipt.ts index 3f0d1e0..a0995ba 100644 --- a/lib/health/HealthReceipt.ts +++ b/lib/health/HealthReceipt.ts @@ -1,4 +1,4 @@ -declare const HealthProof: unique symbol; +declare const HealthProof: unique symbol export type HealthReceipt = { - [HealthProof]: never; -}; + [HealthProof]: never +} diff --git a/lib/health/checkFns/CheckResult.ts b/lib/health/checkFns/CheckResult.ts index 2d7bbda..1b2f54f 100644 --- a/lib/health/checkFns/CheckResult.ts +++ b/lib/health/checkFns/CheckResult.ts @@ -1,6 +1,6 @@ -import { HealthStatus } from "../../types"; +import { HealthStatus } from "../../types" export type CheckResult = { - status: HealthStatus; - message?: string; -}; + status: HealthStatus + message?: string +} diff --git a/lib/health/checkFns/checkPortListening.ts b/lib/health/checkFns/checkPortListening.ts index 9d840cb..fb74902 100644 --- a/lib/health/checkFns/checkPortListening.ts +++ b/lib/health/checkFns/checkPortListening.ts @@ -1,5 +1,5 @@ -import { Effects } from "../../types"; -import { CheckResult } from "./CheckResult"; +import { Effects } from "../../types" +import { CheckResult } from "./CheckResult" export function containsAddress(x: string, port: number) { const readPorts = x .split("\n") @@ -8,8 +8,8 @@ export function containsAddress(x: string, port: number) { .map((x) => x.split(" ").filter(Boolean)[1]?.split(":")?.[1]) .filter(Boolean) .map((x) => Number.parseInt(x, 16)) - .filter(Number.isFinite); - return readPorts.indexOf(port) >= 0; + .filter(Number.isFinite) + return readPorts.indexOf(port) >= 0 } /** @@ -26,12 +26,12 @@ export async function checkPortListening( ): Promise { const hasAddress = containsAddress(await effects.runCommand(`cat /proc/net/tcp`), port) || - containsAddress(await effects.runCommand("cat /proc/net/udp"), port); + containsAddress(await effects.runCommand("cat /proc/net/udp"), port) if (hasAddress) { - return { status: "passing", message }; + return { status: "passing", message } } return { status: "failing", message: error, - }; + } } diff --git a/lib/health/checkFns/checkWebUrl.ts b/lib/health/checkFns/checkWebUrl.ts index 8f9ffdf..4b0acd5 100644 --- a/lib/health/checkFns/checkWebUrl.ts +++ b/lib/health/checkFns/checkWebUrl.ts @@ -1,6 +1,6 @@ -import { Effects } from "../../types"; -import { CheckResult } from "./CheckResult"; -import { timeoutPromise } from "./index"; +import { Effects } from "../../types" +import { CheckResult } from "./CheckResult" +import { timeoutPromise } from "./index" /** * This is a helper function to check if a web url is reachable. @@ -23,9 +23,9 @@ export const checkWebUrl = async ( message: successMessage, })) .catch((e) => { - effects.warn(`Error while fetching URL: ${url}`); - effects.error(JSON.stringify(e)); - effects.error(e.toString()); - return { status: "failing" as const, message: errorMessage }; - }); -}; + effects.console.warn(`Error while fetching URL: ${url}`) + effects.console.error(JSON.stringify(e)) + effects.console.error(e.toString()) + return { status: "failing" as const, message: errorMessage } + }) +} diff --git a/lib/health/checkFns/index.ts b/lib/health/checkFns/index.ts index 184f273..d33d5ad 100644 --- a/lib/health/checkFns/index.ts +++ b/lib/health/checkFns/index.ts @@ -1,11 +1,11 @@ -import { runHealthScript } from "./runHealthScript"; -export { checkPortListening } from "./checkPortListening"; -export { CheckResult } from "./CheckResult"; -export { checkWebUrl } from "./checkWebUrl"; +import { runHealthScript } from "./runHealthScript" +export { checkPortListening } from "./checkPortListening" +export { CheckResult } from "./CheckResult" +export { checkWebUrl } from "./checkWebUrl" export function timeoutPromise(ms: number, { message = "Timed out" } = {}) { return new Promise((resolve, reject) => setTimeout(() => reject(new Error(message)), ms), - ); + ) } -export { runHealthScript }; +export { runHealthScript } diff --git a/lib/health/checkFns/runHealthScript.ts b/lib/health/checkFns/runHealthScript.ts index f84b942..ad1ebfe 100644 --- a/lib/health/checkFns/runHealthScript.ts +++ b/lib/health/checkFns/runHealthScript.ts @@ -1,6 +1,6 @@ -import { CommandType, Effects } from "../../types"; -import { CheckResult } from "./CheckResult"; -import { timeoutPromise } from "./index"; +import { CommandType, Effects } from "../../types" +import { CheckResult } from "./CheckResult" +import { timeoutPromise } from "./index" /** * Running a health script, is used when we want to have a simple @@ -23,13 +23,13 @@ export const runHealthScript = async ( effects.runCommand(runCommand, { timeoutMillis: timeout }), timeoutPromise(timeout), ]).catch((e) => { - effects.warn(errorMessage); - effects.warn(JSON.stringify(e)); - effects.warn(e.toString()); - throw { status: "failing", message: errorMessage } as CheckResult; - }); + effects.console.warn(errorMessage) + effects.console.warn(JSON.stringify(e)) + effects.console.warn(e.toString()) + throw { status: "failing", message: errorMessage } as CheckResult + }) return { status: "passing", message: message(res), - } as CheckResult; -}; + } as CheckResult +} diff --git a/lib/health/index.ts b/lib/health/index.ts index 6a50a75..45a2b3c 100644 --- a/lib/health/index.ts +++ b/lib/health/index.ts @@ -1,6 +1,6 @@ -export * as checkFns from "./checkFns"; -export * as trigger from "./trigger"; +export * as checkFns from "./checkFns" +export * as trigger from "./trigger" -export { TriggerInput } from "./trigger/TriggerInput"; -export { HealthReceipt } from "./HealthReceipt"; -export { ReadyProof } from "../mainFn/ReadyProof"; +export { TriggerInput } from "./trigger/TriggerInput" +export { HealthReceipt } from "./HealthReceipt" +export { ReadyProof } from "../mainFn/ReadyProof" diff --git a/lib/health/trigger/TriggerInput.ts b/lib/health/trigger/TriggerInput.ts index 18e7756..8885c70 100644 --- a/lib/health/trigger/TriggerInput.ts +++ b/lib/health/trigger/TriggerInput.ts @@ -1,4 +1,4 @@ export type TriggerInput = { - lastResult?: "success" | "failure" | null; - hadSuccess?: boolean; -}; + lastResult?: "success" | "failure" | null + hadSuccess?: boolean +} diff --git a/lib/health/trigger/changeOnFirstSuccess.ts b/lib/health/trigger/changeOnFirstSuccess.ts index aa0c151..03d1cd5 100644 --- a/lib/health/trigger/changeOnFirstSuccess.ts +++ b/lib/health/trigger/changeOnFirstSuccess.ts @@ -1,31 +1,31 @@ -import { TriggerInput } from "./TriggerInput"; -import { Trigger } from "./index"; +import { TriggerInput } from "./TriggerInput" +import { Trigger } from "./index" export function changeOnFirstSuccess(o: { - beforeFirstSuccess: Trigger; - afterFirstSuccess: Trigger; + beforeFirstSuccess: Trigger + afterFirstSuccess: Trigger }): Trigger { return async function* (getInput) { - const beforeFirstSuccess = o.beforeFirstSuccess(getInput); - yield; - let currentValue = getInput(); - beforeFirstSuccess.next(); + const beforeFirstSuccess = o.beforeFirstSuccess(getInput) + yield + let currentValue = getInput() + beforeFirstSuccess.next() for ( let res = await beforeFirstSuccess.next(); currentValue?.lastResult !== "success" && !res.done; res = await beforeFirstSuccess.next() ) { - yield; - currentValue = getInput(); + yield + currentValue = getInput() } - const afterFirstSuccess = o.afterFirstSuccess(getInput); + const afterFirstSuccess = o.afterFirstSuccess(getInput) for ( let res = await afterFirstSuccess.next(); !res.done; res = await afterFirstSuccess.next() ) { - yield; - currentValue = getInput(); + yield + currentValue = getInput() } - }; + } } diff --git a/lib/health/trigger/cooldownTrigger.ts b/lib/health/trigger/cooldownTrigger.ts index 27454e0..991e810 100644 --- a/lib/health/trigger/cooldownTrigger.ts +++ b/lib/health/trigger/cooldownTrigger.ts @@ -1,8 +1,8 @@ export function cooldownTrigger(timeMs: number) { return async function* () { while (true) { - await new Promise((resolve) => setTimeout(resolve, timeMs)); - yield; + await new Promise((resolve) => setTimeout(resolve, timeMs)) + yield } - }; + } } diff --git a/lib/health/trigger/defaultTrigger.ts b/lib/health/trigger/defaultTrigger.ts index 74cdf86..7c34cc7 100644 --- a/lib/health/trigger/defaultTrigger.ts +++ b/lib/health/trigger/defaultTrigger.ts @@ -1,7 +1,7 @@ -import { cooldownTrigger } from "./cooldownTrigger"; -import { changeOnFirstSuccess } from "./changeOnFirstSuccess"; +import { cooldownTrigger } from "./cooldownTrigger" +import { changeOnFirstSuccess } from "./changeOnFirstSuccess" export const defaultTrigger = changeOnFirstSuccess({ beforeFirstSuccess: cooldownTrigger(0), afterFirstSuccess: cooldownTrigger(30000), -}); +}) diff --git a/lib/health/trigger/index.ts b/lib/health/trigger/index.ts index 91f6982..6da0342 100644 --- a/lib/health/trigger/index.ts +++ b/lib/health/trigger/index.ts @@ -1,7 +1,7 @@ -import { TriggerInput } from "./TriggerInput"; -export { changeOnFirstSuccess } from "./changeOnFirstSuccess"; -export { cooldownTrigger } from "./cooldownTrigger"; +import { TriggerInput } from "./TriggerInput" +export { changeOnFirstSuccess } from "./changeOnFirstSuccess" +export { cooldownTrigger } from "./cooldownTrigger" export type Trigger = ( getInput: () => TriggerInput, -) => AsyncIterator; +) => AsyncIterator diff --git a/lib/index.ts b/lib/index.ts index c01ca20..79bd444 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,18 +1,18 @@ -export * as backup from "./backup"; -export * as config from "./config"; -export * as configBuilder from "./config/builder"; -export * as configTypes from "./config/configTypes"; -export * as health from "./health"; -export * as healthUtil from "./health/checkFns"; -export * as mainFn from "./mainFn"; -export * as matches from "ts-matches"; -export * as T from "./types"; -export * as TOML from "@iarna/toml"; -export * as Types from "./types"; -export * as util from "./util"; -export * as YAML from "yaml"; -export * as properties from "./properties"; -export * as autoconfig from "./autoconfig"; -export * as actions from "./actions"; -export * as manifest from "./manifest"; -export * as inits from "./inits"; +export * as backup from "./backup" +export * as config from "./config" +export * as configBuilder from "./config/builder" +export * as configTypes from "./config/configTypes" +export * as health from "./health" +export * as healthUtil from "./health/checkFns" +export * as mainFn from "./mainFn" +export * as matches from "ts-matches" +export * as T from "./types" +export * as TOML from "@iarna/toml" +export * as Types from "./types" +export * as util from "./util" +export * as YAML from "yaml" +export * as properties from "./properties" +export * as autoconfig from "./autoconfig" +export * as actions from "./actions" +export * as manifest from "./manifest" +export * as inits from "./inits" diff --git a/lib/inits/index.ts b/lib/inits/index.ts index eac14a9..09dbb98 100644 --- a/lib/inits/index.ts +++ b/lib/inits/index.ts @@ -1,3 +1,3 @@ -export { setupInit } from "./setupInit"; -export { setupUninstall } from "./setupUninstall"; -export { setupInstall } from "./setupInstall"; +export { setupInit } from "./setupInit" +export { setupUninstall } from "./setupUninstall" +export { setupInstall } from "./setupInstall" diff --git a/lib/inits/migrations/Migration.ts b/lib/inits/migrations/Migration.ts index 6f84ece..f52aad2 100644 --- a/lib/inits/migrations/Migration.ts +++ b/lib/inits/migrations/Migration.ts @@ -1,28 +1,28 @@ -import { ManifestVersion } from "../../manifest/ManifestTypes"; -import { Effects } from "../../types"; -import { Utils } from "../../util"; +import { ManifestVersion } from "../../manifest/ManifestTypes" +import { Effects } from "../../types" +import { Utils } from "../../util" export class Migration { constructor( readonly options: { - version: Version; - up: (opts: { effects: Effects }) => Promise; - down: (opts: { effects: Effects }) => Promise; + version: Version + up: (opts: { effects: Effects }) => Promise + down: (opts: { effects: Effects }) => Promise }, ) {} static of(options: { - version: Version; - up: (opts: { effects: Effects }) => Promise; - down: (opts: { effects: Effects }) => Promise; + version: Version + up: (opts: { effects: Effects }) => Promise + down: (opts: { effects: Effects }) => Promise }) { - return new Migration(options); + return new Migration(options) } async up(opts: { effects: Effects }) { - this.up(opts); + this.up(opts) } async down(opts: { effects: Effects }) { - this.down(opts); + this.down(opts) } } diff --git a/lib/inits/migrations/setupMigrations.ts b/lib/inits/migrations/setupMigrations.ts index 2913f93..1543780 100644 --- a/lib/inits/migrations/setupMigrations.ts +++ b/lib/inits/migrations/setupMigrations.ts @@ -1,9 +1,9 @@ -import { setupActions } from "../../actions/setupActions"; -import { EmVer } from "../../emverLite/mod"; -import { GenericManifest } from "../../manifest/ManifestTypes"; -import { ExpectedExports } from "../../types"; -import { once } from "../../util/once"; -import { Migration } from "./Migration"; +import { setupActions } from "../../actions/setupActions" +import { EmVer } from "../../emverLite/mod" +import { GenericManifest } from "../../manifest/ManifestTypes" +import { ExpectedExports } from "../../types" +import { once } from "../../util/once" +import { Migration } from "./Migration" export class Migrations { private constructor( @@ -13,27 +13,27 @@ export class Migrations { private sortedMigrations = once(() => { const migrationsAsVersions = (this.migrations as Array>).map( (x) => [EmVer.parse(x.options.version), x] as const, - ); - migrationsAsVersions.sort((a, b) => a[0].compareForSort(b[0])); - return migrationsAsVersions; - }); - private currentVersion = once(() => EmVer.parse(this.manifest.version)); + ) + migrationsAsVersions.sort((a, b) => a[0].compareForSort(b[0])) + return migrationsAsVersions + }) + private currentVersion = once(() => EmVer.parse(this.manifest.version)) static of>>( manifest: GenericManifest, ...migrations: EnsureUniqueId ) { - return new Migrations(manifest, migrations as Array>); + return new Migrations(manifest, migrations as Array>) } async init({ effects, previousVersion, }: Parameters[0]) { if (!!previousVersion) { - const previousVersionEmVer = EmVer.parse(previousVersion); + const previousVersionEmVer = EmVer.parse(previousVersion) for (const [_, migration] of this.sortedMigrations() .filter((x) => x[0].greaterThan(previousVersionEmVer)) .filter((x) => x[0].lessThanOrEqual(this.currentVersion()))) { - await migration.up({ effects }); + await migration.up({ effects }) } } } @@ -42,12 +42,12 @@ export class Migrations { nextVersion, }: Parameters[0]) { if (!!nextVersion) { - const nextVersionEmVer = EmVer.parse(nextVersion); - const reversed = [...this.sortedMigrations()].reverse(); + const nextVersionEmVer = EmVer.parse(nextVersion) + const reversed = [...this.sortedMigrations()].reverse() for (const [_, migration] of reversed .filter((x) => x[0].greaterThan(nextVersionEmVer)) .filter((x) => x[0].lessThanOrEqual(this.currentVersion()))) { - await migration.down({ effects }); + await migration.down({ effects }) } } } @@ -57,7 +57,7 @@ export function setupMigrations>>( manifest: GenericManifest, ...migrations: EnsureUniqueId ) { - return Migrations.of(manifest, ...migrations); + return Migrations.of(manifest, ...migrations) } // prettier-ignore diff --git a/lib/inits/setupInit.ts b/lib/inits/setupInit.ts index 5b1ccd3..c782b2c 100644 --- a/lib/inits/setupInit.ts +++ b/lib/inits/setupInit.ts @@ -1,24 +1,24 @@ -import { ExpectedExports } from "../types"; -import { Migrations } from "./migrations/setupMigrations"; -import { Install } from "./setupInstall"; -import { Uninstall } from "./setupUninstall"; +import { ExpectedExports } from "../types" +import { Migrations } from "./migrations/setupMigrations" +import { Install } from "./setupInstall" +import { Uninstall } from "./setupUninstall" export function setupInit( migrations: Migrations, install: Install, uninstall: Uninstall, ): { - init: ExpectedExports.init; - uninit: ExpectedExports.uninit; + init: ExpectedExports.init + uninit: ExpectedExports.uninit } { return { init: async (opts) => { - await migrations.init(opts); - await install.init(opts); + await migrations.init(opts) + await install.init(opts) }, uninit: async (opts) => { - await migrations.uninit(opts); - await uninstall.uninit(opts); + await migrations.uninit(opts) + await uninstall.uninit(opts) }, - }; + } } diff --git a/lib/inits/setupInstall.ts b/lib/inits/setupInstall.ts index 021f34e..67c9569 100644 --- a/lib/inits/setupInstall.ts +++ b/lib/inits/setupInstall.ts @@ -1,24 +1,24 @@ -import { Effects, ExpectedExports } from "../types"; -import { Utils, utils } from "../util"; +import { Effects, ExpectedExports } from "../types" +import { Utils, utils } from "../util" export type InstallFn = (opts: { - effects: Effects; - utils: Utils; -}) => Promise; + effects: Effects + utils: Utils +}) => Promise export class Install { private constructor(readonly fn: InstallFn) {} static of(fn: InstallFn) { - return new Install(fn); + return new Install(fn) } async init({ effects, previousVersion, }: Parameters[0]) { - if (!previousVersion) await this.fn({ effects, utils: utils(effects) }); + if (!previousVersion) await this.fn({ effects, utils: utils(effects) }) } } export function setupInstall(fn: InstallFn) { - return Install.of(fn); + return Install.of(fn) } diff --git a/lib/inits/setupUninstall.ts b/lib/inits/setupUninstall.ts index ae99f35..5352001 100644 --- a/lib/inits/setupUninstall.ts +++ b/lib/inits/setupUninstall.ts @@ -1,24 +1,24 @@ -import { Effects, ExpectedExports } from "../types"; -import { Utils, utils } from "../util"; +import { Effects, ExpectedExports } from "../types" +import { Utils, utils } from "../util" export type UninstallFn = (opts: { - effects: Effects; - utils: Utils; -}) => Promise; + effects: Effects + utils: Utils +}) => Promise export class Uninstall { private constructor(readonly fn: UninstallFn) {} static of(fn: UninstallFn) { - return new Uninstall(fn); + return new Uninstall(fn) } async uninit({ effects, nextVersion, }: Parameters[0]) { - if (!nextVersion) await this.fn({ effects, utils: utils(effects) }); + if (!nextVersion) await this.fn({ effects, utils: utils(effects) }) } } export function setupUninstall(fn: UninstallFn) { - return Uninstall.of(fn); + return Uninstall.of(fn) } diff --git a/lib/mainFn/AddressReceipt.ts b/lib/mainFn/AddressReceipt.ts index 11aef2f..d57d856 100644 --- a/lib/mainFn/AddressReceipt.ts +++ b/lib/mainFn/AddressReceipt.ts @@ -1,4 +1,4 @@ -declare const AddressProof: unique symbol; +declare const AddressProof: unique symbol export type AddressReceipt = { - [AddressProof]: never; -}; + [AddressProof]: never +} diff --git a/lib/mainFn/Daemons.ts b/lib/mainFn/Daemons.ts index d3141a7..935c956 100644 --- a/lib/mainFn/Daemons.ts +++ b/lib/mainFn/Daemons.ts @@ -1,28 +1,28 @@ -import { HealthReceipt, ReadyProof } from "../health"; -import { CheckResult } from "../health/checkFns"; -import { Trigger } from "../health/trigger"; -import { defaultTrigger } from "../health/trigger/defaultTrigger"; -import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types"; -import { InterfaceReceipt } from "./interfaceReceipt"; +import { HealthReceipt, ReadyProof } from "../health" +import { CheckResult } from "../health/checkFns" +import { Trigger } from "../health/trigger" +import { defaultTrigger } from "../health/trigger/defaultTrigger" +import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types" +import { InterfaceReceipt } from "./interfaceReceipt" type Daemon< Ids extends string | never, Command extends string, Id extends string, > = { - id: Id; - command: ValidIfNoStupidEscape | [string, ...string[]]; + id: Id + command: ValidIfNoStupidEscape | [string, ...string[]] ready: { display: null | { - name: string; - message: string; - }; - fn: () => Promise | CheckResult; - trigger?: Trigger; - }; - requires?: Exclude[]; - intervalTime?: number; -}; + name: string + message: string + } + fn: () => Promise | CheckResult + trigger?: Trigger + } + requires?: Exclude[] + intervalTime?: number +} /** * Used during the main of a function, it allows us to describe and ensure a set of daemons are running. @@ -56,49 +56,49 @@ export class Daemons { ) {} static of(config: { - effects: Effects; - started: (onTerm: () => void) => null; - interfaceReceipt: InterfaceReceipt; - healthReceipts: HealthReceipt[]; + effects: Effects + started: (onTerm: () => void) => null + interfaceReceipt: InterfaceReceipt + healthReceipts: HealthReceipt[] }) { - return new Daemons(config.effects, config.started); + return new Daemons(config.effects, config.started) } addDaemon( newDaemon: Daemon, ) { - const daemons = ((this?.daemons ?? []) as any[]).concat(newDaemon); - return new Daemons(this.effects, this.started, daemons); + const daemons = ((this?.daemons ?? []) as any[]).concat(newDaemon) + return new Daemons(this.effects, this.started, daemons) } async build() { - const daemonsStarted = {} as Record>; - const { effects } = this; - const daemons = this.daemons ?? []; + const daemonsStarted = {} as Record> + const { effects } = this + const daemons = this.daemons ?? [] for (const daemon of daemons) { const requiredPromise = Promise.all( daemon.requires?.map((id) => daemonsStarted[id]) ?? [], - ); + ) daemonsStarted[daemon.id] = requiredPromise.then(async () => { - const { command } = daemon; + const { command } = daemon - const child = effects.runDaemon(command); - let currentInput = {}; - const getCurrentInput = () => currentInput; + const child = effects.runDaemon(command) + let currentInput = {} + const getCurrentInput = () => currentInput const trigger = (daemon.ready.trigger ?? defaultTrigger)( getCurrentInput, - ); + ) for ( let res = await trigger.next(); !res.done; res = await trigger.next() ) { - const response = await daemon.ready.fn(); + const response = await daemon.ready.fn() if (response.status === "passing") { - return child; + return child } } - return child; - }); + return child + }) } return { async term() { @@ -106,15 +106,15 @@ export class Daemons { Object.values>(daemonsStarted).map((x) => x.then((x) => x.term()), ), - ); + ) }, async wait() { await Promise.all( Object.values>(daemonsStarted).map((x) => x.then((x) => x.wait()), ), - ); + ) }, - }; + } } } diff --git a/lib/mainFn/LocalBinding.ts b/lib/mainFn/LocalBinding.ts index b013756..6775517 100644 --- a/lib/mainFn/LocalBinding.ts +++ b/lib/mainFn/LocalBinding.ts @@ -1,11 +1,31 @@ -import { Origin } from "./Origin"; +import { once } from "../util/once" +import { Origin } from "./Origin" +/** + * Pulled from https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html + * to test ipv4 addresses + */ +export const regexToTestIp4 = once(() => /(?:[0-9]{1,3}\.){3}[0-9]{1,3}/) +/** + * Pulled from https://ihateregex.io/expr/ipv6/ + * to test ipv6 addresses + */ +export const ipv6 = once( + () => + /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/, +) export class LocalBinding { - constructor(readonly localHost: string, readonly ipHost: string) {} + constructor(readonly localHost: string, readonly ipHosts: string[]) {} createOrigins(protocol: string) { return { local: new Origin(protocol, this.localHost), - ip: new Origin(protocol, this.ipHost), - }; + ip: this.ipHosts.map((x) => new Origin(protocol, x)), + ipv4: this.ipHosts + .filter(regexToTestIp4().test) + .map((x) => new Origin(protocol, x)), + ipv6: this.ipHosts + .filter(ipv6().test) + .map((x) => new Origin(protocol, x)), + } } } diff --git a/lib/mainFn/LocalPort.ts b/lib/mainFn/LocalPort.ts index ce886f7..a70762c 100644 --- a/lib/mainFn/LocalPort.ts +++ b/lib/mainFn/LocalPort.ts @@ -1,15 +1,16 @@ -import { Effects } from "../types"; -import { LocalBinding } from "./LocalBinding"; +import { Effects } from "../types" +import { LocalBinding } from "./LocalBinding" export class LocalPort { - constructor(readonly effects: Effects, readonly id: string) {} - async bindLan(internalPort: number) { - const port = await this.effects.bindLan({ + constructor(readonly effects: Effects) {} + static async bindLan(effects: Effects, internalPort: number) { + const port = await effects.bindLan({ internalPort, - name: this.id, - }); - const localAddress = `${await this.effects.getLocalHostname()}:${port}`; - const ipAddress = `${await this.effects.getIPHostname()}:${port}`; - return new LocalBinding(localAddress, ipAddress); + }) + const localAddress = `${await effects.getLocalHostname()}:${port}` + const ipAddress = await ( + await effects.getIPHostname() + ).map((x) => `${x}:${port}`) + return new LocalBinding(localAddress, ipAddress) } } diff --git a/lib/mainFn/NetworkBuilder.ts b/lib/mainFn/NetworkBuilder.ts index 4edbdac..3157673 100644 --- a/lib/mainFn/NetworkBuilder.ts +++ b/lib/mainFn/NetworkBuilder.ts @@ -1,17 +1,14 @@ -import { Effects } from "../types"; -import { LocalPort } from "./LocalPort"; -import { TorHostname } from "./TorHostname"; +import { Effects } from "../types" +import { LocalPort } from "./LocalPort" +import { TorHostname } from "./TorHostname" export class NetworkBuilder { static of(effects: Effects) { - return new NetworkBuilder(effects); + return new NetworkBuilder(effects) } private constructor(private effects: Effects) {} getTorHostName(id: string) { - return new TorHostname(this.effects, id); - } - getPort(id: string) { - return new LocalPort(this.effects, id); + return new TorHostname(this.effects, id) } } diff --git a/lib/mainFn/NetworkInterfaceBuilder.ts b/lib/mainFn/NetworkInterfaceBuilder.ts index 936819a..b7cb50d 100644 --- a/lib/mainFn/NetworkInterfaceBuilder.ts +++ b/lib/mainFn/NetworkInterfaceBuilder.ts @@ -1,25 +1,25 @@ -import { Effects } from "../types"; -import { AddressReceipt } from "./AddressReceipt"; -import { Origin } from "./Origin"; +import { Effects } from "../types" +import { AddressReceipt } from "./AddressReceipt" +import { Origin } from "./Origin" export class NetworkInterfaceBuilder { constructor( readonly options: { - effects: Effects; - name: string; - id: string; - description: string; - ui: boolean; - basic?: null | { password: string; username: string }; - path?: string; - search?: Record; + effects: Effects + name: string + id: string + description: string + ui: boolean + basic?: null | { password: string; username: string } + path?: string + search?: Record }, ) {} async exportAddresses(addresses: Iterable) { - const { name, description, id, ui, path, search } = this.options; + const { name, description, id, ui, path, search } = this.options for (const origin of addresses) { - const address = origin.withAuth(this.options.basic); + const address = origin.withAuth(this.options.basic) await this.options.effects.exportAddress({ name, description, @@ -28,8 +28,8 @@ export class NetworkInterfaceBuilder { ui, path, search, - }); + }) } - return {} as AddressReceipt; + return {} as AddressReceipt } } diff --git a/lib/mainFn/Origin.ts b/lib/mainFn/Origin.ts index 2d1961c..02b964c 100644 --- a/lib/mainFn/Origin.ts +++ b/lib/mainFn/Origin.ts @@ -4,8 +4,8 @@ export class Origin { withAuth( origin?: | { - password: string; - username: string; + password: string + username: string } | null | undefined, @@ -13,6 +13,6 @@ export class Origin { // prettier-ignore const urlAuth = !!(origin) ? `${origin.username}:${origin.password}@` : ''; - return `${this.protocol}://${urlAuth}${this.host}`; + return `${this.protocol}://${urlAuth}${this.host}` } } diff --git a/lib/mainFn/ReadyProof.ts b/lib/mainFn/ReadyProof.ts index b88b064..7fa4631 100644 --- a/lib/mainFn/ReadyProof.ts +++ b/lib/mainFn/ReadyProof.ts @@ -1,4 +1,4 @@ -export declare const ReadyProof: unique symbol; +export declare const ReadyProof: unique symbol export type ReadyReceipt = { - [ReadyProof]: never; -}; + [ReadyProof]: never +} diff --git a/lib/mainFn/RunningMainRet.ts b/lib/mainFn/RunningMainRet.ts index ef1fd25..69cf1ee 100644 --- a/lib/mainFn/RunningMainRet.ts +++ b/lib/mainFn/RunningMainRet.ts @@ -1,7 +1,7 @@ -import { Daemon } from "../types"; -import { ReadyProof } from "./ReadyProof"; +import { Daemon } from "../types" +import { ReadyProof } from "./ReadyProof" export type RunningMainRet = { - [ReadyProof]: never; - daemon: Daemon; -}; + [ReadyProof]: never + daemon: Daemon +} diff --git a/lib/mainFn/TorBinding.ts b/lib/mainFn/TorBinding.ts index c51d182..54b2ac1 100644 --- a/lib/mainFn/TorBinding.ts +++ b/lib/mainFn/TorBinding.ts @@ -1,8 +1,8 @@ -import { Origin } from "./Origin"; +import { Origin } from "./Origin" export class TorBinding { constructor(readonly host: string) {} createOrigin(protocol: string) { - return new Origin(protocol, this.host); + return new Origin(protocol, this.host) } } diff --git a/lib/mainFn/TorHostname.ts b/lib/mainFn/TorHostname.ts index 9a3f5ce..ef8b068 100644 --- a/lib/mainFn/TorHostname.ts +++ b/lib/mainFn/TorHostname.ts @@ -1,17 +1,17 @@ -import { Effects } from "../types"; -import { TorBinding } from "./TorBinding"; +import { Effects } from "../types" +import { TorBinding } from "./TorBinding" export class TorHostname { constructor(readonly effects: Effects, readonly id: string) {} static of(effects: Effects, id: string) { - return new TorHostname(effects, id); + return new TorHostname(effects, id) } async bindTor(internalPort: number, externalPort: number) { const address = await this.effects.bindTor({ internalPort, name: this.id, externalPort, - }); - return new TorBinding(address); + }) + return new TorBinding(address) } } diff --git a/lib/mainFn/exportInterfaces.ts b/lib/mainFn/exportInterfaces.ts index 19ee867..007def1 100644 --- a/lib/mainFn/exportInterfaces.ts +++ b/lib/mainFn/exportInterfaces.ts @@ -1,8 +1,8 @@ -import { AddressReceipt } from "./AddressReceipt"; -import { InterfaceReceipt } from "./interfaceReceipt"; +import { AddressReceipt } from "./AddressReceipt" +import { InterfaceReceipt } from "./interfaceReceipt" export const exportInterfaces = ( _firstProof: AddressReceipt, ..._rest: AddressReceipt[] -) => ({} as InterfaceReceipt); -export default exportInterfaces; +) => ({} as InterfaceReceipt) +export default exportInterfaces diff --git a/lib/mainFn/index.ts b/lib/mainFn/index.ts index 105b9d5..fde5af8 100644 --- a/lib/mainFn/index.ts +++ b/lib/mainFn/index.ts @@ -1,16 +1,16 @@ -import { Effects, ExpectedExports } from "../types"; -import { Utils, utils } from "../util"; -import { Daemons } from "./Daemons"; -export * as network from "./exportInterfaces"; -export { LocalBinding } from "./LocalBinding"; -export { LocalPort } from "./LocalPort"; -export { NetworkBuilder } from "./NetworkBuilder"; -export { NetworkInterfaceBuilder } from "./NetworkInterfaceBuilder"; -export { Origin } from "./Origin"; -export { TorBinding } from "./TorBinding"; -export { TorHostname } from "./TorHostname"; +import { Effects, ExpectedExports } from "../types" +import { Utils, utils } from "../util" +import { Daemons } from "./Daemons" +export * as network from "./exportInterfaces" +export { LocalBinding } from "./LocalBinding" +export { LocalPort } from "./LocalPort" +export { NetworkBuilder } from "./NetworkBuilder" +export { NetworkInterfaceBuilder } from "./NetworkInterfaceBuilder" +export { Origin } from "./Origin" +export { TorBinding } from "./TorBinding" +export { TorHostname } from "./TorHostname" -export { Daemons } from "./Daemons"; +export { Daemons } from "./Daemons" /** * Used to ensure that the main function is running with the valid proofs. @@ -24,16 +24,16 @@ export { Daemons } from "./Daemons"; */ export const setupMain = ( fn: (o: { - effects: Effects; - started(onTerm: () => void): null; - utils: Utils; + effects: Effects + started(onTerm: () => void): null + utils: Utils }) => Promise>, ): ExpectedExports.main => { return async (options) => { const result = await fn({ ...options, utils: utils(options.effects), - }); - await result.build().then((x) => x.wait()); - }; -}; + }) + await result.build().then((x) => x.wait()) + } +} diff --git a/lib/mainFn/interfaceReceipt.ts b/lib/mainFn/interfaceReceipt.ts index ac25d00..24873e6 100644 --- a/lib/mainFn/interfaceReceipt.ts +++ b/lib/mainFn/interfaceReceipt.ts @@ -1,4 +1,4 @@ -declare const InterfaceProof: unique symbol; +declare const InterfaceProof: unique symbol export type InterfaceReceipt = { - [InterfaceProof]: never; -}; + [InterfaceProof]: never +} diff --git a/lib/manifest/ManifestTypes.ts b/lib/manifest/ManifestTypes.ts index 49ca1e8..8600942 100644 --- a/lib/manifest/ManifestTypes.ts +++ b/lib/manifest/ManifestTypes.ts @@ -1,96 +1,96 @@ -import { ValidEmVer } from "../emverLite/mod"; -import { ActionMetaData } from "../types"; +import { ValidEmVer } from "../emverLite/mod" +import { ActionMetaData } from "../types" export interface Container { /** This should be pointing to a docker container name */ - image: string; + image: string /** These should match the manifest data volumes */ - mounts: Record; + mounts: Record /** Default is 64mb */ - shmSizeMb?: `${number}${"mb" | "gb" | "b" | "kb"}`; + shmSizeMb?: `${number}${"mb" | "gb" | "b" | "kb"}` /** if more than 30s to shutdown */ - sigtermTimeout?: `${number}${"s" | "m" | "h"}`; + sigtermTimeout?: `${number}${"s" | "m" | "h"}` } -export type ManifestVersion = ValidEmVer; +export type ManifestVersion = ValidEmVer export interface GenericManifest { /** The package identifier used by the OS. This must be unique amongst all other known packages */ - id: string; + id: string /** A human readable service title */ - title: string; + title: string /** Service version - accepts up to four digits, where the last confirms to revisions necessary for StartOs - see documentation: https://github.com/Start9Labs/emver-rs. This value will change with each release of the service */ - version: ManifestVersion; + version: ManifestVersion /** Release notes for the update - can be a string, paragraph or URL */ - releaseNotes: string; + releaseNotes: string /** The type of license for the project. Include the LICENSE in the root of the project directory. A license is required for a Start9 package.*/ - license: string; // name of license + license: string // name of license /** A list of normie (hosted, SaaS, custodial, etc) services this services intends to replace */ - replaces: string[]; + replaces: string[] /** The Start9 wrapper repository URL for the package. This repo contains the manifest file (this), any scripts necessary for configuration, backups, actions, or health checks (more below). This key must exist. But could be embedded into the source repository */ - wrapperRepo: string; + wrapperRepo: string /** The original project repository URL. There is no upstream repo in this example */ - upstreamRepo: string; + upstreamRepo: string /** URL to the support site / channel for the project. This key can be omitted if none exists, or it can link to the original project repository issues */ - supportSite: string; + supportSite: string /** URL to the marketing site for the project. If there is no marketing site, it can link to the original project repository */ - marketingSite: string; + marketingSite: string /** URL where users can donate to the upstream project */ - donationUrl: string | null; + donationUrl: string | null /**Human readable descriptions for the service. These are used throughout the StartOS user interface, primarily in the marketplace. */ description: { /**This is the first description visible to the user in the marketplace */ - short: string; + short: string /** This description will display with additional details in the service's individual marketplace page */ - long: string; - }; + long: string + } /** These assets are static files necessary for packaging the service for Start9 (into an s9pk). Each value is a path to the specified asset. If an asset is missing from this list, or otherwise denoted, it will be defaulted to the values denoted below. */ assets: { - icon: string; // file path - instructions: string; // file path - license: string; // file path - }; + icon: string // file path + instructions: string // file path + license: string // file path + } /**Defines the containers needed to run the main and mounted volumes */ - containers: Record; + containers: Record /**This denotes any data, asset, or pointer volumes that should be connected when the "docker run" command is invoked */ - volumes: Record; - actions: Array; + volumes: Record + actions: Array alerts: { - install: string | null; - update: string | null; - uninstall: string | null; - restore: string | null; - start: string | null; - stop: string | null; - }; - dependencies: Record; + install: string | null + update: string | null + uninstall: string | null + restore: string | null + start: string | null + stop: string | null + } + dependencies: Record } export interface Dependency { /** The range of versions that would satisfy the dependency * ie: >=3.4.5 && <4.0.0 */ - version: string; + version: string /** * A human readable explanation on what the dependency is used for */ - description: string | null; + description: string | null requirement: | { - type: "opt-in"; + type: "opt-in" /** * The human readable explanation on how to opt-in to the dependency */ - how: string; + how: string } | { - type: "opt-out"; + type: "opt-out" /** * The human readable explanation on how to opt-out to the dependency */ - how: string; + how: string } | { - type: "required"; - }; + type: "required" + } } diff --git a/lib/manifest/index.ts b/lib/manifest/index.ts index 01aeefd..9f82e84 100644 --- a/lib/manifest/index.ts +++ b/lib/manifest/index.ts @@ -1,2 +1,2 @@ -export { setupManifest } from "./setupManifest"; -export * as ManifestTypes from "./ManifestTypes"; +export { setupManifest } from "./setupManifest" +export * as ManifestTypes from "./ManifestTypes" diff --git a/lib/manifest/setupManifest.ts b/lib/manifest/setupManifest.ts index 455611d..e8970e5 100644 --- a/lib/manifest/setupManifest.ts +++ b/lib/manifest/setupManifest.ts @@ -1,4 +1,4 @@ -import { GenericManifest, ManifestVersion } from "./ManifestTypes"; +import { GenericManifest, ManifestVersion } from "./ManifestTypes" export function setupManifest< Id extends string, @@ -6,11 +6,11 @@ export function setupManifest< Dependencies extends Record, Volumes extends Record, Manifest extends GenericManifest & { - dependencies: Dependencies; - id: Id; - version: Version; - volumes: Volumes; + dependencies: Dependencies + id: Id + version: Version + volumes: Volumes }, >(manifest: Manifest): Manifest { - return manifest; + return manifest } diff --git a/lib/properties/PropertyGroup.ts b/lib/properties/PropertyGroup.ts index a9df920..26a8dc2 100644 --- a/lib/properties/PropertyGroup.ts +++ b/lib/properties/PropertyGroup.ts @@ -1,18 +1,18 @@ -import { PackagePropertyGroup } from "../types"; -import { PropertyString } from "./PropertyString"; +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; + 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/PropertyString.ts b/lib/properties/PropertyString.ts index 465b515..7e69899 100644 --- a/lib/properties/PropertyString.ts +++ b/lib/properties/PropertyString.ts @@ -1,4 +1,4 @@ -import { PackagePropertyString } from "../types"; +import { PackagePropertyString } from "../types" export class PropertyString { private constructor(readonly data: PackagePropertyString) {} @@ -6,6 +6,6 @@ export class PropertyString { return new PropertyString({ ...value, type: "string", - }); + }) } } diff --git a/lib/properties/index.ts b/lib/properties/index.ts index 819a331..c5afe99 100644 --- a/lib/properties/index.ts +++ b/lib/properties/index.ts @@ -1,15 +1,15 @@ -import { ExpectedExports, Properties } from "../types"; +import { ExpectedExports, Properties } from "../types" -import { PropertyGroup } from "./PropertyGroup"; -import { PropertyString } from "./PropertyString"; -export { PropertyGroup } from "./PropertyGroup"; -export { PropertyString } from "./PropertyString"; +import { PropertyGroup } from "./PropertyGroup" +import { PropertyString } from "./PropertyString" +export { PropertyGroup } from "./PropertyGroup" +export { PropertyString } from "./PropertyString" -export const test = ""; +export const test = "" export type UnionToIntersection = ((x: T) => any) extends (x: infer R) => any ? R - : never; + : never /** * This is used during creating the type of properties fn in the service package. @@ -20,18 +20,18 @@ export type UnionToIntersection = ((x: T) => any) extends (x: infer R) => any */ export function setupProperties( fn: (args: { - wrapperData: WrapperData; + wrapperData: WrapperData }) => void | Promise | Promise<(PropertyGroup | PropertyString)[]>, ): ExpectedExports.properties { return (async (options) => { const result = await fn( options as { - wrapperData: WrapperData & typeof options.wrapperData; + wrapperData: WrapperData & typeof options.wrapperData }, - ); + ) if (result) { - const answer: Properties = result.map((x) => x.data); - return answer; + const answer: Properties = result.map((x) => x.data) + return answer } - }) as ExpectedExports.properties; + }) as ExpectedExports.properties } diff --git a/lib/test/configBuilder.test.ts b/lib/test/configBuilder.test.ts index 08371b5..12dfe3b 100644 --- a/lib/test/configBuilder.test.ts +++ b/lib/test/configBuilder.test.ts @@ -1,24 +1,24 @@ -import { testOutput } from "./output.test"; -import { Config } from "../config/builder/config"; -import { List } from "../config/builder/list"; -import { Value } from "../config/builder/value"; -import { Variants } from "../config/builder/variants"; +import { testOutput } from "./output.test" +import { Config } from "../config/builder/config" +import { List } from "../config/builder/list" +import { Value } from "../config/builder/value" +import { Variants } from "../config/builder/variants" describe("builder tests", () => { test("text", () => { const bitcoinPropertiesBuilt: { "peer-tor-address": { - name: string; - description: string | null; - type: "text"; - }; + name: string + description: string | null + type: "text" + } } = Config.of({ "peer-tor-address": Value.text({ name: "Peer tor address", description: "The Tor address of the peer interface", - required: true, + required: { default: null }, }), - }).build(); + }).build() expect(JSON.stringify(bitcoinPropertiesBuilt)).toEqual( /*json*/ `{ "peer-tor-address": { @@ -38,9 +38,9 @@ describe("builder tests", () => { .replaceAll("\n", " ") .replaceAll(/\s{2,}/g, "") .replaceAll(": ", ":"), - ); - }); -}); + ) + }) +}) describe("values", () => { test("toggle", () => { @@ -49,71 +49,70 @@ describe("values", () => { description: null, warning: null, default: null, - }); - const validator = value.validator(); - validator.unsafeCast(false); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast(false) + testOutput()(null) + }) test("text", () => { + const value = Value.text({ + name: "Testing", + required: { default: null }, + }) + const validator = value.validator() + const rawIs = value.build() + validator.unsafeCast("test text") + expect(() => validator.unsafeCast(null)).toThrowError() + testOutput()(null) + }) + test("text", () => { + const value = Value.text({ + name: "Testing", + required: { default: "null" }, + }) + const validator = value.validator() + const rawIs = value.build() + validator.unsafeCast("test text") + expect(() => validator.unsafeCast(null)).toThrowError() + testOutput()(null) + }) + test("optional text", () => { const value = Value.text({ name: "Testing", required: false, - description: null, - warning: null, - masked: false, - placeholder: null, - minLength: null, - maxLength: null, - patterns: [], - inputmode: "text", - }); - const validator = value.validator(); - validator.unsafeCast("test text"); - testOutput()(null); - }); - test("text", () => { - const value = Value.text({ - name: "Testing", - required: true, - description: null, - warning: null, - masked: false, - placeholder: null, - minLength: null, - maxLength: null, - patterns: [], - inputmode: "text", - }); - const validator = value.validator(); - validator.unsafeCast("test text"); - testOutput()(null); - }); + }) + const validator = value.validator() + const rawIs = value.build() + validator.unsafeCast("test text") + validator.unsafeCast(null) + testOutput()(null) + }) test("color", () => { const value = Value.color({ name: "Testing", required: false, description: null, warning: null, - }); - const validator = value.validator(); - validator.unsafeCast("#000000"); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast("#000000") + testOutput()(null) + }) test("datetime", () => { const value = Value.datetime({ name: "Testing", - required: true, + required: { default: null }, description: null, warning: null, inputmode: "date", min: null, max: null, step: null, - }); - const validator = value.validator(); - validator.unsafeCast("2021-01-01"); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast("2021-01-01") + testOutput()(null) + }) test("optional datetime", () => { const value = Value.datetime({ name: "Testing", @@ -124,11 +123,11 @@ describe("values", () => { min: null, max: null, step: null, - }); - const validator = value.validator(); - validator.unsafeCast("2021-01-01"); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast("2021-01-01") + testOutput()(null) + }) test("textarea", () => { const value = Value.textarea({ name: "Testing", @@ -138,15 +137,15 @@ describe("values", () => { minLength: null, maxLength: null, placeholder: null, - }); - const validator = value.validator(); - validator.unsafeCast("test text"); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast("test text") + testOutput()(null) + }) test("number", () => { const value = Value.number({ name: "Testing", - required: true, + required: { default: null }, integer: false, description: null, warning: null, @@ -155,11 +154,11 @@ describe("values", () => { step: null, units: null, placeholder: null, - }); - const validator = value.validator(); - validator.unsafeCast(2); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast(2) + testOutput()(null) + }) test("optional number", () => { const value = Value.number({ name: "Testing", @@ -172,28 +171,28 @@ describe("values", () => { step: null, units: null, placeholder: null, - }); - const validator = value.validator(); - validator.unsafeCast(2); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast(2) + testOutput()(null) + }) test("select", () => { const value = Value.select({ name: "Testing", - required: true, + required: { default: null }, values: { a: "A", b: "B", }, description: null, warning: null, - }); - const validator = value.validator(); - validator.unsafeCast("a"); - validator.unsafeCast("b"); - expect(() => validator.unsafeCast(null)).toThrowError(); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast("a") + validator.unsafeCast("b") + expect(() => validator.unsafeCast(null)).toThrowError() + testOutput()(null) + }) test("nullable select", () => { const value = Value.select({ name: "Testing", @@ -204,13 +203,13 @@ describe("values", () => { }, description: null, warning: null, - }); - const validator = value.validator(); - validator.unsafeCast("a"); - validator.unsafeCast("b"); - validator.unsafeCast(null); - testOutput()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast("a") + validator.unsafeCast("b") + validator.unsafeCast(null) + testOutput()(null) + }) test("multiselect", () => { const value = Value.multiselect({ name: "Testing", @@ -223,12 +222,12 @@ describe("values", () => { warning: null, minLength: null, maxLength: null, - }); - const validator = value.validator(); - validator.unsafeCast([]); - validator.unsafeCast(["a", "b"]); - testOutput>()(null); - }); + }) + const validator = value.validator() + validator.unsafeCast([]) + validator.unsafeCast(["a", "b"]) + testOutput>()(null) + }) test("object", () => { const value = Value.object( { @@ -244,16 +243,16 @@ describe("values", () => { default: null, }), }), - ); - const validator = value.validator(); - validator.unsafeCast({ a: true }); - testOutput()(null); - }); + ) + const validator = value.validator() + validator.unsafeCast({ a: true }) + testOutput()(null) + }) test("union", () => { const value = Value.union( { name: "Testing", - required: true, + required: { default: null }, description: null, warning: null, default: null, @@ -271,14 +270,14 @@ describe("values", () => { }), }, }), - ); - const validator = value.validator(); - validator.unsafeCast({ unionSelectKey: "a", unionValueKey: { b: false } }); - type Test = typeof validator._TYPE; + ) + const validator = value.validator() + validator.unsafeCast({ unionSelectKey: "a", unionValueKey: { b: false } }) + type Test = typeof validator._TYPE testOutput()( null, - ); - }); + ) + }) test("list", () => { const value = Value.list( List.number( @@ -289,12 +288,12 @@ describe("values", () => { integer: false, }, ), - ); - const validator = value.validator(); - validator.unsafeCast([1, 2, 3]); - testOutput()(null); - }); -}); + ) + const validator = value.validator() + validator.unsafeCast([1, 2, 3]) + testOutput()(null) + }) +}) describe("Builder List", () => { test("obj", () => { @@ -314,11 +313,11 @@ describe("Builder List", () => { }), }, ), - ); - const validator = value.validator(); - validator.unsafeCast([{ test: true }]); - testOutput()(null); - }); + ) + const validator = value.validator() + validator.unsafeCast([{ test: true }]) + testOutput()(null) + }) test("text", () => { const value = Value.list( List.text( @@ -329,11 +328,11 @@ describe("Builder List", () => { patterns: [], }, ), - ); - const validator = value.validator(); - validator.unsafeCast(["test", "text"]); - testOutput()(null); - }); + ) + const validator = value.validator() + validator.unsafeCast(["test", "text"]) + testOutput()(null) + }) test("number", () => { const value = Value.list( List.number( @@ -342,12 +341,12 @@ describe("Builder List", () => { }, { integer: true }, ), - ); - const validator = value.validator(); - validator.unsafeCast([12, 45]); - testOutput()(null); - }); -}); + ) + const validator = value.validator() + validator.unsafeCast([12, 45]) + testOutput()(null) + }) +}) describe("Nested nullable values", () => { test("Testing text", () => { @@ -358,15 +357,13 @@ describe("Nested nullable values", () => { "If no name is provided, the name from config will be used", required: false, }), - }); - const validator = value.validator(); - validator.unsafeCast({ a: null }); - validator.unsafeCast({ a: "test" }); - expect(() => validator.unsafeCast({ a: 4 })).toThrowError(); - testOutput()( - null, - ); - }); + }) + const validator = value.validator() + validator.unsafeCast({ a: null }) + validator.unsafeCast({ a: "test" }) + expect(() => validator.unsafeCast({ a: 4 })).toThrowError() + testOutput()(null) + }) test("Testing number", () => { const value = Config.of({ a: Value.number({ @@ -382,15 +379,13 @@ describe("Nested nullable values", () => { step: null, units: null, }), - }); - const validator = value.validator(); - validator.unsafeCast({ a: null }); - validator.unsafeCast({ a: 5 }); - expect(() => validator.unsafeCast({ a: "4" })).toThrowError(); - testOutput()( - null, - ); - }); + }) + const validator = value.validator() + validator.unsafeCast({ a: null }) + validator.unsafeCast({ a: 5 }) + expect(() => validator.unsafeCast({ a: "4" })).toThrowError() + testOutput()(null) + }) test("Testing color", () => { const value = Config.of({ a: Value.color({ @@ -400,15 +395,13 @@ describe("Nested nullable values", () => { required: false, warning: null, }), - }); - const validator = value.validator(); - validator.unsafeCast({ a: null }); - validator.unsafeCast({ a: "5" }); - expect(() => validator.unsafeCast({ a: 4 })).toThrowError(); - testOutput()( - null, - ); - }); + }) + const validator = value.validator() + validator.unsafeCast({ a: null }) + validator.unsafeCast({ a: "5" }) + expect(() => validator.unsafeCast({ a: 4 })).toThrowError() + testOutput()(null) + }) test("Testing select", () => { const value = Config.of({ a: Value.select({ @@ -421,7 +414,7 @@ describe("Nested nullable values", () => { a: "A", }, }), - }); + }) const higher = Value.select({ name: "Temp Name", description: "If no name is provided, the name from config will be used", @@ -430,14 +423,14 @@ describe("Nested nullable values", () => { values: { a: "A", }, - }).build(); + }).build() - const validator = value.validator(); - validator.unsafeCast({ a: null }); - validator.unsafeCast({ a: "a" }); - expect(() => validator.unsafeCast({ a: "4" })).toThrowError(); - testOutput()(null); - }); + const validator = value.validator() + validator.unsafeCast({ a: null }) + validator.unsafeCast({ a: "a" }) + expect(() => validator.unsafeCast({ a: "4" })).toThrowError() + testOutput()(null) + }) test("Testing multiselect", () => { const value = Config.of({ a: Value.multiselect({ @@ -453,11 +446,11 @@ describe("Nested nullable values", () => { minLength: null, maxLength: null, }), - }); - const validator = value.validator(); - validator.unsafeCast({ a: [] }); - validator.unsafeCast({ a: ["a"] }); - expect(() => validator.unsafeCast({ a: "4" })).toThrowError(); - testOutput()(null); - }); -}); + }) + const validator = value.validator() + validator.unsafeCast({ a: [] }) + validator.unsafeCast({ a: ["a"] }) + expect(() => validator.unsafeCast({ a: "4" })).toThrowError() + testOutput()(null) + }) +}) diff --git a/lib/test/configTypes.test.ts b/lib/test/configTypes.test.ts index d3d19e0..e535f07 100644 --- a/lib/test/configTypes.test.ts +++ b/lib/test/configTypes.test.ts @@ -1,25 +1,25 @@ -import { ListValueSpecOf, isValueSpecListOf } from "../config/configTypes"; -import { Config } from "../config/builder/config"; -import { List } from "../config/builder/list"; -import { Value } from "../config/builder/value"; +import { ListValueSpecOf, isValueSpecListOf } from "../config/configTypes" +import { Config } from "../config/builder/config" +import { List } from "../config/builder/list" +import { Value } from "../config/builder/value" describe("Config Types", () => { test("isValueSpecListOf", () => { - const options = [List.obj, List.text, List.number]; + const options = [List.obj, List.text, List.number] for (const option of options) { - const test = option({} as any, { spec: Config.of({}) } as any) as any; - const someList = Value.list(test).build(); + const test = option({} as any, { spec: Config.of({}) } as any) as any + const someList = Value.list(test).build() if (isValueSpecListOf(someList, "text")) { - someList.spec satisfies ListValueSpecOf<"text">; + someList.spec satisfies ListValueSpecOf<"text"> } else if (isValueSpecListOf(someList, "number")) { - someList.spec satisfies ListValueSpecOf<"number">; + someList.spec satisfies ListValueSpecOf<"number"> } else if (isValueSpecListOf(someList, "object")) { - someList.spec satisfies ListValueSpecOf<"object">; + someList.spec satisfies ListValueSpecOf<"object"> } else { throw new Error( "Failed to figure out the type: " + JSON.stringify(someList), - ); + ) } } - }); -}); + }) +}) diff --git a/lib/test/emverList.test.ts b/lib/test/emverList.test.ts index e65d0e4..43919aa 100644 --- a/lib/test/emverList.test.ts +++ b/lib/test/emverList.test.ts @@ -1,262 +1,262 @@ -import { EmVer, notRange, rangeAnd, rangeOf, rangeOr } from "../emverLite/mod"; +import { EmVer, notRange, rangeAnd, rangeOf, rangeOr } from "../emverLite/mod" describe("EmVer", () => { { { - const checker = rangeOf("*"); + const checker = rangeOf("*") test("rangeOf('*')", () => { - checker.check("1"); - checker.check("1.2"); - checker.check("1.2.3"); - checker.check("1.2.3.4"); + checker.check("1") + checker.check("1.2") + checker.check("1.2.3") + checker.check("1.2.3.4") // @ts-expect-error - checker.check("1.2.3.4.5"); + checker.check("1.2.3.4.5") // @ts-expect-error - checker.check("1.2.3.4.5.6"); - expect(checker.check("1")).toEqual(true); - expect(checker.check("1.2")).toEqual(true); - expect(checker.check("1.2.3.4")).toEqual(true); - }); + checker.check("1.2.3.4.5.6") + expect(checker.check("1")).toEqual(true) + expect(checker.check("1.2")).toEqual(true) + expect(checker.check("1.2.3.4")).toEqual(true) + }) test("rangeOf('*') invalid", () => { // @ts-expect-error - expect(() => checker.check("a")).toThrow(); + expect(() => checker.check("a")).toThrow() // @ts-expect-error - expect(() => checker.check("")).toThrow(); - expect(() => checker.check("1..3")).toThrow(); - }); + expect(() => checker.check("")).toThrow() + expect(() => checker.check("1..3")).toThrow() + }) } { - const checker = rangeOf(">1.2.3.4"); + const checker = rangeOf(">1.2.3.4") test(`rangeOf(">1.2.3.4") valid`, () => { - expect(checker.check("2-beta123")).toEqual(true); - expect(checker.check("2")).toEqual(true); - expect(checker.check("1.2.3.5")).toEqual(true); + expect(checker.check("2-beta123")).toEqual(true) + expect(checker.check("2")).toEqual(true) + expect(checker.check("1.2.3.5")).toEqual(true) // @ts-expect-error - expect(checker.check("1.2.3.4.1")).toEqual(true); - }); + expect(checker.check("1.2.3.4.1")).toEqual(true) + }) test(`rangeOf(">1.2.3.4") invalid`, () => { - expect(checker.check("1.2.3.4")).toEqual(false); - expect(checker.check("1.2.3")).toEqual(false); - expect(checker.check("1")).toEqual(false); - }); + expect(checker.check("1.2.3.4")).toEqual(false) + expect(checker.check("1.2.3")).toEqual(false) + expect(checker.check("1")).toEqual(false) + }) } { - const checker = rangeOf("=1.2.3"); + const checker = rangeOf("=1.2.3") test(`rangeOf("=1.2.3") valid`, () => { - expect(checker.check("1.2.3")).toEqual(true); - }); + expect(checker.check("1.2.3")).toEqual(true) + }) test(`rangeOf("=1.2.3") invalid`, () => { - expect(checker.check("2")).toEqual(false); - expect(checker.check("1.2.3.1")).toEqual(false); - expect(checker.check("1.2")).toEqual(false); - }); + expect(checker.check("2")).toEqual(false) + expect(checker.check("1.2.3.1")).toEqual(false) + expect(checker.check("1.2")).toEqual(false) + }) } { - const checker = rangeOf(">=1.2.3.4"); + const checker = rangeOf(">=1.2.3.4") test(`rangeOf(">=1.2.3.4") valid`, () => { - expect(checker.check("2")).toEqual(true); - expect(checker.check("1.2.3.5")).toEqual(true); + expect(checker.check("2")).toEqual(true) + expect(checker.check("1.2.3.5")).toEqual(true) // @ts-expect-error - expect(checker.check("1.2.3.4.1")).toEqual(true); - expect(checker.check("1.2.3.4")).toEqual(true); - }); + expect(checker.check("1.2.3.4.1")).toEqual(true) + expect(checker.check("1.2.3.4")).toEqual(true) + }) test(`rangeOf(">=1.2.3.4") invalid`, () => { - expect(checker.check("1.2.3")).toEqual(false); - expect(checker.check("1")).toEqual(false); - }); + expect(checker.check("1.2.3")).toEqual(false) + expect(checker.check("1")).toEqual(false) + }) } { - const checker = rangeOf("<1.2.3.4"); + const checker = rangeOf("<1.2.3.4") test(`rangeOf("<1.2.3.4") invalid`, () => { - expect(checker.check("2")).toEqual(false); - expect(checker.check("1.2.3.5")).toEqual(false); + expect(checker.check("2")).toEqual(false) + expect(checker.check("1.2.3.5")).toEqual(false) // @ts-expect-error - expect(checker.check("1.2.3.4.1")).toEqual(false); - expect(checker.check("1.2.3.4")).toEqual(false); - }); + expect(checker.check("1.2.3.4.1")).toEqual(false) + expect(checker.check("1.2.3.4")).toEqual(false) + }) test(`rangeOf("<1.2.3.4") valid`, () => { - expect(checker.check("1.2.3")).toEqual(true); - expect(checker.check("1")).toEqual(true); - }); + expect(checker.check("1.2.3")).toEqual(true) + expect(checker.check("1")).toEqual(true) + }) } { - const checker = rangeOf("<=1.2.3.4"); + const checker = rangeOf("<=1.2.3.4") test(`rangeOf("<=1.2.3.4") invalid`, () => { - expect(checker.check("2")).toEqual(false); - expect(checker.check("1.2.3.5")).toEqual(false); + expect(checker.check("2")).toEqual(false) + expect(checker.check("1.2.3.5")).toEqual(false) // @ts-expect-error - expect(checker.check("1.2.3.4.1")).toEqual(false); - }); + expect(checker.check("1.2.3.4.1")).toEqual(false) + }) test(`rangeOf("<=1.2.3.4") valid`, () => { - expect(checker.check("1.2.3")).toEqual(true); - expect(checker.check("1")).toEqual(true); - expect(checker.check("1.2.3.4")).toEqual(true); - }); + expect(checker.check("1.2.3")).toEqual(true) + expect(checker.check("1")).toEqual(true) + expect(checker.check("1.2.3.4")).toEqual(true) + }) } { - const checkA = rangeOf(">1"); - const checkB = rangeOf("<=2"); + const checkA = rangeOf(">1") + const checkB = rangeOf("<=2") - const checker = rangeAnd(checkA, checkB); + const checker = rangeAnd(checkA, checkB) test(`simple and(checkers) valid`, () => { - expect(checker.check("2")).toEqual(true); + expect(checker.check("2")).toEqual(true) - expect(checker.check("1.1")).toEqual(true); - }); + expect(checker.check("1.1")).toEqual(true) + }) test(`simple and(checkers) invalid`, () => { - expect(checker.check("2.1")).toEqual(false); - expect(checker.check("1")).toEqual(false); - expect(checker.check("0")).toEqual(false); - }); + expect(checker.check("2.1")).toEqual(false) + expect(checker.check("1")).toEqual(false) + expect(checker.check("0")).toEqual(false) + }) } { - const checkA = rangeOf("<1"); - const checkB = rangeOf("=2"); + const checkA = rangeOf("<1") + const checkB = rangeOf("=2") - const checker = rangeOr(checkA, checkB); + const checker = rangeOr(checkA, checkB) test(`simple or(checkers) valid`, () => { - expect(checker.check("2")).toEqual(true); - expect(checker.check("0.1")).toEqual(true); - }); + expect(checker.check("2")).toEqual(true) + expect(checker.check("0.1")).toEqual(true) + }) test(`simple or(checkers) invalid`, () => { - expect(checker.check("2.1")).toEqual(false); - expect(checker.check("1")).toEqual(false); - expect(checker.check("1.1")).toEqual(false); - }); + expect(checker.check("2.1")).toEqual(false) + expect(checker.check("1")).toEqual(false) + expect(checker.check("1.1")).toEqual(false) + }) } { - const checker = rangeOf("1.2.*"); + const checker = rangeOf("1.2.*") test(`rangeOf(1.2.*) valid`, () => { - expect(checker.check("1.2")).toEqual(true); - expect(checker.check("1.2.1")).toEqual(true); - }); + expect(checker.check("1.2")).toEqual(true) + expect(checker.check("1.2.1")).toEqual(true) + }) test(`rangeOf(1.2.*) invalid`, () => { - expect(checker.check("1.3")).toEqual(false); - expect(checker.check("1.3.1")).toEqual(false); + expect(checker.check("1.3")).toEqual(false) + expect(checker.check("1.3.1")).toEqual(false) - expect(checker.check("1.1.1")).toEqual(false); - expect(checker.check("1.1")).toEqual(false); - expect(checker.check("1")).toEqual(false); + expect(checker.check("1.1.1")).toEqual(false) + expect(checker.check("1.1")).toEqual(false) + expect(checker.check("1")).toEqual(false) - expect(checker.check("2")).toEqual(false); - }); + expect(checker.check("2")).toEqual(false) + }) } { - const checker = notRange(rangeOf("1.2.*")); + const checker = notRange(rangeOf("1.2.*")) test(`notRange(rangeOf(1.2.*)) valid`, () => { - expect(checker.check("1.3")).toEqual(true); - expect(checker.check("1.3.1")).toEqual(true); + expect(checker.check("1.3")).toEqual(true) + expect(checker.check("1.3.1")).toEqual(true) - expect(checker.check("1.1.1")).toEqual(true); - expect(checker.check("1.1")).toEqual(true); - expect(checker.check("1")).toEqual(true); + expect(checker.check("1.1.1")).toEqual(true) + expect(checker.check("1.1")).toEqual(true) + expect(checker.check("1")).toEqual(true) - expect(checker.check("2")).toEqual(true); - }); + expect(checker.check("2")).toEqual(true) + }) test(`notRange(rangeOf(1.2.*)) invalid `, () => { - expect(checker.check("1.2")).toEqual(false); - expect(checker.check("1.2.1")).toEqual(false); - }); + expect(checker.check("1.2")).toEqual(false) + expect(checker.check("1.2.1")).toEqual(false) + }) } { - const checker = rangeOf("!1.2.*"); + const checker = rangeOf("!1.2.*") test(`!(rangeOf(1.2.*)) valid`, () => { - expect(checker.check("1.3")).toEqual(true); - expect(checker.check("1.3.1")).toEqual(true); + expect(checker.check("1.3")).toEqual(true) + expect(checker.check("1.3.1")).toEqual(true) - expect(checker.check("1.1.1")).toEqual(true); - expect(checker.check("1.1")).toEqual(true); - expect(checker.check("1")).toEqual(true); + expect(checker.check("1.1.1")).toEqual(true) + expect(checker.check("1.1")).toEqual(true) + expect(checker.check("1")).toEqual(true) - expect(checker.check("2")).toEqual(true); - }); + expect(checker.check("2")).toEqual(true) + }) test(`!(rangeOf(1.2.*)) invalid `, () => { - expect(checker.check("1.2")).toEqual(false); - expect(checker.check("1.2.1")).toEqual(false); - }); + expect(checker.check("1.2")).toEqual(false) + expect(checker.check("1.2.1")).toEqual(false) + }) } { test(`no and ranges`, () => { - expect(() => rangeAnd()).toThrow(); - }); + expect(() => rangeAnd()).toThrow() + }) test(`no or ranges`, () => { - expect(() => rangeOr()).toThrow(); - }); + expect(() => rangeOr()).toThrow() + }) } { - const checker = rangeOf("!>1.2.3.4"); + const checker = rangeOf("!>1.2.3.4") test(`rangeOf("!>1.2.3.4") invalid`, () => { - expect(checker.check("2")).toEqual(false); - expect(checker.check("1.2.3.5")).toEqual(false); + expect(checker.check("2")).toEqual(false) + expect(checker.check("1.2.3.5")).toEqual(false) // @ts-expect-error - expect(checker.check("1.2.3.4.1")).toEqual(false); - }); + expect(checker.check("1.2.3.4.1")).toEqual(false) + }) test(`rangeOf("!>1.2.3.4") valid`, () => { - expect(checker.check("1.2.3.4")).toEqual(true); - expect(checker.check("1.2.3")).toEqual(true); - expect(checker.check("1")).toEqual(true); - }); + expect(checker.check("1.2.3.4")).toEqual(true) + expect(checker.check("1.2.3")).toEqual(true) + expect(checker.check("1")).toEqual(true) + }) } { test(">1 && =1.2", () => { - const checker = rangeOf(">1 && =1.2"); + const checker = rangeOf(">1 && =1.2") - expect(checker.check("1.2")).toEqual(true); - expect(checker.check("1.2.1")).toEqual(false); - }); + expect(checker.check("1.2")).toEqual(true) + expect(checker.check("1.2.1")).toEqual(false) + }) test("=1 || =2", () => { - const checker = rangeOf("=1 || =2"); + const checker = rangeOf("=1 || =2") - expect(checker.check("1")).toEqual(true); - expect(checker.check("2")).toEqual(true); - expect(checker.check("3")).toEqual(false); - }); + expect(checker.check("1")).toEqual(true) + expect(checker.check("2")).toEqual(true) + expect(checker.check("3")).toEqual(false) + }) test(">1 && =1.2 || =2", () => { - const checker = rangeOf(">1 && =1.2 || =2"); + const checker = rangeOf(">1 && =1.2 || =2") - expect(checker.check("1.2")).toEqual(true); - expect(checker.check("1")).toEqual(false); - expect(checker.check("2")).toEqual(true); - expect(checker.check("3")).toEqual(false); - }); + expect(checker.check("1.2")).toEqual(true) + expect(checker.check("1")).toEqual(false) + expect(checker.check("2")).toEqual(true) + expect(checker.check("3")).toEqual(false) + }) test("&& before || order of operationns: <1.5 && >1 || >1.5 && <3", () => { - const checker = rangeOf("<1.5 && >1 || >1.5 && <3"); - expect(checker.check("1.1")).toEqual(true); - expect(checker.check("2")).toEqual(true); + const checker = rangeOf("<1.5 && >1 || >1.5 && <3") + expect(checker.check("1.1")).toEqual(true) + expect(checker.check("2")).toEqual(true) - expect(checker.check("1.5")).toEqual(false); - expect(checker.check("1")).toEqual(false); - expect(checker.check("3")).toEqual(false); - }); + expect(checker.check("1.5")).toEqual(false) + expect(checker.check("1")).toEqual(false) + expect(checker.check("3")).toEqual(false) + }) test("Compare function on the emver", () => { - const a = EmVer.from("1.2.3"); - const b = EmVer.from("1.2.4"); + const a = EmVer.from("1.2.3") + const b = EmVer.from("1.2.4") - expect(a.compare(b)).toEqual("less"); - expect(b.compare(a)).toEqual("greater"); - expect(a.compare(a)).toEqual("equal"); - }); + expect(a.compare(b)).toEqual("less") + expect(b.compare(a)).toEqual("greater") + expect(a.compare(a)).toEqual("equal") + }) test("Compare for sort function on the emver", () => { - const a = EmVer.from("1.2.3"); - const b = EmVer.from("1.2.4"); + const a = EmVer.from("1.2.3") + const b = EmVer.from("1.2.4") - expect(a.compareForSort(b)).toEqual(-1); - expect(b.compareForSort(a)).toEqual(1); - expect(a.compareForSort(a)).toEqual(0); - }); + expect(a.compareForSort(b)).toEqual(-1) + expect(b.compareForSort(a)).toEqual(1) + expect(a.compareForSort(a)).toEqual(0) + }) } } -}); +}) diff --git a/lib/test/health.readyCheck.test.ts b/lib/test/health.readyCheck.test.ts index ef5b9b6..49efcc7 100644 --- a/lib/test/health.readyCheck.test.ts +++ b/lib/test/health.readyCheck.test.ts @@ -1,4 +1,4 @@ -import { containsAddress } from "../health/checkFns/checkPortListening"; +import { containsAddress } from "../health/checkFns/checkPortListening" describe("Health ready check", () => { it("Should be able to parse an example information", () => { @@ -9,9 +9,9 @@ describe("Health ready check", () => { 1: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21634477 1 0000000000000000 100 0 0 10 0 2: 0B00007F:9671 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21635458 1 0000000000000000 100 0 0 10 0 3: 00000000:0D73 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21634479 1 0000000000000000 100 0 0 10 0 - `; + ` - expect(containsAddress(input, 80)).toBe(true); - expect(containsAddress(input, 1234)).toBe(false); - }); -}); + expect(containsAddress(input, 80)).toBe(true) + expect(containsAddress(input, 1234)).toBe(false) + }) +}) diff --git a/lib/test/makeOutput.ts b/lib/test/makeOutput.ts index 212e107..2364d4e 100644 --- a/lib/test/makeOutput.ts +++ b/lib/test/makeOutput.ts @@ -1,4 +1,4 @@ -import { writeConvertedFileFromOld } from "../../scripts/oldSpecToBuilder"; +import { writeConvertedFileFromOld } from "../../scripts/oldSpecToBuilder" writeConvertedFileFromOld( "./lib/test/output.ts", // Make the location @@ -408,4 +408,4 @@ writeConvertedFileFromOld( { startSdk: "../", }, -); +) diff --git a/lib/test/output.test.ts b/lib/test/output.test.ts index 6e5ad78..6cb0cc2 100644 --- a/lib/test/output.test.ts +++ b/lib/test/output.test.ts @@ -3,44 +3,44 @@ import { unionSelectKey, UnionValueKey, unionValueKey, -} from "../config/configTypes"; -import { deepMerge } from "../util"; -import { InputSpec, matchInputSpec } from "./output"; +} from "../config/configTypes" +import { deepMerge } from "../util" +import { InputSpec, matchInputSpec } from "./output" export type IfEquals = (() => G extends T ? 1 : 2) extends () => G extends U ? 1 : 2 ? Y - : N; + : N export function testOutput(): (c: IfEquals) => null { - return () => null; + return () => null } /// Testing the types of the input spec -testOutput()(null); -testOutput()(null); -testOutput()(null); +testOutput()(null) +testOutput()(null) +testOutput()(null) -testOutput()(null); +testOutput()(null) testOutput< InputSpec["rpc"]["advanced"]["serialversion"], "segwit" | "non-segwit" ->()(null); -testOutput()(null); +>()(null) +testOutput()(null) testOutput< InputSpec["advanced"]["peers"]["addnode"][0]["hostname"], string | null | undefined ->()(null); +>()(null) testOutput< InputSpec["testListUnion"][0]["union"][UnionValueKey]["name"], string ->()(null); +>()(null) testOutput()( null, -); +) // @ts-expect-error Because enable should be a boolean -testOutput()(null); +testOutput()(null) // prettier-ignore // @ts-expect-error Expect that the string is the one above testOutput()(null); @@ -98,24 +98,24 @@ describe("Inputs", () => { }, bloomfilters: { peerbloomfilters: false }, }, - }; + } test("test valid input", () => { - const output = matchInputSpec.unsafeCast(validInput); - expect(output).toEqual(validInput); - }); + const output = matchInputSpec.unsafeCast(validInput) + expect(output).toEqual(validInput) + }) test("test no longer care about the conversion of min/max and validating", () => { matchInputSpec.unsafeCast( deepMerge({}, validInput, { rpc: { advanced: { threads: 0 } } }), - ); - }); + ) + }) test("test errors should throw for number in string", () => { expect(() => matchInputSpec.unsafeCast( deepMerge({}, validInput, { rpc: { enable: 2 } }), ), - ).toThrowError(); - }); + ).toThrowError() + }) test("Test that we set serialversion to something not segwit or non-segwit", () => { expect(() => matchInputSpec.unsafeCast( @@ -123,6 +123,6 @@ describe("Inputs", () => { rpc: { advanced: { serialversion: "testing" } }, }), ), - ).toThrowError(); - }); -}); + ).toThrowError() + }) +}) diff --git a/lib/test/util.deepMerge.test.ts b/lib/test/util.deepMerge.test.ts index 7edc256..8f3e518 100644 --- a/lib/test/util.deepMerge.test.ts +++ b/lib/test/util.deepMerge.test.ts @@ -1,18 +1,18 @@ -import { deepMerge } from "../util/deepMerge"; +import { deepMerge } from "../util/deepMerge" describe("deepMerge", () => { test("deepMerge({}, {a: 1}, {b: 2}) should return {a: 1, b: 2}", () => { - expect(deepMerge({}, { a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 }); - }); + expect(deepMerge({}, { a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 }) + }) test("deepMerge(null, [1,2,3]) should equal [1,2,3]", () => { - expect(deepMerge(null, [1, 2, 3])).toEqual([1, 2, 3]); - }); + expect(deepMerge(null, [1, 2, 3])).toEqual([1, 2, 3]) + }) test("deepMerge({a: {b: 1, c:2}}, {a: {b: 3}}) should equal {a: {b: 3, c: 2}}", () => { expect(deepMerge({ a: { b: 1, c: 2 } }, { a: { b: 3 } })).toEqual({ a: { b: 3, c: 2 }, - }); - }); + }) + }) test("deepMerge([1,2,3], [2,3,4]) should equal [2,3,4]", () => { - expect(deepMerge([1, 2, 3], [2, 3, 4])).toEqual([2, 3, 4]); - }); -}); + expect(deepMerge([1, 2, 3], [2, 3, 4])).toEqual([2, 3, 4]) + }) +}) diff --git a/lib/test/wrapperData.test.ts b/lib/test/wrapperData.test.ts index 2cdd2de..4aba8ff 100644 --- a/lib/test/wrapperData.test.ts +++ b/lib/test/wrapperData.test.ts @@ -1,81 +1,79 @@ -import { T } from ".."; -import { utils } from "../util"; +import { T } from ".." +import { utils } from "../util" type WrapperType = { config: { - someValue: string; - }; -}; + someValue: string + } +} const todo = (): A => { - throw new Error("not implemented"); -}; -const noop = () => {}; + throw new Error("not implemented") +} +const noop = () => {} describe("wrapperData", () => { test.skip("types", async () => { utils(todo()).setOwnWrapperData( "/config/someValue", "someValue", - ); + ) utils(todo()).setOwnWrapperData( "/config/someValue", // @ts-expect-error Type is wrong for the setting value 5, - ); + ) utils(todo()).setOwnWrapperData( // @ts-expect-error Path is wrong "/config/someVae3lue", "someValue", - ); + ) todo().setWrapperData({ path: "/config/someValue", value: "someValueIn", - }); + }) todo().setWrapperData({ //@ts-expect-error Path is wrong path: "/config/someValue", //@ts-expect-error Path is wrong value: "someValueIn", - }); + }) todo().setWrapperData({ //@ts-expect-error Path is wrong path: "/config/some2Value", value: "someValueIn", - }); - - (await utils(todo()) + }) + ;(await utils(todo()) .getOwnWrapperData("/config/someValue") - .const()) satisfies string; - (await utils(todo()) + .const()) satisfies string + ;(await utils(todo()) .getOwnWrapperData("/config") - .const()) satisfies WrapperType["config"]; + .const()) satisfies WrapperType["config"] await utils(todo()) // @ts-expect-error Path is wrong .getOwnWrapperData("/config/somdsfeValue") - .const(); - (await utils(todo()) + .const() + ;(await utils(todo()) .getOwnWrapperData("/config/someValue") // @ts-expect-error satisfies type is wrong - .const()) satisfies number; - (await utils(todo()) + .const()) satisfies number + ;(await utils(todo()) // @ts-expect-error Path is wrong .getOwnWrapperData("/config/") - .const()) satisfies WrapperType["config"]; - - (await todo().getWrapperData({ + .const()) satisfies WrapperType["config"] + ;(await todo().getWrapperData({ path: "/config/someValue", callback: noop, - })) satisfies string; + })) satisfies string await todo().getWrapperData({ // @ts-expect-error Path is wrong as in it doesn't match above path: "/config/someV2alue", callback: noop, - }); + }) await todo().getWrapperData({ // @ts-expect-error Path is wrong as in it doesn't exists in wrapper type path: "/config/someV2alue", callback: noop, - }); - }); -}); + }) + }) +}) diff --git a/lib/types.ts b/lib/types.ts index f0b3058..1b36cb6 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,38 +1,36 @@ -export * as configTypes from "./config/configTypes"; -import { InputSpec } from "./config/configTypes"; -import { DependenciesReceipt } from "./config/setupConfig"; +export * as configTypes from "./config/configTypes" +import { InputSpec } from "./config/configTypes" +import { DependenciesReceipt } from "./config/setupConfig" export type ExportedAction = (options: { - effects: Effects; - input?: Record; -}) => Promise; + effects: Effects + input?: Record +}) => Promise export namespace ExpectedExports { - version: 1; + version: 1 /** Set configuration is called after we have modified and saved the configuration in the start9 ui. Use this to make a file for the docker to read from for configuration. */ export type setConfig = (options: { - effects: Effects; - input: Record; - }) => Promise; + effects: Effects + input: Record + }) => Promise /** Get configuration returns a shape that describes the format that the start9 ui will generate, and later send to the set config */ export type getConfig = (options: { - effects: Effects; - config: unknown; - }) => Promise; + effects: Effects + config: unknown + }) => Promise // /** These are how we make sure the our dependency configurations are valid and if not how to fix them. */ // export type dependencies = Dependencies; /** For backing up service data though the startOS UI */ - export type createBackup = (options: { - effects: Effects; - }) => Promise; + export type createBackup = (options: { effects: Effects }) => Promise /** For restoring service data that was previously backed up using the startOS UI create backup flow. Backup restores are also triggered via the startOS UI, or doing a system restore flow during setup. */ export type restoreBackup = (options: { - effects: Effects; - }) => Promise; + 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: { - wrapperData: WrapperData; - }) => Promise; + wrapperData: WrapperData + }) => Promise // /** Health checks are used to determine if the service is working properly after starting // * A good use case is if we are using a web server, seeing if we can get to the web server. @@ -48,49 +46,49 @@ export namespace ExpectedExports { * service starting, and that file would indicate that it would rescan all the data. */ export type actions = { - [id: string]: ExportedAction; - }; + [id: string]: ExportedAction + } /** * This is the entrypoint for the main container. Used to start up something like the service that the * package represents, like running a bitcoind in a bitcoind-wrapper. */ export type main = (options: { - effects: Effects; - started(onTerm: () => void): null; - }) => Promise; + effects: Effects + started(onTerm: () => void): null + }) => Promise /** * After a shutdown, if we wanted to do any operations to clean up things, like * set the action as unavailable or something. */ export type afterShutdown = (options: { - effects: Effects; - }) => Promise; + effects: Effects + }) => Promise /** * Every time a package completes an install, this function is called before the main. * Can be used to do migration like things. */ export type init = (options: { - effects: Effects; - previousVersion: null | string; - }) => Promise; + effects: Effects + previousVersion: null | string + }) => Promise /** This will be ran during any time a package is uninstalled, for example during a update * this will be called. */ export type uninit = (options: { - effects: Effects; - nextVersion: null | string; - }) => Promise; + effects: Effects + nextVersion: null | string + }) => Promise /** Auto configure is used to make sure that other dependencies have the values t * that this service could use. */ - export type autoConfig = Record; + export type autoConfig = Record } -export type TimeMs = number; -export type VersionString = string; +export type TimeMs = number +export type VersionString = string /** * AutoConfigure is used as the value to the key of package id, @@ -99,17 +97,17 @@ export type VersionString = string; export type AutoConfigure = { /** Checks are called to make sure that our dependency is in the correct shape. If a known error is returned we know that the dependency needs modification */ check(options: { - effects: Effects; - localConfig: unknown; - remoteConfig: unknown; - }): Promise; + effects: Effects + localConfig: unknown + remoteConfig: unknown + }): Promise /** This is called after we know that the dependency package needs a new configuration, this would be a transform for defaults */ autoConfigure(options: { - effects: Effects; - localConfig: unknown; - remoteConfig: unknown; - }): Promise; -}; + effects: Effects + localConfig: unknown + remoteConfig: unknown + }): Promise +} export type ValidIfNoStupidEscape = A extends | `${string}'"'"'${string}` @@ -117,126 +115,130 @@ export type ValidIfNoStupidEscape = A extends ? never : "" extends A & "" ? never - : A; + : A export type ConfigRes = { /** This should be the previous config, that way during set config we start with the previous */ - config?: null | Record; + config?: null | Record /** Shape that is describing the form in the ui */ - spec: InputSpec; -}; + spec: InputSpec +} -declare const DaemonProof: unique symbol; +declare const DaemonProof: unique symbol export type DaemonReceipt = { - [DaemonProof]: never; -}; + [DaemonProof]: never +} export type Daemon = { - wait(): Promise; - term(): Promise; - [DaemonProof]: never; -}; + wait(): Promise + term(): Promise + [DaemonProof]: never +} -export type HealthStatus = "passing" | "warning" | "failing" | "disabled"; +export type HealthStatus = "passing" | "warning" | "failing" | "disabled" export type CommandType = | ValidIfNoStupidEscape - | [string, ...string[]]; + | [string, ...string[]] export type DaemonReturned = { - wait(): Promise; - term(): Promise; -}; + wait(): Promise + term(): Promise +} export type ActionMetaData = { - name: string; - description: string; - id: string; - input: null | InputSpec; - runningOnly: boolean; + name: string + description: string + id: string + input: null | InputSpec + runningOnly: boolean /** * So the ordering of the actions is by alphabetical order of the group, then followed by the alphabetical of the actions */ - group?: string; -}; + group?: string +} /** Used to reach out from the pure js runtime */ export type Effects = { /** Usable when not sandboxed */ writeFile(input: { - path: string; - volumeId: string; - toWrite: string; - }): Promise; - readFile(input: { volumeId: string; path: string }): Promise; - metadata(input: { volumeId: string; path: string }): Promise; + path: string + volumeId: string + toWrite: string + }): Promise + readFile(input: { volumeId: string; path: string }): Promise + metadata(input: { volumeId: string; path: string }): Promise /** Create a directory. Usable when not sandboxed */ - createDir(input: { volumeId: string; path: string }): Promise; + createDir(input: { volumeId: string; path: string }): Promise - readDir(input: { volumeId: string; path: string }): Promise; + readDir(input: { volumeId: string; path: string }): Promise /** Remove a directory. Usable when not sandboxed */ - removeDir(input: { volumeId: string; path: string }): Promise; - removeFile(input: { volumeId: string; path: string }): Promise; + removeDir(input: { volumeId: string; path: string }): Promise + removeFile(input: { volumeId: string; path: string }): Promise /** Write a json file into an object. Usable when not sandboxed */ writeJsonFile(input: { - volumeId: string; - path: string; - toWrite: Record; - }): Promise; + volumeId: string + path: string + toWrite: Record + }): Promise /** Read a json file into an object */ readJsonFile(input: { - volumeId: string; - path: string; - }): Promise>; + volumeId: string + path: string + }): Promise> runCommand( command: ValidIfNoStupidEscape | [string, ...string[]], input?: { - timeoutMillis?: number; + timeoutMillis?: number }, - ): Promise; + ): Promise runShellDaemon(command: string): { - wait(): Promise; - term(): Promise; - }; + wait(): Promise + term(): Promise + } runDaemon( command: ValidIfNoStupidEscape | [string, ...string[]], - ): DaemonReturned; + ): DaemonReturned /** Uses the chown on the system */ - chown(input: { volumeId: string; path: string; uid: string }): Promise; + chown(input: { volumeId: string; path: string; uid: string }): Promise /** Uses the chmod on the system */ - chmod(input: { volumeId: string; path: string; mode: string }): Promise; + chmod(input: { volumeId: string; path: string; mode: string }): Promise - sleep(timeMs: TimeMs): Promise; + sleep(timeMs: TimeMs): Promise - /** Log at the trace level */ - trace(whatToPrint: string): void; - /** Log at the warn level */ - warn(whatToPrint: string): void; - /** Log at the error level */ - error(whatToPrint: string): void; - /** Log at the debug level */ - debug(whatToPrint: string): void; - /** Log at the info level */ - info(whatToPrint: string): void; + console: { + /** Log at the trace level */ + log(whatToPrint: string): void + /** Log at the trace level */ + trace(whatToPrint: string): void + /** Log at the warn level */ + warn(whatToPrint: string): void + /** Log at the error level */ + error(whatToPrint: string): void + /** Log at the debug level */ + debug(whatToPrint: string): void + /** Log at the info level */ + info(whatToPrint: string): void + } /** Sandbox mode lets us read but not write */ - is_sandboxed(): boolean; + is_sandboxed(): boolean /** Check that a file exists or not */ - exists(input: { volumeId: string; path: string }): Promise; + exists(input: { volumeId: string; path: string }): Promise /** Declaring that we are opening a interface on some protocal for local network * Returns the port exposed */ - bindLan(options: { internalPort: number; name: string }): Promise; + bindLan(options: { internalPort: number }): Promise /** Declaring that we are opening a interface on some protocal for tor network */ bindTor(options: { - internalPort: number; - name: string; - externalPort: number; - }): Promise; + internalPort: number + name: string + externalPort: number + }): Promise /** Similar to the fetch api via the mdn, this is simplified but the point is * to get something from some website, and return the response. @@ -244,123 +246,123 @@ export type Effects = { fetch( url: string, options?: { - method?: "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "PATCH"; - headers?: Record; - body?: string; + method?: "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "PATCH" + headers?: Record + body?: string }, ): Promise<{ - method: string; - ok: boolean; - status: number; - headers: Record; - body?: string | null; + method: string + ok: boolean + status: number + headers: Record + body?: string | null /// Returns the body as a string - text(): Promise; + text(): Promise /// Returns the body as a json - json(): Promise; - }>; + json(): Promise + }> /** * Run rsync between two volumes. This is used to backup data between volumes. * This is a long running process, and a structure that we can either wait for, or get the progress of. */ runRsync(options: { - srcVolume: string; - dstVolume: string; - srcPath: string; - dstPath: string; + srcVolume: string + dstVolume: string + srcPath: string + dstPath: string // rsync options: https://linux.die.net/man/1/rsync - options: BackupOptions; + options: BackupOptions }): { - id: () => Promise; - wait: () => Promise; - progress: () => Promise; - }; + id: () => Promise + wait: () => Promise + progress: () => Promise + } /** Get a value in a json like data, can be observed and subscribed */ getWrapperData(options: { /** 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/) */ - path: Path & EnsureWrapperDataPath; - callback: (config: unknown, previousConfig: unknown) => void; - }): Promise>; + path: Path & EnsureWrapperDataPath + callback: (config: unknown, previousConfig: unknown) => void + }): Promise> /** Used to store values that can be accessed and subscribed to */ setWrapperData(options: { /** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */ - path: Path & EnsureWrapperDataPath; - value: ExtractWrapperData; - }): Promise; + path: Path & EnsureWrapperDataPath + value: ExtractWrapperData + }): Promise - getLocalHostname(): Promise; - getIPHostname(): Promise; + getLocalHostname(): Promise + getIPHostname(): Promise /** Get the address for another service for tor interfaces */ getServiceTorHostname( interfaceId: string, packageId?: string, - ): Promise; + ): Promise /** * Get the port address for another service */ getServicePortForward( internalPort: number, packageId?: string, - ): Promise; + ): Promise /** When we want to create a link in the front end interfaces, and example is * exposing a url to view a web service */ exportAddress(options: { /** The title of this field to be dsimplayed */ - name: string; + name: string /** Human readable description, used as tooltip usually */ - description: string; + description: string /** URI location */ - address: string; - id: string; + address: string + id: string /** Defaults to false, but describes if this address can be opened in a browser as an * ui interface */ - ui?: boolean; + ui?: boolean /** * The id is that a path will create a link in the ui that can go to specific pages, like * admin, or settings, or something like that. * Default = '' */ - path?: string; + path?: string /** * This is the query params in the url, and is a map of key value pairs * Default = {} * if empty then will not be added to the url */ - search?: Record; - }): Promise; + search?: Record + }): Promise /** *Remove an address that was exported. Used problably during main or during setConfig. * @param options */ - removeAddress(options: { id: string }): Promise; + removeAddress(options: { id: string }): Promise /** * * @param options */ - exportAction(options: ActionMetaData): Promise; + exportAction(options: ActionMetaData): Promise /** * Remove an action that was exported. Used problably during main or during setConfig. */ - removeAction(options: { id: string }): Promise; + removeAction(options: { id: string }): Promise - getConfigured(): Promise; + getConfigured(): Promise /** * This called after a valid set config as well as during init. * @param configured */ - setConfigured(configured: boolean): Promise; + setConfigured(configured: boolean): Promise /** * @@ -369,27 +371,27 @@ export type Effects = { getSslCertificate: ( packageId: string, algorithm?: "ecdsa" | "ed25519", - ) => [string, string, string]; + ) => [string, string, string] /** * @returns PEM encoded ssl key (ecdsa) */ - getSslKey: (packageId: string, algorithm?: "ecdsa" | "ed25519") => string; + getSslKey: (packageId: string, algorithm?: "ecdsa" | "ed25519") => string setHealth(o: { - name: string; - status: HealthStatus; - message?: string; - }): Promise; + name: string + status: HealthStatus + message?: string + }): Promise /** Set the dependencies of what the service needs, usually ran during the set config as a best practice */ - setDependencies(dependencies: Dependencies): Promise; + setDependencies(dependencies: Dependencies): Promise /** Exists could be useful during the runtime to know if some service exists, option dep */ - exists(packageId: PackageId): Promise; + exists(packageId: PackageId): Promise /** Exists could be useful during the runtime to know if some service is running, option dep */ - running(packageId: PackageId): Promise; - restart(): void; - shutdown(): void; -}; + running(packageId: PackageId): Promise + restart(): void + shutdown(): void +} // prettier-ignore export type ExtractWrapperData = @@ -408,41 +410,41 @@ export type EnsureWrapperDataPath = _EnsureWra /* rsync options: https://linux.die.net/man/1/rsync */ export type BackupOptions = { - delete: boolean; - force: boolean; - ignoreExisting: boolean; - exclude: string[]; -}; + delete: boolean + force: boolean + ignoreExisting: boolean + exclude: string[] +} /** * This is the metadata that is returned from the metadata call. */ export type Metadata = { - fileType: string; - isDir: boolean; - isFile: boolean; - isSymlink: boolean; - len: number; - modified?: Date; - accessed?: Date; - created?: Date; - readonly: boolean; - uid: number; - gid: number; - mode: number; -}; + fileType: string + isDir: boolean + isFile: boolean + isSymlink: boolean + len: number + modified?: Date + accessed?: Date + created?: Date + readonly: boolean + uid: number + gid: number + mode: number +} export type MigrationRes = { - configured: boolean; -}; + configured: boolean +} export type ActionResult = { - message: string; + message: string value: null | { - value: string; - copyable: boolean; - qr: boolean; - }; -}; + value: string + copyable: boolean + qr: boolean + } +} export type SetResult = { /** These are the unix process signals */ signal: @@ -478,52 +480,52 @@ export type SetResult = { | "SIGPWR" | "SIGSYS" | "SIGEMT" - | "SIGINFO"; - "depends-on": DependsOn; -}; + | "SIGINFO" + "depends-on": DependsOn +} -export type PackageId = string; -export type Message = string; -export type DependencyKind = "running" | "exists"; +export type PackageId = string +export type Message = string +export type DependencyKind = "running" | "exists" export type DependsOn = { - [packageId: string]: string[]; -}; + [packageId: string]: string[] +} export type KnownError = | { error: string } | { - "error-code": [number, string] | readonly [number, string]; - }; + "error-code": [number, string] | readonly [number, string] + } -export type PackageProperties = PackagePropertyGroup | PackagePropertyString; +export type PackageProperties = PackagePropertyGroup | PackagePropertyString export type PackagePropertyString = { - type: "string"; - name: string; - description: string | null; - value: string; + type: "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; -}; + masked: boolean +} export type PackagePropertyGroup = { - value: PackageProperties[]; - type: "object"; - name: string; - description: string; -}; + value: PackageProperties[] + type: "object" + name: string + description: string +} -export type Properties = PackageProperties[]; +export type Properties = PackageProperties[] export type Dependency = { - id: PackageId; - kind: DependencyKind; -}; -export type Dependencies = Array; + id: PackageId + kind: DependencyKind +} +export type Dependencies = Array export type DeepPartial = T extends {} ? { [P in keyof T]?: DeepPartial } - : T; + : T diff --git a/lib/util/deepEqual.ts b/lib/util/deepEqual.ts index b5a533f..8e6ba4b 100644 --- a/lib/util/deepEqual.ts +++ b/lib/util/deepEqual.ts @@ -1,19 +1,19 @@ -import { object } from "ts-matches"; +import { object } from "ts-matches" export function deepEqual(...args: unknown[]) { - if (!object.test(args[args.length - 1])) return args[args.length - 1]; - const objects = args.filter(object.test); + if (!object.test(args[args.length - 1])) return args[args.length - 1] + const objects = args.filter(object.test) if (objects.length === 0) { - for (const x of args) if (x !== args[0]) return false; - return true; + for (const x of args) if (x !== args[0]) return false + return true } - if (objects.length !== args.length) return false; - const allKeys = new Set(objects.flatMap((x) => Object.keys(x))); + if (objects.length !== args.length) return false + const allKeys = new Set(objects.flatMap((x) => Object.keys(x))) for (const key of allKeys) { for (const x of objects) { - if (!(key in x)) return false; - if (!deepEqual((objects[0] as any)[key], (x as any)[key])) return false; + if (!(key in x)) return false + if (!deepEqual((objects[0] as any)[key], (x as any)[key])) return false } } - return true; + return true } diff --git a/lib/util/deepMerge.ts b/lib/util/deepMerge.ts index a4c8422..ae68c24 100644 --- a/lib/util/deepMerge.ts +++ b/lib/util/deepMerge.ts @@ -1,17 +1,17 @@ -import { object } from "ts-matches"; +import { object } from "ts-matches" export function deepMerge(...args: unknown[]): unknown { - const lastItem = (args as any)[args.length - 1]; - if (!object.test(lastItem)) return lastItem; - const objects = args.filter(object.test).filter((x) => !Array.isArray(x)); - if (objects.length === 0) return lastItem as any; - if (objects.length === 1) objects.unshift({}); - const allKeys = new Set(objects.flatMap((x) => Object.keys(x))); + const lastItem = (args as any)[args.length - 1] + if (!object.test(lastItem)) return lastItem + const objects = args.filter(object.test).filter((x) => !Array.isArray(x)) + if (objects.length === 0) return lastItem as any + if (objects.length === 1) objects.unshift({}) + const allKeys = new Set(objects.flatMap((x) => Object.keys(x))) for (const key of allKeys) { const filteredValues = objects.flatMap((x) => key in x ? [(x as any)[key]] : [], - ); - (objects as any)[0][key] = deepMerge(...filteredValues); + ) + ;(objects as any)[0][key] = deepMerge(...filteredValues) } - return objects[0] as any; + return objects[0] as any } diff --git a/lib/util/fileHelper.ts b/lib/util/fileHelper.ts index 787caec..75e8a57 100644 --- a/lib/util/fileHelper.ts +++ b/lib/util/fileHelper.ts @@ -1,10 +1,10 @@ -import * as matches from "ts-matches"; -import * as YAML from "yaml"; -import * as TOML from "@iarna/toml"; -import * as T from "../types"; -import { exists } from "."; +import * as matches from "ts-matches" +import * as YAML from "yaml" +import * as TOML from "@iarna/toml" +import * as T from "../types" +import { exists } from "." -const previousPath = /(.+?)\/([^/]*)$/; +const previousPath = /(.+?)\/([^/]*)$/ /** * Used in the get config and the set config exported functions. @@ -59,19 +59,19 @@ export class FileHelper { readonly readData: (stringValue: string) => A, ) {} async write(data: A, effects: T.Effects) { - let matched; + let matched if ((matched = previousPath.exec(this.path))) { await effects.createDir({ volumeId: this.volume, path: matched[1], - }); + }) } await effects.writeFile({ path: this.path, volumeId: this.volume, toWrite: this.writeData(data), - }); + }) } async read(effects: T.Effects) { if ( @@ -80,14 +80,14 @@ export class FileHelper { volumeId: this.volume, })) ) { - return null; + return null } return this.readData( await effects.readFile({ path: this.path, volumeId: this.volume, }), - ); + ) } static raw( path: string, @@ -95,7 +95,7 @@ export class FileHelper { toFile: (dataIn: A) => string, fromFile: (rawData: string) => A, ) { - return new FileHelper(path, volume, toFile, fromFile); + return new FileHelper(path, volume, toFile, fromFile) } static json( path: string, @@ -106,12 +106,12 @@ export class FileHelper { path, volume, (inData) => { - return JSON.stringify(inData, null, 2); + return JSON.stringify(inData, null, 2) }, (inString) => { - return shape.unsafeCast(JSON.parse(inString)); + return shape.unsafeCast(JSON.parse(inString)) }, - ); + ) } static toml>( path: string, @@ -122,12 +122,12 @@ export class FileHelper { path, volume, (inData) => { - return JSON.stringify(inData, null, 2); + return JSON.stringify(inData, null, 2) }, (inString) => { - return shape.unsafeCast(TOML.parse(inString)); + return shape.unsafeCast(TOML.parse(inString)) }, - ); + ) } static yaml>( path: string, @@ -138,13 +138,13 @@ export class FileHelper { path, volume, (inData) => { - return JSON.stringify(inData, null, 2); + return JSON.stringify(inData, null, 2) }, (inString) => { - return shape.unsafeCast(YAML.parse(inString)); + return shape.unsafeCast(YAML.parse(inString)) }, - ); + ) } } -export default FileHelper; +export default FileHelper diff --git a/lib/util/getWrapperData.ts b/lib/util/getWrapperData.ts index eeeaa2b..c90e7af 100644 --- a/lib/util/getWrapperData.ts +++ b/lib/util/getWrapperData.ts @@ -1,6 +1,6 @@ -import { Parser } from "ts-matches"; -import { Effects, EnsureWrapperDataPath, ExtractWrapperData } from "../types"; -import { NoAny } from "."; +import { Parser } from "ts-matches" +import { Effects, EnsureWrapperDataPath, ExtractWrapperData } from "../types" +import { NoAny } from "." export class WrapperData { constructor( @@ -8,7 +8,7 @@ export class WrapperData { readonly path: Path & EnsureWrapperDataPath, readonly options: { /** Defaults to what ever the package currently in */ - packageId?: string | undefined; + packageId?: string | undefined } = {}, ) {} @@ -17,27 +17,27 @@ export class WrapperData { ...this.options, path: this.path as any, callback: this.effects.restart, - }); + }) } once() { return this.effects.getWrapperData({ ...this.options, path: this.path as any, callback: () => {}, - }); + }) } async *watch() { while (true) { - let callback: () => void; + let callback: () => void const waitForNext = new Promise((resolve) => { - callback = resolve; - }); + callback = resolve + }) yield await this.effects.getWrapperData({ ...this.options, path: this.path as any, callback: () => callback(), - }); - await waitForNext; + }) + await waitForNext } } } @@ -46,8 +46,8 @@ export function getWrapperData( path: Path & EnsureWrapperDataPath, options: { /** Defaults to what ever the package currently in */ - packageId?: string | undefined; + packageId?: string | undefined } = {}, ) { - return new WrapperData(effects, path as any, options); + return new WrapperData(effects, path as any, options) } diff --git a/lib/util/index.ts b/lib/util/index.ts index 628838d..051d85e 100644 --- a/lib/util/index.ts +++ b/lib/util/index.ts @@ -1,23 +1,23 @@ -import { Parser } from "ts-matches"; -import * as T from "../types"; -import FileHelper from "./fileHelper"; -import nullIfEmpty from "./nullIfEmpty"; -import { WrapperData, getWrapperData } from "./getWrapperData"; +import { Parser } from "ts-matches" +import * as T from "../types" +import FileHelper from "./fileHelper" +import nullIfEmpty from "./nullIfEmpty" +import { WrapperData, getWrapperData } from "./getWrapperData" import { CheckResult, checkPortListening, checkWebUrl, -} from "../health/checkFns"; -import { LocalPort, NetworkBuilder, TorHostname } from "../mainFn"; -import { ExtractWrapperData } from "../types"; +} from "../health/checkFns" +import { LocalBinding, LocalPort, NetworkBuilder, TorHostname } from "../mainFn" +import { ExtractWrapperData } from "../types" -export { guardAll, typeFromProps } from "./propertiesMatcher"; -export { default as nullIfEmpty } from "./nullIfEmpty"; -export { FileHelper } from "./fileHelper"; -export { getWrapperData } from "./getWrapperData"; -export { deepEqual } from "./deepEqual"; -export { deepMerge } from "./deepMerge"; -export { once } from "./once"; +export { guardAll, typeFromProps } from "./propertiesMatcher" +export { default as nullIfEmpty } from "./nullIfEmpty" +export { FileHelper } from "./fileHelper" +export { getWrapperData } from "./getWrapperData" +export { deepEqual } from "./deepEqual" +export { deepMerge } from "./deepMerge" +export { once } from "./once" // prettier-ignore export type FlattenIntersection = @@ -25,7 +25,7 @@ T extends ArrayLike ? T : T extends object ? {} & {[P in keyof T]: T[P]} : T; -export type _ = FlattenIntersection; +export type _ = FlattenIntersection /** Used to check if the file exists before hand */ export const exists = ( @@ -35,63 +35,63 @@ export const exists = ( effects.metadata(props).then( (_) => true, (_) => false, - ); + ) export const isKnownError = (e: unknown): e is T.KnownError => - e instanceof Object && ("error" in e || "error-code" in e); + e instanceof Object && ("error" in e || "error-code" in e) -type Cdr = A extends [unknown, ...infer Cdr] ? Cdr : []; +type Cdr = A extends [unknown, ...infer Cdr] ? Cdr : [] -declare const affine: unique symbol; +declare const affine: unique symbol function withAffine() { - return {} as { [affine]: B }; + return {} as { [affine]: B } } export type WrapperDataOptionals = { - validator?: Parser>; + validator?: Parser> /** Defaults to what ever the package currently in */ - packageId?: string | undefined; -}; + packageId?: string | undefined +} export type Utils = { - readFile: (fileHelper: FileHelper) => ReturnType["read"]>; + readFile: (fileHelper: FileHelper) => ReturnType["read"]> writeFile: ( fileHelper: FileHelper, data: A, - ) => ReturnType["write"]>; + ) => ReturnType["write"]> getWrapperData: ( packageId: string, path: T.EnsureWrapperDataPath, - ) => WrapperData; + ) => WrapperData getOwnWrapperData: ( path: T.EnsureWrapperDataPath, - ) => WrapperData; + ) => WrapperData setOwnWrapperData: ( path: T.EnsureWrapperDataPath, value: ExtractWrapperData, - ) => Promise; + ) => Promise checkPortListening( port: number, options?: { - error?: string; - message?: string; + error?: string + message?: string }, - ): Promise; + ): Promise checkWebUrl( url: string, options?: { - timeout?: number; - successMessage?: string; - errorMessage?: string; + timeout?: number + successMessage?: string + errorMessage?: string }, - ): Promise; - localPort: (id: string) => LocalPort; - networkBuilder: () => NetworkBuilder; - torHostName: (id: string) => TorHostname; - exists: (props: { path: string; volumeId: string }) => Promise; - nullIfEmpty: typeof nullIfEmpty; -}; + ): Promise + bindLan: (port: number) => Promise + networkBuilder: () => NetworkBuilder + torHostName: (id: string) => TorHostname + exists: (props: { path: string; volumeId: string }) => Promise + nullIfEmpty: typeof nullIfEmpty +} export const utils = ( effects: T.Effects, ): Utils => ({ @@ -113,14 +113,14 @@ export const utils = ( ) => effects.setWrapperData({ value, path: path as any }), checkPortListening: checkPortListening.bind(null, effects), checkWebUrl: checkWebUrl.bind(null, effects), - localPort: (id: string) => new LocalPort(effects, id), + bindLan: async (port: number) => LocalPort.bindLan(effects, port), networkBuilder: () => NetworkBuilder.of(effects), torHostName: (id: string) => TorHostname.of(effects, id), -}); +}) -type NeverPossible = { [affine]: string }; +type NeverPossible = { [affine]: string } export type NoAny = NeverPossible extends A ? keyof NeverPossible extends keyof A ? never : A - : A; + : A diff --git a/lib/util/nullIfEmpty.ts b/lib/util/nullIfEmpty.ts index 936e598..0777b45 100644 --- a/lib/util/nullIfEmpty.ts +++ b/lib/util/nullIfEmpty.ts @@ -5,6 +5,6 @@ * @returns */ export default function nullIfEmpty(s: null | Record) { - if (s === null) return null; - return Object.keys(s).length === 0 ? null : s; + if (s === null) return null + return Object.keys(s).length === 0 ? null : s } diff --git a/lib/util/once.ts b/lib/util/once.ts index d4a55e5..5f689b0 100644 --- a/lib/util/once.ts +++ b/lib/util/once.ts @@ -1,9 +1,9 @@ export function once(fn: () => B): () => B { - let result: [B] | [] = []; + let result: [B] | [] = [] return () => { if (!result.length) { - result = [fn()]; + result = [fn()] } - return result[0]; - }; + return result[0] + } } diff --git a/lib/util/propertiesMatcher.ts b/lib/util/propertiesMatcher.ts index 337dfa2..df6987d 100644 --- a/lib/util/propertiesMatcher.ts +++ b/lib/util/propertiesMatcher.ts @@ -1,13 +1,13 @@ -import * as matches from "ts-matches"; -import { Parser, Validator } from "ts-matches"; +import * as matches from "ts-matches" +import { Parser, Validator } from "ts-matches" import { UnionSelectKey, UnionValueKey, ValueSpec as ValueSpecAny, InputSpec, -} from "../config/configTypes"; -import { Config } from "../config/builder/config"; -import { _ } from "../util"; +} from "../config/configTypes" +import { Config } from "../config/builder/config" +import { _ } from "../util" const { string, @@ -20,19 +20,19 @@ const { literals, boolean, nill, -} = matches; +} = matches -type TypeToggle = "toggle"; -type TypeText = "text"; -type TypeTextarea = "textarea"; -type TypeNumber = "number"; -type TypeObject = "object"; -type TypeList = "list"; -type TypeSelect = "select"; -type TypeMultiselect = "multiselect"; -type TypeColor = "color"; -type TypeDatetime = "datetime"; -type TypeUnion = "union"; +type TypeToggle = "toggle" +type TypeText = "text" +type TypeTextarea = "textarea" +type TypeNumber = "number" +type TypeObject = "object" +type TypeList = "list" +type TypeSelect = "select" +type TypeMultiselect = "multiselect" +type TypeColor = "color" +type TypeDatetime = "datetime" +type TypeUnion = "union" // prettier-ignore type GuardDefaultRequired = @@ -56,7 +56,7 @@ type GuardToggle = A extends { type: TypeToggle } ? GuardDefaultRequired : unknown -type TrueKeyOf = _ extends Record ? keyof T : never; +type TrueKeyOf = _ extends Record ? keyof T : never // prettier-ignore type GuardObject = A extends { type: TypeObject, spec: infer B } ? ( @@ -94,7 +94,7 @@ type AsString = A extends | null | undefined ? `${A}` - : "UnknownValue"; + : "UnknownValue" // prettier-ignore type VariantValue = A extends { name: string, spec: infer B } ? TypeFromProps<_> : @@ -116,44 +116,44 @@ export type GuardAll = GuardNumber & GuardSelect & GuardMultiselect & GuardColor & - GuardDatetime; + GuardDatetime // prettier-ignore export type TypeFromProps = A extends Config ? TypeFromProps : A extends Record ? { [K in keyof A & string]: _> } : unknown; -const isType = object({ type: string }); +const isType = object({ type: string }) const matchVariant = object({ name: string, spec: unknown, -}); -const recordString = dictionary([string, unknown]); -const matchDefault = object({ default: unknown }); +}) +const recordString = dictionary([string, unknown]) +const matchDefault = object({ default: unknown }) const matchRequired = object( { required: literals(false), default: nill, }, ["default"], -); -const matchInteger = object({ integer: literals(true) }); -const matchSpec = object({ spec: recordString }); +) +const matchInteger = object({ integer: literals(true) }) +const matchSpec = object({ spec: recordString }) const matchUnion = object({ variants: dictionary([string, matchVariant]), -}); +}) const matchValues = object({ values: dictionary([string, string]), -}); +}) function withInteger(parser: Parser, value: unknown) { if (matchInteger.test(value)) { - return parser.validate(Number.isInteger, "isIntegral"); + return parser.validate(Number.isInteger, "isIntegral") } - return parser; + return parser } function requiredParser(parser: Parser, value: unknown) { - if (matchRequired.test(value)) return parser.optional(); - return parser; + if (matchRequired.test(value)) return parser.optional() + return parser } /** @@ -168,60 +168,60 @@ export function guardAll( value: A, ): Parser> { if (!isType.test(value)) { - return unknown as any; + return unknown as any } switch (value.type) { case "toggle": - return requiredParser(boolean, value) as any; + return requiredParser(boolean, value) as any case "text": - return requiredParser(string, value) as any; + return requiredParser(string, value) as any case "textarea": - return requiredParser(string, value) as any; + return requiredParser(string, value) as any case "color": - return requiredParser(string, value) as any; + return requiredParser(string, value) as any case "datetime": - return requiredParser(string, value) as any; + return requiredParser(string, value) as any case "number": - return requiredParser(withInteger(number, value), value) as any; + return requiredParser(withInteger(number, value), value) as any case "object": if (matchSpec.test(value)) { - return requiredParser(typeFromProps(value.spec), value) as any; + return requiredParser(typeFromProps(value.spec), value) as any } - return unknown as any; + return unknown as any case "list": { - const spec = (matchSpec.test(value) && value.spec) || {}; + const spec = (matchSpec.test(value) && value.spec) || {} return requiredParser( matches.arrayOf(guardAll(spec as any)), value, - ) as any; + ) as any } case "select": if (matchValues.test(value)) { - const valueKeys = Object.keys(value.values); + const valueKeys = Object.keys(value.values) return requiredParser( literals(valueKeys[0], ...valueKeys), value, - ) as any; + ) as any } - return unknown as any; + return unknown as any case "multiselect": if (matchValues.test(value)) { - const valueKeys = Object.keys(value.values); + const valueKeys = Object.keys(value.values) return requiredParser( arrayOf(literals(valueKeys[0], ...valueKeys)), value, - ) as any; + ) as any } - return unknown as any; + return unknown as any case "union": if (matchUnion.test(value)) { @@ -234,12 +234,12 @@ export function guardAll( unionValueKey: typeFromProps(spec), }), ), - ) as any; + ) as any } - return unknown as any; + return unknown as any } - return unknown as any; + return unknown as any } /** * InputSpec: Tells the UI how to ask for information, verification, and will send the service a config in a shape via the spec. @@ -252,7 +252,7 @@ export function guardAll( export function typeFromProps( valueDictionary: A, ): Parser> { - if (!recordString.test(valueDictionary)) return unknown as any; + if (!recordString.test(valueDictionary)) return unknown as any return object( Object.fromEntries( Object.entries(valueDictionary).map(([key, value]) => [ @@ -260,5 +260,5 @@ export function typeFromProps( guardAll(value), ]), ), - ) as any; + ) as any } diff --git a/package.json b/package.json index 673a77a..e3a4bb3 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "prettier": { "trailingComma": "all", "tabWidth": 2, - "semi": true, + "semi": false, "singleQuote": false }, "devDependencies": { diff --git a/scripts/oldSpecToBuilder.ts b/scripts/oldSpecToBuilder.ts index 59c596e..609be53 100644 --- a/scripts/oldSpecToBuilder.ts +++ b/scripts/oldSpecToBuilder.ts @@ -1,6 +1,6 @@ -import camelCase from "lodash/camelCase"; -import * as fs from "fs"; -import { string } from "ts-matches"; +import camelCase from "lodash/camelCase" +import * as fs from "fs" +import { string } from "ts-matches" export async function writeConvertedFileFromOld( file: string, @@ -11,48 +11,46 @@ export async function writeConvertedFileFromOld( file, await makeFileContentFromOld(inputData, options), (err) => console.error(err), - ); + ) } export default async function makeFileContentFromOld( inputData: Promise | any, { startSdk = "start-sdk", nested = true } = {}, ) { - const outputLines: string[] = []; + const outputLines: string[] = [] outputLines.push(` import {Config, Value, List, Variants} from '${startSdk}/config/builder' -`); - const data = await inputData; +`) + const data = await inputData - const namedConsts = new Set(["Config", "Value", "List"]); - const configName = newConst("InputSpec", convertInputSpec(data)); + const namedConsts = new Set(["Config", "Value", "List"]) + const configName = newConst("InputSpec", convertInputSpec(data)) const configMatcherName = newConst( "matchInputSpec", `${configName}.validator()`, - ); - outputLines.push( - `export type InputSpec = typeof ${configMatcherName}._TYPE;`, - ); + ) + outputLines.push(`export type InputSpec = typeof ${configMatcherName}._TYPE;`) - return outputLines.join("\n"); + return outputLines.join("\n") function newConst(key: string, data: string) { - const variableName = getNextConstName(camelCase(key)); - outputLines.push(`export const ${variableName} = ${data};`); - return variableName; + const variableName = getNextConstName(camelCase(key)) + outputLines.push(`export const ${variableName} = ${data};`) + return variableName } function maybeNewConst(key: string, data: string) { - if (nested) return data; - return newConst(key, data); + if (nested) return data + return newConst(key, data) } function convertInputSpec(data: any) { - let answer = "Config.of({"; + let answer = "Config.of({" for (const [key, value] of Object.entries(data)) { - const variableName = maybeNewConst(key, convertValueSpec(value)); + const variableName = maybeNewConst(key, convertValueSpec(value)) - answer += `${JSON.stringify(key)}: ${variableName},`; + answer += `${JSON.stringify(key)}: ${variableName},` } - return `${answer}})`; + return `${answer}})` } function convertValueSpec(value: any): string { switch (value.type) { @@ -72,15 +70,15 @@ export default async function makeFileContentFromOld( }, null, 2, - )})`; + )})` } return `${rangeToTodoComment(value?.range)}Value.text(${JSON.stringify( { name: value.name || null, // prettier-ignore required: ( - value.default != null && !value.nullable ? {default: value.default} : - value.default != null && value.nullable ? {defaultWithRequired: value.default} : + value.default != null ? {default: value.default} : + value.nullable === false ? {default: null} : !value.nullable ), description: value.description || null, @@ -101,7 +99,7 @@ export default async function makeFileContentFromOld( }, null, 2, - )})`; + )})` } case "number": { return `${rangeToTodoComment( @@ -113,8 +111,8 @@ export default async function makeFileContentFromOld( warning: value.warning || null, // prettier-ignore required: ( - value.default != null && !value.nullable ? {default: value.default} : - value.default != null && value.nullable ? {defaultWithRequired: value.default} : + value.default != null ? {default: value.default} : + value.nullable === false ? {default: null} : !value.nullable ), min: null, @@ -126,7 +124,7 @@ export default async function makeFileContentFromOld( }, null, 2, - )})`; + )})` } case "boolean": { return `Value.toggle(${JSON.stringify( @@ -138,18 +136,18 @@ export default async function makeFileContentFromOld( }, null, 2, - )})`; + )})` } case "enum": { const allValueNames = new Set([ ...(value?.["values"] || []), ...Object.keys(value?.["value-names"] || {}), - ]); + ]) const values = Object.fromEntries( Array.from(allValueNames) .filter(string.test) .map((key) => [key, value?.spec?.["value-names"]?.[key] || key]), - ); + ) return `Value.select(${JSON.stringify( { name: value.name || null, @@ -157,33 +155,33 @@ export default async function makeFileContentFromOld( warning: value.warning || null, // prettier-ignore - required: ( - value.default != null && !value.nullable ? {default: value.default} : - value.default != null && value.nullable ? {defaultWithRequired: value.default} : + required:( + value.default != null ? {default: value.default} : + value.nullable === false ? {default: null} : !value.nullable ), values, }, null, 2, - )} as const)`; + )} as const)` } case "object": { const specName = maybeNewConst( value.name + "_spec", convertInputSpec(value.spec), - ); + ) return `Value.object({ name: ${JSON.stringify(value.name || null)}, description: ${JSON.stringify(value.description || null)}, warning: ${JSON.stringify(value.warning || null)}, - }, ${specName})`; + }, ${specName})` } case "union": { const variants = maybeNewConst( value.name + "_variants", convertVariants(value.variants, value.tag["variant-names"] || {}), - ); + ) return `Value.union({ name: ${JSON.stringify(value.name || null)}, @@ -193,21 +191,21 @@ export default async function makeFileContentFromOld( // prettier-ignore required: ${JSON.stringify( // prettier-ignore - value.default != null && !value.nullable ? {default: value.default} : - value.default != null && value.nullable ? {defaultWithRequired: value.default} : - !value.nullable, + value.default != null ? {default: value.default} : + value.nullable === false ? {default: null} : + !value.nullable, )}, - }, ${variants})`; + }, ${variants})` } case "list": { - const list = maybeNewConst(value.name + "_list", convertList(value)); - return `Value.list(${list})`; + const list = maybeNewConst(value.name + "_list", convertList(value)) + return `Value.list(${list})` } case "pointer": { - return `/* TODO deal with point removed ${JSON.stringify(value)} */`; + return `/* TODO deal with point removed ${JSON.stringify(value)} */` } } - throw Error(`Unknown type "${value.type}"`); + throw Error(`Unknown type "${value.type}"`) } function convertList(value: any) { @@ -237,7 +235,7 @@ export default async function makeFileContentFromOld( : [], minLength: null, maxLength: null, - })})`; + })})` } case "number": { return `${rangeToTodoComment(value?.range)}List.number(${JSON.stringify( @@ -257,13 +255,13 @@ export default async function makeFileContentFromOld( max: null, units: value?.spec?.units || null, placeholder: value?.spec?.placeholder || null, - })})`; + })})` } case "enum": { const allValueNames = new Set( ...(value?.spec?.["values"] || []), ...Object.keys(value?.spec?.["value-names"] || {}), - ); + ) const values = Object.fromEntries( Array.from(allValueNames) .filter(string.test) @@ -271,7 +269,7 @@ export default async function makeFileContentFromOld( key, value?.spec?.["value-names"]?.[key] || key, ]), - ); + ) return `${rangeToTodoComment( value?.range, )}Value.multiselect(${JSON.stringify( @@ -286,13 +284,13 @@ export default async function makeFileContentFromOld( }, null, 2, - )})`; + )})` } case "object": { const specName = maybeNewConst( value.name + "_spec", convertInputSpec(value.spec.spec), - ); + ) return `${rangeToTodoComment(value?.range)}List.obj({ name: ${JSON.stringify(value.name || null)}, minLength: ${JSON.stringify(null)}, @@ -304,7 +302,7 @@ export default async function makeFileContentFromOld( spec: ${specName}, displayAs: ${JSON.stringify(value?.spec?.["display-as"] || null)}, uniqueBy: ${JSON.stringify(value?.spec?.["unique-by"] || null)}, - })`; + })` } case "union": { const variants = maybeNewConst( @@ -313,7 +311,7 @@ export default async function makeFileContentFromOld( value.spec.variants, value.spec["variant-names"] || {}, ), - ); + ) const unionValueName = maybeNewConst( value.name + "_union", `${rangeToTodoComment(value?.range)} @@ -323,11 +321,15 @@ export default async function makeFileContentFromOld( value?.spec?.tag?.description || null, )}, warning: ${JSON.stringify(value?.spec?.tag?.warning || null)}, - required: ${JSON.stringify(!(value?.spec?.tag?.nullable || false))}, + required: ${JSON.stringify( + !(value?.spec?.tag?.nullable || false) + ? { default: null } + : false, + )}, default: ${JSON.stringify(value?.spec?.default || null)}, }, ${variants}) `, - ); + ) const listConfig = maybeNewConst( value.name + "_list_config", ` @@ -335,7 +337,7 @@ export default async function makeFileContentFromOld( "union": ${unionValueName} }) `, - ); + ) return `${rangeToTodoComment(value?.range)}List.obj({ name:${JSON.stringify(value.name || null)}, minLength:${JSON.stringify(null)}, @@ -347,37 +349,37 @@ export default async function makeFileContentFromOld( spec: ${listConfig}, displayAs: ${JSON.stringify(value?.spec?.["display-as"] || null)}, uniqueBy: ${JSON.stringify(value?.spec?.["unique-by"] || null)}, - })`; + })` } } - throw new Error(`Unknown subtype "${value.subtype}"`); + throw new Error(`Unknown subtype "${value.subtype}"`) } function convertVariants( variants: Record, variantNames: Record, ): string { - let answer = "Variants.of({"; + let answer = "Variants.of({" for (const [key, value] of Object.entries(variants)) { - const variantSpec = maybeNewConst(key, convertInputSpec(value)); + const variantSpec = maybeNewConst(key, convertInputSpec(value)) answer += `"${key}": {name: "${ variantNames[key] || key - }", spec: ${variantSpec}},`; + }", spec: ${variantSpec}},` } - return `${answer}})`; + return `${answer}})` } function getNextConstName(name: string, i = 0): string { - const newName = !i ? name : name + i; + const newName = !i ? name : name + i if (namedConsts.has(newName)) { - return getNextConstName(name, i + 1); + return getNextConstName(name, i + 1) } - namedConsts.add(newName); - return newName; + namedConsts.add(newName) + return newName } } function rangeToTodoComment(range: string | undefined) { - if (!range) return ""; - return `/* TODO: Convert range for this value (${range})*/`; + if (!range) return "" + return `/* TODO: Convert range for this value (${range})*/` }