@learnpack/learnpack 2.1.25 → 2.1.27

Sign up to get free protection for your applications and to get access to all the features.
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
  }