@learnpack/learnpack 2.1.24 → 2.1.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. package/README.md +16 -16
  2. package/bin/run +17 -17
  3. package/bin/run.cmd +3 -3
  4. package/lib/commands/audit.d.ts +6 -6
  5. package/lib/commands/audit.js +342 -317
  6. package/lib/commands/clean.d.ts +8 -8
  7. package/lib/commands/clean.js +25 -25
  8. package/lib/commands/download.d.ts +13 -13
  9. package/lib/commands/download.js +55 -55
  10. package/lib/commands/init.d.ts +9 -9
  11. package/lib/commands/init.js +123 -123
  12. package/lib/commands/login.d.ts +14 -14
  13. package/lib/commands/login.js +37 -37
  14. package/lib/commands/logout.d.ts +14 -14
  15. package/lib/commands/logout.js +37 -37
  16. package/lib/commands/publish.d.ts +14 -14
  17. package/lib/commands/publish.js +82 -82
  18. package/lib/commands/start.d.ts +7 -7
  19. package/lib/commands/start.js +165 -165
  20. package/lib/commands/test.d.ts +6 -6
  21. package/lib/commands/test.js +62 -62
  22. package/lib/index.d.ts +1 -1
  23. package/lib/index.js +4 -4
  24. package/lib/managers/config/allowed_files.d.ts +5 -5
  25. package/lib/managers/config/allowed_files.js +30 -30
  26. package/lib/managers/config/defaults.d.ts +39 -37
  27. package/lib/managers/config/defaults.js +40 -38
  28. package/lib/managers/config/exercise.d.ts +36 -36
  29. package/lib/managers/config/exercise.js +233 -230
  30. package/lib/managers/config/index.d.ts +3 -3
  31. package/lib/managers/config/index.js +320 -302
  32. package/lib/managers/file.d.ts +13 -13
  33. package/lib/managers/file.js +134 -134
  34. package/lib/managers/gitpod.d.ts +3 -3
  35. package/lib/managers/gitpod.js +67 -67
  36. package/lib/managers/server/index.d.ts +6 -6
  37. package/lib/managers/server/index.js +58 -51
  38. package/lib/managers/server/routes.d.ts +4 -4
  39. package/lib/managers/server/routes.js +167 -167
  40. package/lib/managers/session.d.ts +3 -3
  41. package/lib/managers/session.js +104 -104
  42. package/lib/managers/socket.d.ts +3 -3
  43. package/lib/managers/socket.js +164 -164
  44. package/lib/managers/test.js +84 -84
  45. package/lib/models/action.d.ts +2 -2
  46. package/lib/models/action.js +2 -2
  47. package/lib/models/audit.d.ts +15 -15
  48. package/lib/models/audit.js +2 -2
  49. package/lib/models/config-manager.d.ts +21 -21
  50. package/lib/models/config-manager.js +2 -2
  51. package/lib/models/config.d.ts +62 -60
  52. package/lib/models/config.js +2 -2
  53. package/lib/models/counter.d.ts +11 -11
  54. package/lib/models/counter.js +2 -2
  55. package/lib/models/errors.d.ts +15 -15
  56. package/lib/models/errors.js +2 -2
  57. package/lib/models/exercise-obj.d.ts +27 -27
  58. package/lib/models/exercise-obj.js +2 -2
  59. package/lib/models/file.d.ts +5 -5
  60. package/lib/models/file.js +2 -2
  61. package/lib/models/findings.d.ts +17 -17
  62. package/lib/models/findings.js +2 -2
  63. package/lib/models/flags.d.ts +10 -10
  64. package/lib/models/flags.js +2 -2
  65. package/lib/models/front-matter.d.ts +11 -11
  66. package/lib/models/front-matter.js +2 -2
  67. package/lib/models/gitpod-data.d.ts +16 -16
  68. package/lib/models/gitpod-data.js +2 -2
  69. package/lib/models/language.d.ts +4 -4
  70. package/lib/models/language.js +2 -2
  71. package/lib/models/package.d.ts +7 -7
  72. package/lib/models/package.js +2 -2
  73. package/lib/models/plugin-config.d.ts +16 -16
  74. package/lib/models/plugin-config.js +2 -2
  75. package/lib/models/session.d.ts +23 -23
  76. package/lib/models/session.js +2 -2
  77. package/lib/models/socket.d.ts +31 -31
  78. package/lib/models/socket.js +2 -2
  79. package/lib/models/status.d.ts +1 -1
  80. package/lib/models/status.js +2 -2
  81. package/lib/models/success-types.d.ts +1 -1
  82. package/lib/models/success-types.js +2 -2
  83. package/lib/plugin/command/compile.d.ts +6 -6
  84. package/lib/plugin/command/compile.js +18 -18
  85. package/lib/plugin/command/test.d.ts +6 -6
  86. package/lib/plugin/command/test.js +25 -25
  87. package/lib/plugin/index.d.ts +27 -27
  88. package/lib/plugin/index.js +7 -7
  89. package/lib/plugin/plugin.d.ts +8 -8
  90. package/lib/plugin/plugin.js +68 -68
  91. package/lib/plugin/utils.d.ts +16 -16
  92. package/lib/plugin/utils.js +58 -58
  93. package/lib/ui/download.d.ts +5 -5
  94. package/lib/ui/download.js +61 -61
  95. package/lib/utils/BaseCommand.d.ts +8 -8
  96. package/lib/utils/BaseCommand.js +41 -41
  97. package/lib/utils/SessionCommand.d.ts +10 -10
  98. package/lib/utils/SessionCommand.js +47 -47
  99. package/lib/utils/api.d.ts +12 -12
  100. package/lib/utils/api.js +173 -173
  101. package/lib/utils/audit.d.ts +16 -16
  102. package/lib/utils/audit.js +302 -302
  103. package/lib/utils/console.d.ts +12 -12
  104. package/lib/utils/console.js +19 -19
  105. package/lib/utils/errors.d.ts +17 -17
  106. package/lib/utils/errors.js +100 -100
  107. package/lib/utils/exercisesQueue.d.ts +9 -9
  108. package/lib/utils/exercisesQueue.js +38 -38
  109. package/lib/utils/fileQueue.d.ts +40 -40
  110. package/lib/utils/fileQueue.js +168 -168
  111. package/lib/utils/misc.d.ts +1 -1
  112. package/lib/utils/misc.js +23 -23
  113. package/lib/utils/validators.d.ts +5 -5
  114. package/lib/utils/validators.js +17 -17
  115. package/lib/utils/watcher.d.ts +2 -2
  116. package/lib/utils/watcher.js +23 -23
  117. package/oclif.manifest.json +1 -1
  118. package/package.json +138 -138
  119. package/src/commands/audit.ts +443 -418
  120. package/src/commands/clean.ts +29 -29
  121. package/src/commands/download.ts +62 -62
  122. package/src/commands/login.ts +42 -42
  123. package/src/commands/logout.ts +43 -43
  124. package/src/commands/publish.ts +107 -107
  125. package/src/commands/start.ts +238 -234
  126. package/src/commands/test.ts +85 -85
  127. package/src/index.ts +1 -1
  128. package/src/managers/config/allowed_files.ts +29 -29
  129. package/src/managers/config/defaults.ts +2 -0
  130. package/src/managers/config/exercise.ts +309 -302
  131. package/src/managers/config/index.ts +22 -1
  132. package/src/managers/file.ts +169 -169
  133. package/src/managers/gitpod.ts +84 -84
  134. package/src/managers/server/index.ts +77 -69
  135. package/src/managers/session.ts +118 -118
  136. package/src/managers/socket.ts +239 -239
  137. package/src/managers/test.ts +83 -83
  138. package/src/models/action.ts +3 -3
  139. package/src/models/config-manager.ts +23 -23
  140. package/src/models/config.ts +2 -0
  141. package/src/models/counter.ts +11 -11
  142. package/src/models/errors.ts +22 -22
  143. package/src/models/file.ts +5 -5
  144. package/src/models/findings.ts +18 -18
  145. package/src/models/flags.ts +10 -10
  146. package/src/models/front-matter.ts +11 -11
  147. package/src/models/gitpod-data.ts +19 -19
  148. package/src/models/language.ts +4 -4
  149. package/src/models/package.ts +7 -7
  150. package/src/models/plugin-config.ts +17 -17
  151. package/src/models/session.ts +26 -26
  152. package/src/models/socket.ts +48 -48
  153. package/src/models/status.ts +15 -15
  154. package/src/models/success-types.ts +1 -1
  155. package/src/plugin/command/compile.ts +17 -17
  156. package/src/plugin/command/test.ts +30 -30
  157. package/src/plugin/index.ts +6 -6
  158. package/src/plugin/plugin.ts +94 -94
  159. package/src/plugin/utils.ts +87 -87
  160. package/src/types/node-fetch.d.ts +1 -1
  161. package/src/ui/download.ts +71 -71
  162. package/src/utils/BaseCommand.ts +48 -48
  163. package/src/utils/SessionCommand.ts +48 -48
  164. package/src/utils/api.ts +194 -194
  165. package/src/utils/audit.ts +395 -395
  166. package/src/utils/console.ts +24 -24
  167. package/src/utils/errors.ts +117 -117
  168. package/src/utils/exercisesQueue.ts +51 -51
  169. package/src/utils/fileQueue.ts +198 -198
  170. package/src/utils/misc.ts +23 -23
  171. package/src/utils/templates/gitignore.txt +19 -19
  172. package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.es.md +24 -24
  173. package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.md +24 -24
  174. package/src/utils/templates/incremental/README.ejs +4 -4
  175. package/src/utils/templates/incremental/README.es.ejs +4 -4
  176. package/src/utils/templates/isolated/01-hello-world/README.es.md +26 -26
  177. package/src/utils/templates/isolated/01-hello-world/README.md +26 -26
  178. package/src/utils/templates/isolated/README.ejs +4 -4
  179. package/src/utils/templates/isolated/README.es.ejs +4 -4
  180. package/src/utils/templates/no-grading/README.ejs +4 -4
  181. package/src/utils/templates/no-grading/README.es.ejs +4 -4
  182. package/src/utils/validators.ts +18 -18
@@ -1,230 +1,233 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.filterFiles = exports.detect = exports.isDirectory = exports.shouldBeVisible = exports.isCodable = exports.validateExerciseDirectoryName = exports.exercise = void 0;
4
- const p = require("path");
5
- // import frontMatter from 'front-matter'
6
- const fs = require("fs");
7
- const console_1 = require("../../utils/console");
8
- const allowed_files_1 = require("./allowed_files");
9
- // eslint-disable-next-line
10
- const frontMatter = require("front-matter");
11
- exports.exercise = (path, position, configObject) => {
12
- const { config, exercises } = configObject;
13
- let slug = p.basename(path);
14
- if (!exports.validateExerciseDirectoryName(slug)) {
15
- console_1.default.error(`Exercise directory ${slug} has an invalid name, it has to start with two or three digits followed by words separated by underscors or hyphen (no white spaces). e.g: 01.12-hello-world`);
16
- }
17
- // get all the files
18
- const files = fs.readdirSync(path);
19
- /**
20
- * build the translation array like:
21
- {
22
- "us": "path/to/Readme.md",
23
- "es": "path/to/Readme.es.md"
24
- }
25
- */
26
- const translations = {};
27
- for (const file of files.filter(file => file.toLowerCase().includes("readme"))) {
28
- const parts = file.split(".");
29
- if (parts.length === 3)
30
- translations[parts[1]] = file;
31
- else
32
- translations.us = file;
33
- }
34
- // if the slug is a dot, it means there is not "exercises" folder, and its just a single README.md
35
- if (slug === ".")
36
- slug = "default-index";
37
- const detected = exports.detect(configObject, files);
38
- const exerciseObj = {
39
- position,
40
- path,
41
- slug,
42
- translations,
43
- language: detected === null || detected === void 0 ? void 0 : detected.language,
44
- entry: (detected === null || detected === void 0 ? void 0 : detected.entry) ? path + "/" + detected.entry : null,
45
- title: slug || "Exercise",
46
- graded: files.some(file => file.toLowerCase().startsWith("test.") ||
47
- file.toLowerCase().startsWith("tests.")),
48
- files: exports.filterFiles(files, path),
49
- // if the exercises was on the config before I may keep the status done
50
- done: Array.isArray(exercises) &&
51
- typeof exercises[position] !== "undefined" &&
52
- path.slice(Math.max(0, path.indexOf("exercises/") + 10)) ===
53
- exercises[position].slug ?
54
- exercises[position].done :
55
- false,
56
- getReadme: function (lang = null) {
57
- if (lang === "us")
58
- lang = null; // <-- english is default, no need to append it to the file name
59
- if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`)) {
60
- console_1.default.error(`Language ${lang} not found for exercise ${slug}, switching to default language`);
61
- if (lang)
62
- lang = null;
63
- if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`))
64
- throw new Error("Readme file not found for exercise: " + this.path + "/README.md");
65
- }
66
- const content = fs.readFileSync(`${this.path}/README${lang ? "." + lang : ""}.md`, "utf8");
67
- const attr = frontMatter(content);
68
- return attr;
69
- },
70
- getFile: function (name) {
71
- const file = this.files.find((f) => f.name === name);
72
- if (!file || !fs.existsSync(file.path)) {
73
- throw new Error(`File not found: + ${file === null || file === void 0 ? void 0 : file.path}`);
74
- }
75
- else if (fs.lstatSync(file.path).isDirectory()) {
76
- return ("Error: This is not a file to be read, but a directory: " + file.path);
77
- }
78
- // get file content
79
- const content = fs.readFileSync(file.path);
80
- // create reset folder
81
- if (!fs.existsSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets`))
82
- fs.mkdirSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets`);
83
- if (!fs.existsSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/` + this.slug)) {
84
- fs.mkdirSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/` + this.slug);
85
- if (!fs.existsSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/${this.slug}/${name}`)) {
86
- fs.writeFileSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/${this.slug}/${name}`, content);
87
- }
88
- }
89
- return content;
90
- },
91
- saveFile: function (name, content) {
92
- const file = this.files.find((f) => f.name === name);
93
- if (file) {
94
- if (!fs.existsSync(file.path)) {
95
- throw new Error("File not found: " + file.path);
96
- }
97
- return fs.writeFileSync(file.path, content, "utf8");
98
- }
99
- },
100
- getTestReport: function () {
101
- var _a;
102
- const _path = `${(_a = configObject === null || configObject === void 0 ? void 0 : configObject.confPath) === null || _a === void 0 ? void 0 : _a.base}/reports/${this.slug}.json`;
103
- if (!fs.existsSync(_path))
104
- return {};
105
- const content = fs.readFileSync(_path);
106
- const data = JSON.parse(`${content}`);
107
- return data;
108
- },
109
- };
110
- return exerciseObj;
111
- };
112
- exports.validateExerciseDirectoryName = (str) => {
113
- if (str === "./")
114
- return true;
115
- // TODO: Add nameValidationREgex from the config
116
- const regex = /^(\d{2,3}(\.\d{1,2})?-([\dA-Za-z]+(-|_)?)+)$/;
117
- return regex.test(str);
118
- };
119
- exports.isCodable = (str) => {
120
- const extension = p.extname(str);
121
- return allowed_files_1.default.extensions.includes(extension.slice(1).toLowerCase());
122
- };
123
- const isNotConfiguration = (str) => {
124
- return !allowed_files_1.default.names.includes(str);
125
- };
126
- exports.shouldBeVisible = function (file) {
127
- return (
128
- // doest not have "test." on their name
129
- !file.name.toLocaleLowerCase().includes("test.") &&
130
- !file.name.toLocaleLowerCase().includes("tests.") &&
131
- !file.name.toLocaleLowerCase().includes(".hide.") &&
132
- // ignore hidden files
133
- file.name.charAt(0) !== "." &&
134
- // ignore learn.json and bc.json
135
- !file.name.toLocaleLowerCase().includes("learn.json") &&
136
- !file.name.toLocaleLowerCase().includes("bc.json") &&
137
- // ignore images, videos, vectors, etc.
138
- exports.isCodable(file.name) &&
139
- isNotConfiguration(file.name) &&
140
- // readme's and directories
141
- !file.name.toLowerCase().includes("readme.") &&
142
- !exports.isDirectory(file.path) &&
143
- file.name.charAt(0) !== "_");
144
- };
145
- exports.isDirectory = (source) => {
146
- // if(path.basename(source) === path.basename(config.dirPath)) return false
147
- return fs.lstatSync(source).isDirectory();
148
- };
149
- exports.detect = (configObject, files) => {
150
- if (!configObject) {
151
- return;
152
- }
153
- const { config } = configObject;
154
- if (!config)
155
- throw new Error("No configuration found during the engine detection");
156
- if (!config.entries)
157
- throw new Error("No configuration found for entries, please add a 'entries' object with the default file name for your exercise entry file that is going to be used while compiling, for example: index.html for html, app.py for python3, etc.");
158
- // A language was found on the config object, but this language will only be used as last resort, learnpack will try to guess each exercise language independently based on file extension (js, jsx, html, etc.)
159
- let hasFiles = files.filter(f => f.includes(".py"));
160
- if (hasFiles.length > 0)
161
- return {
162
- language: "python3",
163
- entry: hasFiles.find(f => config.entries.python3 === f),
164
- };
165
- hasFiles = files.filter(f => f.includes(".java"));
166
- if (hasFiles.length > 0)
167
- return {
168
- language: "java",
169
- entry: hasFiles.find(f => config.entries.java === f),
170
- };
171
- hasFiles = files.filter(f => f.includes(".jsx"));
172
- if (hasFiles.length > 0)
173
- return {
174
- language: "react",
175
- entry: hasFiles.find(f => config.entries.react === f),
176
- };
177
- const hasHTML = files.filter(f => f.includes("index.html"));
178
- const hasIndexJS = files.find(f => f.includes("index.js"));
179
- const hasJS = files.filter(f => f.includes(".js"));
180
- // angular, vue, vanillajs needs to have at least 2 files (html,css,js),
181
- // the test.js and the entry file in js
182
- // if not its just another HTML
183
- if (hasIndexJS && hasHTML.length > 0)
184
- return {
185
- language: "vanillajs",
186
- entry: hasIndexJS,
187
- };
188
- if (hasHTML.length > 0)
189
- return {
190
- language: "html",
191
- entry: hasHTML.find(f => config.entries.html === f),
192
- };
193
- if (hasJS.length > 0)
194
- return {
195
- language: "node",
196
- entry: hasJS.find(f => config.entries.node === f),
197
- };
198
- return {
199
- language: null,
200
- entry: null,
201
- };
202
- };
203
- exports.filterFiles = (files, basePath = ".") => files
204
- .map((ex) => ({
205
- path: basePath + "/" + ex,
206
- name: ex,
207
- hidden: !exports.shouldBeVisible({
208
- name: ex,
209
- path: basePath + "/" + ex,
210
- }),
211
- }))
212
- .sort((f1, f2) => {
213
- const score = {
214
- // sorting priority
215
- "index.html": 1,
216
- "styles.css": 2,
217
- "styles.scss": 2,
218
- "style.css": 2,
219
- "style.scss": 2,
220
- "index.css": 2,
221
- "index.scss": 2,
222
- "index.js": 3,
223
- };
224
- return score[f1.name] < score[f2.name] ? -1 : 1;
225
- });
226
- exports.default = {
227
- exercise: exports.exercise,
228
- detect: exports.detect,
229
- filterFiles: exports.filterFiles,
230
- };
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterFiles = exports.detect = exports.isDirectory = exports.shouldBeVisible = exports.isCodable = exports.validateExerciseDirectoryName = exports.exercise = void 0;
4
+ const p = require("path");
5
+ // import frontMatter from 'front-matter'
6
+ const fs = require("fs");
7
+ const console_1 = require("../../utils/console");
8
+ const allowed_files_1 = require("./allowed_files");
9
+ // eslint-disable-next-line
10
+ const frontMatter = require("front-matter");
11
+ exports.exercise = (path, position, configObject) => {
12
+ const { config, exercises } = configObject;
13
+ let slug = p.basename(path);
14
+ if (!exports.validateExerciseDirectoryName(slug)) {
15
+ console_1.default.error(`Exercise directory ${slug} has an invalid name, it has to start with two or three digits followed by words separated by underscors or hyphen (no white spaces). e.g: 01.12-hello-world`);
16
+ }
17
+ // get all the files
18
+ const files = fs.readdirSync(path);
19
+ /**
20
+ * build the translation array like:
21
+ {
22
+ "us": "path/to/Readme.md",
23
+ "es": "path/to/Readme.es.md"
24
+ }
25
+ */
26
+ const translations = {};
27
+ for (const file of files.filter(file => file.toLowerCase().includes("readme"))) {
28
+ const parts = file.split(".");
29
+ if (parts.length === 3)
30
+ translations[parts[1]] = file;
31
+ else
32
+ translations.us = file;
33
+ }
34
+ // if the slug is a dot, it means there is not "exercises" folder, and its just a single README.md
35
+ if (slug === ".")
36
+ slug = "default-index";
37
+ const detected = exports.detect(configObject, files);
38
+ const exerciseObj = {
39
+ position,
40
+ path,
41
+ slug,
42
+ translations,
43
+ language: detected === null || detected === void 0 ? void 0 : detected.language,
44
+ entry: (detected === null || detected === void 0 ? void 0 : detected.entry) ? path + "/" + detected.entry : null,
45
+ title: slug || "Exercise",
46
+ graded: files.some((file) => file.toLowerCase().startsWith("test.") ||
47
+ file.toLowerCase().startsWith("tests.")),
48
+ files: exports.filterFiles(files, path),
49
+ // if the exercises was on the config before I may keep the status done
50
+ done: Array.isArray(exercises) &&
51
+ typeof exercises[position] !== "undefined" &&
52
+ path.slice(Math.max(0, path.indexOf("exercises/") + 10)) ===
53
+ exercises[position].slug ?
54
+ exercises[position].done :
55
+ false,
56
+ getReadme: function (lang = null) {
57
+ if (lang === "us")
58
+ lang = null; // <-- english is default, no need to append it to the file name
59
+ if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`)) {
60
+ console_1.default.error(`Language ${lang} not found for exercise ${slug}, switching to default language`);
61
+ if (lang)
62
+ lang = null;
63
+ if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`))
64
+ throw new Error("Readme file not found for exercise: " + this.path + "/README.md");
65
+ }
66
+ const content = fs.readFileSync(`${this.path}/README${lang ? "." + lang : ""}.md`, "utf8");
67
+ const attr = frontMatter(content);
68
+ return attr;
69
+ },
70
+ getFile: function (name) {
71
+ const file = this.files.find((f) => f.name === name);
72
+ if (!file || !fs.existsSync(file.path)) {
73
+ throw new Error(`File not found: + ${file === null || file === void 0 ? void 0 : file.path}`);
74
+ }
75
+ else if (fs.lstatSync(file.path).isDirectory()) {
76
+ return ("Error: This is not a file to be read, but a directory: " + file.path);
77
+ }
78
+ // get file content
79
+ const content = fs.readFileSync(file.path);
80
+ // create reset folder
81
+ if (!fs.existsSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets`))
82
+ fs.mkdirSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets`);
83
+ if (!fs.existsSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/` + this.slug)) {
84
+ fs.mkdirSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/` + this.slug);
85
+ for (const _file of this.files) {
86
+ const fileContent = fs.readFileSync(_file.path);
87
+ if (!fs.existsSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/${this.slug}/${_file.name}`)) {
88
+ fs.writeFileSync(`${config === null || config === void 0 ? void 0 : config.dirPath}/resets/${this.slug}/${_file.name}`, fileContent);
89
+ }
90
+ }
91
+ }
92
+ return content;
93
+ },
94
+ saveFile: function (name, content) {
95
+ const file = this.files.find((f) => f.name === name);
96
+ if (file) {
97
+ if (!fs.existsSync(file.path)) {
98
+ throw new Error("File not found: " + file.path);
99
+ }
100
+ return fs.writeFileSync(file.path, content, "utf8");
101
+ }
102
+ },
103
+ getTestReport: function () {
104
+ var _a;
105
+ const _path = `${(_a = configObject === null || configObject === void 0 ? void 0 : configObject.confPath) === null || _a === void 0 ? void 0 : _a.base}/reports/${this.slug}.json`;
106
+ if (!fs.existsSync(_path))
107
+ return {};
108
+ const content = fs.readFileSync(_path);
109
+ const data = JSON.parse(`${content}`);
110
+ return data;
111
+ },
112
+ };
113
+ return exerciseObj;
114
+ };
115
+ exports.validateExerciseDirectoryName = (str) => {
116
+ if (str === "./")
117
+ return true;
118
+ // TODO: Add nameValidationREgex from the config
119
+ const regex = /^(\d{2,3}(\.\d{1,2})?-([\dA-Za-z]+(-|_)?)+)$/;
120
+ return regex.test(str);
121
+ };
122
+ exports.isCodable = (str) => {
123
+ const extension = p.extname(str);
124
+ return allowed_files_1.default.extensions.includes(extension.slice(1).toLowerCase());
125
+ };
126
+ const isNotConfiguration = (str) => {
127
+ return !allowed_files_1.default.names.includes(str);
128
+ };
129
+ exports.shouldBeVisible = function (file) {
130
+ return (
131
+ // doest not have "test." on their name
132
+ !file.name.toLocaleLowerCase().includes("test.") &&
133
+ !file.name.toLocaleLowerCase().includes("tests.") &&
134
+ !file.name.toLocaleLowerCase().includes(".hide.") &&
135
+ // ignore hidden files
136
+ file.name.charAt(0) !== "." &&
137
+ // ignore learn.json and bc.json
138
+ !file.name.toLocaleLowerCase().includes("learn.json") &&
139
+ !file.name.toLocaleLowerCase().includes("bc.json") &&
140
+ // ignore images, videos, vectors, etc.
141
+ exports.isCodable(file.name) &&
142
+ isNotConfiguration(file.name) &&
143
+ // readme's and directories
144
+ !file.name.toLowerCase().includes("readme.") &&
145
+ !exports.isDirectory(file.path) &&
146
+ file.name.charAt(0) !== "_");
147
+ };
148
+ exports.isDirectory = (source) => {
149
+ // if(path.basename(source) === path.basename(config.dirPath)) return false
150
+ return fs.lstatSync(source).isDirectory();
151
+ };
152
+ exports.detect = (configObject, files) => {
153
+ if (!configObject) {
154
+ return;
155
+ }
156
+ const { config } = configObject;
157
+ if (!config)
158
+ throw new Error("No configuration found during the engine detection");
159
+ if (!config.entries)
160
+ throw new Error("No configuration found for entries, please add a 'entries' object with the default file name for your exercise entry file that is going to be used while compiling, for example: index.html for html, app.py for python3, etc.");
161
+ // A language was found on the config object, but this language will only be used as last resort, learnpack will try to guess each exercise language independently based on file extension (js, jsx, html, etc.)
162
+ let hasFiles = files.filter(f => f.includes(".py"));
163
+ if (hasFiles.length > 0)
164
+ return {
165
+ language: "python3",
166
+ entry: hasFiles.find(f => config.entries.python3 === f),
167
+ };
168
+ hasFiles = files.filter(f => f.includes(".java"));
169
+ if (hasFiles.length > 0)
170
+ return {
171
+ language: "java",
172
+ entry: hasFiles.find(f => config.entries.java === f),
173
+ };
174
+ hasFiles = files.filter(f => f.includes(".jsx"));
175
+ if (hasFiles.length > 0)
176
+ return {
177
+ language: "react",
178
+ entry: hasFiles.find(f => config.entries.react === f),
179
+ };
180
+ const hasHTML = files.filter(f => f.includes("index.html"));
181
+ const hasIndexJS = files.find(f => f.includes("index.js"));
182
+ const hasJS = files.filter(f => f.includes(".js"));
183
+ // angular, vue, vanillajs needs to have at least 2 files (html,css,js),
184
+ // the test.js and the entry file in js
185
+ // if not its just another HTML
186
+ if (hasIndexJS && hasHTML.length > 0)
187
+ return {
188
+ language: "vanillajs",
189
+ entry: hasIndexJS,
190
+ };
191
+ if (hasHTML.length > 0)
192
+ return {
193
+ language: "html",
194
+ entry: hasHTML.find(f => config.entries.html === f),
195
+ };
196
+ if (hasJS.length > 0)
197
+ return {
198
+ language: "node",
199
+ entry: hasJS.find(f => config.entries.node === f),
200
+ };
201
+ return {
202
+ language: null,
203
+ entry: null,
204
+ };
205
+ };
206
+ exports.filterFiles = (files, basePath = ".") => files
207
+ .map((ex) => ({
208
+ path: basePath + "/" + ex,
209
+ name: ex,
210
+ hidden: !exports.shouldBeVisible({
211
+ name: ex,
212
+ path: basePath + "/" + ex,
213
+ }),
214
+ }))
215
+ .sort((f1, f2) => {
216
+ const score = {
217
+ // sorting priority
218
+ "index.html": 1,
219
+ "styles.css": 2,
220
+ "styles.scss": 2,
221
+ "style.css": 2,
222
+ "style.scss": 2,
223
+ "index.css": 2,
224
+ "index.scss": 2,
225
+ "index.js": 3,
226
+ };
227
+ return score[f1.name] < score[f2.name] ? -1 : 1;
228
+ });
229
+ exports.default = {
230
+ exercise: exports.exercise,
231
+ detect: exports.detect,
232
+ filterFiles: exports.filterFiles,
233
+ };
@@ -1,3 +1,3 @@
1
- import { IConfigManagerAttributes, IConfigManager } from "../../models/config-manager";
2
- declare const _default: ({ grading, mode, disableGrading, version, }: IConfigManagerAttributes) => Promise<IConfigManager>;
3
- export default _default;
1
+ import { IConfigManagerAttributes, IConfigManager } from "../../models/config-manager";
2
+ declare const _default: ({ grading, mode, disableGrading, version, }: IConfigManagerAttributes) => Promise<IConfigManager>;
3
+ export default _default;