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