@learnpack/learnpack 2.1.27 → 2.1.29

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. package/README.md +10 -10
  2. package/lib/commands/audit.d.ts +6 -0
  3. package/lib/commands/audit.js +342 -0
  4. package/lib/commands/clean.d.ts +8 -0
  5. package/lib/commands/clean.js +25 -0
  6. package/lib/commands/download.d.ts +13 -0
  7. package/lib/commands/download.js +55 -0
  8. package/lib/commands/init.d.ts +9 -0
  9. package/lib/commands/init.js +123 -0
  10. package/lib/commands/login.d.ts +14 -0
  11. package/lib/commands/login.js +37 -0
  12. package/lib/commands/logout.d.ts +14 -0
  13. package/lib/commands/logout.js +37 -0
  14. package/lib/commands/publish.d.ts +14 -0
  15. package/lib/commands/publish.js +82 -0
  16. package/lib/commands/start.d.ts +7 -0
  17. package/lib/commands/start.js +176 -0
  18. package/lib/commands/test.d.ts +6 -0
  19. package/lib/commands/test.js +62 -0
  20. package/lib/index.d.ts +1 -0
  21. package/lib/index.js +4 -0
  22. package/lib/managers/config/allowed_files.d.ts +5 -0
  23. package/lib/managers/config/allowed_files.js +30 -0
  24. package/lib/managers/config/defaults.d.ts +39 -0
  25. package/lib/managers/config/defaults.js +40 -0
  26. package/lib/managers/config/exercise.d.ts +36 -0
  27. package/lib/managers/config/exercise.js +233 -0
  28. package/lib/managers/config/index.d.ts +3 -0
  29. package/lib/managers/config/index.js +320 -0
  30. package/lib/managers/file.d.ts +14 -0
  31. package/lib/managers/file.js +141 -0
  32. package/lib/managers/gitpod.d.ts +3 -0
  33. package/lib/managers/gitpod.js +67 -0
  34. package/lib/managers/server/index.d.ts +6 -0
  35. package/lib/managers/server/index.js +58 -0
  36. package/lib/managers/server/routes.d.ts +4 -0
  37. package/lib/managers/server/routes.js +201 -0
  38. package/lib/managers/session.d.ts +3 -0
  39. package/lib/managers/session.js +131 -0
  40. package/lib/managers/socket.d.ts +3 -0
  41. package/lib/managers/socket.js +178 -0
  42. package/lib/managers/test.d.ts +0 -0
  43. package/lib/managers/test.js +84 -0
  44. package/lib/models/action.d.ts +2 -0
  45. package/lib/models/action.js +2 -0
  46. package/lib/models/audit.d.ts +15 -0
  47. package/lib/models/audit.js +2 -0
  48. package/lib/models/config-manager.d.ts +21 -0
  49. package/lib/models/config-manager.js +2 -0
  50. package/lib/models/config.d.ts +62 -0
  51. package/lib/models/config.js +2 -0
  52. package/lib/models/counter.d.ts +11 -0
  53. package/lib/models/counter.js +2 -0
  54. package/lib/models/errors.d.ts +15 -0
  55. package/lib/models/errors.js +2 -0
  56. package/lib/models/exercise-obj.d.ts +30 -0
  57. package/lib/models/exercise-obj.js +2 -0
  58. package/lib/models/file.d.ts +5 -0
  59. package/lib/models/file.js +2 -0
  60. package/lib/models/findings.d.ts +17 -0
  61. package/lib/models/findings.js +2 -0
  62. package/lib/models/flags.d.ts +10 -0
  63. package/lib/models/flags.js +2 -0
  64. package/lib/models/front-matter.d.ts +11 -0
  65. package/lib/models/front-matter.js +2 -0
  66. package/lib/models/gitpod-data.d.ts +16 -0
  67. package/lib/models/gitpod-data.js +2 -0
  68. package/lib/models/language.d.ts +4 -0
  69. package/lib/models/language.js +2 -0
  70. package/lib/models/package.d.ts +7 -0
  71. package/lib/models/package.js +2 -0
  72. package/lib/models/plugin-config.d.ts +16 -0
  73. package/lib/models/plugin-config.js +2 -0
  74. package/lib/models/session.d.ts +26 -0
  75. package/lib/models/session.js +2 -0
  76. package/lib/models/socket.d.ts +32 -0
  77. package/lib/models/socket.js +2 -0
  78. package/lib/models/status.d.ts +1 -0
  79. package/lib/models/status.js +2 -0
  80. package/lib/models/success-types.d.ts +1 -0
  81. package/lib/models/success-types.js +2 -0
  82. package/lib/plugin/command/compile.d.ts +6 -0
  83. package/lib/plugin/command/compile.js +18 -0
  84. package/lib/plugin/command/test.d.ts +6 -0
  85. package/lib/plugin/command/test.js +25 -0
  86. package/lib/plugin/index.d.ts +27 -0
  87. package/lib/plugin/index.js +7 -0
  88. package/lib/plugin/plugin.d.ts +8 -0
  89. package/lib/plugin/plugin.js +68 -0
  90. package/lib/plugin/utils.d.ts +16 -0
  91. package/lib/plugin/utils.js +58 -0
  92. package/lib/ui/download.d.ts +5 -0
  93. package/lib/ui/download.js +61 -0
  94. package/lib/utils/BaseCommand.d.ts +8 -0
  95. package/lib/utils/BaseCommand.js +41 -0
  96. package/lib/utils/SessionCommand.d.ts +10 -0
  97. package/lib/utils/SessionCommand.js +47 -0
  98. package/lib/utils/api.d.ts +14 -0
  99. package/lib/utils/api.js +218 -0
  100. package/lib/utils/audit.d.ts +16 -0
  101. package/lib/utils/audit.js +302 -0
  102. package/lib/utils/console.d.ts +12 -0
  103. package/lib/utils/console.js +19 -0
  104. package/lib/utils/errors.d.ts +17 -0
  105. package/lib/utils/errors.js +100 -0
  106. package/lib/utils/exercisesQueue.d.ts +9 -0
  107. package/lib/utils/exercisesQueue.js +38 -0
  108. package/lib/utils/fileQueue.d.ts +40 -0
  109. package/lib/utils/fileQueue.js +168 -0
  110. package/lib/utils/misc.d.ts +1 -0
  111. package/lib/utils/misc.js +23 -0
  112. package/lib/utils/validators.d.ts +5 -0
  113. package/lib/utils/validators.js +17 -0
  114. package/lib/utils/watcher.d.ts +2 -0
  115. package/lib/utils/watcher.js +23 -0
  116. package/oclif.manifest.json +1 -1
  117. package/package.json +2 -1
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const console_1 = require("../utils/console");
4
+ const storage = require("node-persist");
5
+ const cli_ux_1 = require("cli-ux");
6
+ const HOST = "https://breathecode.herokuapp.com";
7
+ const RIGOBOT_HOST = "https://rigobot.herokuapp.com";
8
+ // eslint-disable-next-line
9
+ const _fetch = require("node-fetch");
10
+ const fetch = async (url, options = {}) => {
11
+ const headers = { "Content-Type": "application/json" };
12
+ console_1.default.log(`Fetching ${url}`);
13
+ let session = null;
14
+ try {
15
+ session = await storage.getItem("bc-payload");
16
+ if (session.token && session.token !== "" && !url.includes("/token"))
17
+ headers.Authorization = "Token " + session.token;
18
+ }
19
+ catch (_a) { }
20
+ try {
21
+ const resp = await _fetch(url, Object.assign(Object.assign({}, options), { headers: Object.assign(Object.assign({}, headers), options.headers) }));
22
+ if (resp.status >= 200 && resp.status < 300)
23
+ return await resp.json();
24
+ if (resp.status === 401)
25
+ throw APIError("Invalid authentication credentials", 401);
26
+ else if (resp.status === 404)
27
+ throw APIError("Package not found", 404);
28
+ else if (resp.status >= 500)
29
+ throw APIError("Impossible to connect with the server", 500);
30
+ else if (resp.status >= 400) {
31
+ const error = await resp.json();
32
+ if (error.detail || error.error) {
33
+ throw APIError(error.detail || error.error);
34
+ }
35
+ else if (error.nonFieldErrors) {
36
+ throw APIError(error.nonFieldErrors[0], error);
37
+ }
38
+ else if (typeof error === "object") {
39
+ if (Object.keys(error).length > 0) {
40
+ const key = error[Object.keys(error)[0]];
41
+ throw APIError(`${key}: ${error[key][0]}`, error);
42
+ }
43
+ }
44
+ else {
45
+ throw APIError("Uknown error");
46
+ }
47
+ }
48
+ else
49
+ throw APIError("Uknown error");
50
+ }
51
+ catch (error) {
52
+ console_1.default.error(error.message);
53
+ throw error;
54
+ }
55
+ };
56
+ const login = async (identification, password) => {
57
+ try {
58
+ cli_ux_1.default.action.start(`Looking for credentials with ${identification}`);
59
+ await cli_ux_1.default.wait(1000);
60
+ const url = `${HOST}/v1/auth/login/`;
61
+ // Console.log(url);
62
+ const data = await fetch(url, {
63
+ body: JSON.stringify({
64
+ email: identification,
65
+ password: password,
66
+ }),
67
+ method: "post",
68
+ });
69
+ cli_ux_1.default.action.stop("ready");
70
+ const payload = await loginRigo(data.token);
71
+ return Object.assign(Object.assign({}, data), { rigobot: payload });
72
+ }
73
+ catch (error) {
74
+ cli_ux_1.default.action.stop("error");
75
+ console_1.default.error(error.message);
76
+ console_1.default.debug(error);
77
+ }
78
+ };
79
+ const loginRigo = async (token) => {
80
+ const rigoUrl = `${RIGOBOT_HOST}/v1/auth/me/token?breathecode_token=${token}`;
81
+ const rigoResp = await _fetch(rigoUrl);
82
+ const rigobotJson = await rigoResp.json();
83
+ return rigobotJson;
84
+ };
85
+ const getOpenAIToken = async () => {
86
+ const token = await storage.getItem("openai-token");
87
+ return token;
88
+ };
89
+ const getRigoFeedback = async (readme, currentCode) => {
90
+ const payload = {
91
+ current_code: Buffer.from(currentCode).toString("base64"),
92
+ tutorial: Buffer.from(readme).toString("base64"),
93
+ };
94
+ const session = await storage.getItem("bc-payload");
95
+ const response = await _fetch(`${RIGOBOT_HOST}/v1/conversation/feedback/`, {
96
+ method: "POST",
97
+ headers: {
98
+ "Content-Type": "application/json",
99
+ Authorization: `Token ${session.rigobot.key}`,
100
+ },
101
+ body: JSON.stringify(payload),
102
+ });
103
+ const responseData = await response.json();
104
+ return responseData.feedback;
105
+ };
106
+ const publish = async (config) => {
107
+ const keys = [
108
+ "difficulty",
109
+ "language",
110
+ "skills",
111
+ "technologies",
112
+ "slug",
113
+ "repository",
114
+ "author",
115
+ "title",
116
+ ];
117
+ const payload = {};
118
+ for (const k of keys)
119
+ config[k] ? (payload[k] = config[k]) : null;
120
+ try {
121
+ console.log("Package to publish:", payload);
122
+ cli_ux_1.default.action.start("Updating package information...");
123
+ await cli_ux_1.default.wait(1000);
124
+ const data = await fetch(`${HOST}/v1/package/${config.slug}`, {
125
+ method: "PUT",
126
+ body: JSON.stringify(payload),
127
+ });
128
+ cli_ux_1.default.action.stop("ready");
129
+ return data;
130
+ }
131
+ catch (error) {
132
+ console.log("payload", payload);
133
+ console_1.default.error(error.message);
134
+ console_1.default.debug(error);
135
+ throw error;
136
+ }
137
+ };
138
+ const update = async (config) => {
139
+ try {
140
+ cli_ux_1.default.action.start("Updating package information...");
141
+ await cli_ux_1.default.wait(1000);
142
+ const data = await fetch(`${HOST}/v1/package/`, {
143
+ method: "POST",
144
+ body: JSON.stringify(config),
145
+ });
146
+ cli_ux_1.default.action.stop("ready");
147
+ return data;
148
+ }
149
+ catch (error) {
150
+ console_1.default.error(error.message);
151
+ console_1.default.debug(error);
152
+ throw error;
153
+ }
154
+ };
155
+ const getPackage = async (slug) => {
156
+ try {
157
+ cli_ux_1.default.action.start("Downloading package information...");
158
+ await cli_ux_1.default.wait(1000);
159
+ const data = await fetch(`${HOST}/v1/package/${slug}`);
160
+ cli_ux_1.default.action.stop("ready");
161
+ return data;
162
+ }
163
+ catch (error) {
164
+ if (error.status === 404)
165
+ console_1.default.error(`Package ${slug} does not exist`);
166
+ else
167
+ console_1.default.error(`Package ${slug} does not exist`);
168
+ console_1.default.debug(error);
169
+ throw error;
170
+ }
171
+ };
172
+ const getLangs = async () => {
173
+ try {
174
+ cli_ux_1.default.action.start("Downloading language options...");
175
+ await cli_ux_1.default.wait(1000);
176
+ const data = await fetch(`${HOST}/v1/package/language`);
177
+ cli_ux_1.default.action.stop("ready");
178
+ return data;
179
+ }
180
+ catch (error) {
181
+ if (error.status === 404)
182
+ console_1.default.error("Package slug does not exist");
183
+ else
184
+ console_1.default.error("Package slug does not exist");
185
+ console_1.default.debug(error);
186
+ throw error;
187
+ }
188
+ };
189
+ const getAllPackages = async ({ lang = "", slug = "", }) => {
190
+ try {
191
+ cli_ux_1.default.action.start("Downloading packages...");
192
+ await cli_ux_1.default.wait(1000);
193
+ const data = await fetch(`${HOST}/v1/package/all?limit=100&language=${lang}&slug=${slug}`);
194
+ cli_ux_1.default.action.stop("ready");
195
+ return data;
196
+ }
197
+ catch (error) {
198
+ console_1.default.error(`Package ${slug} does not exist`);
199
+ console_1.default.debug(error);
200
+ throw error;
201
+ }
202
+ };
203
+ const APIError = (error, code) => {
204
+ const message = error.message || error;
205
+ const _err = new Error(message);
206
+ _err.status = code || 400;
207
+ return _err;
208
+ };
209
+ exports.default = {
210
+ login,
211
+ publish,
212
+ update,
213
+ getPackage,
214
+ getLangs,
215
+ getAllPackages,
216
+ getRigoFeedback,
217
+ getOpenAIToken,
218
+ };
@@ -0,0 +1,16 @@
1
+ import { IAuditErrors } from "../models/audit";
2
+ import { IConfigObj } from "../models/config";
3
+ import { ICounter } from "../models/counter";
4
+ import { IFindings } from "../models/findings";
5
+ import { IExercise } from "../models/exercise-obj";
6
+ declare const _default: {
7
+ isUrl: (url: string, errors: IAuditErrors[], counter: ICounter) => Promise<boolean>;
8
+ checkForEmptySpaces: (str: string) => boolean;
9
+ checkLearnpackClean: (configObj: IConfigObj, errors: IAuditErrors[]) => void;
10
+ findInFile: (types: string[], content: string) => IFindings;
11
+ checkUrl: (config: IConfigObj, filePath: string, fileName: string, exercise: IExercise | undefined, errors: IAuditErrors[], warnings: IAuditErrors[], counter: ICounter | undefined) => Promise<boolean>;
12
+ writeFile: (content: string, filePath: string) => Promise<void>;
13
+ showErrors: (errors: IAuditErrors[], counter: ICounter | undefined) => Promise<unknown>;
14
+ showWarnings: (warnings: IAuditErrors[]) => Promise<unknown>;
15
+ };
16
+ export default _default;
@@ -0,0 +1,302 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const console_1 = require("./console");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+ // eslint-disable-next-line
7
+ const fetch = require("node-fetch");
8
+ // eslint-disable-next-line
9
+ const fm = require("front-matter");
10
+ // This function checks if a url is valid.
11
+ const isUrl = async (url, errors, counter) => {
12
+ const regexUrl = /(https?:\/\/[\w./-]+)/gm;
13
+ counter.links.total++;
14
+ if (!regexUrl.test(url)) {
15
+ counter.links.error++;
16
+ errors.push({
17
+ exercise: undefined,
18
+ msg: `The repository value of the configuration file is not a link: ${url}`,
19
+ });
20
+ return false;
21
+ }
22
+ const res = await fetch(url, { method: "HEAD" });
23
+ if (!res.ok) {
24
+ counter.links.error++;
25
+ errors.push({
26
+ exercise: undefined,
27
+ msg: `The link of the repository is broken: ${url}`,
28
+ });
29
+ }
30
+ return true;
31
+ };
32
+ const checkForEmptySpaces = (str) => {
33
+ const isEmpty = true;
34
+ for (const letter of str) {
35
+ if (letter !== " ") {
36
+ return false;
37
+ }
38
+ }
39
+ return isEmpty;
40
+ };
41
+ const checkLearnpackClean = (configObj, errors) => {
42
+ var _a, _b, _c, _d, _e, _f, _g, _h;
43
+ if ((((_a = configObj.config) === null || _a === void 0 ? void 0 : _a.outputPath) &&
44
+ fs.existsSync((_b = configObj.config) === null || _b === void 0 ? void 0 : _b.outputPath)) ||
45
+ fs.existsSync(`${(_c = configObj.config) === null || _c === void 0 ? void 0 : _c.dirPath}/_app`) ||
46
+ fs.existsSync(`${(_d = configObj.config) === null || _d === void 0 ? void 0 : _d.dirPath}/reports`) ||
47
+ fs.existsSync(`${(_e = configObj.config) === null || _e === void 0 ? void 0 : _e.dirPath}/resets`) ||
48
+ fs.existsSync(`${(_f = configObj.config) === null || _f === void 0 ? void 0 : _f.dirPath}/app.tar.gz`) ||
49
+ fs.existsSync(`${(_g = configObj.config) === null || _g === void 0 ? void 0 : _g.dirPath}/config.json`) ||
50
+ fs.existsSync(`${(_h = configObj.config) === null || _h === void 0 ? void 0 : _h.dirPath}/vscode_queue.json`)) {
51
+ errors.push({
52
+ exercise: undefined,
53
+ msg: "You have to run learnpack clean command",
54
+ });
55
+ }
56
+ };
57
+ const findInFile = (types, content) => {
58
+ const regex = {
59
+ relativeImages: /!\[.*]\s*\((((\.\/)?(\.{2}\/){1,5})(.*\/)*(.[^\s/]*\.[A-Za-z]{2,4})\S*)\)/gm,
60
+ externalImages: /!\[.*]\((https?:\/(\/[^)/]+)+\/?)\)/gm,
61
+ markdownLinks: /(\s)+\[.*]\((https?:\/(\/[^)/]+)+\/?)\)/gm,
62
+ url: /(https?:\/\/[\w./-]+)/gm,
63
+ uploadcare: /https:\/\/ucarecdn.com\/(?:.*\/)*([\w./-]+)/gm,
64
+ };
65
+ const validTypes = Object.keys(regex);
66
+ if (!Array.isArray(types))
67
+ types = [types];
68
+ const findings = {};
69
+ for (const type of types) {
70
+ if (!validTypes.includes(type))
71
+ throw new Error("Invalid type: " + type);
72
+ else
73
+ findings[type] = {};
74
+ }
75
+ for (const type of types) {
76
+ let m;
77
+ while ((m = regex[type].exec(content)) !== null) {
78
+ // This is necessary to avoid infinite loops with zero-width matches
79
+ if (m.index === regex.lastIndex) {
80
+ regex.lastIndex++;
81
+ }
82
+ // The result can be accessed through the `m`-variable.
83
+ // m.forEach((match, groupIndex) => values.push(match));
84
+ findings[type][m[0]] = {
85
+ content: m[0],
86
+ absUrl: m[1],
87
+ mdUrl: m[2],
88
+ relUrl: m[6],
89
+ };
90
+ }
91
+ }
92
+ return findings;
93
+ };
94
+ // This function checks that each of the url's are working.
95
+ const checkUrl = async (config, filePath, fileName, exercise, errors, warnings, counter) => {
96
+ var _a, _b, _c, _d;
97
+ if (!fs.existsSync(filePath))
98
+ return false;
99
+ const content = fs.readFileSync(filePath).toString();
100
+ const isEmpty = checkForEmptySpaces(content);
101
+ if (isEmpty || !content)
102
+ errors.push({
103
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
104
+ msg: `This file (${fileName}) doesn't have any content inside.`,
105
+ });
106
+ const frontmatter = fm(content);
107
+ for (const attribute in frontmatter.attributes) {
108
+ if (Object.prototype.hasOwnProperty.call(frontmatter.attributes, attribute) &&
109
+ (attribute === "intro" || attribute === "tutorial")) {
110
+ counter && counter.links.total++;
111
+ try {
112
+ // eslint-disable-next-line
113
+ let res = await fetch(frontmatter.attributes[attribute], {
114
+ method: "HEAD",
115
+ });
116
+ if (!res.ok) {
117
+ counter && counter.links.error++;
118
+ errors.push({
119
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
120
+ msg: `This link is broken (${res.ok}): ${frontmatter.attributes[attribute]}`,
121
+ });
122
+ }
123
+ }
124
+ catch (_e) {
125
+ counter && counter.links.error++;
126
+ errors.push({
127
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
128
+ msg: `This link is broken: ${frontmatter.attributes[attribute]}`,
129
+ });
130
+ }
131
+ }
132
+ }
133
+ // Check url's of each README file.
134
+ const findings = findInFile(["relativeImages", "externalImages", "markdownLinks"], content);
135
+ for (const finding in findings) {
136
+ if (Object.prototype.hasOwnProperty.call(findings, finding)) {
137
+ const obj = findings[finding];
138
+ // Valdites all the relative path images.
139
+ if (finding === "relativeImages" && Object.keys(obj).length > 0) {
140
+ for (const img in obj) {
141
+ if (Object.prototype.hasOwnProperty.call(obj, img)) {
142
+ // Validates if the image is in the assets folder.
143
+ counter && counter.images.total++;
144
+ const relativePath = path
145
+ .relative(exercise ? exercise.path.replace(/\\/gm, "/") : "./", `${(_a = config.config) === null || _a === void 0 ? void 0 : _a.dirPath}/assets/${obj[img].relUrl}`)
146
+ .replace(/\\/gm, "/");
147
+ if (relativePath !== obj[img].absUrl.split("?").shift()) {
148
+ counter && counter.images.error++;
149
+ errors.push({
150
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
151
+ msg: `This relative path (${obj[img].relUrl}) is not pointing to the assets folder.`,
152
+ });
153
+ }
154
+ if (!fs.existsSync(`${(_b = config.config) === null || _b === void 0 ? void 0 : _b.dirPath}/assets/${obj[img].relUrl}`)) {
155
+ counter && counter.images.error++;
156
+ errors.push({
157
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
158
+ msg: `The file ${obj[img].relUrl} doesn't exist in the assets folder.`,
159
+ });
160
+ }
161
+ }
162
+ }
163
+ }
164
+ else if (finding === "externalImages" && Object.keys(obj).length > 0) {
165
+ // Valdites all the aboslute path images.
166
+ for (const img in obj) {
167
+ if (Object.prototype.hasOwnProperty.call(obj, img)) {
168
+ counter && counter.images.total++;
169
+ if (fs.existsSync(`${(_c = config.config) === null || _c === void 0 ? void 0 : _c.dirPath}/assets${obj[img].mdUrl
170
+ .split("?")
171
+ .shift()}`)) {
172
+ const relativePath = path
173
+ .relative(exercise ? exercise.path.replace(/\\/gm, "/") : "./", `${(_d = config.config) === null || _d === void 0 ? void 0 : _d.dirPath}/assets/${obj[img].mdUrl}`)
174
+ .replace(/\\/gm, "/");
175
+ warnings.push({
176
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
177
+ 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}".`,
178
+ });
179
+ }
180
+ try {
181
+ // eslint-disable-next-line
182
+ let res = await fetch(obj[img].absUrl, {
183
+ method: "HEAD",
184
+ });
185
+ if (!res.ok) {
186
+ counter && counter.images.error++;
187
+ errors.push({
188
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
189
+ msg: `This link is broken: ${obj[img].absUrl}`,
190
+ });
191
+ }
192
+ }
193
+ catch (_f) {
194
+ counter && counter.images.error++;
195
+ errors.push({
196
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
197
+ msg: `This link is broken: ${obj[img].absUrl}`,
198
+ });
199
+ }
200
+ }
201
+ }
202
+ }
203
+ else if (finding === "markdownLinks" && Object.keys(obj).length > 0) {
204
+ for (const link in obj) {
205
+ if (Object.prototype.hasOwnProperty.call(obj, link)) {
206
+ counter && counter.links.total++;
207
+ if (!obj[link].mdUrl.includes("twitter")) {
208
+ try {
209
+ // eslint-disable-next-line
210
+ let res = await fetch(obj[link].mdUrl, {
211
+ method: "HEAD",
212
+ });
213
+ if (res.status > 399 && res.status < 500) {
214
+ counter && counter.links.error++;
215
+ errors.push({
216
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
217
+ msg: `This link is broken: ${obj[link].mdUrl}`,
218
+ });
219
+ }
220
+ }
221
+ catch (_g) {
222
+ counter && counter.links.error++;
223
+ errors.push({
224
+ exercise: exercise === null || exercise === void 0 ? void 0 : exercise.title,
225
+ msg: `This link is broken: ${obj[link].mdUrl}`,
226
+ });
227
+ }
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ }
234
+ return true;
235
+ };
236
+ // This function writes a given file with the given content.
237
+ const writeFile = async (content, filePath) => {
238
+ try {
239
+ await fs.promises.writeFile(filePath, content);
240
+ }
241
+ catch (error) {
242
+ if (error)
243
+ console_1.default.error(`We weren't able to write the file in this path "${filePath}".`, error);
244
+ }
245
+ };
246
+ // This function checks if there are errors, and show them in the console at the end.
247
+ const showErrors = (errors, counter) => {
248
+ return new Promise((resolve, reject) => {
249
+ if (errors) {
250
+ if (errors.length > 0) {
251
+ console_1.default.log("Checking for errors...");
252
+ for (const [i, error] of errors.entries())
253
+ console_1.default.error(`${i + 1}) ${error.msg} ${error.exercise ? `(Exercise: ${error.exercise})` : ""}`);
254
+ if (counter) {
255
+ console_1.default.error(` We found ${errors.length} error${errors.length > 1 ? "s" : ""} among ${counter.images.total} images, ${counter.links.total} link, ${counter.readmeFiles} README files and ${counter.exercises} exercises.`);
256
+ }
257
+ else {
258
+ console_1.default.error(` We found ${errors.length} error${errors.length > 1 ? "s" : ""} related with the project integrity.`);
259
+ }
260
+ process.exit(1);
261
+ }
262
+ else {
263
+ if (counter) {
264
+ console_1.default.success(`We didn't find any errors in this repository among ${counter.images.total} images, ${counter.links.total} link, ${counter.readmeFiles} README files and ${counter.exercises} exercises.`);
265
+ }
266
+ else {
267
+ console_1.default.success(`We didn't find any errors in this repository.`);
268
+ }
269
+ process.exit(0);
270
+ }
271
+ }
272
+ else {
273
+ reject("Failed");
274
+ }
275
+ });
276
+ };
277
+ // This function checks if there are warnings, and show them in the console at the end.
278
+ const showWarnings = (warnings) => {
279
+ return new Promise((resolve, reject) => {
280
+ if (warnings) {
281
+ if (warnings.length > 0) {
282
+ console_1.default.log("Checking for warnings...");
283
+ for (const [i, warning] of warnings.entries())
284
+ console_1.default.warning(`${i + 1}) ${warning.msg} ${warning.exercise ? `File: ${warning.exercise}` : ""}`);
285
+ }
286
+ resolve("SUCCESS");
287
+ }
288
+ else {
289
+ reject("Failed");
290
+ }
291
+ });
292
+ };
293
+ exports.default = {
294
+ isUrl,
295
+ checkForEmptySpaces,
296
+ checkLearnpackClean,
297
+ findInFile,
298
+ checkUrl,
299
+ writeFile,
300
+ showErrors,
301
+ showWarnings,
302
+ };
@@ -0,0 +1,12 @@
1
+ declare const _default: {
2
+ _debug: boolean;
3
+ startDebug: () => void;
4
+ log: (msg: string | Array<string>, ...args: Array<any>) => void;
5
+ error: (msg: string, ...args: Array<any>) => void;
6
+ success: (msg: string, ...args: Array<any>) => void;
7
+ info: (msg: string, ...args: Array<any>) => void;
8
+ help: (msg: string) => void;
9
+ debug(...args: Array<any>): void;
10
+ warning: (msg: string) => void;
11
+ };
12
+ export default _default;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const chalk = require("chalk");
4
+ exports.default = {
5
+ // _debug: true,
6
+ _debug: process.env.DEBUG === 'true',
7
+ startDebug: function () {
8
+ this._debug = true;
9
+ },
10
+ log: (msg, ...args) => console.log(chalk.gray(msg), ...args),
11
+ error: (msg, ...args) => console.log(chalk.red('⨉ ' + msg), ...args),
12
+ success: (msg, ...args) => console.log(chalk.green('✓ ' + msg), ...args),
13
+ info: (msg, ...args) => console.log(chalk.blue('ⓘ ' + msg), ...args),
14
+ help: (msg) => console.log(`${chalk.white.bold('⚠ help:')} ${chalk.white(msg)}`),
15
+ debug(...args) {
16
+ this._debug && console.log(chalk.magentaBright('⚠ debug: '), args);
17
+ },
18
+ warning: (msg) => console.log(`${chalk.yellow('⚠ warning:')} ${chalk.yellow(msg)}`),
19
+ };
@@ -0,0 +1,17 @@
1
+ import { ISolution, IError } from '../models/errors';
2
+ export declare const getSolution: (slug?: string | undefined) => ISolution;
3
+ export declare const ValidationError: (error: IError | string) => IError;
4
+ export declare const NotFoundError: (error: IError | string) => IError;
5
+ export declare const CompilerError: (error: IError | string) => IError;
6
+ export declare const TestingError: (error: IError | string) => IError;
7
+ export declare const AuthError: (error: IError | string) => IError;
8
+ export declare const InternalError: (error: IError | string) => IError;
9
+ declare const _default: {
10
+ ValidationError: (error: string | IError) => IError;
11
+ CompilerError: (error: string | IError) => IError;
12
+ TestingError: (error: string | IError) => IError;
13
+ NotFoundError: (error: string | IError) => IError;
14
+ InternalError: (error: string | IError) => IError;
15
+ AuthError: (error: string | IError) => IError;
16
+ };
17
+ export default _default;