@learnpack/learnpack 2.0.13 → 2.0.16
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +10 -10
- package/lib/commands/audit.d.ts +6 -0
- package/lib/commands/audit.js +369 -0
- package/lib/commands/clean.d.ts +8 -0
- package/lib/commands/clean.js +25 -0
- package/lib/commands/download.d.ts +13 -0
- package/lib/commands/download.js +55 -0
- package/lib/commands/init.d.ts +9 -0
- package/lib/commands/init.js +117 -0
- package/lib/commands/login.d.ts +14 -0
- package/lib/commands/login.js +37 -0
- package/lib/commands/logout.d.ts +14 -0
- package/lib/commands/logout.js +37 -0
- package/lib/commands/publish.d.ts +14 -0
- package/lib/commands/publish.js +82 -0
- package/lib/commands/start.d.ts +7 -0
- package/lib/commands/start.js +165 -0
- package/lib/commands/test.d.ts +6 -0
- package/lib/commands/test.js +62 -0
- package/lib/index.d.ts +1 -0
- package/lib/managers/config/allowed_files.d.ts +5 -0
- package/lib/managers/config/allowed_files.js +30 -0
- package/lib/managers/config/defaults.d.ts +34 -0
- package/lib/managers/config/defaults.js +35 -0
- package/lib/managers/config/exercise.d.ts +36 -0
- package/lib/managers/config/exercise.js +230 -0
- package/lib/managers/config/index.d.ts +3 -0
- package/lib/managers/config/index.js +307 -0
- package/lib/managers/file.d.ts +13 -0
- package/lib/managers/file.js +134 -0
- package/lib/managers/gitpod.d.ts +3 -0
- package/lib/managers/gitpod.js +67 -0
- package/lib/managers/server/index.d.ts +6 -0
- package/lib/managers/server/index.js +51 -0
- package/lib/managers/server/routes.d.ts +4 -0
- package/lib/managers/server/routes.js +160 -0
- package/lib/managers/session.d.ts +3 -0
- package/lib/managers/session.js +104 -0
- package/lib/managers/socket.d.ts +3 -0
- package/lib/managers/socket.js +164 -0
- package/lib/managers/test.d.ts +0 -0
- package/lib/managers/test.js +84 -0
- package/lib/models/action.d.ts +2 -0
- package/lib/models/action.js +2 -0
- package/lib/models/audit-errors.d.ts +4 -0
- package/lib/models/audit-errors.js +2 -0
- package/lib/models/config-manager.d.ts +21 -0
- package/lib/models/config-manager.js +2 -0
- package/lib/models/config.d.ts +57 -0
- package/lib/models/config.js +2 -0
- package/lib/models/counter.d.ts +11 -0
- package/lib/models/counter.js +2 -0
- package/lib/models/errors.d.ts +15 -0
- package/lib/models/errors.js +2 -0
- package/lib/models/exercise-obj.d.ts +27 -0
- package/lib/models/exercise-obj.js +2 -0
- package/lib/models/file.d.ts +5 -0
- package/lib/models/file.js +2 -0
- package/lib/models/findings.d.ts +17 -0
- package/lib/models/findings.js +2 -0
- package/lib/models/flags.d.ts +10 -0
- package/lib/models/flags.js +2 -0
- package/lib/models/front-matter.d.ts +11 -0
- package/lib/models/front-matter.js +2 -0
- package/lib/models/gitpod-data.d.ts +16 -0
- package/lib/models/gitpod-data.js +2 -0
- package/lib/models/language.d.ts +4 -0
- package/lib/models/language.js +2 -0
- package/lib/models/package.d.ts +7 -0
- package/lib/models/package.js +2 -0
- package/lib/models/plugin-config.d.ts +16 -0
- package/lib/models/plugin-config.js +2 -0
- package/lib/models/session.d.ts +23 -0
- package/lib/models/session.js +2 -0
- package/lib/models/socket.d.ts +31 -0
- package/lib/models/socket.js +2 -0
- package/lib/models/status.d.ts +1 -0
- package/lib/models/status.js +2 -0
- package/lib/models/success-types.d.ts +1 -0
- package/lib/models/success-types.js +2 -0
- package/lib/plugin/command/compile.d.ts +6 -0
- package/lib/plugin/command/compile.js +18 -0
- package/lib/plugin/command/test.d.ts +6 -0
- package/lib/plugin/command/test.js +25 -0
- package/lib/plugin/index.d.ts +27 -0
- package/lib/plugin/index.js +7 -0
- package/lib/plugin/plugin.d.ts +8 -0
- package/lib/plugin/plugin.js +68 -0
- package/lib/plugin/utils.d.ts +16 -0
- package/lib/plugin/utils.js +58 -0
- package/lib/ui/download.d.ts +5 -0
- package/lib/ui/download.js +61 -0
- package/lib/utils/BaseCommand.d.ts +8 -0
- package/lib/utils/BaseCommand.js +41 -0
- package/lib/utils/SessionCommand.d.ts +10 -0
- package/lib/utils/SessionCommand.js +47 -0
- package/lib/utils/api.d.ts +12 -0
- package/lib/utils/api.js +173 -0
- package/lib/utils/audit.d.ts +13 -0
- package/lib/utils/audit.js +129 -0
- package/lib/utils/console.d.ts +12 -0
- package/lib/utils/console.js +19 -0
- package/lib/utils/errors.d.ts +17 -0
- package/lib/utils/errors.js +100 -0
- package/lib/utils/exercisesQueue.d.ts +9 -0
- package/lib/utils/exercisesQueue.js +38 -0
- package/lib/utils/fileQueue.d.ts +40 -0
- package/lib/utils/fileQueue.js +168 -0
- package/lib/utils/misc.d.ts +1 -0
- package/lib/utils/misc.js +23 -0
- package/lib/utils/validators.d.ts +5 -0
- package/lib/utils/validators.js +17 -0
- package/lib/utils/watcher.d.ts +2 -0
- package/lib/utils/watcher.js +24 -0
- package/oclif.manifest.json +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
@@ -21,7 +21,7 @@ $ npm install -g @learnpack/learnpack
|
|
21
21
|
$ learnpack COMMAND
|
22
22
|
running command...
|
23
23
|
$ learnpack (-v|--version|version)
|
24
|
-
@learnpack/learnpack/2.0.
|
24
|
+
@learnpack/learnpack/2.0.16 win32-x64 node-v16.14.0
|
25
25
|
$ learnpack --help [COMMAND]
|
26
26
|
USAGE
|
27
27
|
$ learnpack COMMAND
|
@@ -74,7 +74,7 @@ DESCRIPTION
|
|
74
74
|
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
75
75
|
```
|
76
76
|
|
77
|
-
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
77
|
+
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\audit.ts)_
|
78
78
|
|
79
79
|
## `learnpack clean`
|
80
80
|
|
@@ -89,7 +89,7 @@ DESCRIPTION
|
|
89
89
|
Extra documentation goes here
|
90
90
|
```
|
91
91
|
|
92
|
-
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
92
|
+
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\clean.ts)_
|
93
93
|
|
94
94
|
## `learnpack download [PACKAGE]`
|
95
95
|
|
@@ -107,7 +107,7 @@ DESCRIPTION
|
|
107
107
|
Extra documentation goes here
|
108
108
|
```
|
109
109
|
|
110
|
-
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
110
|
+
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\download.ts)_
|
111
111
|
|
112
112
|
## `learnpack help [COMMAND]`
|
113
113
|
|
@@ -138,7 +138,7 @@ OPTIONS
|
|
138
138
|
-h, --grading show CLI help
|
139
139
|
```
|
140
140
|
|
141
|
-
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
141
|
+
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\init.ts)_
|
142
142
|
|
143
143
|
## `learnpack login [PACKAGE]`
|
144
144
|
|
@@ -156,7 +156,7 @@ DESCRIPTION
|
|
156
156
|
Extra documentation goes here
|
157
157
|
```
|
158
158
|
|
159
|
-
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
159
|
+
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\login.ts)_
|
160
160
|
|
161
161
|
## `learnpack logout [PACKAGE]`
|
162
162
|
|
@@ -174,7 +174,7 @@ DESCRIPTION
|
|
174
174
|
Extra documentation goes here
|
175
175
|
```
|
176
176
|
|
177
|
-
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
177
|
+
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\logout.ts)_
|
178
178
|
|
179
179
|
## `learnpack plugins`
|
180
180
|
|
@@ -309,7 +309,7 @@ DESCRIPTION
|
|
309
309
|
Extra documentation goes here
|
310
310
|
```
|
311
311
|
|
312
|
-
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
312
|
+
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\publish.ts)_
|
313
313
|
|
314
314
|
## `learnpack start`
|
315
315
|
|
@@ -330,7 +330,7 @@ OPTIONS
|
|
330
330
|
-w, --watch Watch for file changes
|
331
331
|
```
|
332
332
|
|
333
|
-
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
333
|
+
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\start.ts)_
|
334
334
|
|
335
335
|
## `learnpack test [EXERCISESLUG]`
|
336
336
|
|
@@ -344,5 +344,5 @@ ARGUMENTS
|
|
344
344
|
EXERCISESLUG The name of the exercise to test
|
345
345
|
```
|
346
346
|
|
347
|
-
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.
|
347
|
+
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v2.0.16/src\commands\test.ts)_
|
348
348
|
<!-- commandsstop -->
|
@@ -0,0 +1,369 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const fs = require("fs");
|
4
|
+
const exercise_1 = require("../managers/config/exercise");
|
5
|
+
const console_1 = require("../utils/console");
|
6
|
+
const audit_1 = require("../utils/audit");
|
7
|
+
const SessionCommand_1 = require("../utils/SessionCommand");
|
8
|
+
const path = require("path");
|
9
|
+
// eslint-disable-next-line
|
10
|
+
const fetch = require("node-fetch");
|
11
|
+
// eslint-disable-next-line
|
12
|
+
const fm = require("front-matter");
|
13
|
+
class AuditCommand extends SessionCommand_1.default {
|
14
|
+
async init() {
|
15
|
+
const { flags } = this.parse(AuditCommand);
|
16
|
+
await this.initSession(flags);
|
17
|
+
}
|
18
|
+
async run() {
|
19
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
20
|
+
console_1.default.log('Running command audit...');
|
21
|
+
// Get configuration object.
|
22
|
+
let config = (_a = this.configManager) === null || _a === void 0 ? void 0 : _a.get();
|
23
|
+
if (config) {
|
24
|
+
const errors = [];
|
25
|
+
const warnings = [];
|
26
|
+
const counter = {
|
27
|
+
images: {
|
28
|
+
error: 0,
|
29
|
+
total: 0,
|
30
|
+
},
|
31
|
+
links: {
|
32
|
+
error: 0,
|
33
|
+
total: 0,
|
34
|
+
},
|
35
|
+
exercises: 0,
|
36
|
+
readmeFiles: 0,
|
37
|
+
};
|
38
|
+
// Checks if learnpack clean has been run
|
39
|
+
audit_1.default.checkLearnpackClean(config, errors);
|
40
|
+
// Build exercises if they are not built yet.
|
41
|
+
if (!config.exercises || config.exercises.length === 0) {
|
42
|
+
(_b = this.configManager) === null || _b === void 0 ? void 0 : _b.buildIndex();
|
43
|
+
config = (_c = this.configManager) === null || _c === void 0 ? void 0 : _c.get();
|
44
|
+
}
|
45
|
+
// Check if the exercises folder has some files within any ./exercise
|
46
|
+
const exercisesPath = config.config.exercisesPath;
|
47
|
+
fs.readdir(exercisesPath, (err, files) => {
|
48
|
+
if (err) {
|
49
|
+
return console.log('Unable to scan directory: ' + err);
|
50
|
+
}
|
51
|
+
// listing all files using forEach
|
52
|
+
for (const file of files) {
|
53
|
+
// Do whatever you want to do with the file
|
54
|
+
const filePath = path.join(exercisesPath, file);
|
55
|
+
if (fs.statSync(filePath).isFile())
|
56
|
+
warnings.push({
|
57
|
+
exercise: file,
|
58
|
+
msg: 'This file is not inside any exercise folder.',
|
59
|
+
});
|
60
|
+
}
|
61
|
+
});
|
62
|
+
// This function checks that each of the url's are working.
|
63
|
+
const checkUrl = async (file, exercise) => {
|
64
|
+
var _a, _b, _c, _d;
|
65
|
+
if (!fs.existsSync(file.path))
|
66
|
+
return false;
|
67
|
+
const content = fs.readFileSync(file.path).toString();
|
68
|
+
const isEmpty = audit_1.default.checkForEmptySpaces(content);
|
69
|
+
if (isEmpty || !content)
|
70
|
+
errors.push({
|
71
|
+
exercise: exercise.title,
|
72
|
+
msg: `This file (${file.name}) doesn't have any content inside.`,
|
73
|
+
});
|
74
|
+
const frontmatter = fm(content);
|
75
|
+
for (const attribute in frontmatter.attributes) {
|
76
|
+
if (Object.prototype.hasOwnProperty.call(frontmatter.attributes, attribute) &&
|
77
|
+
(attribute === 'intro' || attribute === 'tutorial')) {
|
78
|
+
counter.links.total++;
|
79
|
+
try {
|
80
|
+
// eslint-disable-next-line
|
81
|
+
let res = await fetch(frontmatter.attributes[attribute], {
|
82
|
+
method: 'HEAD',
|
83
|
+
});
|
84
|
+
if (!res.ok) {
|
85
|
+
counter.links.error++;
|
86
|
+
errors.push({
|
87
|
+
exercise: exercise.title,
|
88
|
+
msg: `This link is broken (${res.ok}): ${frontmatter.attributes[attribute]}`,
|
89
|
+
});
|
90
|
+
}
|
91
|
+
}
|
92
|
+
catch (_e) {
|
93
|
+
counter.links.error++;
|
94
|
+
errors.push({
|
95
|
+
exercise: exercise.title,
|
96
|
+
msg: `This link is broken: ${frontmatter.attributes[attribute]}`,
|
97
|
+
});
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
// Check url's of each README file.
|
102
|
+
const findings = audit_1.default.findInFile(['relativeImages', 'externalImages', 'markdownLinks'], content);
|
103
|
+
for (const finding in findings) {
|
104
|
+
if (Object.prototype.hasOwnProperty.call(findings, finding)) {
|
105
|
+
const obj = findings[finding];
|
106
|
+
// Valdites all the relative path images.
|
107
|
+
if (finding === 'relativeImages' && Object.keys(obj).length > 0) {
|
108
|
+
for (const img in obj) {
|
109
|
+
if (Object.prototype.hasOwnProperty.call(obj, img)) {
|
110
|
+
// Validates if the image is in the assets folder.
|
111
|
+
counter.images.total++;
|
112
|
+
const relativePath = path
|
113
|
+
.relative(exercise.path.replace(/\\/gm, '/'), `${(_a = config.config) === null || _a === void 0 ? void 0 : _a.dirPath}/assets/${obj[img].relUrl}`)
|
114
|
+
.replace(/\\/gm, '/');
|
115
|
+
if (relativePath !== obj[img].absUrl.split('?').shift()) {
|
116
|
+
counter.images.error++;
|
117
|
+
errors.push({
|
118
|
+
exercise: exercise.title,
|
119
|
+
msg: `This relative path (${obj[img].relUrl}) is not pointing to the assets folder.`,
|
120
|
+
});
|
121
|
+
}
|
122
|
+
if (!fs.existsSync(`${(_b = config.config) === null || _b === void 0 ? void 0 : _b.dirPath}/assets/${obj[img].relUrl}`)) {
|
123
|
+
counter.images.error++;
|
124
|
+
errors.push({
|
125
|
+
exercise: exercise.title,
|
126
|
+
msg: `The file ${obj[img].relUrl} doesn't exist in the assets folder.`,
|
127
|
+
});
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
else if (finding === 'externalImages' &&
|
133
|
+
Object.keys(obj).length > 0) {
|
134
|
+
// Valdites all the aboslute path images.
|
135
|
+
for (const img in obj) {
|
136
|
+
if (Object.prototype.hasOwnProperty.call(obj, img)) {
|
137
|
+
counter.images.total++;
|
138
|
+
if (fs.existsSync(`${(_c = config.config) === null || _c === void 0 ? void 0 : _c.dirPath}/assets${obj[img].mdUrl
|
139
|
+
.split('?')
|
140
|
+
.shift()}`)) {
|
141
|
+
const relativePath = path
|
142
|
+
.relative(exercise.path.replace(/\\/gm, '/'), `${(_d = config.config) === null || _d === void 0 ? void 0 : _d.dirPath}/assets/${obj[img].mdUrl}`)
|
143
|
+
.replace(/\\/gm, '/');
|
144
|
+
warnings.push({
|
145
|
+
exercise: exercise.title,
|
146
|
+
msg: `On this exercise you have an image with an absolute path "${obj[img].absUrl}". We recommend you to replace it by the relative path: "${relativePath}".`,
|
147
|
+
});
|
148
|
+
}
|
149
|
+
try {
|
150
|
+
// eslint-disable-next-line
|
151
|
+
let res = await fetch(obj[img].absUrl, { method: "HEAD" });
|
152
|
+
if (!res.ok) {
|
153
|
+
counter.images.error++;
|
154
|
+
errors.push({
|
155
|
+
exercise: exercise.title,
|
156
|
+
msg: `This link is broken: ${obj[img].absUrl}`,
|
157
|
+
});
|
158
|
+
}
|
159
|
+
}
|
160
|
+
catch (_f) {
|
161
|
+
counter.images.error++;
|
162
|
+
errors.push({
|
163
|
+
exercise: exercise.title,
|
164
|
+
msg: `This link is broken: ${obj[img].absUrl}`,
|
165
|
+
});
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
170
|
+
else if (finding === 'markdownLinks' &&
|
171
|
+
Object.keys(obj).length > 0) {
|
172
|
+
for (const link in obj) {
|
173
|
+
if (Object.prototype.hasOwnProperty.call(obj, link)) {
|
174
|
+
counter.links.total++;
|
175
|
+
try {
|
176
|
+
// eslint-disable-next-line
|
177
|
+
let res = await fetch(obj[link].mdUrl, { method: "HEAD" });
|
178
|
+
if (res.status > 399 && res.status < 500) {
|
179
|
+
counter.links.error++;
|
180
|
+
errors.push({
|
181
|
+
exercise: exercise.title,
|
182
|
+
msg: `This link is broken: ${obj[link].mdUrl}`,
|
183
|
+
});
|
184
|
+
}
|
185
|
+
}
|
186
|
+
catch (_g) {
|
187
|
+
counter.links.error++;
|
188
|
+
errors.push({
|
189
|
+
exercise: exercise.title,
|
190
|
+
msg: `This link is broken: ${obj[link].mdUrl}`,
|
191
|
+
});
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
return true;
|
199
|
+
};
|
200
|
+
// This function is being created because the find method doesn't work with promises.
|
201
|
+
const find = async (file, lang, exercise) => {
|
202
|
+
if (file.name === lang) {
|
203
|
+
await checkUrl(file, exercise);
|
204
|
+
return true;
|
205
|
+
}
|
206
|
+
return false;
|
207
|
+
};
|
208
|
+
console_1.default.debug('config', config);
|
209
|
+
console_1.default.info(' Checking if the config file is fine...');
|
210
|
+
// These two lines check if the 'slug' property is inside the configuration object.
|
211
|
+
console_1.default.debug('Checking if the slug property is inside the configuration object...');
|
212
|
+
if (!((_d = config.config) === null || _d === void 0 ? void 0 : _d.slug))
|
213
|
+
errors.push({
|
214
|
+
exercise: undefined,
|
215
|
+
msg: 'The slug property is not in the configuration object',
|
216
|
+
});
|
217
|
+
// These two lines check if the 'repository' property is inside the configuration object.
|
218
|
+
console_1.default.debug('Checking if the repository property is inside the configuration object...');
|
219
|
+
if (!((_e = config.config) === null || _e === void 0 ? void 0 : _e.repository))
|
220
|
+
errors.push({
|
221
|
+
exercise: undefined,
|
222
|
+
msg: 'The repository property is not in the configuration object',
|
223
|
+
});
|
224
|
+
else
|
225
|
+
audit_1.default.isUrl((_f = config.config) === null || _f === void 0 ? void 0 : _f.repository, errors, counter);
|
226
|
+
// These two lines check if the 'description' property is inside the configuration object.
|
227
|
+
console_1.default.debug('Checking if the description property is inside the configuration object...');
|
228
|
+
if (!((_g = config.config) === null || _g === void 0 ? void 0 : _g.description))
|
229
|
+
errors.push({
|
230
|
+
exercise: undefined,
|
231
|
+
msg: 'The description property is not in the configuration object',
|
232
|
+
});
|
233
|
+
if (errors.length === 0)
|
234
|
+
console_1.default.log('The config file is ok');
|
235
|
+
// Validates if images and links are working at every README file.
|
236
|
+
const exercises = config.exercises;
|
237
|
+
const readmeFiles = [];
|
238
|
+
if (exercises && exercises.length > 0) {
|
239
|
+
console_1.default.info(' Checking if the images are working...');
|
240
|
+
for (const index in exercises) {
|
241
|
+
if (Object.prototype.hasOwnProperty.call(exercises, index)) {
|
242
|
+
const exercise = exercises[index];
|
243
|
+
if (!exercise_1.validateExerciseDirectoryName(exercise.title))
|
244
|
+
errors.push({
|
245
|
+
exercise: exercise.title,
|
246
|
+
msg: `The exercise ${exercise.title} has an invalid name.`,
|
247
|
+
});
|
248
|
+
let readmeFilesCount = { exercise: exercise.title, count: 0 };
|
249
|
+
if (Object.keys(exercise.translations).length === 0)
|
250
|
+
errors.push({
|
251
|
+
exercise: exercise.title,
|
252
|
+
msg: `The exercise ${exercise.title} doesn't have a README.md file.`,
|
253
|
+
});
|
254
|
+
if (exercise.language === 'python3' ||
|
255
|
+
exercise.language === 'python') {
|
256
|
+
for (const f of exercise.files.map(f => f)) {
|
257
|
+
if (f.path.includes('test.py') || f.path.includes('tests.py')) {
|
258
|
+
const content = fs.readFileSync(f.path).toString();
|
259
|
+
const isEmpty = audit_1.default.checkForEmptySpaces(content);
|
260
|
+
if (isEmpty || !content)
|
261
|
+
errors.push({
|
262
|
+
exercise: exercise.title,
|
263
|
+
msg: `This file (${f.name}) doesn't have any content inside.`,
|
264
|
+
});
|
265
|
+
}
|
266
|
+
}
|
267
|
+
}
|
268
|
+
else {
|
269
|
+
for (const f of exercise.files.map(f => f)) {
|
270
|
+
if (f.path.includes('test.js') || f.path.includes('tests.js')) {
|
271
|
+
const content = fs.readFileSync(f.path).toString();
|
272
|
+
const isEmpty = audit_1.default.checkForEmptySpaces(content);
|
273
|
+
if (isEmpty || !content)
|
274
|
+
errors.push({
|
275
|
+
exercise: exercise.title,
|
276
|
+
msg: `This file (${f.name}) doesn't have any content inside.`,
|
277
|
+
});
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
for (const lang in exercise.translations) {
|
282
|
+
if (Object.prototype.hasOwnProperty.call(exercise.translations, lang)) {
|
283
|
+
const files = [];
|
284
|
+
const findResultPromises = [];
|
285
|
+
for (const file of exercise.files) {
|
286
|
+
const found = find(file, exercise.translations[lang], exercise);
|
287
|
+
findResultPromises.push(found);
|
288
|
+
}
|
289
|
+
// eslint-disable-next-line
|
290
|
+
let findResults = await Promise.all(findResultPromises);
|
291
|
+
for (const found of findResults) {
|
292
|
+
if (found) {
|
293
|
+
readmeFilesCount = Object.assign(Object.assign({}, readmeFilesCount), { count: readmeFilesCount.count + 1 });
|
294
|
+
files.push(found);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
if (!files.includes(true))
|
298
|
+
errors.push({
|
299
|
+
exercise: exercise.title,
|
300
|
+
msg: "This exercise doesn't have a README.md file.",
|
301
|
+
});
|
302
|
+
}
|
303
|
+
}
|
304
|
+
readmeFiles.push(readmeFilesCount);
|
305
|
+
}
|
306
|
+
}
|
307
|
+
}
|
308
|
+
else
|
309
|
+
errors.push({
|
310
|
+
exercise: undefined,
|
311
|
+
msg: 'The exercises array is empty.',
|
312
|
+
});
|
313
|
+
console_1.default.log(`${counter.images.total - counter.images.error} images ok from ${counter.images.total}`);
|
314
|
+
console_1.default.info(" Checking if important files are missing... (README's, translations, gitignore...)");
|
315
|
+
// Check if all the exercises has the same ammount of README's, this way we can check if they have the same ammount of translations.
|
316
|
+
const files = [];
|
317
|
+
let count = 0;
|
318
|
+
for (const item of readmeFiles) {
|
319
|
+
if (count < item.count)
|
320
|
+
count = item.count;
|
321
|
+
}
|
322
|
+
for (const item of readmeFiles) {
|
323
|
+
if (item.count !== count)
|
324
|
+
files.push(` ${item.exercise}`);
|
325
|
+
}
|
326
|
+
if (files.length > 0) {
|
327
|
+
const filesString = files.join(',');
|
328
|
+
warnings.push({
|
329
|
+
exercise: undefined,
|
330
|
+
msg: files.length === 1 ?
|
331
|
+
`This exercise is missing translations:${filesString}` :
|
332
|
+
`These exercises are missing translations:${filesString}`,
|
333
|
+
});
|
334
|
+
}
|
335
|
+
// Checks if the .gitignore file exists.
|
336
|
+
if (!fs.existsSync('.gitignore'))
|
337
|
+
warnings.push({
|
338
|
+
exercise: undefined,
|
339
|
+
msg: ".gitignore file doesn't exist",
|
340
|
+
});
|
341
|
+
counter.exercises = exercises.length;
|
342
|
+
for (const readme of readmeFiles) {
|
343
|
+
counter.readmeFiles += readme.count;
|
344
|
+
}
|
345
|
+
await audit_1.default.showWarnings(warnings);
|
346
|
+
await audit_1.default.showErrors(errors, counter);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
}
|
350
|
+
AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
|
351
|
+
...
|
352
|
+
learnpack audit checks for the following information in a repository:
|
353
|
+
1. The configuration object has slug, repository and description. (Error)
|
354
|
+
2. The command learnpack clean has been run. (Error)
|
355
|
+
3. If a markdown or test file doesn't have any content. (Error)
|
356
|
+
4. The links are accessing to valid servers. (Error)
|
357
|
+
5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
|
358
|
+
6. The external images are working (If they are pointing to a valid server). (Error)
|
359
|
+
7. The exercises directory names are valid. (Error)
|
360
|
+
8. If an exercise doesn't have a README file. (Error)
|
361
|
+
9. The exercises array (Of the config file) has content. (Error)
|
362
|
+
10. The exercses have the same translations. (Warning)
|
363
|
+
11. The .gitignore file exists. (Warning)
|
364
|
+
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
365
|
+
`;
|
366
|
+
AuditCommand.flags = {
|
367
|
+
// name: flags.string({char: 'n', description: 'name to print'}),
|
368
|
+
};
|
369
|
+
exports.default = AuditCommand;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
// import {flags} from '@oclif/command'
|
4
|
+
const console_1 = require("../utils/console");
|
5
|
+
const SessionCommand_1 = require("../utils/SessionCommand");
|
6
|
+
class CleanCommand extends SessionCommand_1.default {
|
7
|
+
async init() {
|
8
|
+
const { flags } = this.parse(CleanCommand);
|
9
|
+
await this.initSession(flags);
|
10
|
+
}
|
11
|
+
async run() {
|
12
|
+
var _a;
|
13
|
+
const { flags } = this.parse(CleanCommand);
|
14
|
+
(_a = this.configManager) === null || _a === void 0 ? void 0 : _a.clean();
|
15
|
+
console_1.default.success("Package cleaned successfully, ready to publish");
|
16
|
+
}
|
17
|
+
}
|
18
|
+
CleanCommand.description = `Clean the configuration object
|
19
|
+
...
|
20
|
+
Extra documentation goes here
|
21
|
+
`;
|
22
|
+
CleanCommand.flags = {
|
23
|
+
// name: flags.string({char: 'n', description: 'name to print'}),
|
24
|
+
};
|
25
|
+
exports.default = CleanCommand;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Command } from "@oclif/command";
|
2
|
+
declare class DownloadCommand extends Command {
|
3
|
+
static description: string;
|
4
|
+
static flags: any;
|
5
|
+
static args: {
|
6
|
+
name: string;
|
7
|
+
required: boolean;
|
8
|
+
description: string;
|
9
|
+
hidden: boolean;
|
10
|
+
}[];
|
11
|
+
run(): Promise<null | undefined>;
|
12
|
+
}
|
13
|
+
export default DownloadCommand;
|
@@ -0,0 +1,55 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const command_1 = require("@oclif/command");
|
4
|
+
// import fetch from 'node-fetch'
|
5
|
+
const file_1 = require("../managers/file");
|
6
|
+
const console_1 = require("../utils/console");
|
7
|
+
const api_1 = require("../utils/api");
|
8
|
+
const download_1 = require("../ui/download");
|
9
|
+
// const BaseCommand = require('../utils/BaseCommand');
|
10
|
+
class DownloadCommand extends command_1.Command {
|
11
|
+
// async init() {
|
12
|
+
// const {flags} = this.parse(DownloadCommand)
|
13
|
+
// await this.initSession(flags)
|
14
|
+
// }
|
15
|
+
async run() {
|
16
|
+
const { /* flags, */ args } = this.parse(DownloadCommand);
|
17
|
+
// start watching for file changes
|
18
|
+
let _package = args.package;
|
19
|
+
if (!_package) {
|
20
|
+
_package = (await download_1.askPackage());
|
21
|
+
}
|
22
|
+
if (!_package) {
|
23
|
+
return null;
|
24
|
+
}
|
25
|
+
try {
|
26
|
+
const packageInfo = await api_1.default.getAllPackages({ slug: _package });
|
27
|
+
if (packageInfo.results.length === 0)
|
28
|
+
console_1.default.error(`Package ${_package} not found`);
|
29
|
+
else
|
30
|
+
file_1.clone(packageInfo.results[0].repository)
|
31
|
+
.then(_result => {
|
32
|
+
console_1.default.success("Successfully downloaded");
|
33
|
+
console_1.default.info(`You can now CD into the folder like this: $ cd ${_package}`);
|
34
|
+
})
|
35
|
+
.catch(error => console_1.default.error(error.message || error));
|
36
|
+
}
|
37
|
+
catch (_a) { }
|
38
|
+
}
|
39
|
+
}
|
40
|
+
DownloadCommand.description = `Describe the command here
|
41
|
+
...
|
42
|
+
Extra documentation goes here
|
43
|
+
`;
|
44
|
+
DownloadCommand.flags = {
|
45
|
+
// name: flags.string({char: 'n', description: 'name to print'}),
|
46
|
+
};
|
47
|
+
DownloadCommand.args = [
|
48
|
+
{
|
49
|
+
name: "package",
|
50
|
+
required: false,
|
51
|
+
description: "The unique string that identifies this package on learnpack",
|
52
|
+
hidden: false,
|
53
|
+
},
|
54
|
+
];
|
55
|
+
exports.default = DownloadCommand;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import BaseCommand from "../utils/BaseCommand";
|
2
|
+
declare class InitComand extends BaseCommand {
|
3
|
+
static description: string;
|
4
|
+
static flags: {
|
5
|
+
grading: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
|
6
|
+
};
|
7
|
+
run(): Promise<void>;
|
8
|
+
}
|
9
|
+
export default InitComand;
|