@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.
- package/README.md +16 -16
- package/bin/run +17 -17
- package/bin/run.cmd +3 -3
- package/oclif.manifest.json +1 -1
- package/package.json +139 -138
- package/src/commands/audit.ts +134 -109
- package/src/commands/clean.ts +29 -29
- package/src/commands/download.ts +62 -62
- package/src/commands/init.ts +39 -39
- package/src/commands/login.ts +42 -42
- package/src/commands/logout.ts +43 -43
- package/src/commands/publish.ts +107 -107
- package/src/commands/start.ts +264 -234
- package/src/commands/test.ts +85 -85
- package/src/index.ts +1 -1
- package/src/managers/config/allowed_files.ts +29 -29
- package/src/managers/config/defaults.ts +4 -2
- package/src/managers/config/exercise.ts +309 -302
- package/src/managers/config/index.ts +159 -138
- package/src/managers/file.ts +178 -169
- package/src/managers/gitpod.ts +84 -84
- package/src/managers/server/index.ts +78 -69
- package/src/managers/server/routes.ts +139 -90
- package/src/managers/session.ts +147 -118
- package/src/managers/socket.ts +252 -239
- package/src/managers/test.ts +83 -83
- package/src/models/action.ts +10 -3
- package/src/models/config-manager.ts +23 -23
- package/src/models/config.ts +9 -2
- package/src/models/counter.ts +11 -11
- package/src/models/errors.ts +22 -22
- package/src/models/exercise-obj.ts +6 -3
- package/src/models/file.ts +5 -5
- package/src/models/findings.ts +18 -18
- package/src/models/flags.ts +10 -10
- package/src/models/front-matter.ts +11 -11
- package/src/models/gitpod-data.ts +19 -19
- package/src/models/language.ts +4 -4
- package/src/models/package.ts +7 -7
- package/src/models/plugin-config.ts +17 -17
- package/src/models/session.ts +29 -26
- package/src/models/socket.ts +54 -48
- package/src/models/status.ts +16 -15
- package/src/models/success-types.ts +1 -1
- package/src/plugin/command/compile.ts +17 -17
- package/src/plugin/command/test.ts +30 -30
- package/src/plugin/index.ts +6 -6
- package/src/plugin/plugin.ts +94 -94
- package/src/plugin/utils.ts +87 -87
- package/src/types/node-fetch.d.ts +1 -1
- package/src/ui/download.ts +71 -71
- package/src/utils/BaseCommand.ts +48 -48
- package/src/utils/SessionCommand.ts +48 -48
- package/src/utils/api.ts +246 -194
- package/src/utils/audit.ts +392 -395
- package/src/utils/console.ts +24 -24
- package/src/utils/errors.ts +117 -117
- package/src/utils/exercisesQueue.ts +51 -51
- package/src/utils/fileQueue.ts +198 -198
- package/src/utils/misc.ts +23 -23
- package/src/utils/templates/gitignore.txt +19 -19
- package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.es.md +24 -24
- package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.md +24 -24
- package/src/utils/templates/incremental/README.ejs +4 -4
- package/src/utils/templates/incremental/README.es.ejs +4 -4
- package/src/utils/templates/isolated/01-hello-world/README.es.md +26 -26
- package/src/utils/templates/isolated/01-hello-world/README.md +26 -26
- package/src/utils/templates/isolated/README.ejs +4 -4
- package/src/utils/templates/isolated/README.es.ejs +4 -4
- package/src/utils/templates/no-grading/README.ejs +4 -4
- package/src/utils/templates/no-grading/README.es.ejs +4 -4
- package/src/utils/validators.ts +18 -18
- package/src/utils/watcher.ts +14 -14
- package/lib/commands/audit.d.ts +0 -6
- package/lib/commands/audit.js +0 -317
- package/lib/commands/clean.d.ts +0 -8
- package/lib/commands/clean.js +0 -25
- package/lib/commands/download.d.ts +0 -13
- package/lib/commands/download.js +0 -55
- package/lib/commands/init.d.ts +0 -9
- package/lib/commands/init.js +0 -123
- package/lib/commands/login.d.ts +0 -14
- package/lib/commands/login.js +0 -37
- package/lib/commands/logout.d.ts +0 -14
- package/lib/commands/logout.js +0 -37
- package/lib/commands/publish.d.ts +0 -14
- package/lib/commands/publish.js +0 -82
- package/lib/commands/start.d.ts +0 -7
- package/lib/commands/start.js +0 -165
- package/lib/commands/test.d.ts +0 -6
- package/lib/commands/test.js +0 -62
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -4
- package/lib/managers/config/allowed_files.d.ts +0 -5
- package/lib/managers/config/allowed_files.js +0 -30
- package/lib/managers/config/defaults.d.ts +0 -37
- package/lib/managers/config/defaults.js +0 -38
- package/lib/managers/config/exercise.d.ts +0 -36
- package/lib/managers/config/exercise.js +0 -230
- package/lib/managers/config/index.d.ts +0 -3
- package/lib/managers/config/index.js +0 -302
- package/lib/managers/file.d.ts +0 -13
- package/lib/managers/file.js +0 -134
- package/lib/managers/gitpod.d.ts +0 -3
- package/lib/managers/gitpod.js +0 -67
- package/lib/managers/server/index.d.ts +0 -6
- package/lib/managers/server/index.js +0 -51
- package/lib/managers/server/routes.d.ts +0 -4
- package/lib/managers/server/routes.js +0 -167
- package/lib/managers/session.d.ts +0 -3
- package/lib/managers/session.js +0 -104
- package/lib/managers/socket.d.ts +0 -3
- package/lib/managers/socket.js +0 -164
- package/lib/managers/test.d.ts +0 -0
- package/lib/managers/test.js +0 -84
- package/lib/models/action.d.ts +0 -2
- package/lib/models/action.js +0 -2
- package/lib/models/audit.d.ts +0 -15
- package/lib/models/audit.js +0 -2
- package/lib/models/config-manager.d.ts +0 -21
- package/lib/models/config-manager.js +0 -2
- package/lib/models/config.d.ts +0 -60
- package/lib/models/config.js +0 -2
- package/lib/models/counter.d.ts +0 -11
- package/lib/models/counter.js +0 -2
- package/lib/models/errors.d.ts +0 -15
- package/lib/models/errors.js +0 -2
- package/lib/models/exercise-obj.d.ts +0 -27
- package/lib/models/exercise-obj.js +0 -2
- package/lib/models/file.d.ts +0 -5
- package/lib/models/file.js +0 -2
- package/lib/models/findings.d.ts +0 -17
- package/lib/models/findings.js +0 -2
- package/lib/models/flags.d.ts +0 -10
- package/lib/models/flags.js +0 -2
- package/lib/models/front-matter.d.ts +0 -11
- package/lib/models/front-matter.js +0 -2
- package/lib/models/gitpod-data.d.ts +0 -16
- package/lib/models/gitpod-data.js +0 -2
- package/lib/models/language.d.ts +0 -4
- package/lib/models/language.js +0 -2
- package/lib/models/package.d.ts +0 -7
- package/lib/models/package.js +0 -2
- package/lib/models/plugin-config.d.ts +0 -16
- package/lib/models/plugin-config.js +0 -2
- package/lib/models/session.d.ts +0 -23
- package/lib/models/session.js +0 -2
- package/lib/models/socket.d.ts +0 -31
- package/lib/models/socket.js +0 -2
- package/lib/models/status.d.ts +0 -1
- package/lib/models/status.js +0 -2
- package/lib/models/success-types.d.ts +0 -1
- package/lib/models/success-types.js +0 -2
- package/lib/plugin/command/compile.d.ts +0 -6
- package/lib/plugin/command/compile.js +0 -18
- package/lib/plugin/command/test.d.ts +0 -6
- package/lib/plugin/command/test.js +0 -25
- package/lib/plugin/index.d.ts +0 -27
- package/lib/plugin/index.js +0 -7
- package/lib/plugin/plugin.d.ts +0 -8
- package/lib/plugin/plugin.js +0 -68
- package/lib/plugin/utils.d.ts +0 -16
- package/lib/plugin/utils.js +0 -58
- package/lib/ui/download.d.ts +0 -5
- package/lib/ui/download.js +0 -61
- package/lib/utils/BaseCommand.d.ts +0 -8
- package/lib/utils/BaseCommand.js +0 -41
- package/lib/utils/SessionCommand.d.ts +0 -10
- package/lib/utils/SessionCommand.js +0 -47
- package/lib/utils/api.d.ts +0 -12
- package/lib/utils/api.js +0 -173
- package/lib/utils/audit.d.ts +0 -16
- package/lib/utils/audit.js +0 -302
- package/lib/utils/console.d.ts +0 -12
- package/lib/utils/console.js +0 -19
- package/lib/utils/errors.d.ts +0 -17
- package/lib/utils/errors.js +0 -100
- package/lib/utils/exercisesQueue.d.ts +0 -9
- package/lib/utils/exercisesQueue.js +0 -38
- package/lib/utils/fileQueue.d.ts +0 -40
- package/lib/utils/fileQueue.js +0 -168
- package/lib/utils/misc.d.ts +0 -1
- package/lib/utils/misc.js +0 -23
- package/lib/utils/validators.d.ts +0 -5
- package/lib/utils/validators.js +0 -17
- package/lib/utils/watcher.d.ts +0 -2
- 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
|
-
|
|
57
|
-
|
|
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
|
}
|