@learnpack/learnpack 5.0.31 → 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.
@@ -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
@@ -1,5 +1,6 @@
1
1
  import { IFile } from "../models/file"
2
2
  import API from "../utils/api"
3
+ const packageInfo = require("../../package.json")
3
4
  import Console from "../utils/console"
4
5
 
5
6
  const fs = require("fs")
@@ -77,6 +78,7 @@ type TStudent = {
77
78
 
78
79
  export interface ITelemetryJSONSchema {
79
80
  telemetry_id?: string
81
+ version: string
80
82
  user_id?: number | string
81
83
  slug: string
82
84
  agent?: string
@@ -111,6 +113,7 @@ interface ITelemetryManager {
111
113
  user: TUser
112
114
  urls: TTelemetryUrls
113
115
  started: boolean
116
+ version: string
114
117
  salute: (message: string) => void
115
118
  start: (
116
119
  agent: string,
@@ -136,6 +139,7 @@ interface ITelemetryManager {
136
139
  const TelemetryManager: ITelemetryManager = {
137
140
  current: null,
138
141
  urls: {},
142
+ version: packageInfo.version,
139
143
  user: {
140
144
  token: "",
141
145
  id: "",
@@ -160,6 +164,8 @@ const TelemetryManager: ITelemetryManager = {
160
164
  this.current = {
161
165
  telemetry_id: createUUID(),
162
166
  slug: tutorialSlug,
167
+ version: `CLI:${this.version}`,
168
+ user_id: 0,
163
169
  agent,
164
170
  tutorial_started_at: Date.now(),
165
171
  last_interaction_at: Date.now(),
@@ -176,6 +182,10 @@ const TelemetryManager: ITelemetryManager = {
176
182
  this.user.id = this.current.user_id.toString()
177
183
  }
178
184
 
185
+ if (!this.current.version) {
186
+ this.current.version = `CLI:${this.version}`
187
+ }
188
+
179
189
  this.save()
180
190
 
181
191
  this.started = true
@@ -1,12 +1,12 @@
1
- export type TAction =
2
- | "test"
3
- | "log"
4
- | "reload"
5
- | "ready"
6
- | "clean"
7
- | "ask"
8
- | "file_change"
9
- | "dialog"
10
- | "session-refreshed"
11
-
12
- export type ICallback = (...agrs: any[]) => any
1
+ export type TAction =
2
+ | "test"
3
+ | "log"
4
+ | "reload"
5
+ | "ready"
6
+ | "clean"
7
+ | "ask"
8
+ | "file_change"
9
+ | "dialog"
10
+ | "session-refreshed"
11
+
12
+ export type ICallback = (...agrs: any[]) => any