@learnpack/learnpack 5.0.45 → 5.0.47
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 +12 -12
- package/lib/commands/publish.js +1 -4
- package/lib/commands/start.js +2 -0
- package/lib/commands/translate.js +1 -0
- package/lib/managers/config/exercise.js +35 -0
- package/lib/managers/config/index.js +8 -0
- package/lib/managers/server/routes.js +8 -0
- package/lib/models/config-manager.d.ts +2 -0
- package/lib/utils/api.d.ts +1 -0
- package/lib/utils/api.js +3 -3
- package/lib/utils/rigoActions.d.ts +1 -0
- package/lib/utils/rigoActions.js +12 -12
- package/lib/utils/sidebarGenerator.d.ts +10 -0
- package/lib/utils/sidebarGenerator.js +29 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/publish.ts +1 -4
- package/src/commands/start.ts +6 -3
- package/src/commands/translate.ts +1 -0
- package/src/managers/config/exercise.ts +44 -0
- package/src/managers/config/index.ts +12 -0
- package/src/managers/server/routes.ts +20 -0
- package/src/models/config-manager.ts +2 -0
- package/src/utils/api.ts +1 -1
- package/src/utils/rigoActions.ts +2 -2
- package/src/utils/sidebarGenerator.ts +52 -0
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/5.0.
|
24
|
+
@learnpack/learnpack/5.0.47 win32-x64 node-v22.14.0
|
25
25
|
$ learnpack --help [COMMAND]
|
26
26
|
USAGE
|
27
27
|
$ learnpack COMMAND
|
@@ -79,7 +79,7 @@ DESCRIPTION
|
|
79
79
|
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
80
80
|
```
|
81
81
|
|
82
|
-
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
82
|
+
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\audit.ts)_
|
83
83
|
|
84
84
|
## `learnpack breakToken`
|
85
85
|
|
@@ -94,7 +94,7 @@ OPTIONS
|
|
94
94
|
-y, --yes Skip all prompts and initialize an empty project
|
95
95
|
```
|
96
96
|
|
97
|
-
_See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
97
|
+
_See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\breakToken.ts)_
|
98
98
|
|
99
99
|
## `learnpack clean`
|
100
100
|
|
@@ -109,7 +109,7 @@ DESCRIPTION
|
|
109
109
|
Extra documentation goes here
|
110
110
|
```
|
111
111
|
|
112
|
-
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
112
|
+
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\clean.ts)_
|
113
113
|
|
114
114
|
## `learnpack download [PACKAGE]`
|
115
115
|
|
@@ -127,7 +127,7 @@ DESCRIPTION
|
|
127
127
|
Extra documentation goes here
|
128
128
|
```
|
129
129
|
|
130
|
-
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
130
|
+
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\download.ts)_
|
131
131
|
|
132
132
|
## `learnpack help [COMMAND]`
|
133
133
|
|
@@ -159,7 +159,7 @@ OPTIONS
|
|
159
159
|
-y, --yes Skip all prompts and initialize an empty project
|
160
160
|
```
|
161
161
|
|
162
|
-
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
162
|
+
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\init.ts)_
|
163
163
|
|
164
164
|
## `learnpack login [PACKAGE]`
|
165
165
|
|
@@ -177,7 +177,7 @@ DESCRIPTION
|
|
177
177
|
Extra documentation goes here
|
178
178
|
```
|
179
179
|
|
180
|
-
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
180
|
+
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\login.ts)_
|
181
181
|
|
182
182
|
## `learnpack logout [PACKAGE]`
|
183
183
|
|
@@ -195,7 +195,7 @@ DESCRIPTION
|
|
195
195
|
Extra documentation goes here
|
196
196
|
```
|
197
197
|
|
198
|
-
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
198
|
+
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\logout.ts)_
|
199
199
|
|
200
200
|
## `learnpack plugins`
|
201
201
|
|
@@ -327,7 +327,7 @@ OPTIONS
|
|
327
327
|
-s, --strict strict mode
|
328
328
|
```
|
329
329
|
|
330
|
-
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
330
|
+
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\publish.ts)_
|
331
331
|
|
332
332
|
## `learnpack start`
|
333
333
|
|
@@ -349,7 +349,7 @@ OPTIONS
|
|
349
349
|
-y, --yes Skip all prompts and initialize an empty project
|
350
350
|
```
|
351
351
|
|
352
|
-
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
352
|
+
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\start.ts)_
|
353
353
|
|
354
354
|
## `learnpack test [EXERCISESLUG]`
|
355
355
|
|
@@ -366,7 +366,7 @@ OPTIONS
|
|
366
366
|
-y, --yes Skip all prompts and initialize an empty project
|
367
367
|
```
|
368
368
|
|
369
|
-
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
369
|
+
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\test.ts)_
|
370
370
|
|
371
371
|
## `learnpack translate`
|
372
372
|
|
@@ -380,7 +380,7 @@ OPTIONS
|
|
380
380
|
-y, --yes Skip all prompts and initialize an empty project
|
381
381
|
```
|
382
382
|
|
383
|
-
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
383
|
+
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.47/src\commands\translate.ts)_
|
384
384
|
<!-- commandsstop -->
|
385
385
|
|
386
386
|
> > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
|
package/lib/commands/publish.js
CHANGED
@@ -16,10 +16,7 @@ const file_1 = require("../managers/file");
|
|
16
16
|
const api_1 = require("../utils/api");
|
17
17
|
const prompts = require("prompts");
|
18
18
|
const rigoActions_1 = require("../utils/rigoActions");
|
19
|
-
const
|
20
|
-
// const RIGOBOT_HOST =
|
21
|
-
// "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
22
|
-
const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload";
|
19
|
+
const uploadZipEndpont = api_1.RIGOBOT_HOST + "/v1/learnpack/upload";
|
23
20
|
const runAudit = (strict) => {
|
24
21
|
try {
|
25
22
|
console_1.default.info("Running learnpack audit before publishing...");
|
package/lib/commands/start.js
CHANGED
@@ -14,6 +14,7 @@ const file_1 = require("../managers/file");
|
|
14
14
|
const misc_1 = require("../utils/misc");
|
15
15
|
const osOperations_1 = require("../utils/osOperations");
|
16
16
|
const checkNotInstalled_1 = require("../utils/checkNotInstalled");
|
17
|
+
const sidebarGenerator_1 = require("../utils/sidebarGenerator");
|
17
18
|
class StartCommand extends SessionCommand_1.default {
|
18
19
|
// 🛑 IMPORTANT
|
19
20
|
// Every command that will use the configManager needs this init method
|
@@ -36,6 +37,7 @@ class StartCommand extends SessionCommand_1.default {
|
|
36
37
|
console_1.default.debug(`Grading: ${config === null || config === void 0 ? void 0 : config.grading} ${((_c = config === null || config === void 0 ? void 0 : config.disabledActions) === null || _c === void 0 ? void 0 : _c.includes("test")) ? "(disabled)" : ""}, editor: ${config === null || config === void 0 ? void 0 : config.editor.mode} ${config === null || config === void 0 ? void 0 : config.editor.version}, for ${Array.isArray(configObject === null || configObject === void 0 ? void 0 : configObject.exercises) ?
|
37
38
|
configObject === null || configObject === void 0 ? void 0 : configObject.exercises.length :
|
38
39
|
0} exercises found`);
|
40
|
+
(0, sidebarGenerator_1.generateSidebar)((configObject === null || configObject === void 0 ? void 0 : configObject.exercises) || [], (config === null || config === void 0 ? void 0 : config.dirPath) || "");
|
39
41
|
const neededPlugins = await (0, checkNotInstalled_1.checkNotInstalledPlugins)((configObject === null || configObject === void 0 ? void 0 : configObject.exercises) || [], installedPlugins, this);
|
40
42
|
const allDepsInstalled = await (0, checkNotInstalled_1.checkNotInstalledDependencies)(neededPlugins.needed);
|
41
43
|
if (!allDepsInstalled) {
|
@@ -78,6 +78,7 @@ class BuildCommand extends SessionCommand_1.default {
|
|
78
78
|
const response = await (0, rigoActions_1.translateExercise)(rigoToken, {
|
79
79
|
text_to_translate: readme,
|
80
80
|
output_language: language,
|
81
|
+
exercise_slug: exercise,
|
81
82
|
});
|
82
83
|
await (0, creatorUtilities_1.saveTranslatedReadme)(exercise, response.parsed.output_language_code, response.parsed.translation);
|
83
84
|
console_1.default.success(`Translated ${exercise} to ${language} successfully`);
|
@@ -6,6 +6,36 @@ const p = require("path");
|
|
6
6
|
const fs = require("fs");
|
7
7
|
const console_1 = require("../../utils/console");
|
8
8
|
const allowed_files_1 = require("./allowed_files");
|
9
|
+
// function processQuestions(markdown: string): {
|
10
|
+
// updatedMarkdown: string
|
11
|
+
// questions: { id: string; examples: string[] }[]
|
12
|
+
// } {
|
13
|
+
// // Regular expression to find code blocks with language "question"
|
14
|
+
// const questionRegex = /```question([^`]+?)```/g
|
15
|
+
// const questions: { id: string; examples: string[] }[] = []
|
16
|
+
// // Function to generate a random ID
|
17
|
+
// const generateId = () => `id-${Math.random().toString(36).substr(2, 9)}`
|
18
|
+
// // Replace function to modify the matched question block
|
19
|
+
// const updatedMarkdown = markdown.replace(
|
20
|
+
// questionRegex,
|
21
|
+
// (match: string, properties: string) => {
|
22
|
+
// // Check for existing id in the properties
|
23
|
+
// const idMatch = properties.match(/id="([^"]+)"/)
|
24
|
+
// const newId = idMatch ? idMatch[1] : generateId() // Use existing id or generate new one
|
25
|
+
// // Update the properties by adding or updating the id
|
26
|
+
// let updatedProperties = `id="${newId}"${properties.replace(
|
27
|
+
// /id="[^"]+"/,
|
28
|
+
// ""
|
29
|
+
// )}`
|
30
|
+
// // Make sure the properties are separated by a single space
|
31
|
+
// updatedProperties = updatedProperties.replace(/\s+/g, " ").trim()
|
32
|
+
// questions.push({ id: newId, examples: [] })
|
33
|
+
// return `\`\`\`question ${updatedProperties}
|
34
|
+
// \`\`\``
|
35
|
+
// }
|
36
|
+
// )
|
37
|
+
// return { updatedMarkdown, questions }
|
38
|
+
// }
|
9
39
|
// eslint-disable-next-line
|
10
40
|
const frontMatter = require("front-matter");
|
11
41
|
const exercise = (path, position, configObject) => {
|
@@ -26,6 +56,11 @@ const exercise = (path, position, configObject) => {
|
|
26
56
|
const translations = {};
|
27
57
|
for (const file of files.filter(file => file.toLowerCase().includes("readme"))) {
|
28
58
|
const parts = file.split(".");
|
59
|
+
// const content = fs.readFileSync(path + "/" + file, "utf8")
|
60
|
+
// const { updatedMarkdown, questions } = processQuestions(content)
|
61
|
+
// if (questions.length > 0) {
|
62
|
+
// fs.writeFileSync(path + "/" + file, updatedMarkdown, "utf8")
|
63
|
+
// }
|
29
64
|
if (parts.length === 3)
|
30
65
|
translations[parts[1]] = file;
|
31
66
|
else
|
@@ -400,6 +400,14 @@ exports.default = async ({ grading, mode, disableGrading, version, }) => {
|
|
400
400
|
}
|
401
401
|
return false;
|
402
402
|
},
|
403
|
+
getSidebar: () => {
|
404
|
+
var _a;
|
405
|
+
const sidebarPath = path.join(((_a = configObj.config) === null || _a === void 0 ? void 0 : _a.dirPath) || "", "sidebar.json");
|
406
|
+
if (fs.existsSync(sidebarPath)) {
|
407
|
+
return JSON.parse(fs.readFileSync(sidebarPath, "utf8"));
|
408
|
+
}
|
409
|
+
return {};
|
410
|
+
},
|
403
411
|
watchIndex: function (onChange) {
|
404
412
|
var _a;
|
405
413
|
if (configObj.config && !configObj.config.exercisesPath)
|
@@ -13,6 +13,7 @@ const session_1 = require("../../managers/session");
|
|
13
13
|
const telemetry_1 = require("../telemetry");
|
14
14
|
const creatorUtilities_1 = require("../../utils/creatorUtilities");
|
15
15
|
const rigoActions_1 = require("../../utils/rigoActions");
|
16
|
+
const sidebarGenerator_1 = require("../../utils/sidebarGenerator");
|
16
17
|
// import { eventManager } from "../../utils/osOperations"
|
17
18
|
const withHandler = (func) => (req, res) => {
|
18
19
|
try {
|
@@ -267,6 +268,10 @@ async function default_1(app, configObject, configManager) {
|
|
267
268
|
res.end();
|
268
269
|
}
|
269
270
|
}));
|
271
|
+
app.get("/sidebar", withHandler((req, res) => {
|
272
|
+
const sidebar = configManager.getSidebar();
|
273
|
+
res.json(sidebar);
|
274
|
+
}));
|
270
275
|
app.delete("/exercise/:slug/delete", withHandler(async (req, res) => {
|
271
276
|
const exerciseDeleted = configManager.deleteExercise(req.params.slug);
|
272
277
|
if (exerciseDeleted) {
|
@@ -282,6 +287,7 @@ async function default_1(app, configObject, configManager) {
|
|
282
287
|
const { exerciseSlugs, languages } = req.body;
|
283
288
|
const session = await session_1.default.getPayload();
|
284
289
|
const rigoToken = (_a = session === null || session === void 0 ? void 0 : session.rigobot) === null || _a === void 0 ? void 0 : _a.key;
|
290
|
+
const configDirPath = config === null || config === void 0 ? void 0 : config.dirPath;
|
285
291
|
if (!rigoToken) {
|
286
292
|
return res.status(400).json({ error: "RigoToken not found" });
|
287
293
|
}
|
@@ -298,8 +304,10 @@ async function default_1(app, configObject, configManager) {
|
|
298
304
|
const response = await (0, rigoActions_1.translateExercise)(rigoToken, {
|
299
305
|
text_to_translate: readme.body,
|
300
306
|
output_language: language,
|
307
|
+
exercise_slug: slug,
|
301
308
|
});
|
302
309
|
await (0, creatorUtilities_1.saveTranslatedReadme)(slug, response.parsed.output_language_code, response.parsed.translation);
|
310
|
+
(0, sidebarGenerator_1.addExerciseToSidebar)(slug, response.parsed.output_language_code, response.parsed.translated_slug, configDirPath || "");
|
303
311
|
console_1.default.success(`Translated ${slug} to ${language} successfully`);
|
304
312
|
}));
|
305
313
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { TSidebar } from "../utils/sidebarGenerator";
|
1
2
|
import { IConfigObj, TGrading } from "./config";
|
2
3
|
import { IExercise } from "./exercise-obj";
|
3
4
|
export interface IConfigManagerAttributes {
|
@@ -18,6 +19,7 @@ export interface IConfigManager {
|
|
18
19
|
buildIndex: () => boolean | void;
|
19
20
|
watchIndex: (onChange: (...args: Array<any>) => void) => void;
|
20
21
|
save: () => void;
|
22
|
+
getSidebar: () => TSidebar;
|
21
23
|
noCurrentExercise: () => void;
|
22
24
|
getAllExercises: () => IExercise[];
|
23
25
|
}
|
package/lib/utils/api.d.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
export declare const RIGOBOT_HOST = "https://rigobot.herokuapp.com";
|
1
2
|
type TConsumableSlug = "ai-conversation-message" | "ai-compilation" | "ai-tutorial-generation" | "ai-generation" | "learnpack-publish";
|
2
3
|
export declare const countConsumables: (consumables: any, consumableSlug?: TConsumableSlug) => any;
|
3
4
|
export declare const getConsumable: (token: string, consumableSlug?: TConsumableSlug) => Promise<any>;
|
package/lib/utils/api.js
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.validateToken = exports.listUserAcademies = exports.getConsumable = exports.countConsumables = void 0;
|
3
|
+
exports.validateToken = exports.listUserAcademies = exports.getConsumable = exports.countConsumables = exports.RIGOBOT_HOST = void 0;
|
4
4
|
const console_1 = require("../utils/console");
|
5
5
|
const storage = require("node-persist");
|
6
6
|
const cli_ux_1 = require("cli-ux");
|
7
7
|
const axios_1 = require("axios");
|
8
8
|
const HOST = "https://breathecode.herokuapp.com";
|
9
|
-
|
9
|
+
exports.RIGOBOT_HOST = "https://rigobot.herokuapp.com";
|
10
10
|
// const RIGOBOT_HOST = "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
11
11
|
// eslint-disable-next-line
|
12
12
|
const _fetch = require("node-fetch");
|
@@ -86,7 +86,7 @@ const login = async (identification, password) => {
|
|
86
86
|
};
|
87
87
|
const loginRigo = async (token) => {
|
88
88
|
try {
|
89
|
-
const rigoUrl = `${RIGOBOT_HOST}/v1/auth/me/token?breathecode_token=${token}`;
|
89
|
+
const rigoUrl = `${exports.RIGOBOT_HOST}/v1/auth/me/token?breathecode_token=${token}`;
|
90
90
|
const rigoResp = await _fetch(rigoUrl);
|
91
91
|
const rigobotJson = await rigoResp.json();
|
92
92
|
return rigobotJson;
|
@@ -17,6 +17,7 @@ export declare function downloadImage(imageUrl: string, savePath: string): Promi
|
|
17
17
|
type TTranslateInputs = {
|
18
18
|
text_to_translate: string;
|
19
19
|
output_language: string;
|
20
|
+
exercise_slug: string;
|
20
21
|
};
|
21
22
|
export declare const translateExercise: (token: string, inputs: TTranslateInputs) => Promise<any>;
|
22
23
|
type TGenerateCourseIntroductionInputs = {
|
package/lib/utils/rigoActions.js
CHANGED
@@ -9,10 +9,10 @@ const fs_1 = require("fs");
|
|
9
9
|
const console_1 = require("../utils/console");
|
10
10
|
const fs = require("fs");
|
11
11
|
const path = require("path");
|
12
|
-
const
|
12
|
+
const api_1 = require("./api");
|
13
13
|
const createReadme = async (token, inputs) => {
|
14
14
|
try {
|
15
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/423/`, {
|
15
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/423/`, {
|
16
16
|
inputs,
|
17
17
|
include_purpose_objective: false,
|
18
18
|
execute_async: false,
|
@@ -33,7 +33,7 @@ exports.createReadme = createReadme;
|
|
33
33
|
const hasCreatorPermission = async (token) => {
|
34
34
|
console_1.default.debug("Checking if user has creator permission");
|
35
35
|
try {
|
36
|
-
const response = await axios_1.default.get(`${RIGOBOT_HOST}/v1/learnpack/permissions/creator`, {
|
36
|
+
const response = await axios_1.default.get(`${api_1.RIGOBOT_HOST}/v1/learnpack/permissions/creator`, {
|
37
37
|
headers: {
|
38
38
|
"Content-Type": "application/json",
|
39
39
|
Authorization: "Token " + token,
|
@@ -53,7 +53,7 @@ const hasCreatorPermission = async (token) => {
|
|
53
53
|
exports.hasCreatorPermission = hasCreatorPermission;
|
54
54
|
const generateImage = async (token, { prompt }) => {
|
55
55
|
try {
|
56
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/learnpack/tools/images`, {
|
56
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/learnpack/tools/images`, {
|
57
57
|
prompt,
|
58
58
|
}, {
|
59
59
|
headers: {
|
@@ -79,7 +79,7 @@ async function downloadImage(imageUrl, savePath) {
|
|
79
79
|
});
|
80
80
|
}
|
81
81
|
const translateExercise = async (token, inputs) => {
|
82
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/159/`, {
|
82
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/159/`, {
|
83
83
|
inputs: inputs,
|
84
84
|
include_purpose_objective: false,
|
85
85
|
execute_async: false,
|
@@ -93,7 +93,7 @@ const translateExercise = async (token, inputs) => {
|
|
93
93
|
};
|
94
94
|
exports.translateExercise = translateExercise;
|
95
95
|
const generateCourseIntroduction = async (token, inputs) => {
|
96
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/192/`, {
|
96
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/192/`, {
|
97
97
|
inputs: inputs,
|
98
98
|
include_purpose_objective: false,
|
99
99
|
execute_async: false,
|
@@ -107,7 +107,7 @@ const generateCourseIntroduction = async (token, inputs) => {
|
|
107
107
|
};
|
108
108
|
exports.generateCourseIntroduction = generateCourseIntroduction;
|
109
109
|
const interactiveCreation = async (token, inputs) => {
|
110
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/390/`, {
|
110
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/390/`, {
|
111
111
|
inputs: inputs,
|
112
112
|
include_purpose_objective: false,
|
113
113
|
execute_async: false,
|
@@ -121,7 +121,7 @@ const interactiveCreation = async (token, inputs) => {
|
|
121
121
|
};
|
122
122
|
exports.interactiveCreation = interactiveCreation;
|
123
123
|
const createCodeFile = async (token, inputs) => {
|
124
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/456/`, {
|
124
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/456/`, {
|
125
125
|
inputs: inputs,
|
126
126
|
include_purpose_objective: false,
|
127
127
|
execute_async: false,
|
@@ -135,7 +135,7 @@ const createCodeFile = async (token, inputs) => {
|
|
135
135
|
};
|
136
136
|
exports.createCodeFile = createCodeFile;
|
137
137
|
const createCodingReadme = async (token, inputs) => {
|
138
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/489/`, { inputs, include_purpose_objective: false, execute_async: false }, {
|
138
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/489/`, { inputs, include_purpose_objective: false, execute_async: false }, {
|
139
139
|
headers: {
|
140
140
|
"Content-Type": "application/json",
|
141
141
|
Authorization: "Token " + token,
|
@@ -178,7 +178,7 @@ async function createPreviewReadme(tutorialDir, packageInfo, rigoToken, readmeCo
|
|
178
178
|
}
|
179
179
|
async function makeReadmeReadable(rigoToken, inputs) {
|
180
180
|
try {
|
181
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/588/`, { inputs, include_purpose_objective: false, execute_async: false }, {
|
181
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/588/`, { inputs, include_purpose_objective: false, execute_async: false }, {
|
182
182
|
headers: {
|
183
183
|
"Content-Type": "application/json",
|
184
184
|
Authorization: "Token " + rigoToken,
|
@@ -192,7 +192,7 @@ async function makeReadmeReadable(rigoToken, inputs) {
|
|
192
192
|
}
|
193
193
|
}
|
194
194
|
const isValidRigoToken = async (rigobotToken) => {
|
195
|
-
const rigoUrl = `${RIGOBOT_HOST}/v1/auth/token/${rigobotToken}`;
|
195
|
+
const rigoUrl = `${api_1.RIGOBOT_HOST}/v1/auth/token/${rigobotToken}`;
|
196
196
|
const rigoResp = await fetch(rigoUrl);
|
197
197
|
if (!rigoResp.ok) {
|
198
198
|
console_1.default.debug("Invalid Rigobot token", rigoResp.status);
|
@@ -203,7 +203,7 @@ const isValidRigoToken = async (rigobotToken) => {
|
|
203
203
|
};
|
204
204
|
exports.isValidRigoToken = isValidRigoToken;
|
205
205
|
const generateCourseShortName = async (token, inputs) => {
|
206
|
-
const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/852/`, { inputs, include_purpose_objective: false, execute_async: false }, {
|
206
|
+
const response = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/prompting/completion/852/`, { inputs, include_purpose_objective: false, execute_async: false }, {
|
207
207
|
headers: {
|
208
208
|
"Content-Type": "application/json",
|
209
209
|
Authorization: "Token " + token,
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { IExercise } from "../models/exercise-obj";
|
2
|
+
type TTitleTranslations = {
|
3
|
+
[key: string]: string;
|
4
|
+
};
|
5
|
+
export type TSidebar = {
|
6
|
+
[key: string]: TTitleTranslations;
|
7
|
+
};
|
8
|
+
export declare const generateSidebar: (exercises: IExercise[], learnPath: string) => TSidebar;
|
9
|
+
export declare const addExerciseToSidebar: (exerciseSlug: string, targetLanguage: string, translatedSlug: string, learnPath: string) => TSidebar;
|
10
|
+
export {};
|
@@ -0,0 +1,29 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.addExerciseToSidebar = exports.generateSidebar = void 0;
|
4
|
+
const path = require("path");
|
5
|
+
const fs = require("fs");
|
6
|
+
const generateSidebar = (exercises, learnPath) => {
|
7
|
+
const sidebarPath = path.join(learnPath, "sidebar.json");
|
8
|
+
let sidebar = {};
|
9
|
+
if (fs.existsSync(sidebarPath)) {
|
10
|
+
sidebar = JSON.parse(fs.readFileSync(sidebarPath, "utf8"));
|
11
|
+
}
|
12
|
+
for (const exercise of exercises) {
|
13
|
+
sidebar[exercise.slug] = Object.assign(Object.assign({}, sidebar[exercise.slug]), { us: exercise.title });
|
14
|
+
}
|
15
|
+
fs.writeFileSync(sidebarPath, JSON.stringify(sidebar, null, 2));
|
16
|
+
return sidebar;
|
17
|
+
};
|
18
|
+
exports.generateSidebar = generateSidebar;
|
19
|
+
const addExerciseToSidebar = (exerciseSlug, targetLanguage, translatedSlug, learnPath) => {
|
20
|
+
const sidebarPath = path.join(learnPath, "sidebar.json");
|
21
|
+
let sidebar = {};
|
22
|
+
if (fs.existsSync(sidebarPath)) {
|
23
|
+
sidebar = JSON.parse(fs.readFileSync(sidebarPath, "utf8"));
|
24
|
+
}
|
25
|
+
sidebar[exerciseSlug] = Object.assign(Object.assign({}, sidebar[exerciseSlug]), { [targetLanguage]: translatedSlug });
|
26
|
+
fs.writeFileSync(sidebarPath, JSON.stringify(sidebar, null, 2));
|
27
|
+
return sidebar;
|
28
|
+
};
|
29
|
+
exports.addExerciseToSidebar = addExerciseToSidebar;
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"5.0.
|
1
|
+
{"version":"5.0.47","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":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"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":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"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":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"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":"[preview, extension]","options":["extension","preview"]},"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":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@learnpack/learnpack",
|
3
3
|
"description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
|
4
|
-
"version": "5.0.
|
4
|
+
"version": "5.0.47",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/commands/publish.ts
CHANGED
@@ -15,13 +15,10 @@ import {
|
|
15
15
|
downloadEditor,
|
16
16
|
checkIfDirectoryExists,
|
17
17
|
} from "../managers/file"
|
18
|
-
import api, { getConsumable, TAcademy } from "../utils/api"
|
18
|
+
import api, { getConsumable, RIGOBOT_HOST, TAcademy } from "../utils/api"
|
19
19
|
import * as prompts from "prompts"
|
20
20
|
import { generateCourseShortName, isValidRigoToken } from "../utils/rigoActions"
|
21
21
|
|
22
|
-
const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
|
23
|
-
// const RIGOBOT_HOST =
|
24
|
-
// "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
25
22
|
const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
|
26
23
|
|
27
24
|
const runAudit = (strict: boolean) => {
|
package/src/commands/start.ts
CHANGED
@@ -6,7 +6,7 @@ import * as path from "path"
|
|
6
6
|
import SessionCommand from "../utils/SessionCommand"
|
7
7
|
import Console from "../utils/console"
|
8
8
|
import socket from "../managers/socket"
|
9
|
-
import TelemetryManager
|
9
|
+
import TelemetryManager from "../managers/telemetry"
|
10
10
|
import createServer from "../managers/server"
|
11
11
|
import queue from "../utils/fileQueue"
|
12
12
|
import {
|
@@ -17,14 +17,15 @@ import {
|
|
17
17
|
import { prioritizeHTMLFile } from "../utils/misc"
|
18
18
|
|
19
19
|
import { IGitpodData } from "../models/gitpod-data"
|
20
|
-
import {
|
20
|
+
import { IExerciseData } from "../models/exercise-obj"
|
21
21
|
import { eventManager } from "../utils/osOperations"
|
22
|
-
import { cli } from "cli-ux"
|
22
|
+
// import { cli } from "cli-ux"
|
23
23
|
import { TOpenWindowData } from "../models/socket"
|
24
24
|
import {
|
25
25
|
checkNotInstalledPlugins,
|
26
26
|
checkNotInstalledDependencies,
|
27
27
|
} from "../utils/checkNotInstalled"
|
28
|
+
import { generateSidebar } from "../utils/sidebarGenerator"
|
28
29
|
|
29
30
|
export default class StartCommand extends SessionCommand {
|
30
31
|
static description = "Runs a small server with all the exercise instructions"
|
@@ -99,6 +100,8 @@ export default class StartCommand extends SessionCommand {
|
|
99
100
|
} exercises found`
|
100
101
|
)
|
101
102
|
|
103
|
+
generateSidebar(configObject?.exercises || [], config?.dirPath || "")
|
104
|
+
|
102
105
|
const neededPlugins = await checkNotInstalledPlugins(
|
103
106
|
configObject?.exercises || [],
|
104
107
|
installedPlugins,
|
@@ -8,6 +8,43 @@ import { IConfigObj } from "../../models/config"
|
|
8
8
|
import { IFile } from "../../models/file"
|
9
9
|
import { IExercise } from "../../models/exercise-obj"
|
10
10
|
|
11
|
+
// function processQuestions(markdown: string): {
|
12
|
+
// updatedMarkdown: string
|
13
|
+
// questions: { id: string; examples: string[] }[]
|
14
|
+
// } {
|
15
|
+
// // Regular expression to find code blocks with language "question"
|
16
|
+
// const questionRegex = /```question([^`]+?)```/g
|
17
|
+
// const questions: { id: string; examples: string[] }[] = []
|
18
|
+
|
19
|
+
// // Function to generate a random ID
|
20
|
+
// const generateId = () => `id-${Math.random().toString(36).substr(2, 9)}`
|
21
|
+
|
22
|
+
// // Replace function to modify the matched question block
|
23
|
+
// const updatedMarkdown = markdown.replace(
|
24
|
+
// questionRegex,
|
25
|
+
// (match: string, properties: string) => {
|
26
|
+
// // Check for existing id in the properties
|
27
|
+
// const idMatch = properties.match(/id="([^"]+)"/)
|
28
|
+
// const newId = idMatch ? idMatch[1] : generateId() // Use existing id or generate new one
|
29
|
+
|
30
|
+
// // Update the properties by adding or updating the id
|
31
|
+
// let updatedProperties = `id="${newId}"${properties.replace(
|
32
|
+
// /id="[^"]+"/,
|
33
|
+
// ""
|
34
|
+
// )}`
|
35
|
+
|
36
|
+
// // Make sure the properties are separated by a single space
|
37
|
+
// updatedProperties = updatedProperties.replace(/\s+/g, " ").trim()
|
38
|
+
|
39
|
+
// questions.push({ id: newId, examples: [] })
|
40
|
+
|
41
|
+
// return `\`\`\`question ${updatedProperties}
|
42
|
+
// \`\`\``
|
43
|
+
// }
|
44
|
+
// )
|
45
|
+
|
46
|
+
// return { updatedMarkdown, questions }
|
47
|
+
// }
|
11
48
|
// eslint-disable-next-line
|
12
49
|
const frontMatter = require("front-matter")
|
13
50
|
|
@@ -41,6 +78,13 @@ export const exercise = (
|
|
41
78
|
)) {
|
42
79
|
const parts = file.split(".")
|
43
80
|
|
81
|
+
// const content = fs.readFileSync(path + "/" + file, "utf8")
|
82
|
+
// const { updatedMarkdown, questions } = processQuestions(content)
|
83
|
+
|
84
|
+
// if (questions.length > 0) {
|
85
|
+
// fs.writeFileSync(path + "/" + file, updatedMarkdown, "utf8")
|
86
|
+
// }
|
87
|
+
|
44
88
|
if (parts.length === 3)
|
45
89
|
translations[parts[1]] = file
|
46
90
|
else
|
@@ -540,6 +540,18 @@ fs.mkdirSync(dirPath, { recursive: true })
|
|
540
540
|
|
541
541
|
return false
|
542
542
|
},
|
543
|
+
|
544
|
+
getSidebar: () => {
|
545
|
+
const sidebarPath = path.join(
|
546
|
+
configObj.config?.dirPath || "",
|
547
|
+
"sidebar.json"
|
548
|
+
)
|
549
|
+
if (fs.existsSync(sidebarPath)) {
|
550
|
+
return JSON.parse(fs.readFileSync(sidebarPath, "utf8"))
|
551
|
+
}
|
552
|
+
|
553
|
+
return {}
|
554
|
+
},
|
543
555
|
watchIndex: function (onChange: (filename: string) => void) {
|
544
556
|
if (configObj.config && !configObj.config.exercisesPath)
|
545
557
|
throw ValidationError(
|
@@ -14,6 +14,7 @@ import SessionManager from "../../managers/session"
|
|
14
14
|
import TelemetryManager from "../telemetry"
|
15
15
|
import { saveTranslatedReadme } from "../../utils/creatorUtilities"
|
16
16
|
import { translateExercise } from "../../utils/rigoActions"
|
17
|
+
import { addExerciseToSidebar } from "../../utils/sidebarGenerator"
|
17
18
|
// import { eventManager } from "../../utils/osOperations"
|
18
19
|
|
19
20
|
const withHandler =
|
@@ -48,6 +49,7 @@ export default async function (
|
|
48
49
|
create: true,
|
49
50
|
path: `${config?.dirPath}/vscode_queue.json`,
|
50
51
|
})
|
52
|
+
|
51
53
|
app.get(
|
52
54
|
"/config",
|
53
55
|
withHandler((_: express.Request, res: express.Response) => {
|
@@ -382,6 +384,14 @@ throw new Error("File not found: " + filePath)
|
|
382
384
|
})
|
383
385
|
)
|
384
386
|
|
387
|
+
app.get(
|
388
|
+
"/sidebar",
|
389
|
+
withHandler((req: express.Request, res: express.Response) => {
|
390
|
+
const sidebar = configManager.getSidebar()
|
391
|
+
res.json(sidebar)
|
392
|
+
})
|
393
|
+
)
|
394
|
+
|
385
395
|
app.delete(
|
386
396
|
"/exercise/:slug/delete",
|
387
397
|
withHandler(async (req: express.Request, res: express.Response) => {
|
@@ -404,6 +414,8 @@ throw new Error("File not found: " + filePath)
|
|
404
414
|
const session = await SessionManager.getPayload()
|
405
415
|
const rigoToken = session?.rigobot?.key
|
406
416
|
|
417
|
+
const configDirPath = config?.dirPath
|
418
|
+
|
407
419
|
if (!rigoToken) {
|
408
420
|
return res.status(400).json({ error: "RigoToken not found" })
|
409
421
|
}
|
@@ -426,6 +438,7 @@ throw new Error("File not found: " + filePath)
|
|
426
438
|
const response = await translateExercise(rigoToken, {
|
427
439
|
text_to_translate: readme.body,
|
428
440
|
output_language: language,
|
441
|
+
exercise_slug: slug,
|
429
442
|
})
|
430
443
|
|
431
444
|
await saveTranslatedReadme(
|
@@ -434,6 +447,13 @@ throw new Error("File not found: " + filePath)
|
|
434
447
|
response.parsed.translation
|
435
448
|
)
|
436
449
|
|
450
|
+
addExerciseToSidebar(
|
451
|
+
slug,
|
452
|
+
response.parsed.output_language_code,
|
453
|
+
response.parsed.translated_slug,
|
454
|
+
configDirPath || ""
|
455
|
+
)
|
456
|
+
|
437
457
|
Console.success(
|
438
458
|
`Translated ${slug} to ${language} successfully`
|
439
459
|
)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { TSidebar } from "../utils/sidebarGenerator"
|
1
2
|
import { IConfigObj, TGrading } from "./config"
|
2
3
|
import { IExercise } from "./exercise-obj"
|
3
4
|
|
@@ -20,6 +21,7 @@ export interface IConfigManager {
|
|
20
21
|
buildIndex: () => boolean | void
|
21
22
|
watchIndex: (onChange: (...args: Array<any>) => void) => void
|
22
23
|
save: () => void
|
24
|
+
getSidebar: () => TSidebar
|
23
25
|
noCurrentExercise: () => void
|
24
26
|
getAllExercises: () => IExercise[]
|
25
27
|
}
|
package/src/utils/api.ts
CHANGED
@@ -3,7 +3,7 @@ import * as storage from "node-persist"
|
|
3
3
|
import cli from "cli-ux"
|
4
4
|
import axios from "axios"
|
5
5
|
const HOST = "https://breathecode.herokuapp.com"
|
6
|
-
const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
|
6
|
+
export const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
|
7
7
|
// const RIGOBOT_HOST = "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
8
8
|
|
9
9
|
// eslint-disable-next-line
|
package/src/utils/rigoActions.ts
CHANGED
@@ -4,8 +4,7 @@ import Console from "../utils/console"
|
|
4
4
|
import { PackageInfo } from "./creatorUtilities"
|
5
5
|
import * as fs from "fs"
|
6
6
|
import * as path from "path"
|
7
|
-
|
8
|
-
const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
|
7
|
+
import { RIGOBOT_HOST } from "./api"
|
9
8
|
|
10
9
|
type TCreateReadmeInputs = {
|
11
10
|
title: string
|
@@ -113,6 +112,7 @@ export async function downloadImage(
|
|
113
112
|
type TTranslateInputs = {
|
114
113
|
text_to_translate: string
|
115
114
|
output_language: string
|
115
|
+
exercise_slug: string
|
116
116
|
}
|
117
117
|
export const translateExercise = async (
|
118
118
|
token: string,
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import path = require("path")
|
2
|
+
import fs = require("fs")
|
3
|
+
import { IExercise, IExerciseData } from "../models/exercise-obj"
|
4
|
+
|
5
|
+
type TTitleTranslations = {
|
6
|
+
[key: string]: string
|
7
|
+
}
|
8
|
+
|
9
|
+
export type TSidebar = {
|
10
|
+
[key: string]: TTitleTranslations
|
11
|
+
}
|
12
|
+
|
13
|
+
export const generateSidebar = (exercises: IExercise[], learnPath: string) => {
|
14
|
+
const sidebarPath = path.join(learnPath, "sidebar.json")
|
15
|
+
let sidebar: TSidebar = {}
|
16
|
+
if (fs.existsSync(sidebarPath)) {
|
17
|
+
sidebar = JSON.parse(fs.readFileSync(sidebarPath, "utf8"))
|
18
|
+
}
|
19
|
+
|
20
|
+
for (const exercise of exercises) {
|
21
|
+
sidebar[exercise.slug] = {
|
22
|
+
...sidebar[exercise.slug],
|
23
|
+
us: exercise.title,
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
fs.writeFileSync(sidebarPath, JSON.stringify(sidebar, null, 2))
|
28
|
+
|
29
|
+
return sidebar
|
30
|
+
}
|
31
|
+
|
32
|
+
export const addExerciseToSidebar = (
|
33
|
+
exerciseSlug: string,
|
34
|
+
targetLanguage: string,
|
35
|
+
translatedSlug: string,
|
36
|
+
learnPath: string
|
37
|
+
) => {
|
38
|
+
const sidebarPath = path.join(learnPath, "sidebar.json")
|
39
|
+
let sidebar: TSidebar = {}
|
40
|
+
if (fs.existsSync(sidebarPath)) {
|
41
|
+
sidebar = JSON.parse(fs.readFileSync(sidebarPath, "utf8"))
|
42
|
+
}
|
43
|
+
|
44
|
+
sidebar[exerciseSlug] = {
|
45
|
+
...sidebar[exerciseSlug],
|
46
|
+
[targetLanguage]: translatedSlug,
|
47
|
+
}
|
48
|
+
|
49
|
+
fs.writeFileSync(sidebarPath, JSON.stringify(sidebar, null, 2))
|
50
|
+
|
51
|
+
return sidebar
|
52
|
+
}
|