@learnpack/learnpack 2.1.25 → 2.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/README.md +16 -16
  2. package/bin/run +17 -17
  3. package/bin/run.cmd +3 -3
  4. package/oclif.manifest.json +1 -1
  5. package/package.json +139 -138
  6. package/src/commands/audit.ts +134 -109
  7. package/src/commands/clean.ts +29 -29
  8. package/src/commands/download.ts +62 -62
  9. package/src/commands/init.ts +39 -39
  10. package/src/commands/login.ts +42 -42
  11. package/src/commands/logout.ts +43 -43
  12. package/src/commands/publish.ts +107 -107
  13. package/src/commands/start.ts +264 -234
  14. package/src/commands/test.ts +85 -85
  15. package/src/index.ts +1 -1
  16. package/src/managers/config/allowed_files.ts +29 -29
  17. package/src/managers/config/defaults.ts +4 -2
  18. package/src/managers/config/exercise.ts +309 -302
  19. package/src/managers/config/index.ts +159 -138
  20. package/src/managers/file.ts +178 -169
  21. package/src/managers/gitpod.ts +84 -84
  22. package/src/managers/server/index.ts +78 -69
  23. package/src/managers/server/routes.ts +139 -90
  24. package/src/managers/session.ts +147 -118
  25. package/src/managers/socket.ts +252 -239
  26. package/src/managers/test.ts +83 -83
  27. package/src/models/action.ts +10 -3
  28. package/src/models/config-manager.ts +23 -23
  29. package/src/models/config.ts +9 -2
  30. package/src/models/counter.ts +11 -11
  31. package/src/models/errors.ts +22 -22
  32. package/src/models/exercise-obj.ts +6 -3
  33. package/src/models/file.ts +5 -5
  34. package/src/models/findings.ts +18 -18
  35. package/src/models/flags.ts +10 -10
  36. package/src/models/front-matter.ts +11 -11
  37. package/src/models/gitpod-data.ts +19 -19
  38. package/src/models/language.ts +4 -4
  39. package/src/models/package.ts +7 -7
  40. package/src/models/plugin-config.ts +17 -17
  41. package/src/models/session.ts +29 -26
  42. package/src/models/socket.ts +54 -48
  43. package/src/models/status.ts +16 -15
  44. package/src/models/success-types.ts +1 -1
  45. package/src/plugin/command/compile.ts +17 -17
  46. package/src/plugin/command/test.ts +30 -30
  47. package/src/plugin/index.ts +6 -6
  48. package/src/plugin/plugin.ts +94 -94
  49. package/src/plugin/utils.ts +87 -87
  50. package/src/types/node-fetch.d.ts +1 -1
  51. package/src/ui/download.ts +71 -71
  52. package/src/utils/BaseCommand.ts +48 -48
  53. package/src/utils/SessionCommand.ts +48 -48
  54. package/src/utils/api.ts +246 -194
  55. package/src/utils/audit.ts +392 -395
  56. package/src/utils/console.ts +24 -24
  57. package/src/utils/errors.ts +117 -117
  58. package/src/utils/exercisesQueue.ts +51 -51
  59. package/src/utils/fileQueue.ts +198 -198
  60. package/src/utils/misc.ts +23 -23
  61. package/src/utils/templates/gitignore.txt +19 -19
  62. package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.es.md +24 -24
  63. package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.md +24 -24
  64. package/src/utils/templates/incremental/README.ejs +4 -4
  65. package/src/utils/templates/incremental/README.es.ejs +4 -4
  66. package/src/utils/templates/isolated/01-hello-world/README.es.md +26 -26
  67. package/src/utils/templates/isolated/01-hello-world/README.md +26 -26
  68. package/src/utils/templates/isolated/README.ejs +4 -4
  69. package/src/utils/templates/isolated/README.es.ejs +4 -4
  70. package/src/utils/templates/no-grading/README.ejs +4 -4
  71. package/src/utils/templates/no-grading/README.es.ejs +4 -4
  72. package/src/utils/validators.ts +18 -18
  73. package/src/utils/watcher.ts +14 -14
  74. package/lib/commands/audit.d.ts +0 -6
  75. package/lib/commands/audit.js +0 -317
  76. package/lib/commands/clean.d.ts +0 -8
  77. package/lib/commands/clean.js +0 -25
  78. package/lib/commands/download.d.ts +0 -13
  79. package/lib/commands/download.js +0 -55
  80. package/lib/commands/init.d.ts +0 -9
  81. package/lib/commands/init.js +0 -123
  82. package/lib/commands/login.d.ts +0 -14
  83. package/lib/commands/login.js +0 -37
  84. package/lib/commands/logout.d.ts +0 -14
  85. package/lib/commands/logout.js +0 -37
  86. package/lib/commands/publish.d.ts +0 -14
  87. package/lib/commands/publish.js +0 -82
  88. package/lib/commands/start.d.ts +0 -7
  89. package/lib/commands/start.js +0 -165
  90. package/lib/commands/test.d.ts +0 -6
  91. package/lib/commands/test.js +0 -62
  92. package/lib/index.d.ts +0 -1
  93. package/lib/index.js +0 -4
  94. package/lib/managers/config/allowed_files.d.ts +0 -5
  95. package/lib/managers/config/allowed_files.js +0 -30
  96. package/lib/managers/config/defaults.d.ts +0 -37
  97. package/lib/managers/config/defaults.js +0 -38
  98. package/lib/managers/config/exercise.d.ts +0 -36
  99. package/lib/managers/config/exercise.js +0 -230
  100. package/lib/managers/config/index.d.ts +0 -3
  101. package/lib/managers/config/index.js +0 -302
  102. package/lib/managers/file.d.ts +0 -13
  103. package/lib/managers/file.js +0 -134
  104. package/lib/managers/gitpod.d.ts +0 -3
  105. package/lib/managers/gitpod.js +0 -67
  106. package/lib/managers/server/index.d.ts +0 -6
  107. package/lib/managers/server/index.js +0 -51
  108. package/lib/managers/server/routes.d.ts +0 -4
  109. package/lib/managers/server/routes.js +0 -167
  110. package/lib/managers/session.d.ts +0 -3
  111. package/lib/managers/session.js +0 -104
  112. package/lib/managers/socket.d.ts +0 -3
  113. package/lib/managers/socket.js +0 -164
  114. package/lib/managers/test.d.ts +0 -0
  115. package/lib/managers/test.js +0 -84
  116. package/lib/models/action.d.ts +0 -2
  117. package/lib/models/action.js +0 -2
  118. package/lib/models/audit.d.ts +0 -15
  119. package/lib/models/audit.js +0 -2
  120. package/lib/models/config-manager.d.ts +0 -21
  121. package/lib/models/config-manager.js +0 -2
  122. package/lib/models/config.d.ts +0 -60
  123. package/lib/models/config.js +0 -2
  124. package/lib/models/counter.d.ts +0 -11
  125. package/lib/models/counter.js +0 -2
  126. package/lib/models/errors.d.ts +0 -15
  127. package/lib/models/errors.js +0 -2
  128. package/lib/models/exercise-obj.d.ts +0 -27
  129. package/lib/models/exercise-obj.js +0 -2
  130. package/lib/models/file.d.ts +0 -5
  131. package/lib/models/file.js +0 -2
  132. package/lib/models/findings.d.ts +0 -17
  133. package/lib/models/findings.js +0 -2
  134. package/lib/models/flags.d.ts +0 -10
  135. package/lib/models/flags.js +0 -2
  136. package/lib/models/front-matter.d.ts +0 -11
  137. package/lib/models/front-matter.js +0 -2
  138. package/lib/models/gitpod-data.d.ts +0 -16
  139. package/lib/models/gitpod-data.js +0 -2
  140. package/lib/models/language.d.ts +0 -4
  141. package/lib/models/language.js +0 -2
  142. package/lib/models/package.d.ts +0 -7
  143. package/lib/models/package.js +0 -2
  144. package/lib/models/plugin-config.d.ts +0 -16
  145. package/lib/models/plugin-config.js +0 -2
  146. package/lib/models/session.d.ts +0 -23
  147. package/lib/models/session.js +0 -2
  148. package/lib/models/socket.d.ts +0 -31
  149. package/lib/models/socket.js +0 -2
  150. package/lib/models/status.d.ts +0 -1
  151. package/lib/models/status.js +0 -2
  152. package/lib/models/success-types.d.ts +0 -1
  153. package/lib/models/success-types.js +0 -2
  154. package/lib/plugin/command/compile.d.ts +0 -6
  155. package/lib/plugin/command/compile.js +0 -18
  156. package/lib/plugin/command/test.d.ts +0 -6
  157. package/lib/plugin/command/test.js +0 -25
  158. package/lib/plugin/index.d.ts +0 -27
  159. package/lib/plugin/index.js +0 -7
  160. package/lib/plugin/plugin.d.ts +0 -8
  161. package/lib/plugin/plugin.js +0 -68
  162. package/lib/plugin/utils.d.ts +0 -16
  163. package/lib/plugin/utils.js +0 -58
  164. package/lib/ui/download.d.ts +0 -5
  165. package/lib/ui/download.js +0 -61
  166. package/lib/utils/BaseCommand.d.ts +0 -8
  167. package/lib/utils/BaseCommand.js +0 -41
  168. package/lib/utils/SessionCommand.d.ts +0 -10
  169. package/lib/utils/SessionCommand.js +0 -47
  170. package/lib/utils/api.d.ts +0 -12
  171. package/lib/utils/api.js +0 -173
  172. package/lib/utils/audit.d.ts +0 -16
  173. package/lib/utils/audit.js +0 -302
  174. package/lib/utils/console.d.ts +0 -12
  175. package/lib/utils/console.js +0 -19
  176. package/lib/utils/errors.d.ts +0 -17
  177. package/lib/utils/errors.js +0 -100
  178. package/lib/utils/exercisesQueue.d.ts +0 -9
  179. package/lib/utils/exercisesQueue.js +0 -38
  180. package/lib/utils/fileQueue.d.ts +0 -40
  181. package/lib/utils/fileQueue.js +0 -168
  182. package/lib/utils/misc.d.ts +0 -1
  183. package/lib/utils/misc.js +0 -23
  184. package/lib/utils/validators.d.ts +0 -5
  185. package/lib/utils/validators.js +0 -17
  186. package/lib/utils/watcher.d.ts +0 -2
  187. package/lib/utils/watcher.js +0 -23
@@ -1,24 +1,24 @@
1
- import * as path from "path";
2
- import * as fs from "fs";
3
- import * as shell from "shelljs";
4
- import Console from "../../utils/console";
5
- import watch from "../../utils/watcher";
1
+ import * as path from "path"
2
+ import * as fs from "fs"
3
+ import * as shell from "shelljs"
4
+ import Console from "../../utils/console"
5
+ import watch from "../../utils/watcher"
6
6
  import {
7
7
  ValidationError,
8
8
  NotFoundError,
9
9
  InternalError,
10
- } from "../../utils/errors";
10
+ } from "../../utils/errors"
11
11
 
12
- import defaults from "./defaults";
13
- import { exercise } from "./exercise";
12
+ import defaults from "./defaults"
13
+ import { exercise } from "./exercise"
14
14
 
15
- import { rmSync } from "../file";
16
- import { IConfigObj, TConfigObjAttributes, TMode } from "../../models/config";
15
+ import { rmSync } from "../file"
16
+ import { IConfigObj, TConfigObjAttributes, TMode } from "../../models/config"
17
17
  import {
18
18
  IConfigManagerAttributes,
19
19
  IConfigManager,
20
- } from "../../models/config-manager";
21
- import { IFile } from "../../models/file";
20
+ } from "../../models/config-manager"
21
+ import { IFile } from "../../models/file"
22
22
 
23
23
  /* exercise folder name standard */
24
24
 
@@ -30,32 +30,49 @@ const chalk = require("chalk");
30
30
  /* exercise folder name standard */
31
31
 
32
32
  const getConfigPath = () => {
33
- const possibleFileNames = ["learn.json", ".learn/learn.json"];
34
- const config = possibleFileNames.find(file => fs.existsSync(file)) || null;
33
+ const possibleFileNames = ["learn.json", ".learn/learn.json"]
34
+ const config = possibleFileNames.find(file => fs.existsSync(file)) || null
35
35
  if (config && fs.existsSync(".breathecode"))
36
- return { config, base: ".breathecode" };
36
+ return { config, base: ".breathecode" }
37
37
  if (config === null)
38
38
  throw NotFoundError(
39
39
  "learn.json file not found on current folder, is this a learnpack package?"
40
- );
41
- return { config, base: ".learn" };
42
- };
40
+ )
41
+ return { config, base: ".learn" }
42
+ }
43
43
 
44
44
  const getExercisesPath = (base: string) => {
45
- const possibleFileNames = ["./exercises", base + "/exercises", "./"];
46
- return possibleFileNames.find(file => fs.existsSync(file)) || null;
47
- };
45
+ const possibleFileNames = ["./exercises", base + "/exercises", "./"]
46
+ return possibleFileNames.find(file => fs.existsSync(file)) || null
47
+ }
48
48
 
49
49
  const getGitpodAddress = () => {
50
50
  if (shell.exec("gp -h", { silent: true }).code === 0) {
51
51
  return shell
52
52
  .exec("gp url", { silent: true })
53
- .stdout.replace(/(\r\n|\n|\r)/gm, "");
53
+ .stdout.replace(/(\r\n|\n|\r)/gm, "")
54
+ }
55
+
56
+ Console.debug("Gitpod command line tool not found")
57
+ return "http://localhost"
58
+ }
59
+
60
+ const getCodespacesNamespace = () => {
61
+ // https://orange-rotary-phone-wxpg49q5gcg4rp-3000.app.github.dev
62
+ const codespace_name = shell
63
+ .exec("echo $CODESPACE_NAME", { silent: true })
64
+ .stdout.replace(/(\r\n|\n|\r)/gm, "")
65
+
66
+ if (
67
+ !codespace_name ||
68
+ codespace_name === "" ||
69
+ codespace_name === undefined
70
+ ) {
71
+ return null
54
72
  }
55
73
 
56
- Console.debug("Gitpod command line tool not found");
57
- return "http://localhost";
58
- };
74
+ return codespace_name
75
+ }
59
76
 
60
77
  export default async ({
61
78
  grading,
@@ -63,46 +80,46 @@ export default async ({
63
80
  disableGrading,
64
81
  version,
65
82
  }: IConfigManagerAttributes): Promise<IConfigManager> => {
66
- const confPath = getConfigPath();
67
- Console.debug("This is the config path: ", confPath);
83
+ const confPath = getConfigPath()
84
+ Console.debug("This is the config path: ", confPath)
68
85
 
69
- let configObj: IConfigObj = {};
86
+ let configObj: IConfigObj = {}
70
87
 
71
88
  if (confPath) {
72
- const bcContent = fs.readFileSync(confPath.config);
73
- let hiddenBcContent = {};
89
+ const bcContent = fs.readFileSync(confPath.config)
90
+ let hiddenBcContent = {}
74
91
  if (fs.existsSync(confPath.base + "/config.json")) {
75
- hiddenBcContent = fs.readFileSync(confPath.base + "/config.json");
76
- hiddenBcContent = JSON.parse(hiddenBcContent as string);
92
+ hiddenBcContent = fs.readFileSync(confPath.base + "/config.json")
93
+ hiddenBcContent = JSON.parse(hiddenBcContent as string)
77
94
  if (!hiddenBcContent)
78
95
  throw new Error(
79
96
  `Invalid ${confPath.base}/config.json syntax: Unable to parse.`
80
- );
97
+ )
81
98
  }
82
99
 
83
- const jsonConfig = JSON.parse(`${bcContent}`);
100
+ const jsonConfig = JSON.parse(`${bcContent}`)
84
101
  if (!jsonConfig)
85
- throw new Error(`Invalid ${confPath.config} syntax: Unable to parse.`);
102
+ throw new Error(`Invalid ${confPath.config} syntax: Unable to parse.`)
86
103
 
87
- let session: number;
104
+ let session: number
88
105
 
89
106
  // add using id to the installation
90
107
  if (!jsonConfig.session) {
91
- session = Math.floor(Math.random() * 10_000_000_000_000_000_000);
108
+ session = Math.floor(Math.random() * 10_000_000_000_000_000_000)
92
109
  } else {
93
- session = jsonConfig.session;
94
- delete jsonConfig.session;
110
+ session = jsonConfig.session
111
+ delete jsonConfig.session
95
112
  }
96
113
 
97
114
  configObj = deepMerge(hiddenBcContent, {
98
115
  config: jsonConfig,
99
116
  session: session,
100
- });
101
- Console.debug("Content from the configuration .json ", configObj);
117
+ })
118
+ Console.debug("Content from the configuration .json ", configObj)
102
119
  } else {
103
120
  throw ValidationError(
104
121
  "No learn.json file has been found, make sure you are in the folder"
105
- );
122
+ )
106
123
  }
107
124
 
108
125
  configObj = deepMerge(defaults || {}, configObj, {
@@ -110,10 +127,10 @@ export default async ({
110
127
  grading: grading || configObj.config?.grading,
111
128
  configPath: confPath.config,
112
129
  },
113
- });
130
+ })
114
131
 
115
132
  if (configObj.config) {
116
- configObj.config.outputPath = confPath.base + "/dist";
133
+ configObj.config.outputPath = confPath.base + "/dist"
117
134
  }
118
135
 
119
136
  Console.debug("This is your configuration object: ", {
@@ -121,45 +138,50 @@ export default async ({
121
138
  exercises: configObj.exercises ?
122
139
  configObj.exercises.map(e => e.slug) :
123
140
  [],
124
- });
141
+ })
125
142
 
126
143
  // auto detect agent (if possible)
144
+ const codespaces_workspace = getCodespacesNamespace()
127
145
  if (shell.which("gp") && configObj && configObj.config) {
128
- configObj.config.editor.agent = "vscode";
129
- configObj.address = getGitpodAddress();
146
+ configObj.config.editor.agent = "vscode"
147
+ configObj.address = getGitpodAddress()
130
148
  configObj.config.publicUrl = `https://${
131
149
  configObj.config.port
132
- }-${configObj.address?.slice(8)}`;
150
+ }-${configObj.address?.slice(8)}`
151
+ } else if (configObj.config && codespaces_workspace) {
152
+ configObj.config.editor.agent = "vscode"
153
+ configObj.address = `https://${codespaces_workspace}.github.dev`
154
+ configObj.config.publicUrl = `https://${codespaces_workspace}-${configObj.config.port}.app.github.dev`
133
155
  } else if (configObj.config && !configObj.config.editor.agent) {
134
- configObj.config.editor.agent = "localhost";
156
+ configObj.config.editor.agent = "localhost"
135
157
  }
136
158
 
137
159
  if (configObj.config && !configObj.config.publicUrl)
138
- configObj.config.publicUrl = `${configObj.address}:${configObj.config.port}`;
160
+ configObj.config.publicUrl = `${configObj.address}:${configObj.config.port}`
139
161
 
140
162
  // Assign default editor mode if not set already
141
163
  if (configObj.config && !mode) {
142
- configObj.config.editor.mode = mode as TMode;
164
+ configObj.config.editor.mode = mode as TMode
143
165
  }
144
166
 
145
167
  if (configObj.config && !configObj.config.editor.mode)
146
168
  configObj.config.editor.mode =
147
- configObj.config.editor.agent === "localhost" ? "standalone" : "preview";
169
+ configObj.config.editor.agent === "localhost" ? "standalone" : "preview"
148
170
 
149
171
  if (version && configObj.config)
150
- configObj.config.editor.version = version;
172
+ configObj.config.editor.version = version
151
173
  else if (configObj.config && configObj.config.editor.version === null) {
152
- Console.debug("Config version not found, downloading default.");
174
+ Console.debug("Config version not found, downloading default.")
153
175
  const resp = await fetch(
154
176
  "https://raw.githubusercontent.com/learnpack/coding-ide/learnpack/package.json"
155
- );
156
- const packageJSON = await resp.json();
157
- configObj.config.editor.version = packageJSON.version || "1.0.73";
177
+ )
178
+ const packageJSON = await resp.json()
179
+ configObj.config.editor.version = packageJSON.version || "1.0.73"
158
180
  }
159
181
 
160
182
  if (configObj.config) {
161
- configObj.config.dirPath = "./" + confPath.base;
162
- configObj.config.exercisesPath = getExercisesPath(confPath.base) || "./";
183
+ configObj.config.dirPath = "./" + confPath.base
184
+ configObj.config.exercisesPath = getExercisesPath(confPath.base) || "./"
163
185
  }
164
186
 
165
187
  return {
@@ -170,125 +192,125 @@ configObj.config.editor.version = version;
170
192
  const alias = (_l: string) => {
171
193
  const map: any = {
172
194
  python3: "python",
173
- };
195
+ }
174
196
  if (map[_l])
175
- return map[_l];
176
- return _l;
177
- };
197
+ return map[_l]
198
+ return _l
199
+ }
178
200
 
179
201
  // decode aliases
180
- language = alias(language);
202
+ language = alias(language)
181
203
 
182
204
  if (this.validLanguages[language])
183
- return true;
205
+ return true
184
206
 
185
- Console.debug(`Validating engine for ${language} compilation`);
186
- let result = shell.exec("learnpack plugins", { silent: true });
207
+ Console.debug(`Validating engine for ${language} compilation`)
208
+ let result = shell.exec("learnpack plugins", { silent: true })
187
209
 
188
210
  if (
189
211
  result.code === 0 &&
190
212
  result.stdout.includes(`learnpack-${language}`)
191
213
  ) {
192
- this.validLanguages[language] = true;
193
- return true;
214
+ this.validLanguages[language] = true
215
+ return true
194
216
  }
195
217
 
196
- Console.info(`Language engine for ${language} not found, installing...`);
218
+ Console.info(`Language engine for ${language} not found, installing...`)
197
219
  result = shell.exec(`learnpack plugins:install learnpack-${language}`, {
198
220
  silent: true,
199
- });
221
+ })
200
222
  if (result.code === 0) {
201
223
  socket.log(
202
224
  "compiling",
203
225
  "Installing the python compiler, you will have to reset the exercises after installation by writing on your terminal: $ learnpack run"
204
- );
226
+ )
205
227
  Console.info(
206
228
  `Successfully installed the ${language} exercise engine, \n please start learnpack again by running the following command: \n ${chalk.white(
207
229
  "$ learnpack start"
208
230
  )}\n\n `
209
- );
210
- server.terminate();
211
- return false;
231
+ )
232
+ server.terminate()
233
+ return false
212
234
  }
213
235
 
214
- this.validLanguages[language] = false;
215
- socket.error(`Error installing ${language} exercise engine`);
216
- Console.error(`Error installing ${language} exercise engine`);
217
- Console.log(result.stdout);
218
- throw InternalError(`Error installing ${language} exercise engine`);
236
+ this.validLanguages[language] = false
237
+ socket.error(`Error installing ${language} exercise engine`)
238
+ Console.error(`Error installing ${language} exercise engine`)
239
+ Console.log(result.stdout)
240
+ throw InternalError(`Error installing ${language} exercise engine`)
219
241
  },
220
242
  clean: () => {
221
243
  if (configObj.config) {
222
244
  if (configObj.config.outputPath) {
223
- rmSync(configObj.config.outputPath);
245
+ rmSync(configObj.config.outputPath)
224
246
  }
225
247
 
226
- rmSync(configObj.config.dirPath + "/_app");
227
- rmSync(configObj.config.dirPath + "/reports");
228
- rmSync(configObj.config.dirPath + "/.session");
229
- rmSync(configObj.config.dirPath + "/resets");
248
+ rmSync(configObj.config.dirPath + "/_app")
249
+ rmSync(configObj.config.dirPath + "/reports")
250
+ rmSync(configObj.config.dirPath + "/.session")
251
+ rmSync(configObj.config.dirPath + "/resets")
230
252
 
231
253
  // clean tag gz
232
254
  if (fs.existsSync(configObj.config.dirPath + "/app.tar.gz"))
233
- fs.unlinkSync(configObj.config.dirPath + "/app.tar.gz");
255
+ fs.unlinkSync(configObj.config.dirPath + "/app.tar.gz")
234
256
 
235
257
  if (fs.existsSync(configObj.config.dirPath + "/config.json"))
236
- fs.unlinkSync(configObj.config.dirPath + "/config.json");
258
+ fs.unlinkSync(configObj.config.dirPath + "/config.json")
237
259
 
238
260
  if (fs.existsSync(configObj.config.dirPath + "/vscode_queue.json"))
239
- fs.unlinkSync(configObj.config.dirPath + "/vscode_queue.json");
261
+ fs.unlinkSync(configObj.config.dirPath + "/vscode_queue.json")
240
262
  }
241
263
  },
242
264
  getExercise: slug => {
243
- Console.debug("ExercisePath Slug", slug);
265
+ Console.debug("ExercisePath Slug", slug)
244
266
  const exercise = (configObj.exercises || []).find(
245
267
  ex => ex.slug === slug
246
- );
268
+ )
247
269
  if (!exercise)
248
- throw ValidationError(`Exercise ${slug} not found`);
270
+ throw ValidationError(`Exercise ${slug} not found`)
249
271
 
250
- return exercise;
272
+ return exercise
251
273
  },
252
274
  getAllExercises: () => {
253
- return configObj.exercises;
275
+ return configObj.exercises
254
276
  },
255
277
  startExercise: function (slug: string) {
256
- const exercise = this.getExercise(slug);
278
+ const exercise = this.getExercise(slug)
257
279
 
258
280
  // set config.json with current exercise
259
- configObj.currentExercise = exercise.slug;
281
+ configObj.currentExercise = exercise.slug
260
282
 
261
- this.save();
283
+ this.save()
262
284
 
263
285
  // eslint-disable-next-line
264
286
  exercise.files.forEach((f: IFile) => {
265
287
  if (configObj.config) {
266
- const _path = configObj.config.outputPath + "/" + f.name;
288
+ const _path = configObj.config.outputPath + "/" + f.name
267
289
  if (f.hidden === false && fs.existsSync(_path))
268
- fs.unlinkSync(_path);
290
+ fs.unlinkSync(_path)
269
291
  }
270
- });
292
+ })
271
293
 
272
- return exercise;
294
+ return exercise
273
295
  },
274
296
  noCurrentExercise: function () {
275
- configObj.currentExercise = null;
276
- this.save();
297
+ configObj.currentExercise = null
298
+ this.save()
277
299
  },
278
300
  reset: slug => {
279
301
  if (
280
302
  configObj.config &&
281
303
  !fs.existsSync(`${configObj.config.dirPath}/resets/` + slug)
282
304
  )
283
- throw ValidationError("Could not find the original files for " + slug);
305
+ throw ValidationError("Could not find the original files for " + slug)
284
306
 
285
307
  const exercise = (configObj.exercises || []).find(
286
308
  ex => ex.slug === slug
287
- );
309
+ )
288
310
  if (!exercise)
289
311
  throw ValidationError(
290
312
  `Exercise ${slug} not found on the configuration`
291
- );
313
+ )
292
314
 
293
315
  if (configObj.config) {
294
316
  for (const fileName of fs.readdirSync(
@@ -296,111 +318,110 @@ fs.unlinkSync(_path);
296
318
  )) {
297
319
  const content = fs.readFileSync(
298
320
  `${configObj.config?.dirPath}/resets/${slug}/${fileName}`
299
- );
300
- fs.writeFileSync(`${exercise.path}/${fileName}`, content);
321
+ )
322
+ fs.writeFileSync(`${exercise.path}/${fileName}`, content)
301
323
  }
302
324
  }
303
325
  },
304
326
  buildIndex: function () {
305
- Console.info("Building the exercise index...");
327
+ Console.info("Building the exercise index...")
306
328
 
307
329
  const isDirectory = (source: string) => {
308
- const name = path.basename(source);
330
+ const name = path.basename(source)
309
331
  if (name === path.basename(configObj?.config?.dirPath || ""))
310
- return false;
332
+ return false
311
333
  // ignore folders that start with a dot
312
334
  if (name.charAt(0) === "." || name.charAt(0) === "_")
313
- return false;
335
+ return false
314
336
 
315
- return fs.lstatSync(source).isDirectory();
316
- };
337
+ return fs.lstatSync(source).isDirectory()
338
+ }
317
339
 
318
340
  const getDirectories = (source: string) =>
319
341
  fs
320
342
  .readdirSync(source)
321
343
  .map(name => path.join(source, name))
322
- .filter(isDirectory);
344
+ .filter(isDirectory)
323
345
  // add the .learn folder
324
346
  if (!fs.existsSync(confPath.base))
325
- fs.mkdirSync(confPath.base);
347
+ fs.mkdirSync(confPath.base)
326
348
  // add the outout folder where webpack will publish the the html/css/js files
327
349
  if (
328
350
  configObj.config &&
329
351
  configObj.config.outputPath &&
330
352
  !fs.existsSync(configObj.config.outputPath)
331
353
  )
332
- fs.mkdirSync(configObj.config.outputPath);
354
+ fs.mkdirSync(configObj.config.outputPath)
333
355
 
334
356
  // TODO: we could use npm library front-mater to read the title of the exercises from the README.md
335
357
  const grupedByDirectory = getDirectories(
336
358
  configObj?.config?.exercisesPath || ""
337
- );
359
+ )
338
360
  configObj.exercises =
339
361
  grupedByDirectory.length > 0 ?
340
362
  grupedByDirectory.map((path, position) =>
341
363
  exercise(path, position, configObj)
342
364
  ) :
343
- [exercise(configObj?.config?.exercisesPath || "", 0, configObj)];
344
- this.save();
365
+ [exercise(configObj?.config?.exercisesPath || "", 0, configObj)]
366
+ this.save()
345
367
  },
346
368
  watchIndex: function (onChange: () => void) {
347
369
  if (configObj.config && !configObj.config.exercisesPath)
348
370
  throw ValidationError(
349
371
  "No exercises directory to watch: " + configObj.config.exercisesPath
350
- );
372
+ )
351
373
 
352
- this.buildIndex();
374
+ this.buildIndex()
353
375
  watch(configObj?.config?.exercisesPath || "", onChange)
354
376
  .then((/* eventname, filename */) => {
355
- Console.debug("Changes detected on your exercises");
356
- this.buildIndex();
377
+ Console.debug("Changes detected on your exercises")
378
+ this.buildIndex()
357
379
  if (onChange)
358
- onChange();
380
+ onChange()
359
381
  })
360
382
  .catch(error => {
361
- throw error;
362
- });
383
+ throw error
384
+ })
363
385
  },
364
386
  save: () => {
365
- Console.debug("Saving configuration with: ", configObj);
387
+ Console.debug("Saving configuration with: ", configObj)
366
388
 
367
389
  // remove the duplicates form the actions array
368
390
  // configObj.config.actions = [...new Set(configObj.config.actions)];
369
391
  if (configObj.config) {
370
392
  configObj.config.translations = [
371
393
  ...new Set(configObj.config.translations),
372
- ];
373
-
394
+ ]
374
395
  fs.writeFileSync(
375
396
  configObj.config.dirPath + "/config.json",
376
397
  JSON.stringify(configObj, null, 4)
377
- );
398
+ )
378
399
  }
379
400
  },
380
- } as IConfigManager;
381
- };
401
+ } as IConfigManager
402
+ }
382
403
 
383
404
  function deepMerge(...sources: any): any {
384
- let acc: any = {};
405
+ let acc: any = {}
385
406
  for (const source of sources) {
386
407
  if (Array.isArray(source)) {
387
408
  if (!Array.isArray(acc)) {
388
- acc = [];
409
+ acc = []
389
410
  }
390
411
 
391
- acc = [...source];
412
+ acc = [...source]
392
413
  } else if (source instanceof Object) {
393
414
  // eslint-disable-next-line
394
415
  for (let [key, value] of Object.entries(source)) {
395
416
  if (value instanceof Object && key in acc) {
396
- value = deepMerge(acc[key], value);
417
+ value = deepMerge(acc[key], value)
397
418
  }
398
419
 
399
420
  if (value !== undefined)
400
- acc = { ...acc, [key]: value };
421
+ acc = { ...acc, [key]: value }
401
422
  }
402
423
  }
403
424
  }
404
425
 
405
- return acc;
426
+ return acc
406
427
  }