ogi-addon 1.1.0 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,41 +1,41 @@
1
- # OGI-Addon
2
- A library to interface with OpenGameInstaller's addon system.
3
-
4
- # Installation
5
- ```bash
6
- $ npm install ogi-addon
7
- ```
8
-
9
- # Examples
10
- Check out the [test-addon](https://github.com/Nat3z/OpenGameInstaller/tree/main/test-addon) folder to see how to use the addon library.
11
-
12
- # Boilerplate
13
- Your addon should include an `addon.json` file which describes how to setup your addon. It should always include a `run` script so OpenGameInstaller will know how to start your addon.
14
- ```typescript
15
- interface AddonFileConfigurationSchema {
16
- author: string,
17
- scripts: {
18
- setup?: string,
19
- run: string,
20
- preSetup?: string,
21
- postSetup?: string
22
- }
23
- }
24
- ```
25
-
26
- ## How to Develop
27
- In OpenGameInstaller, go to `Settings > General` and use the **local:** prefix to define that your addon is hosted locally instead of through a remote git repository.
28
-
29
- For Example:
30
- ```
31
- local:C:\Users\[you]\Documents\Addon\
32
- ```
33
-
34
- This will allow OpenGameInstaller to launch your addon securely instead of opening up the addon server for unsigned connections.
35
-
36
- ### Disable Signature Requirement for Addons
37
- If you want to debug your addon without relying on OpenGameInstaller to launch it, you can disable the signature requirement.
38
-
39
- ⚠️ **WARNING** This is VERY unsafe to do, as it allows for any malicious program to connect to the addon server without needing to provide the addon secret. We recommend enabling this temporarily for debugging purposes and disabling it once you can.
40
-
1
+ # OGI-Addon
2
+ A library to interface with OpenGameInstaller's addon system.
3
+
4
+ # Installation
5
+ ```bash
6
+ $ npm install ogi-addon
7
+ ```
8
+
9
+ # Examples
10
+ Check out the [test-addon](https://github.com/Nat3z/OpenGameInstaller/tree/main/test-addon) folder to see how to use the addon library.
11
+
12
+ # Boilerplate
13
+ Your addon should include an `addon.json` file which describes how to setup your addon. It should always include a `run` script so OpenGameInstaller will know how to start your addon.
14
+ ```typescript
15
+ interface AddonFileConfigurationSchema {
16
+ author: string,
17
+ scripts: {
18
+ setup?: string,
19
+ run: string,
20
+ preSetup?: string,
21
+ postSetup?: string
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## How to Develop
27
+ In OpenGameInstaller, go to `Settings > General` and use the **local:** prefix to define that your addon is hosted locally instead of through a remote git repository.
28
+
29
+ For Example:
30
+ ```
31
+ local:C:\Users\[you]\Documents\Addon\
32
+ ```
33
+
34
+ This will allow OpenGameInstaller to launch your addon securely instead of opening up the addon server for unsigned connections.
35
+
36
+ ### Disable Signature Requirement for Addons
37
+ If you want to debug your addon without relying on OpenGameInstaller to launch it, you can disable the signature requirement.
38
+
39
+ ⚠️ **WARNING** This is VERY unsafe to do, as it allows for any malicious program to connect to the addon server without needing to provide the addon secret. We recommend enabling this temporarily for debugging purposes and disabling it once you can.
40
+
41
41
  To disable the signature requirement, go to `Settings > Developer` and select **Disable Server Secret Check**. Restart OpenGameInstaller.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/EventResponse.ts"],"sourcesContent":["import { ConfigurationBuilder } from \"./main\";\r\n\r\nexport default class EventResponse<T> {\r\n data: T | undefined = undefined;\r\n deffered: boolean = false;\r\n resolved: boolean = false;\r\n progress: number = 0;\r\n logs: string[] = [];\r\n onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>;\r\n\r\n constructor(onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>) {\r\n this.onInputAsked = onInputAsked;\r\n }\r\n \r\n\r\n public defer() {\r\n this.deffered = true;\r\n }\r\n\r\n /**\r\n * Resolve the event with data. This acts like a promise resolve, and will stop the event from being processed further. **You must always call this method when you are done with the event.** \r\n * @param data {T}\r\n */\r\n public resolve(data: T) {\r\n this.resolved = true;\r\n this.data = data;\r\n }\r\n\r\n /**\r\n * Completes the event and resolves it, but does not return any data. **You must always call this method when you are done with the event.** \r\n */\r\n public complete() {\r\n this.resolved = true;\r\n }\r\n\r\n /**\r\n * Logs a message to the event. This is useful for debugging and logging information to the user. \r\n * @param message {string}\r\n */\r\n public log(message: string) {\r\n this.logs.push(message);\r\n }\r\n\r\n /**\r\n * Send a screen to the client to ask for input. Use the `ConfigurationBuilder` system to build the screen. Once sent to the user, the addon cannot change the screen.\r\n * @async\r\n * @param name {string}\r\n * @param description {string}\r\n * @param screen {ConfigurationBuilder}\r\n * @returns {Promise<{ [key: string]: boolean | string | number }>}\r\n */\r\n public async askForInput(name: string, description: string, screen: ConfigurationBuilder): Promise<{ [key: string]: boolean | string | number; }> {\r\n if (!this.onInputAsked) {\r\n throw new Error('No input asked callback');\r\n }\r\n return await this.onInputAsked(screen, name, description);\r\n }\r\n\r\n \r\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAqB,gBAArB,MAAsC;AAAA,EACpC,OAAsB;AAAA,EACtB,WAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,WAAmB;AAAA,EACnB,OAAiB,CAAC;AAAA,EAClB;AAAA,EAEA,YAAY,cAA2I;AACrJ,SAAK,eAAe;AAAA,EACtB;AAAA,EAGO,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,QAAQ,MAAS;AACtB,SAAK,WAAW;AAChB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,SAAiB;AAC1B,SAAK,KAAK,KAAK,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,YAAY,MAAc,aAAqB,QAAsF;AAChJ,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,WAAO,MAAM,KAAK,aAAa,QAAQ,MAAM,WAAW;AAAA,EAC1D;AAGF;","names":[]}
1
+ {"version":3,"sources":["../src/EventResponse.ts"],"sourcesContent":["import { ConfigurationBuilder } from \"./main\";\n\nexport default class EventResponse<T> {\n data: T | undefined = undefined;\n deffered: boolean = false;\n resolved: boolean = false;\n progress: number = 0;\n logs: string[] = [];\n onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>;\n\n constructor(onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>) {\n this.onInputAsked = onInputAsked;\n }\n \n\n public defer() {\n this.deffered = true;\n }\n\n /**\n * Resolve the event with data. This acts like a promise resolve, and will stop the event from being processed further. **You must always call this method when you are done with the event.** \n * @param data {T}\n */\n public resolve(data: T) {\n this.resolved = true;\n this.data = data;\n }\n\n /**\n * Completes the event and resolves it, but does not return any data. **You must always call this method when you are done with the event.** \n */\n public complete() {\n this.resolved = true;\n }\n\n /**\n * Logs a message to the event. This is useful for debugging and logging information to the user. \n * @param message {string}\n */\n public log(message: string) {\n this.logs.push(message);\n }\n\n /**\n * Send a screen to the client to ask for input. Use the `ConfigurationBuilder` system to build the screen. Once sent to the user, the addon cannot change the screen.\n * @async\n * @param name {string}\n * @param description {string}\n * @param screen {ConfigurationBuilder}\n * @returns {Promise<{ [key: string]: boolean | string | number }>}\n */\n public async askForInput(name: string, description: string, screen: ConfigurationBuilder): Promise<{ [key: string]: boolean | string | number; }> {\n if (!this.onInputAsked) {\n throw new Error('No input asked callback');\n }\n return await this.onInputAsked(screen, name, description);\n }\n\n \n}"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAqB,gBAArB,MAAsC;AAAA,EACpC,OAAsB;AAAA,EACtB,WAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,WAAmB;AAAA,EACnB,OAAiB,CAAC;AAAA,EAClB;AAAA,EAEA,YAAY,cAA2I;AACrJ,SAAK,eAAe;AAAA,EACtB;AAAA,EAGO,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,QAAQ,MAAS;AACtB,SAAK,WAAW;AAChB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,SAAiB;AAC1B,SAAK,KAAK,KAAK,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,YAAY,MAAc,aAAqB,QAAsF;AAChJ,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,WAAO,MAAM,KAAK,aAAa,QAAQ,MAAM,WAAW;AAAA,EAC1D;AAGF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/EventResponse.ts"],"sourcesContent":["import { ConfigurationBuilder } from \"./main\";\r\n\r\nexport default class EventResponse<T> {\r\n data: T | undefined = undefined;\r\n deffered: boolean = false;\r\n resolved: boolean = false;\r\n progress: number = 0;\r\n logs: string[] = [];\r\n onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>;\r\n\r\n constructor(onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>) {\r\n this.onInputAsked = onInputAsked;\r\n }\r\n \r\n\r\n public defer() {\r\n this.deffered = true;\r\n }\r\n\r\n /**\r\n * Resolve the event with data. This acts like a promise resolve, and will stop the event from being processed further. **You must always call this method when you are done with the event.** \r\n * @param data {T}\r\n */\r\n public resolve(data: T) {\r\n this.resolved = true;\r\n this.data = data;\r\n }\r\n\r\n /**\r\n * Completes the event and resolves it, but does not return any data. **You must always call this method when you are done with the event.** \r\n */\r\n public complete() {\r\n this.resolved = true;\r\n }\r\n\r\n /**\r\n * Logs a message to the event. This is useful for debugging and logging information to the user. \r\n * @param message {string}\r\n */\r\n public log(message: string) {\r\n this.logs.push(message);\r\n }\r\n\r\n /**\r\n * Send a screen to the client to ask for input. Use the `ConfigurationBuilder` system to build the screen. Once sent to the user, the addon cannot change the screen.\r\n * @async\r\n * @param name {string}\r\n * @param description {string}\r\n * @param screen {ConfigurationBuilder}\r\n * @returns {Promise<{ [key: string]: boolean | string | number }>}\r\n */\r\n public async askForInput(name: string, description: string, screen: ConfigurationBuilder): Promise<{ [key: string]: boolean | string | number; }> {\r\n if (!this.onInputAsked) {\r\n throw new Error('No input asked callback');\r\n }\r\n return await this.onInputAsked(screen, name, description);\r\n }\r\n\r\n \r\n}"],"mappings":";AAEA,IAAqB,gBAArB,MAAsC;AAAA,EACpC,OAAsB;AAAA,EACtB,WAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,WAAmB;AAAA,EACnB,OAAiB,CAAC;AAAA,EAClB;AAAA,EAEA,YAAY,cAA2I;AACrJ,SAAK,eAAe;AAAA,EACtB;AAAA,EAGO,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,QAAQ,MAAS;AACtB,SAAK,WAAW;AAChB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,SAAiB;AAC1B,SAAK,KAAK,KAAK,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,YAAY,MAAc,aAAqB,QAAsF;AAChJ,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,WAAO,MAAM,KAAK,aAAa,QAAQ,MAAM,WAAW;AAAA,EAC1D;AAGF;","names":[]}
1
+ {"version":3,"sources":["../src/EventResponse.ts"],"sourcesContent":["import { ConfigurationBuilder } from \"./main\";\n\nexport default class EventResponse<T> {\n data: T | undefined = undefined;\n deffered: boolean = false;\n resolved: boolean = false;\n progress: number = 0;\n logs: string[] = [];\n onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>;\n\n constructor(onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>) {\n this.onInputAsked = onInputAsked;\n }\n \n\n public defer() {\n this.deffered = true;\n }\n\n /**\n * Resolve the event with data. This acts like a promise resolve, and will stop the event from being processed further. **You must always call this method when you are done with the event.** \n * @param data {T}\n */\n public resolve(data: T) {\n this.resolved = true;\n this.data = data;\n }\n\n /**\n * Completes the event and resolves it, but does not return any data. **You must always call this method when you are done with the event.** \n */\n public complete() {\n this.resolved = true;\n }\n\n /**\n * Logs a message to the event. This is useful for debugging and logging information to the user. \n * @param message {string}\n */\n public log(message: string) {\n this.logs.push(message);\n }\n\n /**\n * Send a screen to the client to ask for input. Use the `ConfigurationBuilder` system to build the screen. Once sent to the user, the addon cannot change the screen.\n * @async\n * @param name {string}\n * @param description {string}\n * @param screen {ConfigurationBuilder}\n * @returns {Promise<{ [key: string]: boolean | string | number }>}\n */\n public async askForInput(name: string, description: string, screen: ConfigurationBuilder): Promise<{ [key: string]: boolean | string | number; }> {\n if (!this.onInputAsked) {\n throw new Error('No input asked callback');\n }\n return await this.onInputAsked(screen, name, description);\n }\n\n \n}"],"mappings":";AAEA,IAAqB,gBAArB,MAAsC;AAAA,EACpC,OAAsB;AAAA,EACtB,WAAoB;AAAA,EACpB,WAAoB;AAAA,EACpB,WAAmB;AAAA,EACnB,OAAiB,CAAC;AAAA,EAClB;AAAA,EAEA,YAAY,cAA2I;AACrJ,SAAK,eAAe;AAAA,EACtB;AAAA,EAGO,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,QAAQ,MAAS;AACtB,SAAK,WAAW;AAChB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,SAAiB;AAC1B,SAAK,KAAK,KAAK,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,YAAY,MAAc,aAAqB,QAAsF;AAChJ,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,WAAO,MAAM,KAAK,aAAa,QAAQ,MAAM,WAAW;AAAA,EAC1D;AAGF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SearchEngine.ts"],"sourcesContent":["export type SearchResult = {\r\n name: string;\r\n description: string;\r\n coverURL: string;\r\n downloadType: 'torrent' | 'direct' | 'magnet' | 'request';\r\n downloadSize: number;\r\n appID: number;\r\n storefront: 'steam' | 'internal';\r\n filename?: string;\r\n downloadURL?: string;\r\n files?: {\r\n name: string;\r\n downloadURL: string;\r\n }[];\r\n}\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../src/SearchEngine.ts"],"sourcesContent":["export type SearchResult = {\n name: string;\n description: string;\n coverURL: string;\n downloadType: 'torrent' | 'direct' | 'magnet' | 'request';\n downloadSize: number;\n appID: number;\n storefront: 'steam' | 'internal';\n filename?: string;\n downloadURL?: string;\n files?: {\n name: string;\n downloadURL: string;\n }[];\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/Configuration.ts","../../src/config/ConfigurationBuilder.ts"],"sourcesContent":["import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\r\n\r\ninterface DefiniteConfig {\r\n [key: string]: string | number | boolean;\r\n}\r\nexport class Configuration {\r\n readonly storedConfigTemplate: ConfigurationFile;\r\n definiteConfig: DefiniteConfig = {};\r\n constructor(configTemplate: ConfigurationFile) {\r\n this.storedConfigTemplate = configTemplate;\r\n }\r\n\r\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\r\n this.definiteConfig = config;\r\n if (validate) {\r\n const result = this.validateConfig();\r\n return result;\r\n }\r\n return [ true, {} ];\r\n }\r\n // provides falsey or truthy value, and an error message if falsey\r\n private validateConfig(): [ boolean, { [key: string]: string } ] {\r\n const erroredKeys = new Map<string, string>();\r\n for (const key in this.storedConfigTemplate) {\r\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\r\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\r\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\r\n }\r\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\r\n throw new Error('Option ' + key + ' is not of the correct type');\r\n }\r\n\r\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\r\n if (!result[0]) {\r\n erroredKeys.set(key, result[1]);\r\n }\r\n }\r\n\r\n for (const key in this.definiteConfig) {\r\n if (!this.storedConfigTemplate[key]) {\r\n throw new Error('Option ' + key + ' is not defined in the configuration template');\r\n }\r\n }\r\n\r\n if (erroredKeys.size > 0) {\r\n return [ false, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n return [ true, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n getStringValue(optionName: string): string {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'string') {\r\n throw new Error('Option ' + optionName + ' is not a string');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getNumberValue(optionName: string): number {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'number') {\r\n throw new Error('Option ' + optionName + ' is not a number');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getBooleanValue(optionName: string): boolean {\r\n if (this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\r\n throw new Error('Option ' + optionName + ' is not a boolean');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n}\r\n\r\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };","import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n\r\n /**\r\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: NumberOption) => NumberOption }\r\n * @returns \r\n */\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: StringOption) => StringOption }\r\n */\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: BooleanOption) => BooleanOption }\r\n */\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n /**\r\n * Set the name of the option. **REQUIRED**\r\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\r\n */\r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \r\n * @param displayName {string} The display name of the option. \r\n * @returns \r\n */\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\r\n * @param description {string} The description of the option. \r\n * @returns \r\n */\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n /**\r\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\r\n * @param input {unknown} The input to validate\r\n */\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n /**\r\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \r\n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\r\n */\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {string} The default value for the string.\r\n */\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \r\n * @param minTextLength {number} The minimum text length for the string. \r\n */\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \r\n * @param maxTextLength {number} The maximum text length for the string.\r\n */\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the string. This will change how the client renders the input. \r\n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \r\n */\r\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\r\n this.inputType = inputType;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n\r\n /**\r\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\r\n * @param min {number} The minimum value for the number.\r\n */\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the number. This will change how the client renders the input. \r\n * @param type {'range' | 'number'} The input type for the number. \r\n */\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\r\n * @param max {number} The maximum value for the number.\r\n */\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n /**\r\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {number} The default value for the number.\r\n */\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n /**\r\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {boolean} The default value for the boolean.\r\n */\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}"],"mappings":"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","names":["z"]}
1
+ {"version":3,"sources":["../../src/config/Configuration.ts","../../src/config/ConfigurationBuilder.ts"],"sourcesContent":["import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\n\ninterface DefiniteConfig {\n [key: string]: string | number | boolean;\n}\nexport class Configuration {\n readonly storedConfigTemplate: ConfigurationFile;\n definiteConfig: DefiniteConfig = {};\n constructor(configTemplate: ConfigurationFile) {\n this.storedConfigTemplate = configTemplate;\n }\n\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\n this.definiteConfig = config;\n if (validate) {\n const result = this.validateConfig();\n return result;\n }\n return [ true, {} ];\n }\n // provides falsey or truthy value, and an error message if falsey\n private validateConfig(): [ boolean, { [key: string]: string } ] {\n const erroredKeys = new Map<string, string>();\n for (const key in this.storedConfigTemplate) {\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\n }\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\n throw new Error('Option ' + key + ' is not of the correct type');\n }\n\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\n if (!result[0]) {\n erroredKeys.set(key, result[1]);\n }\n }\n\n for (const key in this.definiteConfig) {\n if (!this.storedConfigTemplate[key]) {\n throw new Error('Option ' + key + ' is not defined in the configuration template');\n }\n }\n\n if (erroredKeys.size > 0) {\n return [ false, Object.fromEntries(erroredKeys) ];\n }\n\n return [ true, Object.fromEntries(erroredKeys) ];\n }\n\n getStringValue(optionName: string): string {\n if (!this.definiteConfig[optionName] === null) {\n throw new Error('Option ' + optionName + ' is not defined');\n }\n if (typeof this.definiteConfig[optionName] !== 'string') {\n throw new Error('Option ' + optionName + ' is not a string');\n }\n return this.definiteConfig[optionName];\n }\n\n getNumberValue(optionName: string): number {\n if (!this.definiteConfig[optionName] === null) {\n throw new Error('Option ' + optionName + ' is not defined');\n }\n if (typeof this.definiteConfig[optionName] !== 'number') {\n throw new Error('Option ' + optionName + ' is not a number');\n }\n return this.definiteConfig[optionName];\n }\n\n getBooleanValue(optionName: string): boolean {\n if (this.definiteConfig[optionName] === null) {\n throw new Error('Option ' + optionName + ' is not defined');\n }\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\n throw new Error('Option ' + optionName + ' is not a boolean');\n }\n return this.definiteConfig[optionName];\n }\n}\n\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };","import z, { ZodError } from \"zod\"\n\nexport interface ConfigurationFile {\n [key: string]: ConfigurationOption\n}\n\nconst configValidation = z.object({\n name: z.string().min(1),\n displayName: z.string().min(1),\n description: z.string().min(1),\n})\n\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\n return option.type === 'string';\n }\n\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\n return option.type === 'number';\n}\n\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\n return option.type === 'boolean';\n}\n\nexport class ConfigurationBuilder {\n private options: ConfigurationOption[] = [];\n\n /**\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: NumberOption) => NumberOption }\n * @returns \n */\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\n let newOption = new NumberOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: StringOption) => StringOption }\n */\n public addStringOption(option: (option: StringOption) => StringOption) {\n let newOption = new StringOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: BooleanOption) => BooleanOption }\n */\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\n let newOption = new BooleanOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n public build(includeFunctions: boolean): ConfigurationFile {\n let config: ConfigurationFile = {};\n this.options.forEach(option => {\n // remove all functions from the option object\n if (!includeFunctions) {\n option = JSON.parse(JSON.stringify(option));\n const optionData = configValidation.safeParse(option)\n if (!optionData.success) {\n throw new ZodError(optionData.error.errors)\n }\n\n config[option.name] = option;\n }\n else {\n config[option.name] = option;\n }\n });\n return config;\n }\n}\n\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\nexport class ConfigurationOption {\n public name: string = '';\n public defaultValue: unknown = '';\n public displayName: string = '';\n public description: string = '';\n public type: ConfigurationOptionType = 'unset'\n \n /**\n * Set the name of the option. **REQUIRED**\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\n */\n setName(name: string) {\n this.name = name;\n return this;\n }\n\n /**\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \n * @param displayName {string} The display name of the option. \n * @returns \n */\n setDisplayName(displayName: string) {\n this.displayName = displayName;\n return this;\n }\n\n /**\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\n * @param description {string} The description of the option. \n * @returns \n */\n setDescription(description: string) {\n this.description = description;\n return this;\n }\n\n /**\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\n * @param input {unknown} The input to validate\n */\n validate(input: unknown): [ boolean, string ] {\n throw new Error('Validation code not implemented. Value: ' + input)\n };\n}\n\nexport class StringOption extends ConfigurationOption {\n public allowedValues: string[] = [];\n public minTextLength: number = 0;\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: string = '';\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\n public type: ConfigurationOptionType = 'string'\n\n /**\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\n */\n setAllowedValues(allowedValues: string[]): this {\n this.allowedValues = allowedValues;\n return this;\n }\n\n /**\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {string} The default value for the string.\n */\n setDefaultValue(defaultValue: string): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n /**\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \n * @param minTextLength {number} The minimum text length for the string. \n */\n setMinTextLength(minTextLength: number): this {\n this.minTextLength = minTextLength;\n return this;\n }\n\n /**\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \n * @param maxTextLength {number} The maximum text length for the string.\n */\n setMaxTextLength(maxTextLength: number): this {\n this.maxTextLength = maxTextLength;\n return this;\n }\n\n /**\n * Set the input type for the string. This will change how the client renders the input. \n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \n */\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\n this.inputType = inputType;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'string') {\n return [ false, 'Input is not a string' ];\n }\n if (this.allowedValues.length === 0 && input.length !== 0)\n return [ true, '' ];\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\n }\n\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\n }\n}\n\nexport class NumberOption extends ConfigurationOption {\n public min: number = 0;\n public max: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: number = 0;\n public type: ConfigurationOptionType = 'number'\n public inputType: 'range' | 'number' = 'number';\n\n /**\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\n * @param min {number} The minimum value for the number.\n */\n setMin(min: number): this {\n this.min = min;\n return this;\n }\n\n /**\n * Set the input type for the number. This will change how the client renders the input. \n * @param type {'range' | 'number'} The input type for the number. \n */\n setInputType(type: 'range' | 'number'): this {\n this.inputType = type;\n return this;\n }\n\n /**\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\n * @param max {number} The maximum value for the number.\n */\n setMax(max: number): this {\n this.max = max;\n return this\n }\n\n /**\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {number} The default value for the number.\n */\n setDefaultValue(defaultValue: number): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (isNaN(Number(input))) {\n return [ false, 'Input is not a number' ];\n }\n if (Number(input) < this.min || Number(input) > this.max) {\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\n }\n return [ true, '' ];\n }\n\n}\n\nexport class BooleanOption extends ConfigurationOption {\n public type: ConfigurationOptionType = 'boolean'\n public defaultValue: boolean = false;\n\n /**\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {boolean} The default value for the boolean.\n */\n setDefaultValue(defaultValue: boolean): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'boolean') {\n return [ false, 'Input is not a boolean' ];\n }\n return [ true, '' ];\n }\n\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,iBAA4B;AAM5B,IAAM,mBAAmB,WAAAA,QAAE,OAAO;AAAA,EAChC,MAAM,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAa,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,aAAa,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAC/B,CAAC;AAEM,SAAS,eAAe,QAAqD;AAChF,SAAO,OAAO,SAAS;AACzB;AAEK,SAAS,eAAe,QAAqD;AAClF,SAAO,OAAO,SAAS;AACzB;AAEO,SAAS,gBAAgB,QAAsD;AACpF,SAAO,OAAO,SAAS;AACzB;AAEO,IAAM,uBAAN,MAA2B;AAAA,EACxB,UAAiC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,gBAAgB,QAAsE;AAC3F,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,gBAAgB,QAAgD;AACrE,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,iBAAiB,QAAkD;AACxE,QAAI,YAAY,IAAI,cAAc;AAClC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA,EAEO,MAAM,kBAA8C;AACzD,QAAI,SAA4B,CAAC;AACjC,SAAK,QAAQ,QAAQ,YAAU;AAE7B,UAAI,CAAC,kBAAkB;AACrB,iBAAS,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAC1C,cAAM,aAAa,iBAAiB,UAAU,MAAM;AACpD,YAAI,CAAC,WAAW,SAAS;AACvB,gBAAM,IAAI,oBAAS,WAAW,MAAM,MAAM;AAAA,QAC5C;AAEA,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB,OACK;AACH,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAGO,IAAM,sBAAN,MAA0B;AAAA,EACxB,OAAe;AAAA,EACf,eAAwB;AAAA,EACxB,cAAsB;AAAA,EACtB,cAAsB;AAAA,EACtB,OAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,QAAQ,MAAc;AACpB,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,OAAqC;AAC5C,UAAM,IAAI,MAAM,6CAA6C,KAAK;AAAA,EACpE;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,gBAA0B,CAAC;AAAA,EAC3B,gBAAwB;AAAA,EACxB,gBAAwB,OAAO;AAAA,EAC/B,eAAuB;AAAA,EACvB,YAAqD;AAAA,EACrD,OAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,iBAAiB,eAA+B;AAC9C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,WAA0D;AACrE,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,KAAK,cAAc,WAAW,KAAK,MAAM,WAAW;AACtD,aAAO,CAAE,MAAM,EAAG;AACpB,QAAI,MAAM,SAAS,KAAK,iBAAiB,MAAM,SAAS,KAAK,eAAe;AAC1E,aAAO,CAAE,OAAO,yCAAyC,KAAK,gBAAgB,UAAU,KAAK,gBAAgB,4BAA4B,MAAM,SAAS,cAAe;AAAA,IACzK;AAEA,WAAO,CAAE,KAAK,cAAc,SAAS,KAAK,GAAG,+BAAgC;AAAA,EAC/E;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,MAAc;AAAA,EACd,MAAc,OAAO;AAAA,EACrB,eAAuB;AAAA,EACvB,OAAgC;AAAA,EAChC,YAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,MAAgC;AAC3C,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,MAAM,OAAO,KAAK,CAAC,GAAG;AACxB,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,OAAO,KAAK,IAAI,KAAK,OAAO,OAAO,KAAK,IAAI,KAAK,KAAK;AACxD,aAAO,CAAE,OAAO,sCAAsC,KAAK,MAAM,UAAU,KAAK,GAAI;AAAA,IACtF;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;AAEO,IAAM,gBAAN,cAA4B,oBAAoB;AAAA,EAC9C,OAAgC;AAAA,EAChC,eAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/B,gBAAgB,cAA6B;AAC3C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,WAAW;AAC9B,aAAO,CAAE,OAAO,wBAAyB;AAAA,IAC3C;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;;;ADzQO,IAAM,gBAAN,MAAoB;AAAA,EAChB;AAAA,EACT,iBAAiC,CAAC;AAAA,EAClC,YAAY,gBAAmC;AAC7C,SAAK,uBAAuB;AAAA,EAC9B;AAAA,EAEA,aAAa,QAAwB,WAAoB,MAA8C;AACrG,SAAK,iBAAiB;AACtB,QAAI,UAAU;AACZ,YAAM,SAAS,KAAK,eAAe;AACnC,aAAO;AAAA,IACT;AACA,WAAO,CAAE,MAAM,CAAC,CAAE;AAAA,EACpB;AAAA;AAAA,EAEQ,iBAAyD;AAC/D,UAAM,cAAc,oBAAI,IAAoB;AAC5C,eAAW,OAAO,KAAK,sBAAsB;AAC3C,UAAI,KAAK,eAAe,GAAG,MAAM,QAAQ,KAAK,eAAe,GAAG,MAAM,QAAW;AAC/E,gBAAQ,KAAK,YAAY,MAAM,iDAAiD,KAAK,eAAe,GAAG,CAAC;AACxG,aAAK,eAAe,GAAG,IAAI,KAAK,qBAAqB,GAAG,EAAE;AAAA,MAC5D;AACA,UAAI,KAAK,qBAAqB,GAAG,EAAE,SAAS,OAAO,KAAK,eAAe,GAAG,GAAG;AAC3E,cAAM,IAAI,MAAM,YAAY,MAAM,6BAA6B;AAAA,MACjE;AAEA,YAAM,SAAS,KAAK,qBAAqB,GAAG,EAAE,SAAS,KAAK,eAAe,GAAG,CAAC;AAC/E,UAAI,CAAC,OAAO,CAAC,GAAG;AACd,oBAAY,IAAI,KAAK,OAAO,CAAC,CAAC;AAAA,MAChC;AAAA,IACF;AAEA,eAAW,OAAO,KAAK,gBAAgB;AACrC,UAAI,CAAC,KAAK,qBAAqB,GAAG,GAAG;AACnC,cAAM,IAAI,MAAM,YAAY,MAAM,+CAA+C;AAAA,MACnF;AAAA,IACF;AAEA,QAAI,YAAY,OAAO,GAAG;AACxB,aAAO,CAAE,OAAO,OAAO,YAAY,WAAW,CAAE;AAAA,IAClD;AAEA,WAAO,CAAE,MAAM,OAAO,YAAY,WAAW,CAAE;AAAA,EACjD;AAAA,EAEA,eAAe,YAA4B;AACzC,QAAI,CAAC,KAAK,eAAe,UAAU,MAAM,MAAM;AAC7C,YAAM,IAAI,MAAM,YAAY,aAAa,iBAAiB;AAAA,IAC5D;AACA,QAAI,OAAO,KAAK,eAAe,UAAU,MAAM,UAAU;AACvD,YAAM,IAAI,MAAM,YAAY,aAAa,kBAAkB;AAAA,IAC7D;AACA,WAAO,KAAK,eAAe,UAAU;AAAA,EACvC;AAAA,EAEA,eAAe,YAA4B;AACzC,QAAI,CAAC,KAAK,eAAe,UAAU,MAAM,MAAM;AAC7C,YAAM,IAAI,MAAM,YAAY,aAAa,iBAAiB;AAAA,IAC5D;AACA,QAAI,OAAO,KAAK,eAAe,UAAU,MAAM,UAAU;AACvD,YAAM,IAAI,MAAM,YAAY,aAAa,kBAAkB;AAAA,IAC7D;AACA,WAAO,KAAK,eAAe,UAAU;AAAA,EACvC;AAAA,EAEA,gBAAgB,YAA6B;AAC3C,QAAI,KAAK,eAAe,UAAU,MAAM,MAAM;AAC5C,YAAM,IAAI,MAAM,YAAY,aAAa,iBAAiB;AAAA,IAC5D;AACA,QAAI,OAAO,KAAK,eAAe,UAAU,MAAM,WAAW;AACxD,YAAM,IAAI,MAAM,YAAY,aAAa,mBAAmB;AAAA,IAC9D;AACA,WAAO,KAAK,eAAe,UAAU;AAAA,EACvC;AACF;","names":["z"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/ConfigurationBuilder.ts","../../src/config/Configuration.ts"],"sourcesContent":["import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n\r\n /**\r\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: NumberOption) => NumberOption }\r\n * @returns \r\n */\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: StringOption) => StringOption }\r\n */\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: BooleanOption) => BooleanOption }\r\n */\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n /**\r\n * Set the name of the option. **REQUIRED**\r\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\r\n */\r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \r\n * @param displayName {string} The display name of the option. \r\n * @returns \r\n */\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\r\n * @param description {string} The description of the option. \r\n * @returns \r\n */\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n /**\r\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\r\n * @param input {unknown} The input to validate\r\n */\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n /**\r\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \r\n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\r\n */\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {string} The default value for the string.\r\n */\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \r\n * @param minTextLength {number} The minimum text length for the string. \r\n */\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \r\n * @param maxTextLength {number} The maximum text length for the string.\r\n */\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the string. This will change how the client renders the input. \r\n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \r\n */\r\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\r\n this.inputType = inputType;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n\r\n /**\r\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\r\n * @param min {number} The minimum value for the number.\r\n */\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the number. This will change how the client renders the input. \r\n * @param type {'range' | 'number'} The input type for the number. \r\n */\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\r\n * @param max {number} The maximum value for the number.\r\n */\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n /**\r\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {number} The default value for the number.\r\n */\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n /**\r\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {boolean} The default value for the boolean.\r\n */\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}","import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\r\n\r\ninterface DefiniteConfig {\r\n [key: string]: string | number | boolean;\r\n}\r\nexport class Configuration {\r\n readonly storedConfigTemplate: ConfigurationFile;\r\n definiteConfig: DefiniteConfig = {};\r\n constructor(configTemplate: ConfigurationFile) {\r\n this.storedConfigTemplate = configTemplate;\r\n }\r\n\r\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\r\n this.definiteConfig = config;\r\n if (validate) {\r\n const result = this.validateConfig();\r\n return result;\r\n }\r\n return [ true, {} ];\r\n }\r\n // provides falsey or truthy value, and an error message if falsey\r\n private validateConfig(): [ boolean, { [key: string]: string } ] {\r\n const erroredKeys = new Map<string, string>();\r\n for (const key in this.storedConfigTemplate) {\r\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\r\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\r\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\r\n }\r\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\r\n throw new Error('Option ' + key + ' is not of the correct type');\r\n }\r\n\r\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\r\n if (!result[0]) {\r\n erroredKeys.set(key, result[1]);\r\n }\r\n }\r\n\r\n for (const key in this.definiteConfig) {\r\n if (!this.storedConfigTemplate[key]) {\r\n throw new Error('Option ' + key + ' is not defined in the configuration template');\r\n }\r\n }\r\n\r\n if (erroredKeys.size > 0) {\r\n return [ false, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n return [ true, Object.fromEntries(erroredKeys) ];\r\n }\r\n\r\n getStringValue(optionName: string): string {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'string') {\r\n throw new Error('Option ' + optionName + ' is not a string');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getNumberValue(optionName: string): number {\r\n if (!this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'number') {\r\n throw new Error('Option ' + optionName + ' is not a number');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n\r\n getBooleanValue(optionName: string): boolean {\r\n if (this.definiteConfig[optionName] === null) {\r\n throw new Error('Option ' + optionName + ' is not defined');\r\n }\r\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\r\n throw new Error('Option ' + optionName + ' is not a boolean');\r\n }\r\n return this.definiteConfig[optionName];\r\n }\r\n}\r\n\r\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/config/ConfigurationBuilder.ts","../../src/config/Configuration.ts"],"sourcesContent":["import z, { ZodError } from \"zod\"\n\nexport interface ConfigurationFile {\n [key: string]: ConfigurationOption\n}\n\nconst configValidation = z.object({\n name: z.string().min(1),\n displayName: z.string().min(1),\n description: z.string().min(1),\n})\n\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\n return option.type === 'string';\n }\n\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\n return option.type === 'number';\n}\n\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\n return option.type === 'boolean';\n}\n\nexport class ConfigurationBuilder {\n private options: ConfigurationOption[] = [];\n\n /**\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: NumberOption) => NumberOption }\n * @returns \n */\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\n let newOption = new NumberOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: StringOption) => StringOption }\n */\n public addStringOption(option: (option: StringOption) => StringOption) {\n let newOption = new StringOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: BooleanOption) => BooleanOption }\n */\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\n let newOption = new BooleanOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n public build(includeFunctions: boolean): ConfigurationFile {\n let config: ConfigurationFile = {};\n this.options.forEach(option => {\n // remove all functions from the option object\n if (!includeFunctions) {\n option = JSON.parse(JSON.stringify(option));\n const optionData = configValidation.safeParse(option)\n if (!optionData.success) {\n throw new ZodError(optionData.error.errors)\n }\n\n config[option.name] = option;\n }\n else {\n config[option.name] = option;\n }\n });\n return config;\n }\n}\n\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\nexport class ConfigurationOption {\n public name: string = '';\n public defaultValue: unknown = '';\n public displayName: string = '';\n public description: string = '';\n public type: ConfigurationOptionType = 'unset'\n \n /**\n * Set the name of the option. **REQUIRED**\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\n */\n setName(name: string) {\n this.name = name;\n return this;\n }\n\n /**\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \n * @param displayName {string} The display name of the option. \n * @returns \n */\n setDisplayName(displayName: string) {\n this.displayName = displayName;\n return this;\n }\n\n /**\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\n * @param description {string} The description of the option. \n * @returns \n */\n setDescription(description: string) {\n this.description = description;\n return this;\n }\n\n /**\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\n * @param input {unknown} The input to validate\n */\n validate(input: unknown): [ boolean, string ] {\n throw new Error('Validation code not implemented. Value: ' + input)\n };\n}\n\nexport class StringOption extends ConfigurationOption {\n public allowedValues: string[] = [];\n public minTextLength: number = 0;\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: string = '';\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\n public type: ConfigurationOptionType = 'string'\n\n /**\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\n */\n setAllowedValues(allowedValues: string[]): this {\n this.allowedValues = allowedValues;\n return this;\n }\n\n /**\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {string} The default value for the string.\n */\n setDefaultValue(defaultValue: string): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n /**\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \n * @param minTextLength {number} The minimum text length for the string. \n */\n setMinTextLength(minTextLength: number): this {\n this.minTextLength = minTextLength;\n return this;\n }\n\n /**\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \n * @param maxTextLength {number} The maximum text length for the string.\n */\n setMaxTextLength(maxTextLength: number): this {\n this.maxTextLength = maxTextLength;\n return this;\n }\n\n /**\n * Set the input type for the string. This will change how the client renders the input. \n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \n */\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\n this.inputType = inputType;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'string') {\n return [ false, 'Input is not a string' ];\n }\n if (this.allowedValues.length === 0 && input.length !== 0)\n return [ true, '' ];\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\n }\n\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\n }\n}\n\nexport class NumberOption extends ConfigurationOption {\n public min: number = 0;\n public max: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: number = 0;\n public type: ConfigurationOptionType = 'number'\n public inputType: 'range' | 'number' = 'number';\n\n /**\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\n * @param min {number} The minimum value for the number.\n */\n setMin(min: number): this {\n this.min = min;\n return this;\n }\n\n /**\n * Set the input type for the number. This will change how the client renders the input. \n * @param type {'range' | 'number'} The input type for the number. \n */\n setInputType(type: 'range' | 'number'): this {\n this.inputType = type;\n return this;\n }\n\n /**\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\n * @param max {number} The maximum value for the number.\n */\n setMax(max: number): this {\n this.max = max;\n return this\n }\n\n /**\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {number} The default value for the number.\n */\n setDefaultValue(defaultValue: number): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (isNaN(Number(input))) {\n return [ false, 'Input is not a number' ];\n }\n if (Number(input) < this.min || Number(input) > this.max) {\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\n }\n return [ true, '' ];\n }\n\n}\n\nexport class BooleanOption extends ConfigurationOption {\n public type: ConfigurationOptionType = 'boolean'\n public defaultValue: boolean = false;\n\n /**\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {boolean} The default value for the boolean.\n */\n setDefaultValue(defaultValue: boolean): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'boolean') {\n return [ false, 'Input is not a boolean' ];\n }\n return [ true, '' ];\n }\n\n}","import { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption } from \"./ConfigurationBuilder\";\n\ninterface DefiniteConfig {\n [key: string]: string | number | boolean;\n}\nexport class Configuration {\n readonly storedConfigTemplate: ConfigurationFile;\n definiteConfig: DefiniteConfig = {};\n constructor(configTemplate: ConfigurationFile) {\n this.storedConfigTemplate = configTemplate;\n }\n\n updateConfig(config: DefiniteConfig, validate: boolean = true): [ boolean, { [key: string]: string } ] {\n this.definiteConfig = config;\n if (validate) {\n const result = this.validateConfig();\n return result;\n }\n return [ true, {} ];\n }\n // provides falsey or truthy value, and an error message if falsey\n private validateConfig(): [ boolean, { [key: string]: string } ] {\n const erroredKeys = new Map<string, string>();\n for (const key in this.storedConfigTemplate) {\n if (this.definiteConfig[key] === null || this.definiteConfig[key] === undefined) {\n console.warn('Option ' + key + ' is not defined. Using default value Value: ' + this.definiteConfig[key]);\n this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue as string | number | boolean;\n }\n if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {\n throw new Error('Option ' + key + ' is not of the correct type');\n }\n\n const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);\n if (!result[0]) {\n erroredKeys.set(key, result[1]);\n }\n }\n\n for (const key in this.definiteConfig) {\n if (!this.storedConfigTemplate[key]) {\n throw new Error('Option ' + key + ' is not defined in the configuration template');\n }\n }\n\n if (erroredKeys.size > 0) {\n return [ false, Object.fromEntries(erroredKeys) ];\n }\n\n return [ true, Object.fromEntries(erroredKeys) ];\n }\n\n getStringValue(optionName: string): string {\n if (!this.definiteConfig[optionName] === null) {\n throw new Error('Option ' + optionName + ' is not defined');\n }\n if (typeof this.definiteConfig[optionName] !== 'string') {\n throw new Error('Option ' + optionName + ' is not a string');\n }\n return this.definiteConfig[optionName];\n }\n\n getNumberValue(optionName: string): number {\n if (!this.definiteConfig[optionName] === null) {\n throw new Error('Option ' + optionName + ' is not defined');\n }\n if (typeof this.definiteConfig[optionName] !== 'number') {\n throw new Error('Option ' + optionName + ' is not a number');\n }\n return this.definiteConfig[optionName];\n }\n\n getBooleanValue(optionName: string): boolean {\n if (this.definiteConfig[optionName] === null) {\n throw new Error('Option ' + optionName + ' is not defined');\n }\n if (typeof this.definiteConfig[optionName] !== 'boolean') {\n throw new Error('Option ' + optionName + ' is not a boolean');\n }\n return this.definiteConfig[optionName];\n }\n}\n\nexport { ConfigurationFile, ConfigurationBuilder, BooleanOption, ConfigurationOption, ConfigurationOptionType, NumberOption, StringOption, isBooleanOption, isNumberOption, isStringOption };"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/ConfigurationBuilder.ts"],"sourcesContent":["import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n\r\n /**\r\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: NumberOption) => NumberOption }\r\n * @returns \r\n */\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: StringOption) => StringOption }\r\n */\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: BooleanOption) => BooleanOption }\r\n */\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n /**\r\n * Set the name of the option. **REQUIRED**\r\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\r\n */\r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \r\n * @param displayName {string} The display name of the option. \r\n * @returns \r\n */\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\r\n * @param description {string} The description of the option. \r\n * @returns \r\n */\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n /**\r\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\r\n * @param input {unknown} The input to validate\r\n */\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n /**\r\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \r\n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\r\n */\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {string} The default value for the string.\r\n */\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \r\n * @param minTextLength {number} The minimum text length for the string. \r\n */\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \r\n * @param maxTextLength {number} The maximum text length for the string.\r\n */\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the string. This will change how the client renders the input. \r\n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \r\n */\r\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\r\n this.inputType = inputType;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n\r\n /**\r\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\r\n * @param min {number} The minimum value for the number.\r\n */\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the number. This will change how the client renders the input. \r\n * @param type {'range' | 'number'} The input type for the number. \r\n */\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\r\n * @param max {number} The maximum value for the number.\r\n */\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n /**\r\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {number} The default value for the number.\r\n */\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n /**\r\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {boolean} The default value for the boolean.\r\n */\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAA4B;AAM5B,IAAM,mBAAmB,WAAAA,QAAE,OAAO;AAAA,EAChC,MAAM,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAa,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,aAAa,WAAAA,QAAE,OAAO,EAAE,IAAI,CAAC;AAC/B,CAAC;AAEM,SAAS,eAAe,QAAqD;AAChF,SAAO,OAAO,SAAS;AACzB;AAEK,SAAS,eAAe,QAAqD;AAClF,SAAO,OAAO,SAAS;AACzB;AAEO,SAAS,gBAAgB,QAAsD;AACpF,SAAO,OAAO,SAAS;AACzB;AAEO,IAAM,uBAAN,MAA2B;AAAA,EACxB,UAAiC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,gBAAgB,QAAsE;AAC3F,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,gBAAgB,QAAgD;AACrE,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,iBAAiB,QAAkD;AACxE,QAAI,YAAY,IAAI,cAAc;AAClC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA,EAEO,MAAM,kBAA8C;AACzD,QAAI,SAA4B,CAAC;AACjC,SAAK,QAAQ,QAAQ,YAAU;AAE7B,UAAI,CAAC,kBAAkB;AACrB,iBAAS,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAC1C,cAAM,aAAa,iBAAiB,UAAU,MAAM;AACpD,YAAI,CAAC,WAAW,SAAS;AACvB,gBAAM,IAAI,oBAAS,WAAW,MAAM,MAAM;AAAA,QAC5C;AAEA,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB,OACK;AACH,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAGO,IAAM,sBAAN,MAA0B;AAAA,EACxB,OAAe;AAAA,EACf,eAAwB;AAAA,EACxB,cAAsB;AAAA,EACtB,cAAsB;AAAA,EACtB,OAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,QAAQ,MAAc;AACpB,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,OAAqC;AAC5C,UAAM,IAAI,MAAM,6CAA6C,KAAK;AAAA,EACpE;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,gBAA0B,CAAC;AAAA,EAC3B,gBAAwB;AAAA,EACxB,gBAAwB,OAAO;AAAA,EAC/B,eAAuB;AAAA,EACvB,YAAqD;AAAA,EACrD,OAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,iBAAiB,eAA+B;AAC9C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,WAA0D;AACrE,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,KAAK,cAAc,WAAW,KAAK,MAAM,WAAW;AACtD,aAAO,CAAE,MAAM,EAAG;AACpB,QAAI,MAAM,SAAS,KAAK,iBAAiB,MAAM,SAAS,KAAK,eAAe;AAC1E,aAAO,CAAE,OAAO,yCAAyC,KAAK,gBAAgB,UAAU,KAAK,gBAAgB,4BAA4B,MAAM,SAAS,cAAe;AAAA,IACzK;AAEA,WAAO,CAAE,KAAK,cAAc,SAAS,KAAK,GAAG,+BAAgC;AAAA,EAC/E;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,MAAc;AAAA,EACd,MAAc,OAAO;AAAA,EACrB,eAAuB;AAAA,EACvB,OAAgC;AAAA,EAChC,YAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,MAAgC;AAC3C,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,MAAM,OAAO,KAAK,CAAC,GAAG;AACxB,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,OAAO,KAAK,IAAI,KAAK,OAAO,OAAO,KAAK,IAAI,KAAK,KAAK;AACxD,aAAO,CAAE,OAAO,sCAAsC,KAAK,MAAM,UAAU,KAAK,GAAI;AAAA,IACtF;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;AAEO,IAAM,gBAAN,cAA4B,oBAAoB;AAAA,EAC9C,OAAgC;AAAA,EAChC,eAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/B,gBAAgB,cAA6B;AAC3C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,WAAW;AAC9B,aAAO,CAAE,OAAO,wBAAyB;AAAA,IAC3C;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;","names":["z"]}
1
+ {"version":3,"sources":["../../src/config/ConfigurationBuilder.ts"],"sourcesContent":["import z, { ZodError } from \"zod\"\n\nexport interface ConfigurationFile {\n [key: string]: ConfigurationOption\n}\n\nconst configValidation = z.object({\n name: z.string().min(1),\n displayName: z.string().min(1),\n description: z.string().min(1),\n})\n\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\n return option.type === 'string';\n }\n\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\n return option.type === 'number';\n}\n\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\n return option.type === 'boolean';\n}\n\nexport class ConfigurationBuilder {\n private options: ConfigurationOption[] = [];\n\n /**\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: NumberOption) => NumberOption }\n * @returns \n */\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\n let newOption = new NumberOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: StringOption) => StringOption }\n */\n public addStringOption(option: (option: StringOption) => StringOption) {\n let newOption = new StringOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: BooleanOption) => BooleanOption }\n */\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\n let newOption = new BooleanOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n public build(includeFunctions: boolean): ConfigurationFile {\n let config: ConfigurationFile = {};\n this.options.forEach(option => {\n // remove all functions from the option object\n if (!includeFunctions) {\n option = JSON.parse(JSON.stringify(option));\n const optionData = configValidation.safeParse(option)\n if (!optionData.success) {\n throw new ZodError(optionData.error.errors)\n }\n\n config[option.name] = option;\n }\n else {\n config[option.name] = option;\n }\n });\n return config;\n }\n}\n\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\nexport class ConfigurationOption {\n public name: string = '';\n public defaultValue: unknown = '';\n public displayName: string = '';\n public description: string = '';\n public type: ConfigurationOptionType = 'unset'\n \n /**\n * Set the name of the option. **REQUIRED**\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\n */\n setName(name: string) {\n this.name = name;\n return this;\n }\n\n /**\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \n * @param displayName {string} The display name of the option. \n * @returns \n */\n setDisplayName(displayName: string) {\n this.displayName = displayName;\n return this;\n }\n\n /**\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\n * @param description {string} The description of the option. \n * @returns \n */\n setDescription(description: string) {\n this.description = description;\n return this;\n }\n\n /**\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\n * @param input {unknown} The input to validate\n */\n validate(input: unknown): [ boolean, string ] {\n throw new Error('Validation code not implemented. Value: ' + input)\n };\n}\n\nexport class StringOption extends ConfigurationOption {\n public allowedValues: string[] = [];\n public minTextLength: number = 0;\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: string = '';\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\n public type: ConfigurationOptionType = 'string'\n\n /**\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\n */\n setAllowedValues(allowedValues: string[]): this {\n this.allowedValues = allowedValues;\n return this;\n }\n\n /**\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {string} The default value for the string.\n */\n setDefaultValue(defaultValue: string): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n /**\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \n * @param minTextLength {number} The minimum text length for the string. \n */\n setMinTextLength(minTextLength: number): this {\n this.minTextLength = minTextLength;\n return this;\n }\n\n /**\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \n * @param maxTextLength {number} The maximum text length for the string.\n */\n setMaxTextLength(maxTextLength: number): this {\n this.maxTextLength = maxTextLength;\n return this;\n }\n\n /**\n * Set the input type for the string. This will change how the client renders the input. \n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \n */\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\n this.inputType = inputType;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'string') {\n return [ false, 'Input is not a string' ];\n }\n if (this.allowedValues.length === 0 && input.length !== 0)\n return [ true, '' ];\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\n }\n\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\n }\n}\n\nexport class NumberOption extends ConfigurationOption {\n public min: number = 0;\n public max: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: number = 0;\n public type: ConfigurationOptionType = 'number'\n public inputType: 'range' | 'number' = 'number';\n\n /**\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\n * @param min {number} The minimum value for the number.\n */\n setMin(min: number): this {\n this.min = min;\n return this;\n }\n\n /**\n * Set the input type for the number. This will change how the client renders the input. \n * @param type {'range' | 'number'} The input type for the number. \n */\n setInputType(type: 'range' | 'number'): this {\n this.inputType = type;\n return this;\n }\n\n /**\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\n * @param max {number} The maximum value for the number.\n */\n setMax(max: number): this {\n this.max = max;\n return this\n }\n\n /**\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {number} The default value for the number.\n */\n setDefaultValue(defaultValue: number): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (isNaN(Number(input))) {\n return [ false, 'Input is not a number' ];\n }\n if (Number(input) < this.min || Number(input) > this.max) {\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\n }\n return [ true, '' ];\n }\n\n}\n\nexport class BooleanOption extends ConfigurationOption {\n public type: ConfigurationOptionType = 'boolean'\n public defaultValue: boolean = false;\n\n /**\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {boolean} The default value for the boolean.\n */\n setDefaultValue(defaultValue: boolean): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'boolean') {\n return [ false, 'Input is not a boolean' ];\n }\n return [ true, '' ];\n }\n\n}"],"mappings":"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","names":["z"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/ConfigurationBuilder.ts"],"sourcesContent":["import z, { ZodError } from \"zod\"\r\n\r\nexport interface ConfigurationFile {\r\n [key: string]: ConfigurationOption\r\n}\r\n\r\nconst configValidation = z.object({\r\n name: z.string().min(1),\r\n displayName: z.string().min(1),\r\n description: z.string().min(1),\r\n})\r\n\r\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\r\n return option.type === 'string';\r\n }\r\n\r\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\r\n return option.type === 'number';\r\n}\r\n\r\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\r\n return option.type === 'boolean';\r\n}\r\n\r\nexport class ConfigurationBuilder {\r\n private options: ConfigurationOption[] = [];\r\n\r\n /**\r\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: NumberOption) => NumberOption }\r\n * @returns \r\n */\r\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\r\n let newOption = new NumberOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: StringOption) => StringOption }\r\n */\r\n public addStringOption(option: (option: StringOption) => StringOption) {\r\n let newOption = new StringOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n /**\r\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\r\n * @param option { (option: BooleanOption) => BooleanOption }\r\n */\r\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\r\n let newOption = new BooleanOption();\r\n newOption = option(newOption);\r\n this.options.push(newOption);\r\n return this;\r\n }\r\n\r\n public build(includeFunctions: boolean): ConfigurationFile {\r\n let config: ConfigurationFile = {};\r\n this.options.forEach(option => {\r\n // remove all functions from the option object\r\n if (!includeFunctions) {\r\n option = JSON.parse(JSON.stringify(option));\r\n const optionData = configValidation.safeParse(option)\r\n if (!optionData.success) {\r\n throw new ZodError(optionData.error.errors)\r\n }\r\n\r\n config[option.name] = option;\r\n }\r\n else {\r\n config[option.name] = option;\r\n }\r\n });\r\n return config;\r\n }\r\n}\r\n\r\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\r\nexport class ConfigurationOption {\r\n public name: string = '';\r\n public defaultValue: unknown = '';\r\n public displayName: string = '';\r\n public description: string = '';\r\n public type: ConfigurationOptionType = 'unset'\r\n \r\n /**\r\n * Set the name of the option. **REQUIRED**\r\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\r\n */\r\n setName(name: string) {\r\n this.name = name;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \r\n * @param displayName {string} The display name of the option. \r\n * @returns \r\n */\r\n setDisplayName(displayName: string) {\r\n this.displayName = displayName;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\r\n * @param description {string} The description of the option. \r\n * @returns \r\n */\r\n setDescription(description: string) {\r\n this.description = description;\r\n return this;\r\n }\r\n\r\n /**\r\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\r\n * @param input {unknown} The input to validate\r\n */\r\n validate(input: unknown): [ boolean, string ] {\r\n throw new Error('Validation code not implemented. Value: ' + input)\r\n };\r\n}\r\n\r\nexport class StringOption extends ConfigurationOption {\r\n public allowedValues: string[] = [];\r\n public minTextLength: number = 0;\r\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: string = '';\r\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\r\n public type: ConfigurationOptionType = 'string'\r\n\r\n /**\r\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \r\n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\r\n */\r\n setAllowedValues(allowedValues: string[]): this {\r\n this.allowedValues = allowedValues;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {string} The default value for the string.\r\n */\r\n setDefaultValue(defaultValue: string): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \r\n * @param minTextLength {number} The minimum text length for the string. \r\n */\r\n setMinTextLength(minTextLength: number): this {\r\n this.minTextLength = minTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \r\n * @param maxTextLength {number} The maximum text length for the string.\r\n */\r\n setMaxTextLength(maxTextLength: number): this {\r\n this.maxTextLength = maxTextLength;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the string. This will change how the client renders the input. \r\n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \r\n */\r\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\r\n this.inputType = inputType;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'string') {\r\n return [ false, 'Input is not a string' ];\r\n }\r\n if (this.allowedValues.length === 0 && input.length !== 0)\r\n return [ true, '' ];\r\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\r\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\r\n }\r\n\r\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\r\n }\r\n}\r\n\r\nexport class NumberOption extends ConfigurationOption {\r\n public min: number = 0;\r\n public max: number = Number.MAX_SAFE_INTEGER;\r\n public defaultValue: number = 0;\r\n public type: ConfigurationOptionType = 'number'\r\n public inputType: 'range' | 'number' = 'number';\r\n\r\n /**\r\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\r\n * @param min {number} The minimum value for the number.\r\n */\r\n setMin(min: number): this {\r\n this.min = min;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the input type for the number. This will change how the client renders the input. \r\n * @param type {'range' | 'number'} The input type for the number. \r\n */\r\n setInputType(type: 'range' | 'number'): this {\r\n this.inputType = type;\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\r\n * @param max {number} The maximum value for the number.\r\n */\r\n setMax(max: number): this {\r\n this.max = max;\r\n return this\r\n }\r\n\r\n /**\r\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {number} The default value for the number.\r\n */\r\n setDefaultValue(defaultValue: number): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (isNaN(Number(input))) {\r\n return [ false, 'Input is not a number' ];\r\n }\r\n if (Number(input) < this.min || Number(input) > this.max) {\r\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}\r\n\r\nexport class BooleanOption extends ConfigurationOption {\r\n public type: ConfigurationOptionType = 'boolean'\r\n public defaultValue: boolean = false;\r\n\r\n /**\r\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\r\n * @param defaultValue {boolean} The default value for the boolean.\r\n */\r\n setDefaultValue(defaultValue: boolean): this {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n override validate(input: unknown): [ boolean, string ] {\r\n if (typeof input !== 'boolean') {\r\n return [ false, 'Input is not a boolean' ];\r\n }\r\n return [ true, '' ];\r\n }\r\n\r\n}"],"mappings":";AAAA,OAAO,KAAK,gBAAgB;AAM5B,IAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAC/B,CAAC;AAEM,SAAS,eAAe,QAAqD;AAChF,SAAO,OAAO,SAAS;AACzB;AAEK,SAAS,eAAe,QAAqD;AAClF,SAAO,OAAO,SAAS;AACzB;AAEO,SAAS,gBAAgB,QAAsD;AACpF,SAAO,OAAO,SAAS;AACzB;AAEO,IAAM,uBAAN,MAA2B;AAAA,EACxB,UAAiC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,gBAAgB,QAAsE;AAC3F,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,gBAAgB,QAAgD;AACrE,QAAI,YAAY,IAAI,aAAa;AACjC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,iBAAiB,QAAkD;AACxE,QAAI,YAAY,IAAI,cAAc;AAClC,gBAAY,OAAO,SAAS;AAC5B,SAAK,QAAQ,KAAK,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA,EAEO,MAAM,kBAA8C;AACzD,QAAI,SAA4B,CAAC;AACjC,SAAK,QAAQ,QAAQ,YAAU;AAE7B,UAAI,CAAC,kBAAkB;AACrB,iBAAS,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAC1C,cAAM,aAAa,iBAAiB,UAAU,MAAM;AACpD,YAAI,CAAC,WAAW,SAAS;AACvB,gBAAM,IAAI,SAAS,WAAW,MAAM,MAAM;AAAA,QAC5C;AAEA,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB,OACK;AACH,eAAO,OAAO,IAAI,IAAI;AAAA,MACxB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAGO,IAAM,sBAAN,MAA0B;AAAA,EACxB,OAAe;AAAA,EACf,eAAwB;AAAA,EACxB,cAAsB;AAAA,EACtB,cAAsB;AAAA,EACtB,OAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,QAAQ,MAAc;AACpB,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,aAAqB;AAClC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,OAAqC;AAC5C,UAAM,IAAI,MAAM,6CAA6C,KAAK;AAAA,EACpE;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,gBAA0B,CAAC;AAAA,EAC3B,gBAAwB;AAAA,EACxB,gBAAwB,OAAO;AAAA,EAC/B,eAAuB;AAAA,EACvB,YAAqD;AAAA,EACrD,OAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,iBAAiB,eAA+B;AAC9C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,eAA6B;AAC5C,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,WAA0D;AACrE,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,KAAK,cAAc,WAAW,KAAK,MAAM,WAAW;AACtD,aAAO,CAAE,MAAM,EAAG;AACpB,QAAI,MAAM,SAAS,KAAK,iBAAiB,MAAM,SAAS,KAAK,eAAe;AAC1E,aAAO,CAAE,OAAO,yCAAyC,KAAK,gBAAgB,UAAU,KAAK,gBAAgB,4BAA4B,MAAM,SAAS,cAAe;AAAA,IACzK;AAEA,WAAO,CAAE,KAAK,cAAc,SAAS,KAAK,GAAG,+BAAgC;AAAA,EAC/E;AACF;AAEO,IAAM,eAAN,cAA2B,oBAAoB;AAAA,EAC7C,MAAc;AAAA,EACd,MAAc,OAAO;AAAA,EACrB,eAAuB;AAAA,EACvB,OAAgC;AAAA,EAChC,YAAgC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,MAAgC;AAC3C,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAmB;AACxB,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,cAA4B;AAC1C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,MAAM,OAAO,KAAK,CAAC,GAAG;AACxB,aAAO,CAAE,OAAO,uBAAwB;AAAA,IAC1C;AACA,QAAI,OAAO,KAAK,IAAI,KAAK,OAAO,OAAO,KAAK,IAAI,KAAK,KAAK;AACxD,aAAO,CAAE,OAAO,sCAAsC,KAAK,MAAM,UAAU,KAAK,GAAI;AAAA,IACtF;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;AAEO,IAAM,gBAAN,cAA4B,oBAAoB;AAAA,EAC9C,OAAgC;AAAA,EAChC,eAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/B,gBAAgB,cAA6B;AAC3C,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAES,SAAS,OAAqC;AACrD,QAAI,OAAO,UAAU,WAAW;AAC9B,aAAO,CAAE,OAAO,wBAAyB;AAAA,IAC3C;AACA,WAAO,CAAE,MAAM,EAAG;AAAA,EACpB;AAEF;","names":[]}
1
+ {"version":3,"sources":["../../src/config/ConfigurationBuilder.ts"],"sourcesContent":["import z, { ZodError } from \"zod\"\n\nexport interface ConfigurationFile {\n [key: string]: ConfigurationOption\n}\n\nconst configValidation = z.object({\n name: z.string().min(1),\n displayName: z.string().min(1),\n description: z.string().min(1),\n})\n\nexport function isStringOption(option: ConfigurationOption): option is StringOption {\n return option.type === 'string';\n }\n\nexport function isNumberOption(option: ConfigurationOption): option is NumberOption {\n return option.type === 'number';\n}\n\nexport function isBooleanOption(option: ConfigurationOption): option is BooleanOption {\n return option.type === 'boolean';\n}\n\nexport class ConfigurationBuilder {\n private options: ConfigurationOption[] = [];\n\n /**\n * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: NumberOption) => NumberOption }\n * @returns \n */\n public addNumberOption(option: (option: NumberOption) => NumberOption): ConfigurationBuilder {\n let newOption = new NumberOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: StringOption) => StringOption }\n */\n public addStringOption(option: (option: StringOption) => StringOption) {\n let newOption = new StringOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n /**\n * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.\n * @param option { (option: BooleanOption) => BooleanOption }\n */\n public addBooleanOption(option: (option: BooleanOption) => BooleanOption) {\n let newOption = new BooleanOption();\n newOption = option(newOption);\n this.options.push(newOption);\n return this;\n }\n\n public build(includeFunctions: boolean): ConfigurationFile {\n let config: ConfigurationFile = {};\n this.options.forEach(option => {\n // remove all functions from the option object\n if (!includeFunctions) {\n option = JSON.parse(JSON.stringify(option));\n const optionData = configValidation.safeParse(option)\n if (!optionData.success) {\n throw new ZodError(optionData.error.errors)\n }\n\n config[option.name] = option;\n }\n else {\n config[option.name] = option;\n }\n });\n return config;\n }\n}\n\nexport type ConfigurationOptionType = 'string' | 'number' | 'boolean' | 'unset'\nexport class ConfigurationOption {\n public name: string = '';\n public defaultValue: unknown = '';\n public displayName: string = '';\n public description: string = '';\n public type: ConfigurationOptionType = 'unset'\n \n /**\n * Set the name of the option. **REQUIRED**\n * @param name {string} The name of the option. This is used to reference the option in the configuration file.\n */\n setName(name: string) {\n this.name = name;\n return this;\n }\n\n /**\n * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED** \n * @param displayName {string} The display name of the option. \n * @returns \n */\n setDisplayName(displayName: string) {\n this.displayName = displayName;\n return this;\n }\n\n /**\n * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**\n * @param description {string} The description of the option. \n * @returns \n */\n setDescription(description: string) {\n this.description = description;\n return this;\n }\n\n /**\n * Validation code for the option. This is called when the user provides input to the option. If the validation fails, the user will be prompted to provide input again.\n * @param input {unknown} The input to validate\n */\n validate(input: unknown): [ boolean, string ] {\n throw new Error('Validation code not implemented. Value: ' + input)\n };\n}\n\nexport class StringOption extends ConfigurationOption {\n public allowedValues: string[] = [];\n public minTextLength: number = 0;\n public maxTextLength: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: string = '';\n public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';\n public type: ConfigurationOptionType = 'string'\n\n /**\n * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown. \n * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.\n */\n setAllowedValues(allowedValues: string[]): this {\n this.allowedValues = allowedValues;\n return this;\n }\n\n /**\n * Set the default value for the string. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {string} The default value for the string.\n */\n setDefaultValue(defaultValue: string): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n /**\n * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail. \n * @param minTextLength {number} The minimum text length for the string. \n */\n setMinTextLength(minTextLength: number): this {\n this.minTextLength = minTextLength;\n return this;\n }\n\n /**\n * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail. \n * @param maxTextLength {number} The maximum text length for the string.\n */\n setMaxTextLength(maxTextLength: number): this {\n this.maxTextLength = maxTextLength;\n return this;\n }\n\n /**\n * Set the input type for the string. This will change how the client renders the input. \n * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string. \n */\n setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {\n this.inputType = inputType;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'string') {\n return [ false, 'Input is not a string' ];\n }\n if (this.allowedValues.length === 0 && input.length !== 0)\n return [ true, '' ];\n if (input.length < this.minTextLength || input.length > this.maxTextLength) {\n return [ false, 'Input is not within the text length ' + this.minTextLength + ' and ' + this.maxTextLength + ' characters (currently ' + input.length + ' characters)' ];\n }\n\n return [ this.allowedValues.includes(input), 'Input is not an allowed value' ];\n }\n}\n\nexport class NumberOption extends ConfigurationOption {\n public min: number = 0;\n public max: number = Number.MAX_SAFE_INTEGER;\n public defaultValue: number = 0;\n public type: ConfigurationOptionType = 'number'\n public inputType: 'range' | 'number' = 'number';\n\n /**\n * Set the minimum value for the number. If the user provides a number that is less than this value, the validation will fail.\n * @param min {number} The minimum value for the number.\n */\n setMin(min: number): this {\n this.min = min;\n return this;\n }\n\n /**\n * Set the input type for the number. This will change how the client renders the input. \n * @param type {'range' | 'number'} The input type for the number. \n */\n setInputType(type: 'range' | 'number'): this {\n this.inputType = type;\n return this;\n }\n\n /**\n * Set the maximum value for the number. If the user provides a number that is greater than this value, the validation will fail.\n * @param max {number} The maximum value for the number.\n */\n setMax(max: number): this {\n this.max = max;\n return this\n }\n\n /**\n * Set the default value for the number. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {number} The default value for the number.\n */\n setDefaultValue(defaultValue: number): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (isNaN(Number(input))) {\n return [ false, 'Input is not a number' ];\n }\n if (Number(input) < this.min || Number(input) > this.max) {\n return [ false, 'Input is not within the range of ' + this.min + ' and ' + this.max ];\n }\n return [ true, '' ];\n }\n\n}\n\nexport class BooleanOption extends ConfigurationOption {\n public type: ConfigurationOptionType = 'boolean'\n public defaultValue: boolean = false;\n\n /**\n * Set the default value for the boolean. This value will be used if the user does not provide a value. **HIGHLY RECOMMENDED**\n * @param defaultValue {boolean} The default value for the boolean.\n */\n setDefaultValue(defaultValue: boolean): this {\n this.defaultValue = defaultValue;\n return this;\n }\n\n override validate(input: unknown): [ boolean, string ] {\n if (typeof input !== 'boolean') {\n return [ false, 'Input is not a boolean' ];\n }\n return [ true, '' ];\n }\n\n}"],"mappings":"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","names":[]}
package/build/main.cjs CHANGED
@@ -33,8 +33,9 @@ __export(main_exports, {
33
33
  Configuration: () => Configuration,
34
34
  ConfigurationBuilder: () => ConfigurationBuilder,
35
35
  EventResponse: () => EventResponse,
36
- default: () => OGIAddon,
37
- version: () => version
36
+ SearchTool: () => SearchTool,
37
+ VERSION: () => VERSION,
38
+ default: () => OGIAddon
38
39
  });
39
40
  module.exports = __toCommonJS(main_exports);
40
41
  var import_ws = __toESM(require("ws"), 1);
@@ -384,13 +385,16 @@ var EventResponse = class {
384
385
  }
385
386
  };
386
387
 
388
+ // src/main.ts
389
+ var import_fuse = __toESM(require("fuse.js"), 1);
390
+
387
391
  // package.json
388
392
  var package_default = {
389
393
  name: "ogi-addon",
390
394
  module: "./build/main.js",
391
395
  type: "module",
392
396
  main: "./build/main.cjs",
393
- version: "1.1.0",
397
+ version: "1.1.5",
394
398
  exports: {
395
399
  ".": {
396
400
  import: {
@@ -420,6 +424,7 @@ var package_default = {
420
424
  url: "https://nat3z.com/"
421
425
  },
422
426
  dependencies: {
427
+ "fuse.js": "^7.1.0",
423
428
  ws: "^8.4.0",
424
429
  zod: "^3.23.8"
425
430
  },
@@ -438,7 +443,7 @@ var package_default = {
438
443
 
439
444
  // src/main.ts
440
445
  var defaultPort = 7654;
441
- var version = package_default.version;
446
+ var VERSION = package_default.version;
442
447
  var OGIAddon = class {
443
448
  eventEmitter = new import_node_events.default.EventEmitter();
444
449
  addonWSListener;
@@ -466,6 +471,73 @@ var OGIAddon = class {
466
471
  notify(notification) {
467
472
  this.addonWSListener.send("notification", [notification]);
468
473
  }
474
+ /**
475
+ * Search for items in the OGI Steam-Synced Library. Query can either be a Steam AppID or a Steam Game Name.
476
+ * @param query {string}
477
+ * @param event {EventResponse<BasicLibraryInfo[]>}
478
+ */
479
+ async steamSearch(query, strict = false) {
480
+ const id = this.addonWSListener.send("steam-search", { query, strict });
481
+ return await this.addonWSListener.waitForResponseFromServer(id);
482
+ }
483
+ /**
484
+ * Notify the OGI Addon Server that you are performing a background task. This can be used to help users understand what is happening in the background.
485
+ * @param id {string}
486
+ * @param progress {number}
487
+ * @param logs {string[]}
488
+ */
489
+ async task() {
490
+ const id = Math.random().toString(36).substring(7);
491
+ const progress = 0;
492
+ const logs = [];
493
+ const task = new CustomTask(this.addonWSListener, id, progress, logs);
494
+ this.addonWSListener.send("task-update", { id, progress, logs, finished: false });
495
+ return task;
496
+ }
497
+ };
498
+ var CustomTask = class {
499
+ id;
500
+ progress;
501
+ logs;
502
+ finished = false;
503
+ ws;
504
+ constructor(ws2, id, progress, logs) {
505
+ this.id = id;
506
+ this.progress = progress;
507
+ this.logs = logs;
508
+ this.ws = ws2;
509
+ }
510
+ log(log) {
511
+ this.logs.push(log);
512
+ this.update();
513
+ }
514
+ finish() {
515
+ this.finished = true;
516
+ this.update();
517
+ }
518
+ setProgress(progress) {
519
+ this.progress = progress;
520
+ this.update();
521
+ }
522
+ update() {
523
+ this.ws.send("task-update", { id: this.id, progress: this.progress, logs: this.logs, finished: this.finished });
524
+ }
525
+ };
526
+ var SearchTool = class {
527
+ fuse;
528
+ constructor(items, keys) {
529
+ this.fuse = new import_fuse.default(items, {
530
+ keys,
531
+ threshold: 0.3,
532
+ includeScore: true
533
+ });
534
+ }
535
+ search(query, limit = 10) {
536
+ return this.fuse.search(query).slice(0, limit).map((result) => result.item);
537
+ }
538
+ addItems(items) {
539
+ items.map((item) => this.fuse.add(item));
540
+ }
469
541
  };
470
542
  var OGIAddonWSListener = class {
471
543
  socket;
@@ -480,22 +552,16 @@ var OGIAddonWSListener = class {
480
552
  this.socket = new import_ws.default("ws://localhost:" + defaultPort);
481
553
  this.socket.on("open", () => {
482
554
  console.log("Connected to OGI Addon Server");
483
- console.log("OGI Addon Server Version:", version);
484
- this.socket.send(JSON.stringify({
485
- event: "authenticate",
486
- args: {
487
- ...this.addon.addonInfo,
488
- secret: process.argv[process.argv.length - 1].split("=")[1],
489
- ogiVersion: version
490
- }
491
- }));
555
+ console.log("OGI Addon Server Version:", VERSION);
556
+ this.send("authenticate", {
557
+ ...this.addon.addonInfo,
558
+ secret: process.argv[process.argv.length - 1].split("=")[1],
559
+ ogiVersion: VERSION
560
+ });
492
561
  this.eventEmitter.emit("connect");
493
562
  let configBuilder = new ConfigurationBuilder();
494
563
  this.eventEmitter.emit("configure", configBuilder);
495
- this.socket.send(JSON.stringify({
496
- event: "configure",
497
- args: configBuilder.build(false)
498
- }));
564
+ this.send("configure", configBuilder.build(false));
499
565
  this.addon.config = new Configuration(configBuilder.build(true));
500
566
  });
501
567
  this.socket.on("error", (error) => {
@@ -655,10 +721,13 @@ var OGIAddonWSListener = class {
655
721
  });
656
722
  }
657
723
  send(event, args) {
724
+ const id = Math.random().toString(36).substring(7);
658
725
  this.socket.send(JSON.stringify({
659
726
  event,
660
- args
727
+ args,
728
+ id
661
729
  }));
730
+ return id;
662
731
  }
663
732
  close() {
664
733
  this.socket.close();
@@ -669,6 +738,7 @@ var OGIAddonWSListener = class {
669
738
  Configuration,
670
739
  ConfigurationBuilder,
671
740
  EventResponse,
672
- version
741
+ SearchTool,
742
+ VERSION
673
743
  });
674
744
  //# sourceMappingURL=main.cjs.map