@open-discord-bots/framework 0.3.14 → 0.3.16

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.
Files changed (44) hide show
  1. package/README.md +5 -1
  2. package/dist/api/main.js +1 -1
  3. package/dist/api/modules/responder.js +50 -26
  4. package/package.json +1 -1
  5. package/.gitattributes +0 -2
  6. package/src/api/index.ts +0 -31
  7. package/src/api/main.ts +0 -203
  8. package/src/api/modules/action.ts +0 -89
  9. package/src/api/modules/base.ts +0 -845
  10. package/src/api/modules/builder.ts +0 -1755
  11. package/src/api/modules/checker.ts +0 -1826
  12. package/src/api/modules/client.ts +0 -2345
  13. package/src/api/modules/code.ts +0 -84
  14. package/src/api/modules/component.ts +0 -2000
  15. package/src/api/modules/config.ts +0 -264
  16. package/src/api/modules/console.ts +0 -697
  17. package/src/api/modules/cooldown.ts +0 -369
  18. package/src/api/modules/database.ts +0 -321
  19. package/src/api/modules/event.ts +0 -123
  20. package/src/api/modules/flag.ts +0 -99
  21. package/src/api/modules/fuse.ts +0 -365
  22. package/src/api/modules/helpmenu.ts +0 -273
  23. package/src/api/modules/language.ts +0 -230
  24. package/src/api/modules/permission.ts +0 -363
  25. package/src/api/modules/plugin.ts +0 -294
  26. package/src/api/modules/post.ts +0 -137
  27. package/src/api/modules/progressbar.ts +0 -370
  28. package/src/api/modules/responder.ts +0 -1625
  29. package/src/api/modules/session.ts +0 -181
  30. package/src/api/modules/startscreen.ts +0 -345
  31. package/src/api/modules/state.ts +0 -298
  32. package/src/api/modules/statistic.ts +0 -380
  33. package/src/api/modules/verifybar.ts +0 -68
  34. package/src/api/modules/worker.ts +0 -119
  35. package/src/cli/editConfig.ts +0 -930
  36. package/src/cli/index.ts +0 -152
  37. package/src/index.ts +0 -8
  38. package/src/startup/compilation.ts +0 -204
  39. package/src/startup/dump.ts +0 -46
  40. package/src/startup/errorHandling.ts +0 -42
  41. package/src/startup/pluginLauncher.ts +0 -265
  42. package/src/utilities/index.ts +0 -229
  43. package/tools/cleanup.js +0 -2
  44. package/tsconfig.json +0 -15
@@ -1,930 +0,0 @@
1
- import * as api from "../api/index.js"
2
- import * as utilities from "../utilities/index.js"
3
- import {Terminal, terminal} from "terminal-kit"
4
- import ansis from "ansis"
5
- import {ODCliHeaderOpts, renderHeader} from "./index.js"
6
-
7
- export class ODCliEditConfigInstance {
8
- private readonly opts: ODCliHeaderOpts
9
- private readonly opendiscord: api.ODMain
10
-
11
- constructor(opts:ODCliHeaderOpts,opendiscord:api.ODMain){
12
- this.opts = opts
13
- this.opendiscord = opendiscord
14
- }
15
-
16
- public async renderEditConfig(backFn:(() => api.ODPromiseVoid)){
17
- renderHeader(this.opts,[])
18
- terminal(ansis.bold.green("Please select which config you would like to edit.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
19
-
20
- const checkerList = this.opendiscord.checkers.getAll()
21
- const checkerNameList = checkerList.map((checker) => (checker.options.cliDisplayName ? checker.options.cliDisplayName+" ("+checker.config.file+")" : checker.config.file))
22
- const checkerNameLength = utilities.getLongestLength(checkerNameList)
23
- const finalCheckerNameList = checkerNameList.map((name,index) => name.padEnd(checkerNameLength+5," ")+ansis.gray(checkerList[index].options.cliDisplayDescription ? "=> "+checkerList[index].options.cliDisplayDescription : ""))
24
-
25
- const answer = await terminal.singleColumnMenu(finalCheckerNameList,{
26
- leftPadding:"> ",
27
- style:terminal.cyan,
28
- selectedStyle:terminal.bgDefaultColor.bold,
29
- submittedStyle:terminal.bgBlue,
30
- extraLines:2,
31
- cancelable:true
32
- }).promise
33
-
34
- if (answer.canceled) return await backFn()
35
- const checker = checkerList[answer.selectedIndex]
36
- const configData = checker.config.data as api.ODValidJsonType
37
- await this.chooseConfigStructure(checker,async () => {await this.renderEditConfig(backFn)},checker.structure,configData,{},NaN,["("+checker.config.path+")"])
38
- }
39
-
40
- private async chooseConfigStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerStructure,data:api.ODValidJsonType,parent:Record<string,any>|any[],parentIndex:string|number,path:(string|number)[]){
41
- if (structure instanceof api.ODCheckerObjectStructure && typeof data == "object" && !Array.isArray(data) && data) await this.renderConfigObjectStructureSelector(checker,backFn,structure,data,parent,parentIndex,path)
42
- else if (structure instanceof api.ODCheckerEnabledObjectStructure && typeof data == "object" && !Array.isArray(data) && data) await this.renderConfigEnabledObjectStructureSelector(checker,backFn,structure,data,parent,parentIndex,path)
43
- else if (structure instanceof api.ODCheckerObjectSwitchStructure && typeof data == "object" && !Array.isArray(data) && data) await this.renderConfigObjectSwitchStructureSelector(checker,backFn,structure,data,parent,parentIndex,path)
44
- else if (structure instanceof api.ODCheckerArrayStructure && Array.isArray(data)) await this.renderConfigArrayStructureSelector(checker,backFn,structure,data,parent,parentIndex,path)
45
- else if (structure instanceof api.ODCheckerBooleanStructure && typeof data == "boolean") await this.renderConfigBooleanStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)
46
- else if (structure instanceof api.ODCheckerNumberStructure && typeof data == "number") await this.renderConfigNumberStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)
47
- else if (structure instanceof api.ODCheckerStringStructure && typeof data == "string") await this.renderConfigStringStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)
48
- else if (structure instanceof api.ODCheckerNullStructure && data === null) await this.renderConfigNullStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)
49
- else if (structure instanceof api.ODCheckerTypeSwitchStructure) await this.renderConfigTypeSwitchStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)
50
- else terminal.red.bold("❌ Unable to detect type of variable! Please try to edit this property in the JSON file itself!")
51
- }
52
-
53
- private async renderConfigObjectStructureSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerObjectStructure,data:Record<string,any>,parent:Record<string,any>,parentIndex:string|number,path:(string|number)[]){
54
- if (typeof data != "object" || Array.isArray(data)) throw new api.ODSystemError("OD CLI => Property is not of the type 'object'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
55
- renderHeader(this.opts,path)
56
- terminal(ansis.bold.green("Please select which variable you would like to edit.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
57
- if (!structure.options.children) return await backFn()
58
-
59
- if (structure.options.cliDisplayName){
60
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName)+"\n")
61
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
62
- }
63
-
64
- const list = structure.options.children.filter((child) => !child.cliHideInEditMode)
65
- const nameList = list.map((child) => (child.checker.options.cliDisplayName ? child.checker.options.cliDisplayName : child.key))
66
- const nameLength = utilities.getLongestLength(nameList)
67
- const finalnameList = nameList.map((name,index) => name.padEnd(nameLength+5," ")+ansis.gray((!list[index].checker.options.cliHideDescriptionInParent && list[index].checker.options.cliDisplayDescription) ? "=> "+list[index].checker.options.cliDisplayDescription : ""))
68
-
69
- const answer = await terminal.singleColumnMenu(finalnameList,{
70
- leftPadding:"> ",
71
- style:terminal.cyan,
72
- selectedStyle:terminal.bgDefaultColor.bold.defaultColor,
73
- submittedStyle:terminal.bgBlue,
74
- extraLines:2,
75
- cancelable:true
76
- }).promise
77
-
78
- if (answer.canceled) return await backFn()
79
- const subStructure = list[answer.selectedIndex]
80
- const subData = data[subStructure.key]
81
- await this.chooseConfigStructure(checker,async () => {await this.renderConfigObjectStructureSelector(checker,backFn,structure,data,parent,parentIndex,path)},subStructure.checker,subData,data,subStructure.key,[...path,subStructure.key])
82
- }
83
-
84
- private async renderConfigEnabledObjectStructureSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerEnabledObjectStructure,data:Record<string,any>,parent:Record<string,any>,parentIndex:string|number,path:(string|number)[]){
85
- if (typeof data != "object" || Array.isArray(data)) throw new api.ODSystemError("OD CLI => Property is not of the type 'object'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
86
- const enabledProperty = structure.options.property
87
- const subStructure = structure.options.checker
88
- if (!enabledProperty || !subStructure || !subStructure.options.children) return await backFn()
89
-
90
- if (!subStructure.options.children.find((child) => child.key === structure.options.property)){
91
- if (typeof structure.options.enabledValue == "string") subStructure.options.children.unshift({key:enabledProperty,optional:false,priority:1,checker:new api.ODCheckerStringStructure("opendiscord:CLI-checker-enabled-object-structure",{})})
92
- else if (typeof structure.options.enabledValue == "number") subStructure.options.children.unshift({key:enabledProperty,optional:false,priority:1,checker:new api.ODCheckerNumberStructure("opendiscord:CLI-checker-enabled-object-structure",{})})
93
- else if (typeof structure.options.enabledValue == "boolean") subStructure.options.children.unshift({key:enabledProperty,optional:false,priority:1,checker:new api.ODCheckerBooleanStructure("opendiscord:CLI-checker-enabled-object-structure",{})})
94
- }
95
-
96
- await this.chooseConfigStructure(checker,backFn,subStructure,data,parent,parentIndex,path)
97
- }
98
-
99
- private async renderConfigObjectSwitchStructureSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerObjectSwitchStructure,data:Record<string,any>,parent:Record<string,any>,parentIndex:string|number,path:(string|number)[]){
100
- if (typeof data != "object" || Array.isArray(data)) throw new api.ODSystemError("OD CLI => Property is not of the type 'object'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
101
- if (!structure.options.objects) return await backFn()
102
-
103
- let didMatch: boolean = false
104
- for (const objectTemplate of structure.options.objects){
105
- if (objectTemplate.properties.every((prop) => data[prop.key] === prop.value)){
106
- //object template matches data
107
- const subStructure = objectTemplate.checker
108
- didMatch = true
109
- await this.chooseConfigStructure(checker,backFn,subStructure,data,parent,parentIndex,path)
110
- }
111
- }
112
- if (!didMatch) throw new api.ODSystemError("OD CLI => Unable to detect type of object in the object switch. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
113
- }
114
-
115
- private async renderConfigArrayStructureSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerArrayStructure,data:any[],parent:object,parentIndex:string|number,path:(string|number)[]){
116
- if (!Array.isArray(data)) throw new api.ODSystemError("OD CLI => Property is not of the type 'array'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
117
- renderHeader(this.opts,path)
118
- terminal(ansis.bold.green("Please select what you would like to do.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
119
- if (!structure.options.propertyChecker) return await backFn()
120
-
121
- if (structure.options.cliDisplayName || typeof parentIndex == "string" || !isNaN(parentIndex)){
122
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName ?? parentIndex.toString())+"\n")
123
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
124
- }
125
-
126
- const propertyName = structure.options.cliDisplayPropertyName ?? "index"
127
- const answer = await terminal.singleColumnMenu(data.length < 1 ? ["Add "+propertyName] : [
128
- "Add "+propertyName,
129
- "Edit "+propertyName,
130
- "Move "+propertyName,
131
- "Remove "+propertyName,
132
- "Duplicate "+propertyName
133
- ],{
134
- leftPadding:"> ",
135
- style:terminal.cyan,
136
- selectedStyle:terminal.bgDefaultColor.bold,
137
- submittedStyle:terminal.bgBlue,
138
- extraLines:2,
139
- cancelable:true
140
- }).promise
141
-
142
- const backFnFunc = async () => {await this.renderConfigArrayStructureSelector(checker,backFn,structure,data,parent,parentIndex,path)}
143
-
144
- if (answer.canceled) return await backFn()
145
- if (answer.selectedIndex == 0) await this.chooseAdditionConfigStructure(checker,backFnFunc,async (newData) => {
146
- data[data.length] = newData
147
- await checker.config.save()
148
- await backFnFunc()
149
- },structure.options.propertyChecker,data,data.length,path,[])
150
- else if (answer.selectedIndex == 1) await this.renderConfigArrayStructureEditSelector(checker,backFnFunc,structure,structure.options.propertyChecker,data,parent,parentIndex,path)
151
- else if (answer.selectedIndex == 2) await this.renderConfigArrayStructureMoveSelector(checker,backFnFunc,structure,structure.options.propertyChecker,data,parent,parentIndex,path)
152
- else if (answer.selectedIndex == 3) await this.renderConfigArrayStructureRemoveSelector(checker,backFnFunc,structure,structure.options.propertyChecker,data,parent,parentIndex,path)
153
- else if (answer.selectedIndex == 4) await this.renderConfigArrayStructureDuplicateSelector(checker,backFnFunc,structure,structure.options.propertyChecker,data,parent,parentIndex,path)
154
- }
155
-
156
- private async renderConfigArrayStructureEditSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),arrayStructure:api.ODCheckerArrayStructure,structure:api.ODCheckerStructure,data:any[],parent:object,parentIndex:string|number,path:(string|number)[]){
157
- const propertyName = arrayStructure.options.cliDisplayPropertyName ?? "index"
158
- renderHeader(this.opts,path)
159
- terminal(ansis.bold.green("Please select the "+propertyName+" you would like to edit.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
160
-
161
- const longestDataListName = Math.max(...data.map((d,i) => this.getArrayPreviewStructureNameLength(structure,d,data,i)))
162
- const dataList = data.map((d,i) => (i+1)+". "+this.getArrayPreviewFromStructure(structure,d,data,i,longestDataListName))
163
- const dataAnswer = await terminal.singleColumnMenu(dataList,{
164
- leftPadding:"> ",
165
- style:terminal.cyan,
166
- selectedStyle:terminal.bgDefaultColor.bold,
167
- submittedStyle:terminal.bgBlue,
168
- extraLines:2,
169
- cancelable:true
170
- }).promise
171
-
172
- if (dataAnswer.canceled) return await backFn()
173
- const subData = data[dataAnswer.selectedIndex]
174
- await this.chooseConfigStructure(checker,async () => {await this.renderConfigArrayStructureEditSelector(checker,backFn,arrayStructure,structure,data,parent,parentIndex,path)},structure,subData,data,dataAnswer.selectedIndex,[...path,dataAnswer.selectedIndex])
175
- }
176
-
177
- private async renderConfigArrayStructureMoveSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),arrayStructure:api.ODCheckerArrayStructure,structure:api.ODCheckerStructure,data:any[],parent:Record<string,any>,parentIndex:string|number,path:(string|number)[]): Promise<void> {
178
- const propertyName = arrayStructure.options.cliDisplayPropertyName ?? "index"
179
- renderHeader(this.opts,path)
180
- terminal(ansis.bold.green("Please select the "+propertyName+" you would like to move.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
181
-
182
- const longestDataListName = Math.max(...data.map((d,i) => this.getArrayPreviewStructureNameLength(structure,d,data,i)))
183
- const dataList = data.map((d,i) => (i+1)+". "+this.getArrayPreviewFromStructure(structure,d,data,i,longestDataListName))
184
- const dataAnswer = await terminal.singleColumnMenu(dataList,{
185
- leftPadding:"> ",
186
- style:terminal.cyan,
187
- selectedStyle:terminal.bgDefaultColor.bold,
188
- submittedStyle:terminal.bgBlue,
189
- extraLines:2,
190
- cancelable:true
191
- }).promise
192
-
193
- if (dataAnswer.canceled) return await backFn()
194
-
195
- renderHeader(this.opts,[...path,dataAnswer.selectedIndex])
196
- terminal(ansis.bold.green("Please select the position you would like to move to.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
197
-
198
- const moveAnswer = await terminal.singleColumnMenu(data.map((d,i) => "Position "+(i+1)),{
199
- leftPadding:"> ",
200
- style:terminal.cyan,
201
- selectedStyle:terminal.bgDefaultColor.bold,
202
- submittedStyle:terminal.bgBlue,
203
- extraLines:2,
204
- cancelable:true
205
- }).promise
206
-
207
- if (moveAnswer.canceled) return await this.renderConfigArrayStructureMoveSelector(checker,backFn,arrayStructure,structure,data,parent,parentIndex,path)
208
-
209
- const subData = data[dataAnswer.selectedIndex]
210
- const slicedData = [...data.slice(0,dataAnswer.selectedIndex),...data.slice(dataAnswer.selectedIndex+1)]
211
- const insertedData = [...slicedData.slice(0,moveAnswer.selectedIndex),subData,...slicedData.slice(moveAnswer.selectedIndex)]
212
- insertedData.forEach((d,i) => data[i] = d)
213
-
214
- await checker.config.save()
215
- terminal.bold.blue("\n\n✅ Property moved succesfully!")
216
- await utilities.timer(400)
217
- await backFn()
218
- }
219
-
220
- private async renderConfigArrayStructureRemoveSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),arrayStructure:api.ODCheckerArrayStructure,structure:api.ODCheckerStructure,data:any[],parent:object,parentIndex:string|number,path:(string|number)[]){
221
- const propertyName = arrayStructure.options.cliDisplayPropertyName ?? "index"
222
- renderHeader(this.opts,path)
223
- terminal(ansis.bold.green("Please select the "+propertyName+" you would like to delete.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
224
-
225
- const longestDataListName = Math.max(...data.map((d,i) => this.getArrayPreviewStructureNameLength(structure,d,data,i)))
226
- const dataList = data.map((d,i) => (i+1)+". "+this.getArrayPreviewFromStructure(structure,d,data,i,longestDataListName))
227
- const dataAnswer = await terminal.singleColumnMenu(dataList,{
228
- leftPadding:"> ",
229
- style:terminal.cyan,
230
- selectedStyle:terminal.bgDefaultColor.bold,
231
- submittedStyle:terminal.bgBlue,
232
- extraLines:2,
233
- cancelable:true
234
- }).promise
235
-
236
- if (dataAnswer.canceled) return await backFn()
237
- data.splice(dataAnswer.selectedIndex,1)
238
-
239
- await checker.config.save()
240
- terminal.bold.blue("\n\n✅ Property deleted succesfully!")
241
- await utilities.timer(400)
242
- await backFn()
243
- }
244
-
245
- private async renderConfigArrayStructureDuplicateSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),arrayStructure:api.ODCheckerArrayStructure,structure:api.ODCheckerStructure,data:any[],parent:object,parentIndex:string|number,path:(string|number)[]){
246
- const propertyName = arrayStructure.options.cliDisplayPropertyName ?? "index"
247
- renderHeader(this.opts,path)
248
- terminal(ansis.bold.green("Please select the "+propertyName+" you would like to duplicate.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
249
-
250
- const longestDataListName = Math.max(...data.map((d,i) => this.getArrayPreviewStructureNameLength(structure,d,data,i)))
251
- const dataList = data.map((d,i) => (i+1)+". "+this.getArrayPreviewFromStructure(structure,d,data,i,longestDataListName))
252
- const dataAnswer = await terminal.singleColumnMenu(dataList,{
253
- leftPadding:"> ",
254
- style:terminal.cyan,
255
- selectedStyle:terminal.bgDefaultColor.bold,
256
- submittedStyle:terminal.bgBlue,
257
- extraLines:2,
258
- cancelable:true
259
- }).promise
260
-
261
- if (dataAnswer.canceled) return await backFn()
262
- data.push(JSON.parse(JSON.stringify(data[dataAnswer.selectedIndex])))
263
-
264
- await checker.config.save()
265
- terminal.bold.blue("\n\n✅ Property duplicated succesfully!")
266
- await utilities.timer(400)
267
- await backFn()
268
- }
269
-
270
- private async renderConfigBooleanStructureEditor(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerBooleanStructure,data:boolean,parent:Record<string,any>,parentIndex:string|number,path:(string|number)[]){
271
- if (typeof data != "boolean") throw new api.ODSystemError("OD CLI => Property is not of the type 'boolean'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
272
- renderHeader(this.opts,path)
273
- terminal(ansis.bold.green("You are now editing "+(typeof parentIndex == "string" ? "the boolean property "+ansis.blue("\""+parentIndex+"\"") : "boolean property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
274
-
275
- terminal.gray("\nCurrent value: "+ansis.bold[data ? "green" : "red"](data.toString())+"\n")
276
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
277
-
278
- const answer = await terminal.singleColumnMenu(["false (Disabled)","true (Enabled)"],{
279
- leftPadding:"> ",
280
- style:terminal.cyan,
281
- selectedStyle:terminal.bgDefaultColor.bold,
282
- submittedStyle:terminal.bgBlue,
283
- extraLines:2,
284
- cancelable:true
285
- }).promise
286
-
287
- if (answer.canceled) return await backFn()
288
-
289
- //run config checker
290
- const newValue = (answer.selectedIndex == 0) ? false : true
291
- const newPath = [...path]
292
- newPath.shift()
293
- checker.messages = [] //manually clear previous messages
294
- const isDataValid = structure.check(checker,newValue,newPath)
295
-
296
- if (isDataValid){
297
- parent[parentIndex] = newValue
298
-
299
- await checker.config.save()
300
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
301
- await utilities.timer(400)
302
- await backFn()
303
- }else{
304
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
305
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
306
- terminal.gray("\n"+messages)
307
- await utilities.timer(1000+(2000*checker.messages.length))
308
- await this.renderConfigBooleanStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)
309
- }
310
- }
311
-
312
- private async renderConfigNumberStructureEditor(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerNumberStructure,data:number,parent:Record<string,any>,parentIndex:string|number,path:(string|number)[],prefillValue?:string){
313
- if (typeof data != "number") throw new api.ODSystemError("OD CLI => Property is not of the type 'number'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
314
- renderHeader(this.opts,path)
315
- terminal(ansis.bold.green("You are now editing "+(typeof parentIndex == "string" ? "the number property "+ansis.blue("\""+parentIndex+"\"") : "number property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(insert a new value and press enter, go back using escape)\n"))
316
-
317
- terminal.gray("\nCurrent value: "+ansis.bold.blue(data.toString())+"\n")
318
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
319
-
320
- const answer = await terminal.inputField({
321
- default:prefillValue,
322
- style:terminal.cyan,
323
- cancelable:true
324
- }).promise
325
-
326
- if (typeof answer != "string") return await backFn()
327
-
328
- //run config checker
329
- const newValue = Number(answer.replaceAll(",","."))
330
- const newPath = [...path]
331
- newPath.shift()
332
- checker.messages = [] //manually clear previous messages
333
- const isDataValid = structure.check(checker,newValue,newPath)
334
-
335
- if (isDataValid){
336
- parent[parentIndex] = newValue
337
-
338
- await checker.config.save()
339
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
340
- await utilities.timer(400)
341
- await backFn()
342
- }else{
343
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
344
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
345
- terminal.red("\n"+messages)
346
- await utilities.timer(1000+(2000*checker.messages.length))
347
- await this.renderConfigNumberStructureEditor(checker,backFn,structure,data,parent,parentIndex,path,answer)
348
- }
349
- }
350
-
351
- private async renderConfigStringStructureEditor(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerStringStructure,data:string,parent:Record<string,any>,parentIndex:string|number,path:(string|number)[],prefillValue?:string){
352
- if (typeof data != "string") throw new api.ODSystemError("OD CLI => Property is not of the type 'string'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
353
- renderHeader(this.opts,path)
354
- terminal(ansis.bold.green("You are now editing "+(typeof parentIndex == "string" ? "the string property "+ansis.blue("\""+parentIndex+"\"") : "string property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(insert a new value and press enter, go back using escape)\n"))
355
-
356
- terminal.gray("\nCurrent value:"+(data.includes("\n") ? "\n" : " \"")+ansis.bold.blue(data)+ansis.gray(!data.includes("\n") ? "\"\n" : "\n"))
357
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
358
-
359
- const customExtraOptions = (structure instanceof api.ODCheckerCustomStructure_DiscordId) ? structure.extraOptions : undefined
360
- const customAutocompleteFunc = structure.options.cliAutocompleteFunc ? await structure.options.cliAutocompleteFunc() : null
361
- const autocompleteList = ((customAutocompleteFunc ?? structure.options.cliAutocompleteList) ?? customExtraOptions) ?? structure.options.choices
362
- const autoCompleteMenuOpts: Terminal.SingleLineMenuOptions = {
363
- style:terminal.white,
364
- selectedStyle:terminal.bgBlue.white
365
- }
366
-
367
- const input = terminal.inputField({
368
- default:prefillValue,
369
- style:terminal.cyan,
370
- hintStyle:terminal.gray,
371
- cancelable:false,
372
- autoComplete:autocompleteList,
373
- autoCompleteHint:(!!autocompleteList),
374
- autoCompleteMenu:(autocompleteList) ? autoCompleteMenuOpts as Terminal.Autocompletion : false
375
- })
376
-
377
- terminal.on("key",async (name:string,matches:string[],data:object) => {
378
- if (name == "ESCAPE"){
379
- terminal.removeListener("key","cli-render-string-structure-edit")
380
- input.abort()
381
- await backFn()
382
- }
383
- },({id:"cli-render-string-structure-edit"} as any))
384
-
385
- const answer = await input.promise
386
- terminal.removeListener("key","cli-render-string-structure-edit")
387
- if (typeof answer != "string") return
388
-
389
- //run config checker
390
- const newValue = answer.replaceAll("\\n","\n")
391
- const newPath = [...path]
392
- newPath.shift()
393
- checker.messages = [] //manually clear previous messages
394
- const isDataValid = structure.check(checker,newValue,newPath)
395
-
396
- if (isDataValid){
397
- parent[parentIndex] = newValue
398
-
399
- await checker.config.save()
400
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
401
- await utilities.timer(400)
402
- await backFn()
403
- }else{
404
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
405
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
406
- terminal.red("\n"+messages)
407
- await utilities.timer(1000+(2000*checker.messages.length))
408
- await this.renderConfigStringStructureEditor(checker,backFn,structure,data,parent,parentIndex,path,answer)
409
- }
410
- }
411
-
412
- private async renderConfigNullStructureEditor(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerNullStructure,data:null,parent:Record<string,any>,parentIndex:string|number,path:(string|number)[]){
413
- if (data !== null) throw new api.ODSystemError("OD CLI => Property is not of the type 'null'. Please check your config for possible errors. (index: "+parentIndex+", path: "+path.join(".")+")")
414
- renderHeader(this.opts,path)
415
- terminal(ansis.bold.green("You are now editing "+(typeof parentIndex == "string" ? "the null property "+ansis.blue("\""+parentIndex+"\"") : "null property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
416
-
417
- terminal.gray("\nCurrent value: "+ansis.bold.blue("null")+"\n")
418
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
419
-
420
- const answer = await terminal.singleColumnMenu(["null"],{
421
- leftPadding:"> ",
422
- style:terminal.cyan,
423
- selectedStyle:terminal.bgDefaultColor.bold,
424
- submittedStyle:terminal.bgBlue,
425
- extraLines:2,
426
- cancelable:true
427
- }).promise
428
-
429
- if (answer.canceled) return await backFn()
430
-
431
- //run config checker
432
- const newValue = null
433
- const newPath = [...path]
434
- newPath.shift()
435
- checker.messages = [] //manually clear previous messages
436
- const isDataValid = structure.check(checker,newValue,newPath)
437
-
438
- if (isDataValid){
439
- parent[parentIndex] = newValue
440
-
441
- await checker.config.save()
442
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
443
- await utilities.timer(400)
444
- await backFn()
445
- }else{
446
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
447
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
448
- terminal.red("\n"+messages)
449
- await utilities.timer(1000+(2000*checker.messages.length))
450
- await this.renderConfigNullStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)
451
- }
452
- }
453
-
454
- private async renderConfigTypeSwitchStructureEditor(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),structure:api.ODCheckerTypeSwitchStructure,data:any,parent:object,parentIndex:string|number,path:(string|number)[]){
455
- renderHeader(this.opts,path)
456
- terminal(ansis.bold.green("You are now editing "+(typeof parentIndex == "string" ? "the property "+ansis.blue("\""+parentIndex+"\"") : "property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
457
-
458
- terminal.gray("\nCurrent value: "+ansis.bold.blue(data.toString())+"\n")
459
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
460
-
461
- const actionsList: string[] = []
462
- if (structure.options.boolean) actionsList.push("Edit as boolean")
463
- if (structure.options.string) actionsList.push("Edit as string")
464
- if (structure.options.number) actionsList.push("Edit as number")
465
- if (structure.options.object) actionsList.push("Edit as object")
466
- if (structure.options.array) actionsList.push("Edit as array/list")
467
- if (structure.options.null) actionsList.push("Edit as null")
468
-
469
- const answer = await terminal.singleColumnMenu(actionsList,{
470
- leftPadding:"> ",
471
- style:terminal.cyan,
472
- selectedStyle:terminal.bgDefaultColor.bold,
473
- submittedStyle:terminal.bgBlue,
474
- extraLines:2,
475
- cancelable:true
476
- }).promise
477
-
478
- if (answer.canceled) return await backFn()
479
-
480
- //run selected structure editor (untested)
481
- if (answer.selectedText.startsWith("Edit as boolean") && structure.options.boolean) await this.renderConfigBooleanStructureEditor(checker,async () => {await this.renderConfigTypeSwitchStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)},structure.options.boolean,false,parent,parentIndex,path)
482
- else if (answer.selectedText.startsWith("Edit as string") && structure.options.string) await this.renderConfigStringStructureEditor(checker,async () => {await this.renderConfigTypeSwitchStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)},structure.options.string,data.toString(),parent,parentIndex,path)
483
- else if (answer.selectedText.startsWith("Edit as number") && structure.options.number) await this.renderConfigNumberStructureEditor(checker,async () => {await this.renderConfigTypeSwitchStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)},structure.options.number,0,parent,parentIndex,path)
484
- else if (answer.selectedText.startsWith("Edit as object") && structure.options.object) await this.renderConfigObjectStructureSelector(checker,async () => {await this.renderConfigTypeSwitchStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)},structure.options.object,data,parent,parentIndex,path)
485
- else if (answer.selectedText.startsWith("Edit as array/list") && structure.options.array) await this.renderConfigArrayStructureSelector(checker,async () => {await this.renderConfigTypeSwitchStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)},structure.options.array,data,parent,parentIndex,path)
486
- else if (answer.selectedText.startsWith("Edit as null") && structure.options.null) await this.renderConfigNullStructureEditor(checker,async () => {await this.renderConfigTypeSwitchStructureEditor(checker,backFn,structure,data,parent,parentIndex,path)},structure.options.null,null,parent,parentIndex,path)
487
- }
488
-
489
- private getArrayPreviewStructureNameLength(structure:api.ODCheckerStructure,data:any,parent:Record<string,any>,parentIndex:string|number): number {
490
- if (structure instanceof api.ODCheckerBooleanStructure && typeof data == "boolean") return data.toString().length
491
- else if (structure instanceof api.ODCheckerNumberStructure && typeof data == "number") return data.toString().length
492
- else if (structure instanceof api.ODCheckerStringStructure && typeof data == "string") return data.length
493
- else if (structure instanceof api.ODCheckerNullStructure && data === null) return "Null".length
494
- else if (structure instanceof api.ODCheckerArrayStructure && Array.isArray(data)) return "Array".length
495
- else if (structure instanceof api.ODCheckerObjectStructure && typeof data == "object" && !Array.isArray(data) && data){
496
- if (!structure.options.cliDisplayKeyInParentArray) return "Object".length
497
- else return data[structure.options.cliDisplayKeyInParentArray]?.toString().length ?? 0
498
-
499
- }else if (structure instanceof api.ODCheckerEnabledObjectStructure && typeof data == "object" && !Array.isArray(data) && data){
500
- const subStructure = structure.options.checker
501
- if (!subStructure) return "<unknown-property>".length
502
- return this.getArrayPreviewStructureNameLength(subStructure,data,parent,parentIndex)
503
-
504
- }else if (structure instanceof api.ODCheckerObjectSwitchStructure && typeof data == "object" && !Array.isArray(data) && data){
505
- for (const objectTemplate of (structure.options.objects ?? [])){
506
- if (objectTemplate.properties.every((prop) => data[prop.key] === prop.value)){
507
- //object template matches data
508
- const subStructure = objectTemplate.checker
509
- return this.getArrayPreviewStructureNameLength(subStructure,data,parent,parentIndex)
510
- }
511
- }
512
- return "<unknown-property>".length
513
-
514
- }else if (structure instanceof api.ODCheckerTypeSwitchStructure){
515
- if (typeof data == "boolean" && structure.options.boolean) return this.getArrayPreviewStructureNameLength(structure.options.boolean,data,parent,parentIndex)
516
- else if (typeof data == "number" && structure.options.number) return this.getArrayPreviewStructureNameLength(structure.options.number,data,parent,parentIndex)
517
- else if (typeof data == "string" && structure.options.string) return this.getArrayPreviewStructureNameLength(structure.options.string,data,parent,parentIndex)
518
- else if (typeof data == "object" && !Array.isArray(data) && data && structure.options.object) return this.getArrayPreviewStructureNameLength(structure.options.object,data,parent,parentIndex)
519
- else if (Array.isArray(data) && structure.options.array) return this.getArrayPreviewStructureNameLength(structure.options.array,data,parent,parentIndex)
520
- else if (data === null && structure.options.null) return this.getArrayPreviewStructureNameLength(structure.options.null,data,parent,parentIndex)
521
- else return "<unknown-property>".length
522
- }else return "<unknown-property>".length
523
- }
524
-
525
- private getArrayPreviewFromStructure(structure:api.ODCheckerStructure,data:any,parent:Record<string,any>,parentIndex:string|number,nameLength:number): string {
526
- if (structure instanceof api.ODCheckerBooleanStructure && typeof data == "boolean") return data.toString()
527
- else if (structure instanceof api.ODCheckerNumberStructure && typeof data == "number") return data.toString()
528
- else if (structure instanceof api.ODCheckerStringStructure && typeof data == "string") return data
529
- else if (structure instanceof api.ODCheckerNullStructure && data === null) return "Null"
530
- else if (structure instanceof api.ODCheckerArrayStructure && Array.isArray(data)) return "Array"
531
- else if (structure instanceof api.ODCheckerObjectStructure && typeof data == "object" && !Array.isArray(data) && data){
532
- const additionalKeys = (structure.options.cliDisplayAdditionalKeysInParentArray ?? []).map((key) => key+": "+data[key]?.toString()).join(", ")
533
- if (!structure.options.cliDisplayKeyInParentArray) return "Object"
534
- else return data[structure.options.cliDisplayKeyInParentArray]?.toString().padEnd(nameLength+5," ")+ansis.gray(additionalKeys.length > 0 ? "("+additionalKeys+")" : "")
535
-
536
- }else if (structure instanceof api.ODCheckerEnabledObjectStructure && typeof data == "object" && !Array.isArray(data) && data){
537
- const subStructure = structure.options.checker
538
- if (!subStructure) return "<unknown-property>"
539
- return this.getArrayPreviewFromStructure(subStructure,data,parent,parentIndex,nameLength)
540
-
541
- }else if (structure instanceof api.ODCheckerObjectSwitchStructure && typeof data == "object" && !Array.isArray(data) && data){
542
- for (const objectTemplate of (structure.options.objects ?? [])){
543
- if (objectTemplate.properties.every((prop) => data[prop.key] === prop.value)){
544
- //object template matches data
545
- const subStructure = objectTemplate.checker
546
- return this.getArrayPreviewFromStructure(subStructure,data,parent,parentIndex,nameLength)
547
- }
548
- }
549
- return "<unknown-property>"
550
-
551
- }else if (structure instanceof api.ODCheckerTypeSwitchStructure){
552
- if (typeof data == "boolean" && structure.options.boolean) return this.getArrayPreviewFromStructure(structure.options.boolean,data,parent,parentIndex,nameLength)
553
- else if (typeof data == "number" && structure.options.number) return this.getArrayPreviewFromStructure(structure.options.number,data,parent,parentIndex,nameLength)
554
- else if (typeof data == "string" && structure.options.string) return this.getArrayPreviewFromStructure(structure.options.string,data,parent,parentIndex,nameLength)
555
- else if (typeof data == "object" && !Array.isArray(data) && data && structure.options.object) return this.getArrayPreviewFromStructure(structure.options.object,data,parent,parentIndex,nameLength)
556
- else if (Array.isArray(data) && structure.options.array) return this.getArrayPreviewFromStructure(structure.options.array,data,parent,parentIndex,nameLength)
557
- else if (data === null && structure.options.null) return this.getArrayPreviewFromStructure(structure.options.null,data,parent,parentIndex,nameLength)
558
- else return "<unknown-property>"
559
- }else return "<unknown-property>"
560
- }
561
-
562
- private async chooseAdditionConfigStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[]){
563
- if (structure instanceof api.ODCheckerObjectStructure) await this.renderAdditionConfigObjectStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
564
- else if (structure instanceof api.ODCheckerBooleanStructure) await this.renderAdditionConfigBooleanStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
565
- else if (structure instanceof api.ODCheckerNumberStructure) await this.renderAdditionConfigNumberStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
566
- else if (structure instanceof api.ODCheckerStringStructure) await this.renderAdditionConfigStringStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
567
- else if (structure instanceof api.ODCheckerNullStructure) await this.renderAdditionConfigNullStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
568
- else if (structure instanceof api.ODCheckerEnabledObjectStructure) await this.renderAdditionConfigEnabledObjectStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
569
- else if (structure instanceof api.ODCheckerObjectSwitchStructure) await this.renderAdditionConfigObjectSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
570
- else if (structure instanceof api.ODCheckerArrayStructure) await this.renderAdditionConfigArrayStructureSelector(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
571
- else if (structure instanceof api.ODCheckerTypeSwitchStructure) await this.renderAdditionConfigTypeSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
572
- else await backFn()
573
- }
574
-
575
- private async renderAdditionConfigObjectStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerObjectStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[],localData:Record<string,any>={}){
576
- const children = structure.options.children ?? []
577
- const skipKeys = (structure.options.cliInitSkipKeys ?? [])
578
- //add skipped properties
579
- for (const key of skipKeys){
580
- const childStructure = children.find((c) => c.key == key)
581
- if (childStructure){
582
- const defaultValue = childStructure.checker.options.cliInitDefaultValue
583
- if (childStructure.checker instanceof api.ODCheckerBooleanStructure) localData[key] = (typeof defaultValue == "boolean" ? defaultValue : false)
584
- else if (childStructure.checker instanceof api.ODCheckerNumberStructure) localData[key] = (typeof defaultValue == "number" ? defaultValue : 0)
585
- else if (childStructure.checker instanceof api.ODCheckerStringStructure) localData[key] = (typeof defaultValue == "string" ? defaultValue : "")
586
- else if (childStructure.checker instanceof api.ODCheckerNullStructure) localData[key] = (defaultValue === null ? defaultValue : null)
587
- else if (childStructure.checker instanceof api.ODCheckerArrayStructure) localData[key] = (Array.isArray(defaultValue) ? JSON.parse(JSON.stringify(defaultValue)) : [])
588
- else if (childStructure.checker instanceof api.ODCheckerObjectStructure) localData[key] = ((typeof defaultValue == "object" && !Array.isArray(defaultValue) && defaultValue) ? JSON.parse(JSON.stringify(defaultValue)) : {})
589
- else if (childStructure.checker instanceof api.ODCheckerObjectSwitchStructure) localData[key] = ((typeof defaultValue == "object" && !Array.isArray(defaultValue) && defaultValue) ? JSON.parse(JSON.stringify(defaultValue)) : {})
590
- else if (childStructure.checker instanceof api.ODCheckerEnabledObjectStructure) localData[key] = ((typeof defaultValue == "object" && !Array.isArray(defaultValue) && defaultValue) ? JSON.parse(JSON.stringify(defaultValue)) : {})
591
- else if (childStructure.checker instanceof api.ODCheckerTypeSwitchStructure && typeof defaultValue != "undefined") localData[key] = JSON.parse(JSON.stringify(defaultValue))
592
- else throw new api.ODSystemError("OD CLI => Object skip key has an invalid checker structure! key: "+key)
593
- }
594
- }
595
-
596
- //add properties that need to be configured
597
- const configChildren = children.filter((c) => !skipKeys.includes(c.key)).map((c) => {return {key:c.key,checker:c.checker}})
598
- await this.configureAdditionObjectProperties(checker,configChildren,0,localData,[...path,parentIndex],(typeof parentIndex == "number") ? [...localPath] : [...localPath,parentIndex],async () => {
599
- //go back to previous screen
600
- await backFn()
601
- },async () => {
602
- //finish setup
603
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
604
- await utilities.timer(400)
605
- await nextFn(localData)
606
- })
607
- }
608
-
609
- private async configureAdditionObjectProperties(checker:api.ODChecker,children:{key:string,checker:api.ODCheckerStructure}[],currentIndex:number,localData:Record<string,any>,path:(string|number)[],localPath:(string|number)[],backFn:(() => api.ODPromiseVoid),nextFn:(() => api.ODPromiseVoid)){
610
- if (children.length < 1) return await nextFn()
611
-
612
- const child = children[currentIndex]
613
- await this.chooseAdditionConfigStructure(checker,async () => {
614
- if (children[currentIndex-1]) await this.configureAdditionObjectProperties(checker,children,currentIndex-1,localData,path,localPath,backFn,nextFn)
615
- else await backFn()
616
- },async (data) => {
617
- localData[child.key] = data
618
- if (children[currentIndex+1]) await this.configureAdditionObjectProperties(checker,children,currentIndex+1,localData,path,localPath,backFn,nextFn)
619
- else await nextFn()
620
- },child.checker,localData,child.key,path,localPath)
621
- }
622
-
623
- private async renderAdditionConfigEnabledObjectStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerEnabledObjectStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[]){
624
- const enabledProperty = structure.options.property
625
- const enabledValue = structure.options.enabledValue
626
- const subStructure = structure.options.checker
627
- if (!enabledProperty || !subStructure || !subStructure.options.children) return await backFn()
628
-
629
- let propertyStructure: api.ODCheckerBooleanStructure|api.ODCheckerNumberStructure|api.ODCheckerStringStructure
630
- if (typeof enabledValue == "string") propertyStructure = new api.ODCheckerStringStructure("opendiscord:CLI-checker-enabled-object-structure",{})
631
- else if (typeof enabledValue == "number") propertyStructure = new api.ODCheckerNumberStructure("opendiscord:CLI-checker-enabled-object-structure",{})
632
- else if (typeof enabledValue == "boolean") propertyStructure = new api.ODCheckerBooleanStructure("opendiscord:CLI-checker-enabled-object-structure",{})
633
- else throw new Error("OD CLI => enabled object structure has an invalid type of enabledProperty. It must be a primitive boolean/number/string.")
634
-
635
- const localData: Record<string,any> = {}
636
- await this.chooseAdditionConfigStructure(checker,backFn,async (data) => {
637
- if (data === enabledValue) await this.renderAdditionConfigObjectStructure(checker,async () => {await this.renderAdditionConfigEnabledObjectStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,subStructure,parent,parentIndex,path,localPath,localData)
638
- else{
639
- localData[enabledProperty] = data
640
- //copy old object checker to new object checker => all options get de-referenced (this is needed for the new object skip keys are temporary)
641
- const newStructure = new api.ODCheckerObjectStructure(subStructure.id,structuredClone(subStructure.options))
642
-
643
- //continues to next function
644
- await this.renderAdditionConfigObjectStructure(checker,async () => {await this.renderAdditionConfigEnabledObjectStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,newStructure,parent,parentIndex,path,localPath,localData)
645
- await nextFn(localData)
646
- }
647
- },propertyStructure,localData,enabledProperty,[...path,parentIndex],[...localPath,parentIndex])
648
- }
649
-
650
- private async renderAdditionConfigObjectSwitchStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerObjectSwitchStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[]){
651
- renderHeader(this.opts,[...path,parentIndex])
652
- terminal(ansis.bold.green("What type of object would you like to add?\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
653
-
654
- const answer = await terminal.singleColumnMenu(structure.options.objects.map((obj) => obj.name),{
655
- leftPadding:"> ",
656
- style:terminal.cyan,
657
- selectedStyle:terminal.bgDefaultColor.bold,
658
- submittedStyle:terminal.bgBlue,
659
- extraLines:2,
660
- cancelable:true
661
- }).promise
662
-
663
- if (answer.canceled) return await backFn()
664
- const objectTemplate = structure.options.objects[answer.selectedIndex]
665
-
666
- //copy old object checker to new object checker => all options get de-referenced (this is needed for the new object switch properties which are temporary)
667
- const oldStructure = objectTemplate.checker
668
- const newStructure = new api.ODCheckerObjectStructure(oldStructure.id,structuredClone(oldStructure.options))
669
-
670
- //add the keys of the object switch properties to the 'cliInitSkipKeys' because they need to be skipped.
671
- objectTemplate.properties.map((p) => p.key).forEach((p) => {
672
- if (!newStructure.options.cliInitSkipKeys) newStructure.options.cliInitSkipKeys = [p]
673
- else if (!newStructure.options.cliInitSkipKeys.includes(p)) newStructure.options.cliInitSkipKeys.push(p)
674
- })
675
-
676
- //add structure checkers for all properties
677
- for (const prop of objectTemplate.properties){
678
- if (!newStructure.options.children.find((child) => child.key === prop.key)){
679
- if (typeof prop.value == "string") newStructure.options.children.unshift({key:prop.key,optional:false,priority:1,checker:new api.ODCheckerStringStructure("opendiscord:CLI-checker-object-switch-structure",{cliInitDefaultValue:prop.value})})
680
- else if (typeof prop.value == "number") newStructure.options.children.unshift({key:prop.key,optional:false,priority:1,checker:new api.ODCheckerNumberStructure("opendiscord:CLI-checker-object-switch-structure",{cliInitDefaultValue:prop.value})})
681
- else if (typeof prop.value == "boolean") newStructure.options.children.unshift({key:prop.key,optional:false,priority:1,checker:new api.ODCheckerBooleanStructure("opendiscord:CLI-checker-object-switch-structure",{cliInitDefaultValue:prop.value})})
682
- }
683
- }
684
-
685
- await this.chooseAdditionConfigStructure(checker,backFn,nextFn,newStructure,parent,parentIndex,path,localPath)
686
- }
687
-
688
- private async renderAdditionConfigBooleanStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerBooleanStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[]){
689
- renderHeader(this.opts,[...path,parentIndex])
690
- terminal(ansis.bold.green("You are now creating "+(typeof parentIndex == "string" ? "the boolean property "+ansis.blue("\""+parentIndex+"\"") : "boolean property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
691
-
692
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName ?? [...localPath,parentIndex].join("."))+"\n")
693
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
694
-
695
- const answer = await terminal.singleColumnMenu(["false (Disabled)","true (Enabled)"],{
696
- leftPadding:"> ",
697
- style:terminal.cyan,
698
- selectedStyle:terminal.bgDefaultColor.bold,
699
- submittedStyle:terminal.bgBlue,
700
- extraLines:2,
701
- cancelable:true
702
- }).promise
703
-
704
- if (answer.canceled) return await backFn()
705
-
706
- //run config checker
707
- const newValue = (answer.selectedIndex == 0) ? false : true
708
- const newPath = [...path]
709
- newPath.shift()
710
- checker.messages = [] //manually clear previous messages
711
- const isDataValid = structure.check(checker,newValue,newPath)
712
-
713
- if (isDataValid){
714
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
715
- await utilities.timer(400)
716
- await nextFn(newValue)
717
- }else{
718
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
719
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
720
- terminal.gray("\n"+messages)
721
- await utilities.timer(1000+(2000*checker.messages.length))
722
- await this.renderAdditionConfigBooleanStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
723
- }
724
- }
725
-
726
- private async renderAdditionConfigNumberStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerNumberStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[],prefillValue?:string){
727
- renderHeader(this.opts,[...path,parentIndex])
728
- terminal(ansis.bold.green("You are now creating "+(typeof parentIndex == "string" ? "the number property "+ansis.blue("\""+parentIndex+"\"") : "number property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(insert a new value and press enter, go back using escape)\n"))
729
-
730
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName ?? [...localPath,parentIndex].join("."))+"\n")
731
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
732
-
733
- const answer = await terminal.inputField({
734
- default:prefillValue,
735
- style:terminal.cyan,
736
- cancelable:true
737
- }).promise
738
-
739
- if (typeof answer != "string") return await backFn()
740
-
741
- //run config checker
742
- const newValue = Number(answer.replaceAll(",","."))
743
- const newPath = [...path]
744
- newPath.shift()
745
- checker.messages = [] //manually clear previous messages
746
- const isDataValid = structure.check(checker,newValue,newPath)
747
-
748
- if (isDataValid){
749
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
750
- await utilities.timer(400)
751
- await nextFn(newValue)
752
- }else{
753
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
754
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
755
- terminal.red("\n"+messages)
756
- await utilities.timer(1000+(2000*checker.messages.length))
757
- await this.renderAdditionConfigNumberStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath,answer)
758
- }
759
- }
760
-
761
- private async renderAdditionConfigStringStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerStringStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[],prefillValue?:string){
762
- renderHeader(this.opts,[...path,parentIndex])
763
- terminal(ansis.bold.green("You are now creating "+(typeof parentIndex == "string" ? "the string property "+ansis.blue("\""+parentIndex+"\"") : "string property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(insert a new value and press enter, go back using escape)\n"))
764
-
765
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName ?? [...localPath,parentIndex].join("."))+"\n")
766
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
767
-
768
- const customExtraOptions = (structure instanceof api.ODCheckerCustomStructure_DiscordId) ? structure.extraOptions : undefined
769
- const customAutocompleteFunc = structure.options.cliAutocompleteFunc ? await structure.options.cliAutocompleteFunc() : null
770
- const autocompleteList = ((customAutocompleteFunc ?? structure.options.cliAutocompleteList) ?? customExtraOptions) ?? structure.options.choices
771
- const autoCompleteMenuOpts: Terminal.SingleLineMenuOptions = {
772
- style:terminal.white,
773
- selectedStyle:terminal.bgBlue.white
774
- }
775
-
776
- const input = terminal.inputField({
777
- default:prefillValue,
778
- style:terminal.cyan,
779
- hintStyle:terminal.gray,
780
- cancelable:false,
781
- autoComplete:autocompleteList,
782
- autoCompleteHint:(!!autocompleteList),
783
- autoCompleteMenu:(autocompleteList) ? autoCompleteMenuOpts as Terminal.Autocompletion : false
784
- })
785
-
786
- terminal.on("key",async (name:string,matches:string[],data:object) => {
787
- if (name == "ESCAPE"){
788
- terminal.removeListener("key","cli-render-string-structure-add")
789
- input.abort()
790
- await backFn()
791
- }
792
- },({id:"cli-render-string-structure-add"} as any))
793
-
794
- const answer = await input.promise
795
- terminal.removeListener("key","cli-render-string-structure-add")
796
- if (typeof answer != "string") return
797
-
798
- //run config checker
799
- const newValue = answer.replaceAll("\\n","\n")
800
- const newPath = [...path]
801
- newPath.shift()
802
- checker.messages = [] //manually clear previous messages
803
- const isDataValid = structure.check(checker,newValue,newPath)
804
-
805
- if (isDataValid){
806
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
807
- await utilities.timer(400)
808
- await nextFn(newValue)
809
- }else{
810
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
811
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
812
- terminal.red("\n"+messages)
813
- await utilities.timer(1000+(2000*checker.messages.length))
814
- await this.renderAdditionConfigStringStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath,answer)
815
- }
816
- }
817
-
818
- private async renderAdditionConfigNullStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerNullStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[]){
819
- renderHeader(this.opts,[...path,parentIndex])
820
- terminal(ansis.bold.green("You are now creating "+(typeof parentIndex == "string" ? "the null property "+ansis.blue("\""+parentIndex+"\"") : "null property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
821
-
822
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName ?? [...localPath,parentIndex].join("."))+"\n")
823
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
824
-
825
- const answer = await terminal.singleColumnMenu(["null"],{
826
- leftPadding:"> ",
827
- style:terminal.cyan,
828
- selectedStyle:terminal.bgDefaultColor.bold,
829
- submittedStyle:terminal.bgBlue,
830
- extraLines:2,
831
- cancelable:true
832
- }).promise
833
-
834
- if (answer.canceled) return await backFn()
835
-
836
- //run config checker
837
- const newValue = null
838
- const newPath = [...path]
839
- newPath.shift()
840
- checker.messages = [] //manually clear previous messages
841
- const isDataValid = structure.check(checker,newValue,newPath)
842
-
843
- if (isDataValid){
844
- terminal.bold.blue("\n\n✅ Variable saved succesfully!")
845
- await utilities.timer(400)
846
- await nextFn(newValue)
847
- }else{
848
- const messages = checker.messages.map((msg) => "=> ["+msg.type.toUpperCase()+"] "+msg.message).join("\n")
849
- terminal.bold.blue("\n\n❌ Variable is invalid! Please try again!")
850
- terminal.red("\n"+messages)
851
- await utilities.timer(1000+(2000*checker.messages.length))
852
- await this.renderAdditionConfigNullStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)
853
- }
854
- }
855
-
856
- private async renderAdditionConfigArrayStructureSelector(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerArrayStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[],localData:any[]=[]){
857
- renderHeader(this.opts,[...path,parentIndex])
858
- terminal(ansis.bold.green("Please select what you would like to do with the new array.\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
859
- if (!structure.options.propertyChecker) return await backFn()
860
-
861
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName ?? [...localPath,parentIndex].join("."))+"\n")
862
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
863
-
864
- const propertyName = structure.options.cliDisplayPropertyName ?? "index"
865
- const answer = await terminal.singleColumnMenu(localData.length < 1 ? [ansis.magenta("-> Continue to next variable"),"Add "+propertyName] : [
866
- ansis.magenta("-> Continue to next variable"),
867
- "Add "+propertyName,
868
- "Edit "+propertyName,
869
- "Move "+propertyName,
870
- "Remove "+propertyName,
871
- "Duplicate "+propertyName,
872
-
873
- ],{
874
- leftPadding:"> ",
875
- style:terminal.cyan,
876
- selectedStyle:terminal.bgDefaultColor.bold,
877
- submittedStyle:terminal.bgBlue,
878
- extraLines:2,
879
- cancelable:true
880
- }).promise
881
-
882
- const backFnFunc = async () => {await this.renderAdditionConfigArrayStructureSelector(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath,localData)}
883
-
884
- if (answer.canceled) return await backFn()
885
- if (answer.selectedIndex == 0) await nextFn(localData)
886
- else if (answer.selectedIndex == 1) await this.chooseAdditionConfigStructure(checker,backFnFunc,async (newData) => {
887
- localData[localData.length] = newData
888
- await backFnFunc()
889
- },structure.options.propertyChecker,localData,localData.length,path,[])
890
- else if (answer.selectedIndex == 2) await this.renderConfigArrayStructureEditSelector(checker,backFnFunc,structure,structure.options.propertyChecker,localData,parent,parentIndex,path)
891
- else if (answer.selectedIndex == 3) await this.renderConfigArrayStructureMoveSelector(checker,backFnFunc,structure,structure.options.propertyChecker,localData,parent,parentIndex,path)
892
- else if (answer.selectedIndex == 4) await this.renderConfigArrayStructureRemoveSelector(checker,backFnFunc,structure,structure.options.propertyChecker,localData,parent,parentIndex,path)
893
- else if (answer.selectedIndex == 5) await this.renderConfigArrayStructureDuplicateSelector(checker,backFnFunc,structure,structure.options.propertyChecker,localData,parent,parentIndex,path)
894
- }
895
-
896
- private async renderAdditionConfigTypeSwitchStructure(checker:api.ODChecker,backFn:(() => api.ODPromiseVoid),nextFn:((data:any) => api.ODPromiseVoid),structure:api.ODCheckerTypeSwitchStructure,parent:object|any[],parentIndex:string|number,path:(string|number)[],localPath:(string|number)[]){
897
- renderHeader(this.opts,path)
898
- terminal(ansis.bold.green("You are now creating "+(typeof parentIndex == "string" ? "the property "+ansis.blue("\""+parentIndex+"\"") : "property "+ansis.blue("#"+(parentIndex+1)))+".\n")+ansis.italic.gray("(use arrow keys to navigate, go back using escape)\n"))
899
-
900
- terminal.gray("\nProperty: "+ansis.bold.blue(structure.options.cliDisplayName ?? [...localPath,parentIndex].join("."))+"\n")
901
- terminal.gray("Description: "+ansis.bold(structure.options.cliDisplayDescription ?? "/")+"\n")
902
-
903
- const actionsList: string[] = []
904
- if (structure.options.boolean) actionsList.push("Create as boolean")
905
- if (structure.options.string) actionsList.push("Create as string")
906
- if (structure.options.number) actionsList.push("Create as number")
907
- if (structure.options.object) actionsList.push("Create as object")
908
- if (structure.options.array) actionsList.push("Create as array/list")
909
- if (structure.options.null) actionsList.push("Create as null")
910
-
911
- const answer = await terminal.singleColumnMenu(actionsList,{
912
- leftPadding:"> ",
913
- style:terminal.cyan,
914
- selectedStyle:terminal.bgDefaultColor.bold,
915
- submittedStyle:terminal.bgBlue,
916
- extraLines:2,
917
- cancelable:true
918
- }).promise
919
-
920
- if (answer.canceled) return await backFn()
921
-
922
- //run selected structure editor (untested)
923
- if (answer.selectedText.startsWith("Create as boolean") && structure.options.boolean) await this.renderAdditionConfigBooleanStructure(checker,async () => {await this.renderAdditionConfigTypeSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,structure.options.boolean,parent,parentIndex,path,localPath)
924
- else if (answer.selectedText.startsWith("Create as string") && structure.options.string) await this.renderAdditionConfigStringStructure(checker,async () => {await this.renderAdditionConfigTypeSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,structure.options.string,parent,parentIndex,path,localPath)
925
- else if (answer.selectedText.startsWith("Create as number") && structure.options.number) await this.renderAdditionConfigNumberStructure(checker,async () => {await this.renderAdditionConfigTypeSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,structure.options.number,parent,parentIndex,path,localPath)
926
- else if (answer.selectedText.startsWith("Create as object") && structure.options.object) await this.renderAdditionConfigObjectStructure(checker,async () => {await this.renderAdditionConfigTypeSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,structure.options.object,parent,parentIndex,path,localPath)
927
- else if (answer.selectedText.startsWith("Create as array/list") && structure.options.array) await this.renderAdditionConfigArrayStructureSelector(checker,async () => {await this.renderAdditionConfigTypeSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,structure.options.array,parent,parentIndex,path,localPath)
928
- else if (answer.selectedText.startsWith("Create as null") && structure.options.null) await this.renderAdditionConfigNullStructure(checker,async () => {await this.renderAdditionConfigTypeSwitchStructure(checker,backFn,nextFn,structure,parent,parentIndex,path,localPath)},nextFn,structure.options.null,parent,parentIndex,path,localPath)
929
- }
930
- }