@learnpack/learnpack 2.0.24 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +362 -27
- package/lib/commands/audit.d.ts +1 -1
- package/lib/commands/audit.js +48 -47
- package/lib/managers/config/defaults.d.ts +1 -0
- package/lib/managers/config/defaults.js +15 -14
- package/lib/managers/config/index.js +5 -10
- package/lib/models/config.d.ts +1 -0
- package/lib/utils/fileQueue.js +1 -1
- package/lib/utils/watcher.d.ts +1 -1
- package/lib/utils/watcher.js +5 -6
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/audit.ts +463 -462
- package/src/commands/init.ts +172 -172
- package/src/managers/config/defaults.ts +34 -33
- package/src/managers/config/index.ts +406 -412
- package/src/models/config.ts +1 -0
- package/src/utils/fileQueue.ts +1 -1
- 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/watcher.ts +5 -7
package/lib/commands/audit.js
CHANGED
@@ -17,7 +17,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
17
17
|
}
|
18
18
|
async run() {
|
19
19
|
var _a, _b, _c, _d, _e, _f, _g;
|
20
|
-
console_1.default.log(
|
20
|
+
console_1.default.log("Running command audit...");
|
21
21
|
// Get configuration object.
|
22
22
|
let config = (_a = this.configManager) === null || _a === void 0 ? void 0 : _a.get();
|
23
23
|
if (config) {
|
@@ -46,7 +46,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
46
46
|
const exercisesPath = config.config.exercisesPath;
|
47
47
|
fs.readdir(exercisesPath, (err, files) => {
|
48
48
|
if (err) {
|
49
|
-
return console.log(
|
49
|
+
return console.log("Unable to scan directory: " + err);
|
50
50
|
}
|
51
51
|
// listing all files using forEach
|
52
52
|
for (const file of files) {
|
@@ -55,7 +55,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
55
55
|
if (fs.statSync(filePath).isFile())
|
56
56
|
warnings.push({
|
57
57
|
exercise: file,
|
58
|
-
msg:
|
58
|
+
msg: "This file is not inside any exercise folder.",
|
59
59
|
});
|
60
60
|
}
|
61
61
|
});
|
@@ -74,12 +74,12 @@ class AuditCommand extends SessionCommand_1.default {
|
|
74
74
|
const frontmatter = fm(content);
|
75
75
|
for (const attribute in frontmatter.attributes) {
|
76
76
|
if (Object.prototype.hasOwnProperty.call(frontmatter.attributes, attribute) &&
|
77
|
-
(attribute ===
|
77
|
+
(attribute === "intro" || attribute === "tutorial")) {
|
78
78
|
counter.links.total++;
|
79
79
|
try {
|
80
80
|
// eslint-disable-next-line
|
81
81
|
let res = await fetch(frontmatter.attributes[attribute], {
|
82
|
-
method:
|
82
|
+
method: "HEAD",
|
83
83
|
});
|
84
84
|
if (!res.ok) {
|
85
85
|
counter.links.error++;
|
@@ -99,20 +99,20 @@ class AuditCommand extends SessionCommand_1.default {
|
|
99
99
|
}
|
100
100
|
}
|
101
101
|
// Check url's of each README file.
|
102
|
-
const findings = audit_1.default.findInFile([
|
102
|
+
const findings = audit_1.default.findInFile(["relativeImages", "externalImages", "markdownLinks"], content);
|
103
103
|
for (const finding in findings) {
|
104
104
|
if (Object.prototype.hasOwnProperty.call(findings, finding)) {
|
105
105
|
const obj = findings[finding];
|
106
106
|
// Valdites all the relative path images.
|
107
|
-
if (finding ===
|
107
|
+
if (finding === "relativeImages" && Object.keys(obj).length > 0) {
|
108
108
|
for (const img in obj) {
|
109
109
|
if (Object.prototype.hasOwnProperty.call(obj, img)) {
|
110
110
|
// Validates if the image is in the assets folder.
|
111
111
|
counter.images.total++;
|
112
112
|
const relativePath = path
|
113
|
-
.relative(exercise.path.replace(/\\/gm,
|
114
|
-
.replace(/\\/gm,
|
115
|
-
if (relativePath !== obj[img].absUrl.split(
|
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
116
|
counter.images.error++;
|
117
117
|
errors.push({
|
118
118
|
exercise: exercise.title,
|
@@ -129,18 +129,18 @@ class AuditCommand extends SessionCommand_1.default {
|
|
129
129
|
}
|
130
130
|
}
|
131
131
|
}
|
132
|
-
else if (finding ===
|
132
|
+
else if (finding === "externalImages" &&
|
133
133
|
Object.keys(obj).length > 0) {
|
134
134
|
// Valdites all the aboslute path images.
|
135
135
|
for (const img in obj) {
|
136
136
|
if (Object.prototype.hasOwnProperty.call(obj, img)) {
|
137
137
|
counter.images.total++;
|
138
138
|
if (fs.existsSync(`${(_c = config.config) === null || _c === void 0 ? void 0 : _c.dirPath}/assets${obj[img].mdUrl
|
139
|
-
.split(
|
139
|
+
.split("?")
|
140
140
|
.shift()}`)) {
|
141
141
|
const relativePath = path
|
142
|
-
.relative(exercise.path.replace(/\\/gm,
|
143
|
-
.replace(/\\/gm,
|
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
144
|
warnings.push({
|
145
145
|
exercise: exercise.title,
|
146
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}".`,
|
@@ -167,7 +167,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
167
167
|
}
|
168
168
|
}
|
169
169
|
}
|
170
|
-
else if (finding ===
|
170
|
+
else if (finding === "markdownLinks" &&
|
171
171
|
Object.keys(obj).length > 0) {
|
172
172
|
for (const link in obj) {
|
173
173
|
if (Object.prototype.hasOwnProperty.call(obj, link)) {
|
@@ -175,6 +175,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
175
175
|
try {
|
176
176
|
// eslint-disable-next-line
|
177
177
|
let res = await fetch(obj[link].mdUrl, { method: "HEAD" });
|
178
|
+
console_1.default.log("Response links:", obj[link].mdUrl, res);
|
178
179
|
if (res.status > 399 && res.status < 500) {
|
179
180
|
counter.links.error++;
|
180
181
|
errors.push({
|
@@ -205,38 +206,38 @@ class AuditCommand extends SessionCommand_1.default {
|
|
205
206
|
}
|
206
207
|
return false;
|
207
208
|
};
|
208
|
-
console_1.default.debug(
|
209
|
-
console_1.default.info(
|
209
|
+
console_1.default.debug("config", config);
|
210
|
+
console_1.default.info(" Checking if the config file is fine...");
|
210
211
|
// These two lines check if the 'slug' property is inside the configuration object.
|
211
|
-
console_1.default.debug(
|
212
|
+
console_1.default.debug("Checking if the slug property is inside the configuration object...");
|
212
213
|
if (!((_d = config.config) === null || _d === void 0 ? void 0 : _d.slug))
|
213
214
|
errors.push({
|
214
215
|
exercise: undefined,
|
215
|
-
msg:
|
216
|
+
msg: "The slug property is not in the configuration object",
|
216
217
|
});
|
217
218
|
// These two lines check if the 'repository' property is inside the configuration object.
|
218
|
-
console_1.default.debug(
|
219
|
+
console_1.default.debug("Checking if the repository property is inside the configuration object...");
|
219
220
|
if (!((_e = config.config) === null || _e === void 0 ? void 0 : _e.repository))
|
220
221
|
errors.push({
|
221
222
|
exercise: undefined,
|
222
|
-
msg:
|
223
|
+
msg: "The repository property is not in the configuration object",
|
223
224
|
});
|
224
225
|
else
|
225
226
|
audit_1.default.isUrl((_f = config.config) === null || _f === void 0 ? void 0 : _f.repository, errors, counter);
|
226
227
|
// These two lines check if the 'description' property is inside the configuration object.
|
227
|
-
console_1.default.debug(
|
228
|
+
console_1.default.debug("Checking if the description property is inside the configuration object...");
|
228
229
|
if (!((_g = config.config) === null || _g === void 0 ? void 0 : _g.description))
|
229
230
|
errors.push({
|
230
231
|
exercise: undefined,
|
231
|
-
msg:
|
232
|
+
msg: "The description property is not in the configuration object",
|
232
233
|
});
|
233
234
|
if (errors.length === 0)
|
234
|
-
console_1.default.log(
|
235
|
+
console_1.default.log("The config file is ok");
|
235
236
|
// Validates if images and links are working at every README file.
|
236
237
|
const exercises = config.exercises;
|
237
238
|
const readmeFiles = [];
|
238
239
|
if (exercises && exercises.length > 0) {
|
239
|
-
console_1.default.info(
|
240
|
+
console_1.default.info(" Checking if the images are working...");
|
240
241
|
for (const index in exercises) {
|
241
242
|
if (Object.prototype.hasOwnProperty.call(exercises, index)) {
|
242
243
|
const exercise = exercises[index];
|
@@ -251,10 +252,10 @@ class AuditCommand extends SessionCommand_1.default {
|
|
251
252
|
exercise: exercise.title,
|
252
253
|
msg: `The exercise ${exercise.title} doesn't have a README.md file.`,
|
253
254
|
});
|
254
|
-
if (exercise.language ===
|
255
|
-
exercise.language ===
|
255
|
+
if (exercise.language === "python3" ||
|
256
|
+
exercise.language === "python") {
|
256
257
|
for (const f of exercise.files.map(f => f)) {
|
257
|
-
if (f.path.includes(
|
258
|
+
if (f.path.includes("test.py") || f.path.includes("tests.py")) {
|
258
259
|
const content = fs.readFileSync(f.path).toString();
|
259
260
|
const isEmpty = audit_1.default.checkForEmptySpaces(content);
|
260
261
|
if (isEmpty || !content)
|
@@ -267,7 +268,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
267
268
|
}
|
268
269
|
else {
|
269
270
|
for (const f of exercise.files.map(f => f)) {
|
270
|
-
if (f.path.includes(
|
271
|
+
if (f.path.includes("test.js") || f.path.includes("tests.js")) {
|
271
272
|
const content = fs.readFileSync(f.path).toString();
|
272
273
|
const isEmpty = audit_1.default.checkForEmptySpaces(content);
|
273
274
|
if (isEmpty || !content)
|
@@ -308,7 +309,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
308
309
|
else
|
309
310
|
errors.push({
|
310
311
|
exercise: undefined,
|
311
|
-
msg:
|
312
|
+
msg: "The exercises array is empty.",
|
312
313
|
});
|
313
314
|
console_1.default.log(`${counter.images.total - counter.images.error} images ok from ${counter.images.total}`);
|
314
315
|
console_1.default.info(" Checking if important files are missing... (README's, translations, gitignore...)");
|
@@ -324,7 +325,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
324
325
|
files.push(` ${item.exercise}`);
|
325
326
|
}
|
326
327
|
if (files.length > 0) {
|
327
|
-
const filesString = files.join(
|
328
|
+
const filesString = files.join(",");
|
328
329
|
warnings.push({
|
329
330
|
exercise: undefined,
|
330
331
|
msg: files.length === 1 ?
|
@@ -333,7 +334,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
333
334
|
});
|
334
335
|
}
|
335
336
|
// Checks if the .gitignore file exists.
|
336
|
-
if (!fs.existsSync(
|
337
|
+
if (!fs.existsSync(".gitignore"))
|
337
338
|
warnings.push({
|
338
339
|
exercise: undefined,
|
339
340
|
msg: ".gitignore file doesn't exist",
|
@@ -347,21 +348,21 @@ class AuditCommand extends SessionCommand_1.default {
|
|
347
348
|
}
|
348
349
|
}
|
349
350
|
}
|
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)
|
351
|
+
AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
|
352
|
+
...
|
353
|
+
learnpack audit checks for the following information in a repository:
|
354
|
+
1. The configuration object has slug, repository and description. (Error)
|
355
|
+
2. The command learnpack clean has been run. (Error)
|
356
|
+
3. If a markdown or test file doesn't have any content. (Error)
|
357
|
+
4. The links are accessing to valid servers. (Error)
|
358
|
+
5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
|
359
|
+
6. The external images are working (If they are pointing to a valid server). (Error)
|
360
|
+
7. The exercises directory names are valid. (Error)
|
361
|
+
8. If an exercise doesn't have a README file. (Error)
|
362
|
+
9. The exercises array (Of the config file) has content. (Error)
|
363
|
+
10. The exercses have the same translations. (Warning)
|
364
|
+
11. The .gitignore file exists. (Warning)
|
365
|
+
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
365
366
|
`;
|
366
367
|
AuditCommand.flags = {
|
367
368
|
// name: flags.string({char: 'n', description: 'name to print'}),
|
@@ -8,28 +8,29 @@ exports.default = {
|
|
8
8
|
agent: null,
|
9
9
|
version: null,
|
10
10
|
},
|
11
|
-
dirPath:
|
12
|
-
configPath:
|
13
|
-
outputPath:
|
14
|
-
publicPath:
|
11
|
+
dirPath: "./.learn",
|
12
|
+
configPath: "./learn.json",
|
13
|
+
outputPath: "./.learn/dist",
|
14
|
+
publicPath: "/preview",
|
15
15
|
publicUrl: null,
|
16
|
-
language:
|
17
|
-
|
18
|
-
|
16
|
+
language: "auto",
|
17
|
+
autoPlay: true,
|
18
|
+
grading: "isolated",
|
19
|
+
exercisesPath: "./",
|
19
20
|
webpackTemplate: null,
|
20
21
|
disableGrading: false,
|
21
22
|
disabledActions: [],
|
22
23
|
actions: [],
|
23
24
|
entries: {
|
24
|
-
html:
|
25
|
-
vanillajs:
|
26
|
-
react:
|
27
|
-
node:
|
28
|
-
python3:
|
29
|
-
java:
|
25
|
+
html: "index.html",
|
26
|
+
vanillajs: "index.js",
|
27
|
+
react: "app.jsx",
|
28
|
+
node: "app.js",
|
29
|
+
python3: "app.py",
|
30
|
+
java: "app.java",
|
30
31
|
},
|
31
32
|
},
|
32
|
-
address:
|
33
|
+
address: "http://localhost",
|
33
34
|
currentExercise: null,
|
34
35
|
exercises: [],
|
35
36
|
};
|
@@ -16,12 +16,7 @@ const fetch = require("node-fetch");
|
|
16
16
|
const chalk = require("chalk");
|
17
17
|
/* exercise folder name standard */
|
18
18
|
const getConfigPath = () => {
|
19
|
-
const possibleFileNames = [
|
20
|
-
"learn.json",
|
21
|
-
".learn/learn.json",
|
22
|
-
"bc.json",
|
23
|
-
".breathecode/bc.json",
|
24
|
-
];
|
19
|
+
const possibleFileNames = ["learn.json", ".learn/learn.json"];
|
25
20
|
const config = possibleFileNames.find(file => fs.existsSync(file)) || null;
|
26
21
|
if (config && fs.existsSync(".breathecode"))
|
27
22
|
return { config, base: ".breathecode" };
|
@@ -101,8 +96,8 @@ exports.default = async ({ grading, mode, disableGrading, version, }) => {
|
|
101
96
|
if (configObj.config && !configObj.config.publicUrl)
|
102
97
|
configObj.config.publicUrl = `${configObj.address}:${configObj.config.port}`;
|
103
98
|
// Assign default editor mode if not set already
|
104
|
-
if (configObj.config && mode
|
105
|
-
configObj.config.editor.mode = mode
|
99
|
+
if (configObj.config && !mode) {
|
100
|
+
configObj.config.editor.mode = mode;
|
106
101
|
}
|
107
102
|
if (configObj.config && !configObj.config.editor.mode)
|
108
103
|
configObj.config.editor.mode =
|
@@ -113,7 +108,7 @@ exports.default = async ({ grading, mode, disableGrading, version, }) => {
|
|
113
108
|
console_1.default.debug("Config version not found, downloading default.");
|
114
109
|
const resp = await fetch("https://raw.githubusercontent.com/learnpack/coding-ide/learnpack/package.json");
|
115
110
|
const packageJSON = await resp.json();
|
116
|
-
configObj.config.editor.version = packageJSON.version || "1.0.
|
111
|
+
configObj.config.editor.version = packageJSON.version || "1.0.73";
|
117
112
|
}
|
118
113
|
if (configObj.config) {
|
119
114
|
configObj.config.dirPath = "./" + confPath.base;
|
@@ -259,7 +254,7 @@ exports.default = async ({ grading, mode, disableGrading, version, }) => {
|
|
259
254
|
if (configObj.config && !configObj.config.exercisesPath)
|
260
255
|
throw errors_1.ValidationError("No exercises directory to watch: " + configObj.config.exercisesPath);
|
261
256
|
this.buildIndex();
|
262
|
-
watcher_1.default(((_a = configObj === null || configObj === void 0 ? void 0 : configObj.config) === null || _a === void 0 ? void 0 : _a.exercisesPath) || "")
|
257
|
+
watcher_1.default(((_a = configObj === null || configObj === void 0 ? void 0 : configObj.config) === null || _a === void 0 ? void 0 : _a.exercisesPath) || "", onChange)
|
263
258
|
.then(( /* eventname, filename */) => {
|
264
259
|
console_1.default.debug("Changes detected on your exercises");
|
265
260
|
this.buildIndex();
|
package/lib/models/config.d.ts
CHANGED
package/lib/utils/fileQueue.js
CHANGED
@@ -123,7 +123,7 @@ const onPull = (callback) => {
|
|
123
123
|
loadFile(options.path || "");
|
124
124
|
}
|
125
125
|
catch (_a) {
|
126
|
-
console_1.default.debug("No
|
126
|
+
console_1.default.debug("No previoues queue file, waiting for it to be created...");
|
127
127
|
}
|
128
128
|
if (!watcher) {
|
129
129
|
console_1.default.debug(`Watching ${options.path}`);
|
package/lib/utils/watcher.d.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
declare const _default: (path: string) => Promise<unknown>;
|
1
|
+
declare const _default: (path: string, reloadSocket: () => void) => Promise<unknown>;
|
2
2
|
export default _default;
|
package/lib/utils/watcher.js
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
const chokidar = require("chokidar");
|
4
|
+
const console_1 = require("./console");
|
4
5
|
const debounce = require("debounce");
|
5
|
-
exports.default = (path) => new Promise((resolve /* , reject */) => {
|
6
|
+
exports.default = (path, reloadSocket) => new Promise((resolve /* , reject */) => {
|
7
|
+
console_1.default.debug("PATH:", path);
|
6
8
|
const watcher = chokidar.watch(path, {
|
7
9
|
// TODO: This watcher is not ready yet
|
8
|
-
|
9
|
-
// return new RegExp(_path)
|
10
|
-
// },
|
11
|
-
persistent: true,
|
12
|
-
depth: 1,
|
10
|
+
ignored: /^(?=.*(\.\w+)$)(?!.*\.md$).*$/gm,
|
13
11
|
ignoreInitial: true,
|
14
12
|
});
|
15
13
|
const onChange = (eventname, _filename) => {
|
16
14
|
resolve(eventname /* , filename */);
|
15
|
+
reloadSocket();
|
17
16
|
};
|
18
17
|
watcher.on("all", debounce(onChange, 500, true));
|
19
18
|
// watcher.on('all', onChange)
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"2.
|
1
|
+
{"version":"2.1.2","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[standalone, gitpod]","options":["standalone","gitpod"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]}}}
|
package/package.json
CHANGED