@learnpack/learnpack 5.0.30 → 5.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/lib/commands/audit.js +15 -15
- package/lib/commands/init.js +39 -15
- package/lib/commands/translate.js +2 -10
- package/lib/managers/server/routes.js +38 -0
- package/lib/managers/telemetry.d.ts +2 -0
- package/lib/managers/telemetry.js +7 -0
- package/lib/utils/creatorUtilities.d.ts +2 -0
- package/lib/utils/creatorUtilities.js +48 -7
- package/lib/utils/rigoActions.d.ts +1 -0
- package/lib/utils/rigoActions.js +13 -2
- package/oclif.manifest.json +1 -1
- package/package.json +2 -1
- package/src/commands/audit.ts +449 -449
- package/src/commands/breakToken.ts +36 -36
- package/src/commands/init.ts +48 -17
- package/src/commands/publish.ts +312 -312
- package/src/commands/start.ts +361 -361
- package/src/commands/translate.ts +1 -20
- package/src/managers/config/index.ts +1 -0
- package/src/managers/server/routes.ts +61 -1
- package/src/managers/socket.ts +274 -274
- package/src/managers/telemetry.ts +10 -0
- package/src/models/action.ts +12 -12
- package/src/utils/console.ts +24 -24
- package/src/utils/creatorUtilities.ts +66 -6
- package/src/utils/rigoActions.ts +13 -1
@@ -5,6 +5,7 @@ import * as prompts from "prompts"
|
|
5
5
|
import { translateExercise } from "../utils/rigoActions"
|
6
6
|
import SessionManager from "../managers/session"
|
7
7
|
import Console from "../utils/console"
|
8
|
+
import { saveTranslatedReadme } from "../utils/creatorUtilities"
|
8
9
|
|
9
10
|
// This function list the names of the exercise directories inside the ./exercises folder, if the exercises folder doesn't exist, it will look for the ./.learn/exercises folder
|
10
11
|
const listExercises = async () => {
|
@@ -24,11 +25,6 @@ const listExercises = async () => {
|
|
24
25
|
})
|
25
26
|
}
|
26
27
|
|
27
|
-
const cleanReadme = (readme: string) => {
|
28
|
-
// Replace <text> and </text> with nothing
|
29
|
-
return readme.replace(/<text>/g, "").replace(/<\/text>/g, "")
|
30
|
-
}
|
31
|
-
|
32
28
|
const getReadmeForExercise = async (exercise: string) => {
|
33
29
|
const readmePath = path.join(
|
34
30
|
process.cwd(),
|
@@ -39,20 +35,6 @@ const getReadmeForExercise = async (exercise: string) => {
|
|
39
35
|
return fs.readFileSync(readmePath, "utf8")
|
40
36
|
}
|
41
37
|
|
42
|
-
const saveTranslatedReadme = async (
|
43
|
-
exercise: string,
|
44
|
-
languageCode: string,
|
45
|
-
readme: string
|
46
|
-
) => {
|
47
|
-
const readmePath = path.join(
|
48
|
-
process.cwd(),
|
49
|
-
"exercises",
|
50
|
-
exercise,
|
51
|
-
`README.${languageCode}.md`
|
52
|
-
)
|
53
|
-
fs.writeFileSync(readmePath, cleanReadme(readme))
|
54
|
-
}
|
55
|
-
|
56
38
|
export default class BuildCommand extends SessionCommand {
|
57
39
|
static description =
|
58
40
|
"List all the lessons, the user is able of select many of them to translate to the given languages"
|
@@ -118,7 +100,6 @@ export default class BuildCommand extends SessionCommand {
|
|
118
100
|
text_to_translate: readme,
|
119
101
|
output_language: language,
|
120
102
|
})
|
121
|
-
console.log(response, "RESPONSE")
|
122
103
|
|
123
104
|
await saveTranslatedReadme(
|
124
105
|
exercise,
|
@@ -12,7 +12,9 @@ import { IConfigManager } from "../../models/config-manager"
|
|
12
12
|
import { IExercise } from "../../models/exercise-obj"
|
13
13
|
import SessionManager from "../../managers/session"
|
14
14
|
import TelemetryManager from "../telemetry"
|
15
|
-
import {
|
15
|
+
import { saveTranslatedReadme } from "../../utils/creatorUtilities"
|
16
|
+
import { translateExercise } from "../../utils/rigoActions"
|
17
|
+
// import { eventManager } from "../../utils/osOperations"
|
16
18
|
|
17
19
|
const withHandler =
|
18
20
|
(func: (req: express.Request, res: express.Response) => void) =>
|
@@ -394,6 +396,64 @@ throw new Error("File not found: " + filePath)
|
|
394
396
|
})
|
395
397
|
)
|
396
398
|
|
399
|
+
app.post(
|
400
|
+
"/actions/translate",
|
401
|
+
jsonBodyParser,
|
402
|
+
withHandler(async (req: express.Request, res: express.Response) => {
|
403
|
+
const { exerciseSlugs, languages } = req.body
|
404
|
+
|
405
|
+
const session = await SessionManager.getPayload()
|
406
|
+
const rigoToken = session?.rigobot?.key
|
407
|
+
|
408
|
+
if (!rigoToken) {
|
409
|
+
return res.status(400).json({ error: "RigoToken not found" })
|
410
|
+
}
|
411
|
+
|
412
|
+
const languagesToTranslate: string[] = languages.split(",")
|
413
|
+
|
414
|
+
try {
|
415
|
+
await Promise.all(
|
416
|
+
exerciseSlugs.map(async (slug: string) => {
|
417
|
+
const exercise = configManager.getExercise(slug)
|
418
|
+
if (!exercise) {
|
419
|
+
throw new Error(`Exercise ${slug} not found`)
|
420
|
+
}
|
421
|
+
|
422
|
+
if (exercise.getReadme) {
|
423
|
+
const readme = exercise.getReadme(null)
|
424
|
+
|
425
|
+
await Promise.all(
|
426
|
+
languagesToTranslate.map(async (language: string) => {
|
427
|
+
const response = await translateExercise(rigoToken, {
|
428
|
+
text_to_translate: readme.body,
|
429
|
+
output_language: language,
|
430
|
+
})
|
431
|
+
|
432
|
+
await saveTranslatedReadme(
|
433
|
+
slug,
|
434
|
+
response.parsed.output_language_code,
|
435
|
+
response.parsed.translation
|
436
|
+
)
|
437
|
+
|
438
|
+
Console.success(
|
439
|
+
`Translated ${slug} to ${language} successfully`
|
440
|
+
)
|
441
|
+
})
|
442
|
+
)
|
443
|
+
}
|
444
|
+
})
|
445
|
+
)
|
446
|
+
|
447
|
+
configManager.buildIndex()
|
448
|
+
|
449
|
+
return res.status(200).json({ message: "Translated exercises" })
|
450
|
+
} catch (error) {
|
451
|
+
console.log(error, "ERROR")
|
452
|
+
return res.status(400).json({ error: (error as Error).message })
|
453
|
+
}
|
454
|
+
})
|
455
|
+
)
|
456
|
+
|
397
457
|
app.post(
|
398
458
|
"/exercise/:slug/create",
|
399
459
|
jsonBodyParser,
|
package/src/managers/socket.ts
CHANGED
@@ -1,274 +1,274 @@
|
|
1
|
-
import { Socket, Server } from "socket.io"
|
2
|
-
import Console from "../utils/console"
|
3
|
-
import queue from "../utils/fileQueue"
|
4
|
-
|
5
|
-
import { ISocket, TPossibleActions } from "../models/socket"
|
6
|
-
import { IConfig } from "../models/config"
|
7
|
-
import { ICallback, TAction } from "../models/action"
|
8
|
-
import { IExercise, IExerciseData } from "../models/exercise-obj"
|
9
|
-
import { TStatus } from "../models/status"
|
10
|
-
import { TSuccessType } from "../models/success-types"
|
11
|
-
import * as http from "http"
|
12
|
-
|
13
|
-
const languageToMessage: Record<string, string> = {
|
14
|
-
python3:
|
15
|
-
"Your code executed without erros, but no output is shown on the terminal. Maybe you forgot to include a print statement in your code?",
|
16
|
-
node: "Your code executed without erros, but no output is shown on the terminal. Maybe you forgot to include a console.log statement in your code?",
|
17
|
-
}
|
18
|
-
|
19
|
-
const SocketManager: ISocket = {
|
20
|
-
socket: null,
|
21
|
-
config: null,
|
22
|
-
allowedActions: [],
|
23
|
-
possibleActions: ["build", "reset", "test", "tutorial"],
|
24
|
-
isTestingEnvironment: false,
|
25
|
-
actionCallBacks: {
|
26
|
-
clean: (_, s: { logs: Array<string> }) => {
|
27
|
-
s.logs = []
|
28
|
-
},
|
29
|
-
},
|
30
|
-
addAllowed: function (actions: Array<TPossibleActions> | TPossibleActions) {
|
31
|
-
if (!Array.isArray(actions))
|
32
|
-
actions = [actions]
|
33
|
-
|
34
|
-
// avoid adding the "test" action if grading is disabled
|
35
|
-
if (
|
36
|
-
actions.includes("test") &&
|
37
|
-
this.config?.disabledActions?.includes("test")
|
38
|
-
) {
|
39
|
-
actions = actions.filter((a: TPossibleActions) => a !== "test")
|
40
|
-
}
|
41
|
-
|
42
|
-
this.allowedActions = [
|
43
|
-
...(this.allowedActions || []).filter(
|
44
|
-
(a: TPossibleActions) => !actions.includes(a)
|
45
|
-
),
|
46
|
-
...actions,
|
47
|
-
]
|
48
|
-
},
|
49
|
-
removeAllowed: function (
|
50
|
-
actions: Array<TPossibleActions> | TPossibleActions
|
51
|
-
) {
|
52
|
-
if (!Array.isArray(actions)) {
|
53
|
-
actions = [actions]
|
54
|
-
}
|
55
|
-
|
56
|
-
this.allowedActions = (this.allowedActions || []).filter(
|
57
|
-
(a: TPossibleActions) => !actions.includes(a)
|
58
|
-
)
|
59
|
-
},
|
60
|
-
start: function (
|
61
|
-
config: IConfig,
|
62
|
-
server: http.Server,
|
63
|
-
isTestingEnvironment = false
|
64
|
-
) {
|
65
|
-
this.config = config
|
66
|
-
this.isTestingEnvironment = isTestingEnvironment
|
67
|
-
this.socket = new Server(server, {
|
68
|
-
allowEIO3: true,
|
69
|
-
cors: {
|
70
|
-
origin: "http://localhost:5173",
|
71
|
-
methods: ["GET", "POST"],
|
72
|
-
},
|
73
|
-
})
|
74
|
-
|
75
|
-
this.allowedActions =
|
76
|
-
this.config?.disabledActions?.includes("test") ||
|
77
|
-
this.config?.disableGrading ?
|
78
|
-
this.possibleActions.filter(
|
79
|
-
a => !this.config?.disabledActions?.includes(a) && a !== "test"
|
80
|
-
) :
|
81
|
-
this.possibleActions.filter(a => !this.allowedActions?.includes(a))
|
82
|
-
|
83
|
-
if (this.config?.grading === "incremental") {
|
84
|
-
this.removeAllowed("reset")
|
85
|
-
}
|
86
|
-
|
87
|
-
if (this.socket) {
|
88
|
-
this.socket.on("connection", (socket: Socket) => {
|
89
|
-
Console.debug(
|
90
|
-
"Connection with client successfully established",
|
91
|
-
this.allowedActions
|
92
|
-
)
|
93
|
-
if (!this.isTestingEnvironment) {
|
94
|
-
this.log("ready", ["Ready to compile or test..."])
|
95
|
-
}
|
96
|
-
|
97
|
-
socket.on(
|
98
|
-
"compiler",
|
99
|
-
({ action, data }: { action: string; data: IExerciseData }) => {
|
100
|
-
this.emit("clean", "pending", ["Working..."])
|
101
|
-
if (typeof data.exerciseSlug === "undefined") {
|
102
|
-
this.log("internal-error", ["No exercise slug specified"])
|
103
|
-
Console.error("No exercise slug especified")
|
104
|
-
return
|
105
|
-
}
|
106
|
-
|
107
|
-
if (
|
108
|
-
this.actionCallBacks &&
|
109
|
-
typeof this.actionCallBacks[action] === "function"
|
110
|
-
) {
|
111
|
-
this.actionCallBacks[action](data)
|
112
|
-
} else {
|
113
|
-
this.log("internal-error", ["Uknown action " + action])
|
114
|
-
}
|
115
|
-
}
|
116
|
-
)
|
117
|
-
})
|
118
|
-
}
|
119
|
-
},
|
120
|
-
on: function (action: TAction, callBack: ICallback) {
|
121
|
-
if (this.actionCallBacks) {
|
122
|
-
this.actionCallBacks[action] = callBack
|
123
|
-
}
|
124
|
-
},
|
125
|
-
clean: function (_ = "pending", logs = []) {
|
126
|
-
this.emit("clean", "pending", logs)
|
127
|
-
},
|
128
|
-
ask: function (questions = []) {
|
129
|
-
return new Promise((resolve, _) => {
|
130
|
-
this.emit("ask", "pending", ["Waiting for input..."], questions)
|
131
|
-
|
132
|
-
this.on("input", ({ inputs }: any) => {
|
133
|
-
// Workaround to fix issue because null inputs
|
134
|
-
|
135
|
-
let isNull = false
|
136
|
-
// eslint-disable-next-line
|
137
|
-
inputs.forEach((input: any) => {
|
138
|
-
if (input === null) {
|
139
|
-
isNull = true
|
140
|
-
}
|
141
|
-
})
|
142
|
-
|
143
|
-
if (!isNull) {
|
144
|
-
resolve(inputs)
|
145
|
-
}
|
146
|
-
})
|
147
|
-
})
|
148
|
-
},
|
149
|
-
sessionRefreshed: function (data) {
|
150
|
-
this.emit("session-refreshed", "", [data])
|
151
|
-
},
|
152
|
-
|
153
|
-
reload: function (
|
154
|
-
files: Array<string> | null = null,
|
155
|
-
exercises: Array<string> | null = null
|
156
|
-
) {
|
157
|
-
this.emit("reload", files?.join("") || "", exercises!)
|
158
|
-
},
|
159
|
-
openWindow: function (url = "") {
|
160
|
-
queue.dispatcher().enqueue(queue.events.OPEN_WINDOW, url)
|
161
|
-
this.emit(
|
162
|
-
queue.events.OPEN_WINDOW as TAction,
|
163
|
-
"ready",
|
164
|
-
[`Opening ${url}`],
|
165
|
-
[],
|
166
|
-
[],
|
167
|
-
url
|
168
|
-
)
|
169
|
-
},
|
170
|
-
log: function (
|
171
|
-
status: TStatus,
|
172
|
-
messages: string | Array<string> = [],
|
173
|
-
report: Array<string> = [],
|
174
|
-
data: any = null
|
175
|
-
) {
|
176
|
-
this.emit("log", status, messages, [], report, data)
|
177
|
-
Console.log(messages)
|
178
|
-
},
|
179
|
-
emit: function (
|
180
|
-
action: TAction,
|
181
|
-
status: TStatus | string = "ready",
|
182
|
-
logs: string | Array<string> = [],
|
183
|
-
inputs: Array<string> = [],
|
184
|
-
report: Array<string> = [],
|
185
|
-
data: any = null
|
186
|
-
) {
|
187
|
-
if (
|
188
|
-
this.config?.compiler &&
|
189
|
-
["webpack", "vanillajs", "vue", "react", "css", "html"].includes(
|
190
|
-
this.config?.compiler
|
191
|
-
)
|
192
|
-
) {
|
193
|
-
if (["compiler-success", "compiler-warning"].includes(status))
|
194
|
-
this.addAllowed("preview")
|
195
|
-
if (["compiler-error"].includes(status) || action === "ready")
|
196
|
-
this.removeAllowed("preview")
|
197
|
-
}
|
198
|
-
|
199
|
-
if (this.config?.grading === "incremental") {
|
200
|
-
this.removeAllowed("reset")
|
201
|
-
}
|
202
|
-
|
203
|
-
// eslint-disable-next-line
|
204
|
-
this.config?.disabledActions?.forEach((a) => this.removeAllowed(a))
|
205
|
-
|
206
|
-
this.socket?.emit("compiler", {
|
207
|
-
action,
|
208
|
-
status,
|
209
|
-
logs,
|
210
|
-
allowed: this.allowedActions,
|
211
|
-
inputs,
|
212
|
-
report,
|
213
|
-
data,
|
214
|
-
})
|
215
|
-
},
|
216
|
-
|
217
|
-
ready: function (message: string) {
|
218
|
-
this.log("ready", [message])
|
219
|
-
},
|
220
|
-
success: function (type: TSuccessType, stdout: string, lang) {
|
221
|
-
const types = ["compiler", "testing"]
|
222
|
-
|
223
|
-
if (!types.includes(type))
|
224
|
-
this.fatal(`Invalid socket success type "${type}" on socket`)
|
225
|
-
else if (
|
226
|
-
stdout === "" &&
|
227
|
-
lang &&
|
228
|
-
Object.keys(languageToMessage).includes(lang)
|
229
|
-
) {
|
230
|
-
this.log((type + "-success") as TSuccessType, [languageToMessage[lang]])
|
231
|
-
} else if (stdout === "") {
|
232
|
-
this.log((type + "-success") as TSuccessType, [
|
233
|
-
"No stdout to display on the console",
|
234
|
-
])
|
235
|
-
} else
|
236
|
-
this.log((type + "-success") as TSuccessType, [stdout])
|
237
|
-
},
|
238
|
-
error: function (type: TStatus, stdout: string) {
|
239
|
-
if (!this.config?.editor.hideTerminal) {
|
240
|
-
queue.dispatcher().enqueue(queue.events.OPEN_TERMINAL, "")
|
241
|
-
}
|
242
|
-
|
243
|
-
this.log(type, [stdout])
|
244
|
-
|
245
|
-
if (this.isTestingEnvironment) {
|
246
|
-
this.onTestingFinished({
|
247
|
-
result: "failed",
|
248
|
-
})
|
249
|
-
}
|
250
|
-
},
|
251
|
-
complete: function () {
|
252
|
-
console.log("complete")
|
253
|
-
},
|
254
|
-
dialog: function (message: string, format = "md") {
|
255
|
-
if (!this.socket) {
|
256
|
-
this.fatal("Socket is not initialized")
|
257
|
-
return
|
258
|
-
}
|
259
|
-
|
260
|
-
this.emit("dialog", "talk", [], undefined, undefined, { message, format })
|
261
|
-
},
|
262
|
-
|
263
|
-
fatal: function (msg: string) {
|
264
|
-
this.log("internal-error", [msg])
|
265
|
-
throw msg
|
266
|
-
},
|
267
|
-
onTestingFinished: function (result: any) {
|
268
|
-
if (this.config?.testingFinishedCallback) {
|
269
|
-
this.config.testingFinishedCallback(result)
|
270
|
-
}
|
271
|
-
},
|
272
|
-
}
|
273
|
-
|
274
|
-
export default SocketManager
|
1
|
+
import { Socket, Server } from "socket.io"
|
2
|
+
import Console from "../utils/console"
|
3
|
+
import queue from "../utils/fileQueue"
|
4
|
+
|
5
|
+
import { ISocket, TPossibleActions } from "../models/socket"
|
6
|
+
import { IConfig } from "../models/config"
|
7
|
+
import { ICallback, TAction } from "../models/action"
|
8
|
+
import { IExercise, IExerciseData } from "../models/exercise-obj"
|
9
|
+
import { TStatus } from "../models/status"
|
10
|
+
import { TSuccessType } from "../models/success-types"
|
11
|
+
import * as http from "http"
|
12
|
+
|
13
|
+
const languageToMessage: Record<string, string> = {
|
14
|
+
python3:
|
15
|
+
"Your code executed without erros, but no output is shown on the terminal. Maybe you forgot to include a print statement in your code?",
|
16
|
+
node: "Your code executed without erros, but no output is shown on the terminal. Maybe you forgot to include a console.log statement in your code?",
|
17
|
+
}
|
18
|
+
|
19
|
+
const SocketManager: ISocket = {
|
20
|
+
socket: null,
|
21
|
+
config: null,
|
22
|
+
allowedActions: [],
|
23
|
+
possibleActions: ["build", "reset", "test", "tutorial"],
|
24
|
+
isTestingEnvironment: false,
|
25
|
+
actionCallBacks: {
|
26
|
+
clean: (_, s: { logs: Array<string> }) => {
|
27
|
+
s.logs = []
|
28
|
+
},
|
29
|
+
},
|
30
|
+
addAllowed: function (actions: Array<TPossibleActions> | TPossibleActions) {
|
31
|
+
if (!Array.isArray(actions))
|
32
|
+
actions = [actions]
|
33
|
+
|
34
|
+
// avoid adding the "test" action if grading is disabled
|
35
|
+
if (
|
36
|
+
actions.includes("test") &&
|
37
|
+
this.config?.disabledActions?.includes("test")
|
38
|
+
) {
|
39
|
+
actions = actions.filter((a: TPossibleActions) => a !== "test")
|
40
|
+
}
|
41
|
+
|
42
|
+
this.allowedActions = [
|
43
|
+
...(this.allowedActions || []).filter(
|
44
|
+
(a: TPossibleActions) => !actions.includes(a)
|
45
|
+
),
|
46
|
+
...actions,
|
47
|
+
]
|
48
|
+
},
|
49
|
+
removeAllowed: function (
|
50
|
+
actions: Array<TPossibleActions> | TPossibleActions
|
51
|
+
) {
|
52
|
+
if (!Array.isArray(actions)) {
|
53
|
+
actions = [actions]
|
54
|
+
}
|
55
|
+
|
56
|
+
this.allowedActions = (this.allowedActions || []).filter(
|
57
|
+
(a: TPossibleActions) => !actions.includes(a)
|
58
|
+
)
|
59
|
+
},
|
60
|
+
start: function (
|
61
|
+
config: IConfig,
|
62
|
+
server: http.Server,
|
63
|
+
isTestingEnvironment = false
|
64
|
+
) {
|
65
|
+
this.config = config
|
66
|
+
this.isTestingEnvironment = isTestingEnvironment
|
67
|
+
this.socket = new Server(server, {
|
68
|
+
allowEIO3: true,
|
69
|
+
cors: {
|
70
|
+
origin: "http://localhost:5173",
|
71
|
+
methods: ["GET", "POST"],
|
72
|
+
},
|
73
|
+
})
|
74
|
+
|
75
|
+
this.allowedActions =
|
76
|
+
this.config?.disabledActions?.includes("test") ||
|
77
|
+
this.config?.disableGrading ?
|
78
|
+
this.possibleActions.filter(
|
79
|
+
a => !this.config?.disabledActions?.includes(a) && a !== "test"
|
80
|
+
) :
|
81
|
+
this.possibleActions.filter(a => !this.allowedActions?.includes(a))
|
82
|
+
|
83
|
+
if (this.config?.grading === "incremental") {
|
84
|
+
this.removeAllowed("reset")
|
85
|
+
}
|
86
|
+
|
87
|
+
if (this.socket) {
|
88
|
+
this.socket.on("connection", (socket: Socket) => {
|
89
|
+
Console.debug(
|
90
|
+
"Connection with client successfully established",
|
91
|
+
this.allowedActions
|
92
|
+
)
|
93
|
+
if (!this.isTestingEnvironment) {
|
94
|
+
this.log("ready", ["Ready to compile or test..."])
|
95
|
+
}
|
96
|
+
|
97
|
+
socket.on(
|
98
|
+
"compiler",
|
99
|
+
({ action, data }: { action: string; data: IExerciseData }) => {
|
100
|
+
this.emit("clean", "pending", ["Working..."])
|
101
|
+
if (typeof data.exerciseSlug === "undefined") {
|
102
|
+
this.log("internal-error", ["No exercise slug specified"])
|
103
|
+
Console.error("No exercise slug especified")
|
104
|
+
return
|
105
|
+
}
|
106
|
+
|
107
|
+
if (
|
108
|
+
this.actionCallBacks &&
|
109
|
+
typeof this.actionCallBacks[action] === "function"
|
110
|
+
) {
|
111
|
+
this.actionCallBacks[action](data)
|
112
|
+
} else {
|
113
|
+
this.log("internal-error", ["Uknown action " + action])
|
114
|
+
}
|
115
|
+
}
|
116
|
+
)
|
117
|
+
})
|
118
|
+
}
|
119
|
+
},
|
120
|
+
on: function (action: TAction, callBack: ICallback) {
|
121
|
+
if (this.actionCallBacks) {
|
122
|
+
this.actionCallBacks[action] = callBack
|
123
|
+
}
|
124
|
+
},
|
125
|
+
clean: function (_ = "pending", logs = []) {
|
126
|
+
this.emit("clean", "pending", logs)
|
127
|
+
},
|
128
|
+
ask: function (questions = []) {
|
129
|
+
return new Promise((resolve, _) => {
|
130
|
+
this.emit("ask", "pending", ["Waiting for input..."], questions)
|
131
|
+
|
132
|
+
this.on("input", ({ inputs }: any) => {
|
133
|
+
// Workaround to fix issue because null inputs
|
134
|
+
|
135
|
+
let isNull = false
|
136
|
+
// eslint-disable-next-line
|
137
|
+
inputs.forEach((input: any) => {
|
138
|
+
if (input === null) {
|
139
|
+
isNull = true
|
140
|
+
}
|
141
|
+
})
|
142
|
+
|
143
|
+
if (!isNull) {
|
144
|
+
resolve(inputs)
|
145
|
+
}
|
146
|
+
})
|
147
|
+
})
|
148
|
+
},
|
149
|
+
sessionRefreshed: function (data) {
|
150
|
+
this.emit("session-refreshed", "", [data])
|
151
|
+
},
|
152
|
+
|
153
|
+
reload: function (
|
154
|
+
files: Array<string> | null = null,
|
155
|
+
exercises: Array<string> | null = null
|
156
|
+
) {
|
157
|
+
this.emit("reload", files?.join("") || "", exercises!)
|
158
|
+
},
|
159
|
+
openWindow: function (url = "") {
|
160
|
+
queue.dispatcher().enqueue(queue.events.OPEN_WINDOW, url)
|
161
|
+
this.emit(
|
162
|
+
queue.events.OPEN_WINDOW as TAction,
|
163
|
+
"ready",
|
164
|
+
[`Opening ${url}`],
|
165
|
+
[],
|
166
|
+
[],
|
167
|
+
url
|
168
|
+
)
|
169
|
+
},
|
170
|
+
log: function (
|
171
|
+
status: TStatus,
|
172
|
+
messages: string | Array<string> = [],
|
173
|
+
report: Array<string> = [],
|
174
|
+
data: any = null
|
175
|
+
) {
|
176
|
+
this.emit("log", status, messages, [], report, data)
|
177
|
+
Console.log(messages)
|
178
|
+
},
|
179
|
+
emit: function (
|
180
|
+
action: TAction,
|
181
|
+
status: TStatus | string = "ready",
|
182
|
+
logs: string | Array<string> = [],
|
183
|
+
inputs: Array<string> = [],
|
184
|
+
report: Array<string> = [],
|
185
|
+
data: any = null
|
186
|
+
) {
|
187
|
+
if (
|
188
|
+
this.config?.compiler &&
|
189
|
+
["webpack", "vanillajs", "vue", "react", "css", "html"].includes(
|
190
|
+
this.config?.compiler
|
191
|
+
)
|
192
|
+
) {
|
193
|
+
if (["compiler-success", "compiler-warning"].includes(status))
|
194
|
+
this.addAllowed("preview")
|
195
|
+
if (["compiler-error"].includes(status) || action === "ready")
|
196
|
+
this.removeAllowed("preview")
|
197
|
+
}
|
198
|
+
|
199
|
+
if (this.config?.grading === "incremental") {
|
200
|
+
this.removeAllowed("reset")
|
201
|
+
}
|
202
|
+
|
203
|
+
// eslint-disable-next-line
|
204
|
+
this.config?.disabledActions?.forEach((a) => this.removeAllowed(a))
|
205
|
+
|
206
|
+
this.socket?.emit("compiler", {
|
207
|
+
action,
|
208
|
+
status,
|
209
|
+
logs,
|
210
|
+
allowed: this.allowedActions,
|
211
|
+
inputs,
|
212
|
+
report,
|
213
|
+
data,
|
214
|
+
})
|
215
|
+
},
|
216
|
+
|
217
|
+
ready: function (message: string) {
|
218
|
+
this.log("ready", [message])
|
219
|
+
},
|
220
|
+
success: function (type: TSuccessType, stdout: string, lang) {
|
221
|
+
const types = ["compiler", "testing"]
|
222
|
+
|
223
|
+
if (!types.includes(type))
|
224
|
+
this.fatal(`Invalid socket success type "${type}" on socket`)
|
225
|
+
else if (
|
226
|
+
stdout === "" &&
|
227
|
+
lang &&
|
228
|
+
Object.keys(languageToMessage).includes(lang)
|
229
|
+
) {
|
230
|
+
this.log((type + "-success") as TSuccessType, [languageToMessage[lang]])
|
231
|
+
} else if (stdout === "") {
|
232
|
+
this.log((type + "-success") as TSuccessType, [
|
233
|
+
"No stdout to display on the console",
|
234
|
+
])
|
235
|
+
} else
|
236
|
+
this.log((type + "-success") as TSuccessType, [stdout])
|
237
|
+
},
|
238
|
+
error: function (type: TStatus, stdout: string) {
|
239
|
+
if (!this.config?.editor.hideTerminal) {
|
240
|
+
queue.dispatcher().enqueue(queue.events.OPEN_TERMINAL, "")
|
241
|
+
}
|
242
|
+
|
243
|
+
this.log(type, [stdout])
|
244
|
+
|
245
|
+
if (this.isTestingEnvironment) {
|
246
|
+
this.onTestingFinished({
|
247
|
+
result: "failed",
|
248
|
+
})
|
249
|
+
}
|
250
|
+
},
|
251
|
+
complete: function () {
|
252
|
+
console.log("complete")
|
253
|
+
},
|
254
|
+
dialog: function (message: string, format = "md") {
|
255
|
+
if (!this.socket) {
|
256
|
+
this.fatal("Socket is not initialized")
|
257
|
+
return
|
258
|
+
}
|
259
|
+
|
260
|
+
this.emit("dialog", "talk", [], undefined, undefined, { message, format })
|
261
|
+
},
|
262
|
+
|
263
|
+
fatal: function (msg: string) {
|
264
|
+
this.log("internal-error", [msg])
|
265
|
+
throw msg
|
266
|
+
},
|
267
|
+
onTestingFinished: function (result: any) {
|
268
|
+
if (this.config?.testingFinishedCallback) {
|
269
|
+
this.config.testingFinishedCallback(result)
|
270
|
+
}
|
271
|
+
},
|
272
|
+
}
|
273
|
+
|
274
|
+
export default SocketManager
|