@learnpack/learnpack 5.0.250 → 5.0.252
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/lib/commands/audit.js +1 -1
- package/lib/commands/publish.js +4 -3
- package/lib/commands/serve.d.ts +0 -3
- package/lib/commands/serve.js +24 -45
- package/lib/creatorDist/assets/{index-CZYzWk3G.js → index-CFM_Ypyi.js} +25 -22
- package/lib/creatorDist/index.html +1 -1
- package/lib/managers/config/exercise.js +1 -1
- package/lib/utils/api.js +3 -3
- package/lib/utils/configBuilder.js +1 -1
- package/lib/utils/creatorUtilities.d.ts +1 -0
- package/lib/utils/creatorUtilities.js +5 -1
- package/package.json +1 -1
- package/src/commands/audit.ts +9 -18
- package/src/commands/publish.ts +4 -3
- package/src/commands/serve.ts +39 -65
- package/src/creator/src/App.tsx +1 -1
- package/src/creator/src/utils/rigo.ts +2 -0
- package/src/creatorDist/assets/{index-CZYzWk3G.js → index-CFM_Ypyi.js} +25 -22
- package/src/creatorDist/index.html +1 -1
- package/src/managers/config/exercise.ts +8 -16
- package/src/utils/api.ts +3 -3
- package/src/utils/configBuilder.ts +1 -1
- package/src/utils/creatorUtilities.ts +4 -0
- package/src/utils/templates/incremental/.vscode/schema.json +5 -5
- package/src/utils/templates/isolated/.vscode/schema.json +5 -5
package/lib/commands/audit.js
CHANGED
@@ -309,7 +309,7 @@ class AuditCommand extends SessionCommand_1.default {
|
|
309
309
|
for (const readmeFile of readmeFiles) {
|
310
310
|
// Checking the language of each README file.
|
311
311
|
if (readmeFile === "README.md")
|
312
|
-
translations.push("
|
312
|
+
translations.push("en");
|
313
313
|
else {
|
314
314
|
const regexGroups = translationRegex.exec(readmeFile);
|
315
315
|
if (regexGroups)
|
package/lib/commands/publish.js
CHANGED
@@ -22,6 +22,7 @@ const creatorUtilities_1 = require("../utils/creatorUtilities");
|
|
22
22
|
const uploadZipEndpont = api_1.RIGOBOT_HOST + "/v1/learnpack/upload";
|
23
23
|
const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl, b64IndexReadme, all_translations = []) => {
|
24
24
|
const categories = {
|
25
|
+
en: 9,
|
25
26
|
us: 9,
|
26
27
|
es: 10,
|
27
28
|
};
|
@@ -232,8 +233,8 @@ class BuildCommand extends SessionCommand_1.default {
|
|
232
233
|
const buildManifestPWA = path.join(buildDir, "manifest.webmanifest");
|
233
234
|
if (fs.existsSync(indexHtmlPath)) {
|
234
235
|
let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8");
|
235
|
-
const description = learnJson.description.
|
236
|
-
const title = learnJson.title.
|
236
|
+
const description = learnJson.description.en || "LearnPack is awesome!";
|
237
|
+
const title = learnJson.title.en || "LearnPack: Interactive Learning as a Service";
|
237
238
|
const previewUrl = learnJson.preview ||
|
238
239
|
"https://raw.githubusercontent.com/learnpack/ide/refs/heads/master/public/learnpack.svg";
|
239
240
|
// Replace placeholders and the <title>Old title </title> tag for a new tag with the title
|
@@ -301,7 +302,7 @@ class BuildCommand extends SessionCommand_1.default {
|
|
301
302
|
console.log(res.data);
|
302
303
|
fs.unlinkSync(zipFilePath);
|
303
304
|
this.removeDirectory(buildDir);
|
304
|
-
await (0, exports.handleAssetCreation)(sessionPayload, learnJson, "
|
305
|
+
await (0, exports.handleAssetCreation)(sessionPayload, learnJson, "en", res.data.url, "", []);
|
305
306
|
}
|
306
307
|
catch (error) {
|
307
308
|
if (axios_1.default.isAxiosError(error)) {
|
package/lib/commands/serve.d.ts
CHANGED
package/lib/commands/serve.js
CHANGED
@@ -42,21 +42,16 @@ function findLast(array, predicate) {
|
|
42
42
|
const createLearnJson = (courseInfo) => {
|
43
43
|
// console.log("courseInfo to create learn json", courseInfo)
|
44
44
|
const expectedPreviewUrl = `https://${courseInfo.slug}.learn-pack.com/preview.png`;
|
45
|
-
console.log("Preview url in generated learn.json", expectedPreviewUrl);
|
46
45
|
const language = courseInfo.language || "en";
|
47
46
|
const learnJson = {
|
48
47
|
slug: courseInfo.slug,
|
49
|
-
title:
|
50
|
-
|
51
|
-
|
52
|
-
} :
|
53
|
-
{
|
54
|
-
[language]: courseInfo.title,
|
55
|
-
},
|
48
|
+
title: {
|
49
|
+
[language]: courseInfo.title,
|
50
|
+
},
|
56
51
|
technologies: courseInfo.technologies || [],
|
57
52
|
difficulty: "beginner",
|
58
53
|
description: {
|
59
|
-
[language
|
54
|
+
[language]: courseInfo.description,
|
60
55
|
},
|
61
56
|
grading: "isolated",
|
62
57
|
telemetry: {
|
@@ -96,11 +91,10 @@ const processImage = async (url, description, rigoToken, courseSlug) => {
|
|
96
91
|
};
|
97
92
|
exports.processImage = processImage;
|
98
93
|
const createInitialSidebar = async (slugs, initialLanguage = "en") => {
|
99
|
-
const language = initialLanguage === "en" ? "us" : initialLanguage;
|
100
94
|
const sidebar = {};
|
101
95
|
for (const slug of slugs) {
|
102
96
|
sidebar[slug] = {
|
103
|
-
[
|
97
|
+
[initialLanguage]: slug,
|
104
98
|
};
|
105
99
|
}
|
106
100
|
return sidebar;
|
@@ -126,13 +120,17 @@ const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, cour
|
|
126
120
|
const all_translations = [];
|
127
121
|
for (const lang of availableLangs) {
|
128
122
|
// eslint-disable-next-line no-await-in-loop
|
129
|
-
const indexReadme = await bucket.file(`courses/${courseSlug}/README
|
123
|
+
const indexReadme = await bucket.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`);
|
130
124
|
// eslint-disable-next-line no-await-in-loop
|
131
125
|
const [indexReadmeContent] = await indexReadme.download();
|
132
126
|
const indexReadmeString = indexReadmeContent.toString();
|
133
127
|
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64");
|
134
128
|
// eslint-disable-next-line no-await-in-loop
|
135
129
|
const asset = await (0, publish_1.handleAssetCreation)({ token: bcToken, rigobotToken: rigoToken.trim() }, courseJson, lang, deployUrl, b64IndexReadme, all_translations);
|
130
|
+
if (!asset) {
|
131
|
+
console.log("No se pudo crear el asset, saltando idioma", lang);
|
132
|
+
continue;
|
133
|
+
}
|
136
134
|
all_translations.push(asset.slug);
|
137
135
|
}
|
138
136
|
};
|
@@ -334,13 +332,8 @@ class ServeCommand extends SessionCommand_1.default {
|
|
334
332
|
const { courseSlug } = req.params;
|
335
333
|
const body = req.body;
|
336
334
|
// Save the file as courses/courseSlug/README.md
|
337
|
-
const filePath = `courses/${courseSlug}/README
|
338
|
-
body.parsed.language_code === "en" ?
|
339
|
-
"md" :
|
340
|
-
`${body.parsed.language_code}.md`}`;
|
341
|
-
console.log("Saving initial readme to", filePath);
|
335
|
+
const filePath = `courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(body.parsed.language_code)}`;
|
342
336
|
await uploadFileToBucket(bucket, body.parsed.content, filePath);
|
343
|
-
console.log("Initial readme saved to", filePath);
|
344
337
|
res.json({ status: "SUCCESS" });
|
345
338
|
});
|
346
339
|
app.post("/webhooks/:courseSlug/images/:imageId", async (req, res) => {
|
@@ -497,7 +490,8 @@ class ServeCommand extends SessionCommand_1.default {
|
|
497
490
|
console.log("GET /exercise/:slug/readme");
|
498
491
|
const { slug } = req.params;
|
499
492
|
const courseSlug = req.query.slug;
|
500
|
-
const lang = req.query.lang || "
|
493
|
+
const lang = req.query.lang || "en";
|
494
|
+
console.log("LANG", lang);
|
501
495
|
if (!courseSlug) {
|
502
496
|
return res.status(400).json({ error: "Missing courseSlug" });
|
503
497
|
}
|
@@ -509,15 +503,14 @@ class ServeCommand extends SessionCommand_1.default {
|
|
509
503
|
if (readmeFiles.length === 0) {
|
510
504
|
return res.status(404).json({ error: "No README files found" });
|
511
505
|
}
|
512
|
-
const requestedFilename =
|
513
|
-
`${basePath}README.md` :
|
514
|
-
`${basePath}README.${lang}.md`;
|
506
|
+
const requestedFilename = `${basePath}README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`;
|
515
507
|
let selectedFile = readmeFiles.find(f => f === requestedFilename);
|
516
508
|
if (!selectedFile) {
|
509
|
+
console.log("No se encontro en ese idioma, devolviendo el primero");
|
517
510
|
selectedFile = readmeFiles[0];
|
518
511
|
console.warn(`Requested README not found for lang '${lang}', using '${selectedFile}'`);
|
519
512
|
}
|
520
|
-
let foundLang = "
|
513
|
+
let foundLang = "en";
|
521
514
|
const match = selectedFile.match(/readme(?:\.([a-z]{2}))?\.md$/i);
|
522
515
|
if (match && match[1]) {
|
523
516
|
foundLang = match[1].toLowerCase();
|
@@ -575,7 +568,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
575
568
|
.json({ error: "Missing title or readme content" });
|
576
569
|
}
|
577
570
|
const courseSlug = query.slug;
|
578
|
-
const fileName = `courses/${courseSlug}/exercises/${title}/README${
|
571
|
+
const fileName = `courses/${courseSlug}/exercises/${title}/README${(0, creatorUtilities_1.getReadmeExtension)(language)}`;
|
579
572
|
const file = bucket.file(fileName);
|
580
573
|
await file.save(readme);
|
581
574
|
const created = await file.exists();
|
@@ -614,9 +607,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
614
607
|
const languageCodes = new Set();
|
615
608
|
try {
|
616
609
|
await Promise.all(exerciseSlugs.map(async (slug) => {
|
617
|
-
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${
|
618
|
-
"" :
|
619
|
-
`.${currentLanguage}`}.md`;
|
610
|
+
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${(0, creatorUtilities_1.getReadmeExtension)(currentLanguage)}`;
|
620
611
|
const readme = await bucket.file(readmePath).download();
|
621
612
|
await Promise.all(languagesToTranslate.map(async (language) => {
|
622
613
|
const response = await (0, rigoActions_1.translateExercise)(rigoToken, {
|
@@ -624,18 +615,11 @@ class ServeCommand extends SessionCommand_1.default {
|
|
624
615
|
output_language: language,
|
625
616
|
exercise_slug: slug,
|
626
617
|
});
|
627
|
-
const translatedReadme = await bucket.file(`courses/${courseSlug}/exercises/${slug}/README${response.parsed.output_language_code
|
628
|
-
response.parsed.output_language_code === "en" ?
|
629
|
-
"" :
|
630
|
-
`.${response.parsed.output_language_code}`}.md`);
|
618
|
+
const translatedReadme = await bucket.file(`courses/${courseSlug}/exercises/${slug}/README${(0, creatorUtilities_1.getReadmeExtension)(response.parsed.output_language_code)}`);
|
631
619
|
await translatedReadme.save(response.parsed.translation);
|
632
620
|
languageCodes.add(response.parsed.output_language_code);
|
633
621
|
}));
|
634
622
|
}));
|
635
|
-
if (languageCodes.has("en")) {
|
636
|
-
languageCodes.delete("en");
|
637
|
-
languageCodes.add("us");
|
638
|
-
}
|
639
623
|
const currentLanguages = Object.keys(courseJson.title);
|
640
624
|
for (const languageCode of currentLanguages) {
|
641
625
|
if (languageCodes.has(languageCode)) {
|
@@ -643,7 +627,6 @@ class ServeCommand extends SessionCommand_1.default {
|
|
643
627
|
}
|
644
628
|
}
|
645
629
|
if ([...languageCodes].length > 0) {
|
646
|
-
console.log("TRANSLATING COURSE METADATA", languageCodes);
|
647
630
|
const translatedCourseMetadata = await Promise.all([...languageCodes].map(async (languageCode) => {
|
648
631
|
const result = await (0, rigoActions_1.translateCourseMetadata)(rigoToken, {
|
649
632
|
title: courseJson.title[currentLanguage],
|
@@ -662,9 +645,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
662
645
|
metadata.description;
|
663
646
|
}
|
664
647
|
await uploadFileToBucket(bucket, JSON.stringify(courseJson), `courses/${courseSlug}/learn.json`);
|
665
|
-
const previewReadme = await bucket.file(`courses/${courseSlug}/README${
|
666
|
-
"" :
|
667
|
-
`.${currentLanguage}`}.md`);
|
648
|
+
const previewReadme = await bucket.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(currentLanguage)}`);
|
668
649
|
const [previewReadmeContent] = await previewReadme.download();
|
669
650
|
const previewReadmeContentString = previewReadmeContent.toString();
|
670
651
|
await Promise.all([...languageCodes].map(async (languageCode) => {
|
@@ -674,9 +655,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
674
655
|
exercise_slug: "preview-readme",
|
675
656
|
});
|
676
657
|
await bucket
|
677
|
-
.file(`courses/${courseSlug}/README${
|
678
|
-
"" :
|
679
|
-
`.${languageCode}`}.md`)
|
658
|
+
.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(languageCode)}`)
|
680
659
|
.save(translatedPreviewReadme.parsed.translation);
|
681
660
|
}));
|
682
661
|
}
|
@@ -919,10 +898,10 @@ class ServeCommand extends SessionCommand_1.default {
|
|
919
898
|
};
|
920
899
|
copyDir(uiSrc, buildRoot);
|
921
900
|
const availableLangs = Object.keys(config.title);
|
922
|
-
let selectedLang = "
|
901
|
+
let selectedLang = "en";
|
923
902
|
let title = "";
|
924
|
-
if (availableLangs.includes("
|
925
|
-
title = config.title.
|
903
|
+
if (availableLangs.includes("en")) {
|
904
|
+
title = config.title.en;
|
926
905
|
}
|
927
906
|
else {
|
928
907
|
// Select the first available lang
|
@@ -18251,28 +18251,31 @@ const d2 = async (e) => {
|
|
18251
18251
|
try {
|
18252
18252
|
const l = Ku(15),
|
18253
18253
|
u = `https://9cw5zmww-3000.use2.devtunnels.ms/notifications/${l}`
|
18254
|
-
return
|
18255
|
-
|
18256
|
-
|
18257
|
-
|
18258
|
-
|
18259
|
-
|
18260
|
-
|
18261
|
-
|
18262
|
-
|
18263
|
-
|
18264
|
-
|
18265
|
-
|
18266
|
-
|
18267
|
-
headers: {
|
18268
|
-
"Content-Type": "application/json",
|
18269
|
-
Authorization: `Token ${t}`,
|
18254
|
+
return (
|
18255
|
+
console.log("WEBHOOK URL to send to Rigo", u),
|
18256
|
+
{
|
18257
|
+
res: (
|
18258
|
+
await Pe.post(
|
18259
|
+
`${Ds}/v1/prompting${r ? "/public" : ""}/completion/${
|
18260
|
+
L1 ? "39" : "390"
|
18261
|
+
}/`,
|
18262
|
+
{
|
18263
|
+
inputs: e,
|
18264
|
+
include_purpose_objective: !0,
|
18265
|
+
purpose_slug: n,
|
18266
|
+
webhook_url: u,
|
18270
18267
|
},
|
18271
|
-
|
18272
|
-
|
18273
|
-
|
18274
|
-
|
18275
|
-
|
18268
|
+
{
|
18269
|
+
headers: {
|
18270
|
+
"Content-Type": "application/json",
|
18271
|
+
Authorization: `Token ${t}`,
|
18272
|
+
},
|
18273
|
+
}
|
18274
|
+
)
|
18275
|
+
).data,
|
18276
|
+
notificationId: l,
|
18277
|
+
}
|
18278
|
+
)
|
18276
18279
|
} catch (l) {
|
18277
18280
|
const u = l
|
18278
18281
|
return (
|
@@ -21192,7 +21195,7 @@ function K7() {
|
|
21192
21195
|
y.rigoToken &&
|
21193
21196
|
l({ ...y, rigoToken: "", bcToken: "", userId: "", user: null })
|
21194
21197
|
let $ = T.filter((ee) => ee.lang === r.language)
|
21195
|
-
$.length === 0 && ($ = T.filter((ee) => ee.lang === "
|
21198
|
+
$.length === 0 && ($ = T.filter((ee) => ee.lang === "en"))
|
21196
21199
|
const Q = await p2(
|
21197
21200
|
{
|
21198
21201
|
courseInfo: `${JSON.stringify(
|
@@ -10,7 +10,7 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-CFM_Ypyi.js"></script>
|
14
14
|
<link rel="stylesheet" crossorigin href="/creator/assets/index-DmpsXknz.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
@@ -89,7 +89,7 @@ const exercise = (path, position, configObject) => {
|
|
89
89
|
exercises[position].done :
|
90
90
|
false,
|
91
91
|
getReadme: function (lang = null) {
|
92
|
-
if (lang === "us")
|
92
|
+
if (lang === "en" || lang === "us")
|
93
93
|
lang = null; // <-- english is default, no need to append it to the file name
|
94
94
|
if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`)) {
|
95
95
|
console_1.default.error(`Language ${lang} not found for exercise ${slug}, switching to default language`);
|
package/lib/utils/api.js
CHANGED
@@ -420,7 +420,7 @@ const getCategories = async (token) => {
|
|
420
420
|
const updateRigoAssetID = async (token, slug, asset_id) => {
|
421
421
|
const url = `${exports.RIGOBOT_HOST}/v1/learnpack/package/${slug}/`;
|
422
422
|
const headers = {
|
423
|
-
Authorization:
|
423
|
+
Authorization: "Token " + token.trim(),
|
424
424
|
};
|
425
425
|
try {
|
426
426
|
const response = await axios_1.default.put(url, { asset_id }, { headers });
|
@@ -434,7 +434,7 @@ const updateRigoAssetID = async (token, slug, asset_id) => {
|
|
434
434
|
const createRigoPackage = async (token, slug, config) => {
|
435
435
|
const url = `${exports.RIGOBOT_HOST}/v1/learnpack/package`;
|
436
436
|
const headers = {
|
437
|
-
Authorization:
|
437
|
+
Authorization: "Token " + token.trim(),
|
438
438
|
};
|
439
439
|
try {
|
440
440
|
const response = await axios_1.default.post(url, { slug, config }, { headers });
|
@@ -448,7 +448,7 @@ const createRigoPackage = async (token, slug, config) => {
|
|
448
448
|
let technologiesCache = [];
|
449
449
|
const fetchTechnologies = async () => {
|
450
450
|
const BREATHECODE_PERMANENT_TOKEN = process.env.BREATHECODE_PERMANENT_TOKEN;
|
451
|
-
const LANGS = ["en", "es"
|
451
|
+
const LANGS = ["en", "es"];
|
452
452
|
if (!BREATHECODE_PERMANENT_TOKEN) {
|
453
453
|
throw new Error("BREATHECODE_PERMANENT_TOKEN is not defined in environment variables");
|
454
454
|
}
|
@@ -34,7 +34,7 @@ async function buildConfig(bucket, courseSlug) {
|
|
34
34
|
const fname = parts.pop();
|
35
35
|
const m = fname.match(/^readme(?:\.([a-z]{2}))?\.md$/i);
|
36
36
|
if (m) {
|
37
|
-
const lang = m[1] || "
|
37
|
+
const lang = m[1] || "en";
|
38
38
|
map[slug].translations[lang] = fname;
|
39
39
|
}
|
40
40
|
else {
|
@@ -96,4 +96,5 @@ export declare function countSentences(text: string): number;
|
|
96
96
|
export declare function howManyDifficultParagraphs(paragraphs: TFKGLResult[], maxFKGL: number): number;
|
97
97
|
export declare const appendContentIndex: () => Promise<string | null>;
|
98
98
|
export declare const appendAIRules: () => Promise<string | null>;
|
99
|
+
export declare const getReadmeExtension: (language: string) => string;
|
99
100
|
export {};
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.appendAIRules = exports.appendContentIndex = exports.saveTranslatedReadme = exports.makePackageInfo = exports.getExInfo = exports.slugify = exports.estimateReadingTime = void 0;
|
3
|
+
exports.getReadmeExtension = exports.appendAIRules = exports.appendContentIndex = exports.saveTranslatedReadme = exports.makePackageInfo = exports.getExInfo = exports.slugify = exports.estimateReadingTime = void 0;
|
4
4
|
exports.checkReadability = checkReadability;
|
5
5
|
exports.extractImagesFromMarkdown = extractImagesFromMarkdown;
|
6
6
|
exports.getFilenameFromUrl = getFilenameFromUrl;
|
@@ -405,3 +405,7 @@ const appendAIRules = async () => {
|
|
405
405
|
return null;
|
406
406
|
};
|
407
407
|
exports.appendAIRules = appendAIRules;
|
408
|
+
const getReadmeExtension = (language) => {
|
409
|
+
return language === "en" || language === "us" ? ".md" : `.${language}.md`;
|
410
|
+
};
|
411
|
+
exports.getReadmeExtension = getReadmeExtension;
|
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.252",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/commands/audit.ts
CHANGED
@@ -178,8 +178,7 @@ class AuditCommand extends SessionCommand {
|
|
178
178
|
exercise: undefined,
|
179
179
|
msg: "The repository property is not in the configuration object",
|
180
180
|
})
|
181
|
-
} else
|
182
|
-
Audit.isUrl(config!.config?.repository, errors, counter)
|
181
|
+
} else Audit.isUrl(config!.config?.repository, errors, counter)
|
183
182
|
|
184
183
|
// These two lines check if the 'description' property is inside the configuration object.
|
185
184
|
Console.debug(
|
@@ -196,8 +195,7 @@ Audit.isUrl(config!.config?.repository, errors, counter)
|
|
196
195
|
msg: "The projectType property is mandatory in the configuration object",
|
197
196
|
})
|
198
197
|
|
199
|
-
if (errors.length === 0)
|
200
|
-
Console.log("The config file is ok")
|
198
|
+
if (errors.length === 0) Console.log("The config file is ok")
|
201
199
|
|
202
200
|
// Validates if images and links are working at every README file.
|
203
201
|
const exercises = config!.exercises
|
@@ -314,13 +312,11 @@ Console.log("The config file is ok")
|
|
314
312
|
const files: string[] = []
|
315
313
|
let count = 0
|
316
314
|
for (const item of readmeFiles) {
|
317
|
-
if (count < item.count)
|
318
|
-
count = item.count
|
315
|
+
if (count < item.count) count = item.count
|
319
316
|
}
|
320
317
|
|
321
318
|
for (const item of readmeFiles) {
|
322
|
-
if (item.count !== count)
|
323
|
-
files.push(` ${item.exercise}`)
|
319
|
+
if (item.count !== count) files.push(` ${item.exercise}`)
|
324
320
|
}
|
325
321
|
|
326
322
|
if (files.length > 0) {
|
@@ -390,12 +386,10 @@ files.push(` ${item.exercise}`)
|
|
390
386
|
|
391
387
|
for (const readmeFile of readmeFiles) {
|
392
388
|
// Checking the language of each README file.
|
393
|
-
if (readmeFile === "README.md")
|
394
|
-
translations.push("us")
|
389
|
+
if (readmeFile === "README.md") translations.push("en")
|
395
390
|
else {
|
396
391
|
const regexGroups = translationRegex.exec(readmeFile)
|
397
|
-
if (regexGroups)
|
398
|
-
translations.push(regexGroups[1])
|
392
|
+
if (regexGroups) translations.push(regexGroups[1])
|
399
393
|
}
|
400
394
|
|
401
395
|
const readme = fs.readFileSync(path.resolve(readmeFile)).toString()
|
@@ -450,12 +444,9 @@ translations.push(regexGroups[1])
|
|
450
444
|
const date = new Date()
|
451
445
|
learnjson.validationAt = date.getTime()
|
452
446
|
|
453
|
-
if (errors.length > 0)
|
454
|
-
learnjson.validationStatus = "
|
455
|
-
else
|
456
|
-
learnjson.validationStatus = "warning"
|
457
|
-
else
|
458
|
-
learnjson.validationStatus = "success"
|
447
|
+
if (errors.length > 0) learnjson.validationStatus = "error"
|
448
|
+
else if (warnings.length > 0) learnjson.validationStatus = "warning"
|
449
|
+
else learnjson.validationStatus = "success"
|
459
450
|
|
460
451
|
// Writes the "learn.json" file with all the new properties
|
461
452
|
await fs.promises.writeFile("./learn.json", JSON.stringify(learnjson))
|
package/src/commands/publish.ts
CHANGED
@@ -32,6 +32,7 @@ export const handleAssetCreation = async (
|
|
32
32
|
all_translations: string[] = []
|
33
33
|
) => {
|
34
34
|
const categories: Record<string, number> = {
|
35
|
+
en: 9,
|
35
36
|
us: 9,
|
36
37
|
es: 10,
|
37
38
|
}
|
@@ -346,9 +347,9 @@ class BuildCommand extends SessionCommand {
|
|
346
347
|
if (fs.existsSync(indexHtmlPath)) {
|
347
348
|
let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8")
|
348
349
|
|
349
|
-
const description = learnJson.description.
|
350
|
+
const description = learnJson.description.en || "LearnPack is awesome!"
|
350
351
|
const title =
|
351
|
-
learnJson.title.
|
352
|
+
learnJson.title.en || "LearnPack: Interactive Learning as a Service"
|
352
353
|
|
353
354
|
const previewUrl =
|
354
355
|
learnJson.preview ||
|
@@ -441,7 +442,7 @@ class BuildCommand extends SessionCommand {
|
|
441
442
|
await handleAssetCreation(
|
442
443
|
sessionPayload,
|
443
444
|
learnJson,
|
444
|
-
"
|
445
|
+
"en",
|
445
446
|
res.data.url,
|
446
447
|
"",
|
447
448
|
[]
|
package/src/commands/serve.ts
CHANGED
@@ -36,6 +36,7 @@ import * as dotenv from "dotenv"
|
|
36
36
|
import {
|
37
37
|
extractImagesFromMarkdown,
|
38
38
|
getFilenameFromUrl,
|
39
|
+
getReadmeExtension,
|
39
40
|
} from "../utils/creatorUtilities"
|
40
41
|
// import { handleAssetCreation } from "./publish"
|
41
42
|
import axios from "axios"
|
@@ -66,25 +67,18 @@ export const createLearnJson = (courseInfo: FormState) => {
|
|
66
67
|
// console.log("courseInfo to create learn json", courseInfo)
|
67
68
|
|
68
69
|
const expectedPreviewUrl = `https://${courseInfo.slug}.learn-pack.com/preview.png`
|
69
|
-
console.log("Preview url in generated learn.json", expectedPreviewUrl)
|
70
70
|
|
71
71
|
const language = courseInfo.language || "en"
|
72
72
|
|
73
73
|
const learnJson = {
|
74
74
|
slug: courseInfo.slug,
|
75
|
-
title:
|
76
|
-
language
|
77
|
-
|
78
|
-
us: courseInfo.title,
|
79
|
-
} :
|
80
|
-
{
|
81
|
-
[language]: courseInfo.title,
|
82
|
-
},
|
75
|
+
title: {
|
76
|
+
[language]: courseInfo.title,
|
77
|
+
},
|
83
78
|
technologies: courseInfo.technologies || [],
|
84
79
|
difficulty: "beginner",
|
85
80
|
description: {
|
86
|
-
[language
|
87
|
-
courseInfo.description,
|
81
|
+
[language]: courseInfo.description,
|
88
82
|
},
|
89
83
|
grading: "isolated",
|
90
84
|
telemetry: {
|
@@ -140,12 +134,10 @@ const createInitialSidebar = async (
|
|
140
134
|
slugs: string[],
|
141
135
|
initialLanguage = "en"
|
142
136
|
) => {
|
143
|
-
const language = initialLanguage === "en" ? "us" : initialLanguage
|
144
|
-
|
145
137
|
const sidebar: Record<string, Record<string, string>> = {}
|
146
138
|
for (const slug of slugs) {
|
147
139
|
sidebar[slug] = {
|
148
|
-
[
|
140
|
+
[initialLanguage]: slug,
|
149
141
|
}
|
150
142
|
}
|
151
143
|
|
@@ -208,9 +200,7 @@ const createMultiLangAsset = async (
|
|
208
200
|
for (const lang of availableLangs) {
|
209
201
|
// eslint-disable-next-line no-await-in-loop
|
210
202
|
const indexReadme = await bucket.file(
|
211
|
-
`courses/${courseSlug}/README
|
212
|
-
lang === "us" || lang === "en" ? "md" : `${lang}.md`
|
213
|
-
}`
|
203
|
+
`courses/${courseSlug}/README${getReadmeExtension(lang)}`
|
214
204
|
)
|
215
205
|
// eslint-disable-next-line no-await-in-loop
|
216
206
|
const [indexReadmeContent] = await indexReadme.download()
|
@@ -227,6 +217,11 @@ const createMultiLangAsset = async (
|
|
227
217
|
all_translations
|
228
218
|
)
|
229
219
|
|
220
|
+
if (!asset) {
|
221
|
+
console.log("No se pudo crear el asset, saltando idioma", lang)
|
222
|
+
continue
|
223
|
+
}
|
224
|
+
|
230
225
|
all_translations.push(asset.slug)
|
231
226
|
}
|
232
227
|
}
|
@@ -526,15 +521,10 @@ export default class ServeCommand extends SessionCommand {
|
|
526
521
|
const body = req.body
|
527
522
|
|
528
523
|
// Save the file as courses/courseSlug/README.md
|
529
|
-
const filePath = `courses/${courseSlug}/README
|
530
|
-
body.parsed.language_code
|
531
|
-
|
532
|
-
"md" :
|
533
|
-
`${body.parsed.language_code}.md`
|
534
|
-
}`
|
535
|
-
console.log("Saving initial readme to", filePath)
|
524
|
+
const filePath = `courses/${courseSlug}/README${getReadmeExtension(
|
525
|
+
body.parsed.language_code
|
526
|
+
)}`
|
536
527
|
await uploadFileToBucket(bucket, body.parsed.content, filePath)
|
537
|
-
console.log("Initial readme saved to", filePath)
|
538
528
|
|
539
529
|
res.json({ status: "SUCCESS" })
|
540
530
|
}
|
@@ -778,7 +768,9 @@ export default class ServeCommand extends SessionCommand {
|
|
778
768
|
|
779
769
|
const { slug } = req.params
|
780
770
|
const courseSlug = req.query.slug
|
781
|
-
const lang = req.query.lang || "
|
771
|
+
const lang = req.query.lang || "en"
|
772
|
+
|
773
|
+
console.log("LANG", lang)
|
782
774
|
|
783
775
|
if (!courseSlug) {
|
784
776
|
return res.status(400).json({ error: "Missing courseSlug" })
|
@@ -796,21 +788,21 @@ export default class ServeCommand extends SessionCommand {
|
|
796
788
|
return res.status(404).json({ error: "No README files found" })
|
797
789
|
}
|
798
790
|
|
799
|
-
const requestedFilename =
|
800
|
-
lang
|
801
|
-
|
802
|
-
`${basePath}README.${lang}.md`
|
791
|
+
const requestedFilename = `${basePath}README${getReadmeExtension(
|
792
|
+
lang as string
|
793
|
+
)}`
|
803
794
|
|
804
795
|
let selectedFile = readmeFiles.find(f => f === requestedFilename)
|
805
796
|
|
806
797
|
if (!selectedFile) {
|
798
|
+
console.log("No se encontro en ese idioma, devolviendo el primero")
|
807
799
|
selectedFile = readmeFiles[0]
|
808
800
|
console.warn(
|
809
801
|
`Requested README not found for lang '${lang}', using '${selectedFile}'`
|
810
802
|
)
|
811
803
|
}
|
812
804
|
|
813
|
-
let foundLang = "
|
805
|
+
let foundLang = "en"
|
814
806
|
const match = selectedFile.match(/readme(?:\.([a-z]{2}))?\.md$/i)
|
815
807
|
if (match && match[1]) {
|
816
808
|
foundLang = match[1].toLowerCase()
|
@@ -885,9 +877,9 @@ export default class ServeCommand extends SessionCommand {
|
|
885
877
|
|
886
878
|
const courseSlug = query.slug
|
887
879
|
|
888
|
-
const fileName = `courses/${courseSlug}/exercises/${title}/README${
|
889
|
-
language
|
890
|
-
}
|
880
|
+
const fileName = `courses/${courseSlug}/exercises/${title}/README${getReadmeExtension(
|
881
|
+
language
|
882
|
+
)}`
|
891
883
|
const file = bucket.file(fileName)
|
892
884
|
await file.save(readme)
|
893
885
|
const created = await file.exists()
|
@@ -935,11 +927,9 @@ export default class ServeCommand extends SessionCommand {
|
|
935
927
|
try {
|
936
928
|
await Promise.all(
|
937
929
|
exerciseSlugs.map(async (slug: string) => {
|
938
|
-
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${
|
939
|
-
currentLanguage
|
940
|
-
|
941
|
-
`.${currentLanguage}`
|
942
|
-
}.md`
|
930
|
+
const readmePath = `courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
|
931
|
+
currentLanguage
|
932
|
+
)}`
|
943
933
|
|
944
934
|
const readme = await bucket.file(readmePath).download()
|
945
935
|
|
@@ -952,12 +942,9 @@ export default class ServeCommand extends SessionCommand {
|
|
952
942
|
})
|
953
943
|
|
954
944
|
const translatedReadme = await bucket.file(
|
955
|
-
`courses/${courseSlug}/exercises/${slug}/README${
|
956
|
-
response.parsed.output_language_code
|
957
|
-
|
958
|
-
"" :
|
959
|
-
`.${response.parsed.output_language_code}`
|
960
|
-
}.md`
|
945
|
+
`courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
|
946
|
+
response.parsed.output_language_code
|
947
|
+
)}`
|
961
948
|
)
|
962
949
|
await translatedReadme.save(response.parsed.translation)
|
963
950
|
|
@@ -967,11 +954,6 @@ export default class ServeCommand extends SessionCommand {
|
|
967
954
|
})
|
968
955
|
)
|
969
956
|
|
970
|
-
if (languageCodes.has("en")) {
|
971
|
-
languageCodes.delete("en")
|
972
|
-
languageCodes.add("us")
|
973
|
-
}
|
974
|
-
|
975
957
|
const currentLanguages = Object.keys(courseJson.title)
|
976
958
|
for (const languageCode of currentLanguages) {
|
977
959
|
if (languageCodes.has(languageCode)) {
|
@@ -980,8 +962,6 @@ export default class ServeCommand extends SessionCommand {
|
|
980
962
|
}
|
981
963
|
|
982
964
|
if ([...languageCodes].length > 0) {
|
983
|
-
console.log("TRANSLATING COURSE METADATA", languageCodes)
|
984
|
-
|
985
965
|
const translatedCourseMetadata = await Promise.all(
|
986
966
|
[...languageCodes].map(async languageCode => {
|
987
967
|
const result = await translateCourseMetadata(rigoToken, {
|
@@ -1011,11 +991,7 @@ export default class ServeCommand extends SessionCommand {
|
|
1011
991
|
)
|
1012
992
|
|
1013
993
|
const previewReadme = await bucket.file(
|
1014
|
-
`courses/${courseSlug}/README${
|
1015
|
-
currentLanguage === "us" || currentLanguage === "en" ?
|
1016
|
-
"" :
|
1017
|
-
`.${currentLanguage}`
|
1018
|
-
}.md`
|
994
|
+
`courses/${courseSlug}/README${getReadmeExtension(currentLanguage)}`
|
1019
995
|
)
|
1020
996
|
const [previewReadmeContent] = await previewReadme.download()
|
1021
997
|
const previewReadmeContentString = previewReadmeContent.toString()
|
@@ -1033,11 +1009,9 @@ export default class ServeCommand extends SessionCommand {
|
|
1033
1009
|
|
1034
1010
|
await bucket
|
1035
1011
|
.file(
|
1036
|
-
`courses/${courseSlug}/README${
|
1037
|
-
languageCode
|
1038
|
-
|
1039
|
-
`.${languageCode}`
|
1040
|
-
}.md`
|
1012
|
+
`courses/${courseSlug}/README${getReadmeExtension(
|
1013
|
+
languageCode as string
|
1014
|
+
)}`
|
1041
1015
|
)
|
1042
1016
|
.save(translatedPreviewReadme.parsed.translation)
|
1043
1017
|
})
|
@@ -1436,10 +1410,10 @@ export default class ServeCommand extends SessionCommand {
|
|
1436
1410
|
|
1437
1411
|
const availableLangs = Object.keys(config.title)
|
1438
1412
|
|
1439
|
-
let selectedLang = "
|
1413
|
+
let selectedLang = "en"
|
1440
1414
|
let title = ""
|
1441
|
-
if (availableLangs.includes("
|
1442
|
-
title = config.title.
|
1415
|
+
if (availableLangs.includes("en")) {
|
1416
|
+
title = config.title.en
|
1443
1417
|
} else {
|
1444
1418
|
// Select the first available lang
|
1445
1419
|
title = config.title[availableLangs[0]]
|
package/src/creator/src/App.tsx
CHANGED
@@ -174,7 +174,7 @@ function App() {
|
|
174
174
|
let techs = technologies.filter((t) => t.lang === formState.language)
|
175
175
|
|
176
176
|
if (techs.length === 0) {
|
177
|
-
techs = technologies.filter((t) => t.lang === "
|
177
|
+
techs = technologies.filter((t) => t.lang === "en")
|
178
178
|
}
|
179
179
|
|
180
180
|
const res = await publicInteractiveCreation(
|
@@ -24,6 +24,8 @@ export const publicInteractiveCreation = async (
|
|
24
24
|
"https://9cw5zmww-3000.use2.devtunnels.ms"
|
25
25
|
}/notifications/${randomUID}`
|
26
26
|
|
27
|
+
console.log("WEBHOOK URL to send to Rigo", webhookUrl)
|
28
|
+
|
27
29
|
const response = await axios.post(
|
28
30
|
`${RIGOBOT_HOST}/v1/prompting${
|
29
31
|
publicRequest ? "/public" : ""
|
@@ -18251,28 +18251,31 @@ const d2 = async (e) => {
|
|
18251
18251
|
try {
|
18252
18252
|
const l = Ku(15),
|
18253
18253
|
u = `https://9cw5zmww-3000.use2.devtunnels.ms/notifications/${l}`
|
18254
|
-
return
|
18255
|
-
|
18256
|
-
|
18257
|
-
|
18258
|
-
|
18259
|
-
|
18260
|
-
|
18261
|
-
|
18262
|
-
|
18263
|
-
|
18264
|
-
|
18265
|
-
|
18266
|
-
|
18267
|
-
headers: {
|
18268
|
-
"Content-Type": "application/json",
|
18269
|
-
Authorization: `Token ${t}`,
|
18254
|
+
return (
|
18255
|
+
console.log("WEBHOOK URL to send to Rigo", u),
|
18256
|
+
{
|
18257
|
+
res: (
|
18258
|
+
await Pe.post(
|
18259
|
+
`${Ds}/v1/prompting${r ? "/public" : ""}/completion/${
|
18260
|
+
L1 ? "39" : "390"
|
18261
|
+
}/`,
|
18262
|
+
{
|
18263
|
+
inputs: e,
|
18264
|
+
include_purpose_objective: !0,
|
18265
|
+
purpose_slug: n,
|
18266
|
+
webhook_url: u,
|
18270
18267
|
},
|
18271
|
-
|
18272
|
-
|
18273
|
-
|
18274
|
-
|
18275
|
-
|
18268
|
+
{
|
18269
|
+
headers: {
|
18270
|
+
"Content-Type": "application/json",
|
18271
|
+
Authorization: `Token ${t}`,
|
18272
|
+
},
|
18273
|
+
}
|
18274
|
+
)
|
18275
|
+
).data,
|
18276
|
+
notificationId: l,
|
18277
|
+
}
|
18278
|
+
)
|
18276
18279
|
} catch (l) {
|
18277
18280
|
const u = l
|
18278
18281
|
return (
|
@@ -21192,7 +21195,7 @@ function K7() {
|
|
21192
21195
|
y.rigoToken &&
|
21193
21196
|
l({ ...y, rigoToken: "", bcToken: "", userId: "", user: null })
|
21194
21197
|
let $ = T.filter((ee) => ee.lang === r.language)
|
21195
|
-
$.length === 0 && ($ = T.filter((ee) => ee.lang === "
|
21198
|
+
$.length === 0 && ($ = T.filter((ee) => ee.lang === "en"))
|
21196
21199
|
const Q = await p2(
|
21197
21200
|
{
|
21198
21201
|
courseInfo: `${JSON.stringify(
|
@@ -10,7 +10,7 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-CFM_Ypyi.js"></script>
|
14
14
|
<link rel="stylesheet" crossorigin href="/creator/assets/index-DmpsXknz.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
@@ -85,15 +85,12 @@ export const exercise = (
|
|
85
85
|
// fs.writeFileSync(path + "/" + file, updatedMarkdown, "utf8")
|
86
86
|
// }
|
87
87
|
|
88
|
-
if (parts.length === 3)
|
89
|
-
translations
|
90
|
-
else
|
91
|
-
translations.us = file
|
88
|
+
if (parts.length === 3) translations[parts[1]] = file
|
89
|
+
else translations.us = file
|
92
90
|
}
|
93
91
|
|
94
92
|
// if the slug is a dot, it means there is not "exercises" folder, and its just a single README.md
|
95
|
-
if (slug === ".")
|
96
|
-
slug = "default-index"
|
93
|
+
if (slug === ".") slug = "default-index"
|
97
94
|
|
98
95
|
const detected = detect(configObject, files)
|
99
96
|
|
@@ -120,16 +117,14 @@ slug = "default-index"
|
|
120
117
|
exercises[position].done :
|
121
118
|
false,
|
122
119
|
getReadme: function (lang = null) {
|
123
|
-
if (lang === "us")
|
124
|
-
lang = null // <-- english is default, no need to append it to the file name
|
120
|
+
if (lang === "en" || lang === "us") lang = null // <-- english is default, no need to append it to the file name
|
125
121
|
|
126
122
|
if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`)) {
|
127
123
|
Console.error(
|
128
124
|
`Language ${lang} not found for exercise ${slug}, switching to default language`
|
129
125
|
)
|
130
126
|
|
131
|
-
if (lang)
|
132
|
-
lang = null
|
127
|
+
if (lang) lang = null
|
133
128
|
|
134
129
|
if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`))
|
135
130
|
throw new Error(
|
@@ -169,8 +164,7 @@ lang = null
|
|
169
164
|
|
170
165
|
for (const _file of this.files) {
|
171
166
|
const stats = fs.statSync(_file.path)
|
172
|
-
if (stats.isDirectory() || _file.hidden)
|
173
|
-
continue
|
167
|
+
if (stats.isDirectory() || _file.hidden) continue
|
174
168
|
const fileContent = fs.readFileSync(_file.path)
|
175
169
|
if (
|
176
170
|
!fs.existsSync(`${config?.dirPath}/resets/${this.slug}/${_file.name}`)
|
@@ -217,8 +211,7 @@ continue
|
|
217
211
|
getTestReport: function () {
|
218
212
|
const _path = `${configObject?.confPath?.base}/reports/${this.slug}.json`
|
219
213
|
|
220
|
-
if (!fs.existsSync(_path))
|
221
|
-
return {}
|
214
|
+
if (!fs.existsSync(_path)) return {}
|
222
215
|
|
223
216
|
const content = fs.readFileSync(_path)
|
224
217
|
const data = JSON.parse(`${content}`)
|
@@ -230,8 +223,7 @@ return {}
|
|
230
223
|
}
|
231
224
|
|
232
225
|
export const validateExerciseDirectoryName = (str: string) => {
|
233
|
-
if (str === "./")
|
234
|
-
return true
|
226
|
+
if (str === "./") return true
|
235
227
|
// TODO: Add nameValidationREgex from the config
|
236
228
|
const regex = /^(\d{2,3}(\.\d{1,2})?-([\dA-Za-z]+(-|_)?)+)$/
|
237
229
|
return regex.test(str)
|
package/src/utils/api.ts
CHANGED
@@ -536,7 +536,7 @@ const updateRigoAssetID = async (
|
|
536
536
|
) => {
|
537
537
|
const url = `${RIGOBOT_HOST}/v1/learnpack/package/${slug}/`
|
538
538
|
const headers = {
|
539
|
-
Authorization:
|
539
|
+
Authorization: "Token " + token.trim(),
|
540
540
|
}
|
541
541
|
try {
|
542
542
|
const response = await axios.put(url, { asset_id }, { headers })
|
@@ -550,7 +550,7 @@ const updateRigoAssetID = async (
|
|
550
550
|
const createRigoPackage = async (token: string, slug: string, config: any) => {
|
551
551
|
const url = `${RIGOBOT_HOST}/v1/learnpack/package`
|
552
552
|
const headers = {
|
553
|
-
Authorization:
|
553
|
+
Authorization: "Token " + token.trim(),
|
554
554
|
}
|
555
555
|
try {
|
556
556
|
const response = await axios.post(url, { slug, config }, { headers })
|
@@ -570,7 +570,7 @@ let technologiesCache: TTechnology[] = []
|
|
570
570
|
|
571
571
|
export const fetchTechnologies = async () => {
|
572
572
|
const BREATHECODE_PERMANENT_TOKEN = process.env.BREATHECODE_PERMANENT_TOKEN
|
573
|
-
const LANGS = ["en", "es"
|
573
|
+
const LANGS = ["en", "es"]
|
574
574
|
|
575
575
|
if (!BREATHECODE_PERMANENT_TOKEN) {
|
576
576
|
throw new Error(
|
@@ -59,7 +59,7 @@ export async function buildConfig(
|
|
59
59
|
const fname = parts.pop()!
|
60
60
|
const m = fname.match(/^readme(?:\.([a-z]{2}))?\.md$/i)
|
61
61
|
if (m) {
|
62
|
-
const lang = m[1] || "
|
62
|
+
const lang = m[1] || "en"
|
63
63
|
map[slug].translations[lang] = fname
|
64
64
|
} else {
|
65
65
|
map[slug].files.push({
|
@@ -12,14 +12,14 @@
|
|
12
12
|
"title": {
|
13
13
|
"type": "object",
|
14
14
|
"properties": {
|
15
|
-
"
|
15
|
+
"en": {
|
16
16
|
"type": "string"
|
17
17
|
},
|
18
18
|
"es": {
|
19
19
|
"type": "string"
|
20
20
|
}
|
21
21
|
},
|
22
|
-
"required": ["
|
22
|
+
"required": ["en"]
|
23
23
|
},
|
24
24
|
"repository": {
|
25
25
|
"type": "string",
|
@@ -32,14 +32,14 @@
|
|
32
32
|
"description": {
|
33
33
|
"type": "object",
|
34
34
|
"properties": {
|
35
|
-
"
|
35
|
+
"en": {
|
36
36
|
"type": "string"
|
37
37
|
},
|
38
38
|
"es": {
|
39
39
|
"type": "string"
|
40
40
|
}
|
41
41
|
},
|
42
|
-
"required": ["
|
42
|
+
"required": ["en"]
|
43
43
|
},
|
44
44
|
"duration": {
|
45
45
|
"type": "integer"
|
@@ -96,7 +96,7 @@
|
|
96
96
|
"intro": {
|
97
97
|
"type": "object",
|
98
98
|
"properties": {
|
99
|
-
"
|
99
|
+
"en": {
|
100
100
|
"type": "string",
|
101
101
|
"format": "uri"
|
102
102
|
},
|
@@ -12,14 +12,14 @@
|
|
12
12
|
"title": {
|
13
13
|
"type": "object",
|
14
14
|
"properties": {
|
15
|
-
"
|
15
|
+
"en": {
|
16
16
|
"type": "string"
|
17
17
|
},
|
18
18
|
"es": {
|
19
19
|
"type": "string"
|
20
20
|
}
|
21
21
|
},
|
22
|
-
"required": ["
|
22
|
+
"required": ["en"]
|
23
23
|
},
|
24
24
|
"repository": {
|
25
25
|
"type": "string",
|
@@ -32,14 +32,14 @@
|
|
32
32
|
"description": {
|
33
33
|
"type": "object",
|
34
34
|
"properties": {
|
35
|
-
"
|
35
|
+
"en": {
|
36
36
|
"type": "string"
|
37
37
|
},
|
38
38
|
"es": {
|
39
39
|
"type": "string"
|
40
40
|
}
|
41
41
|
},
|
42
|
-
"required": ["
|
42
|
+
"required": ["en"]
|
43
43
|
},
|
44
44
|
"duration": {
|
45
45
|
"type": "integer"
|
@@ -96,7 +96,7 @@
|
|
96
96
|
"intro": {
|
97
97
|
"type": "object",
|
98
98
|
"properties": {
|
99
|
-
"
|
99
|
+
"en": {
|
100
100
|
"type": "string",
|
101
101
|
"format": "uri"
|
102
102
|
},
|