course-format-ts 1.0.0

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.
Files changed (239) hide show
  1. package/.idea/edu-format-ts.iml +10 -0
  2. package/.idea/inspectionProfiles/Project_Default.xml +28 -0
  3. package/.idea/misc.xml +4 -0
  4. package/.idea/modules.xml +8 -0
  5. package/.idea/vcs.xml +6 -0
  6. package/AGENTS.md +1 -0
  7. package/dist/courseFormat/AnswerPlaceholder.d.ts +37 -0
  8. package/dist/courseFormat/AnswerPlaceholder.js +101 -0
  9. package/dist/courseFormat/AnswerPlaceholderComparator.d.ts +4 -0
  10. package/dist/courseFormat/AnswerPlaceholderComparator.js +8 -0
  11. package/dist/courseFormat/AnswerPlaceholderDependency.d.ts +19 -0
  12. package/dist/courseFormat/AnswerPlaceholderDependency.js +91 -0
  13. package/dist/courseFormat/CheckFeedback.d.ts +20 -0
  14. package/dist/courseFormat/CheckFeedback.js +58 -0
  15. package/dist/courseFormat/CheckResult.d.ts +33 -0
  16. package/dist/courseFormat/CheckResult.js +58 -0
  17. package/dist/courseFormat/CheckResultSeverity.d.ts +7 -0
  18. package/dist/courseFormat/CheckResultSeverity.js +17 -0
  19. package/dist/courseFormat/CheckStatus.d.ts +5 -0
  20. package/dist/courseFormat/CheckStatus.js +9 -0
  21. package/dist/courseFormat/Course.d.ts +68 -0
  22. package/dist/courseFormat/Course.js +165 -0
  23. package/dist/courseFormat/CourseMode.d.ts +4 -0
  24. package/dist/courseFormat/CourseMode.js +8 -0
  25. package/dist/courseFormat/CourseVisibility.d.ts +4 -0
  26. package/dist/courseFormat/CourseVisibility.js +8 -0
  27. package/dist/courseFormat/CourseraCourse.d.ts +5 -0
  28. package/dist/courseFormat/CourseraCourse.js +15 -0
  29. package/dist/courseFormat/DescriptionFormat.d.ts +5 -0
  30. package/dist/courseFormat/DescriptionFormat.js +9 -0
  31. package/dist/courseFormat/EduCourse.d.ts +17 -0
  32. package/dist/courseFormat/EduCourse.js +42 -0
  33. package/dist/courseFormat/EduFile.d.ts +22 -0
  34. package/dist/courseFormat/EduFile.js +110 -0
  35. package/dist/courseFormat/EduFileErrorHighlightLevel.d.ts +5 -0
  36. package/dist/courseFormat/EduFileErrorHighlightLevel.js +9 -0
  37. package/dist/courseFormat/EduFormatNames.d.ts +75 -0
  38. package/dist/courseFormat/EduFormatNames.js +80 -0
  39. package/dist/courseFormat/EduTestInfo.d.ts +28 -0
  40. package/dist/courseFormat/EduTestInfo.js +68 -0
  41. package/dist/courseFormat/EduVersions.d.ts +2 -0
  42. package/dist/courseFormat/EduVersions.js +5 -0
  43. package/dist/courseFormat/FileContents.d.ts +36 -0
  44. package/dist/courseFormat/FileContents.js +67 -0
  45. package/dist/courseFormat/FileContentsFactory.d.ts +17 -0
  46. package/dist/courseFormat/FileContentsFactory.js +2 -0
  47. package/dist/courseFormat/FrameworkLesson.d.ts +9 -0
  48. package/dist/courseFormat/FrameworkLesson.js +28 -0
  49. package/dist/courseFormat/ItemContainer.d.ts +13 -0
  50. package/dist/courseFormat/ItemContainer.js +45 -0
  51. package/dist/courseFormat/JBAccountUserInfo.d.ts +9 -0
  52. package/dist/courseFormat/JBAccountUserInfo.js +20 -0
  53. package/dist/courseFormat/Language.d.ts +4 -0
  54. package/dist/courseFormat/Language.js +33 -0
  55. package/dist/courseFormat/Lesson.d.ts +20 -0
  56. package/dist/courseFormat/Lesson.js +56 -0
  57. package/dist/courseFormat/LessonContainer.d.ts +16 -0
  58. package/dist/courseFormat/LessonContainer.js +54 -0
  59. package/dist/courseFormat/PluginInfo.d.ts +7 -0
  60. package/dist/courseFormat/PluginInfo.js +15 -0
  61. package/dist/courseFormat/Section.d.ts +8 -0
  62. package/dist/courseFormat/Section.js +27 -0
  63. package/dist/courseFormat/StudyItem.d.ts +20 -0
  64. package/dist/courseFormat/StudyItem.js +47 -0
  65. package/dist/courseFormat/Tags.d.ts +16 -0
  66. package/dist/courseFormat/Tags.js +42 -0
  67. package/dist/courseFormat/TaskFile.d.ts +26 -0
  68. package/dist/courseFormat/TaskFile.js +72 -0
  69. package/dist/courseFormat/UserInfo.d.ts +3 -0
  70. package/dist/courseFormat/UserInfo.js +2 -0
  71. package/dist/courseFormat/Vendor.d.ts +7 -0
  72. package/dist/courseFormat/Vendor.js +14 -0
  73. package/dist/courseFormat/attempts/Attempt.d.ts +12 -0
  74. package/dist/courseFormat/attempts/Attempt.js +25 -0
  75. package/dist/courseFormat/attempts/AttemptBase.d.ts +9 -0
  76. package/dist/courseFormat/attempts/AttemptBase.js +28 -0
  77. package/dist/courseFormat/attempts/DataTaskAttempt.d.ts +6 -0
  78. package/dist/courseFormat/attempts/DataTaskAttempt.js +24 -0
  79. package/dist/courseFormat/attempts/Dataset.d.ts +12 -0
  80. package/dist/courseFormat/attempts/Dataset.js +21 -0
  81. package/dist/courseFormat/fileUtils.d.ts +5 -0
  82. package/dist/courseFormat/fileUtils.js +32 -0
  83. package/dist/courseFormat/hyperskill/HyperskillCourse.d.ts +13 -0
  84. package/dist/courseFormat/hyperskill/HyperskillCourse.js +25 -0
  85. package/dist/courseFormat/hyperskill/HyperskillProject.d.ts +10 -0
  86. package/dist/courseFormat/hyperskill/HyperskillProject.js +16 -0
  87. package/dist/courseFormat/hyperskill/HyperskillStage.d.ts +8 -0
  88. package/dist/courseFormat/hyperskill/HyperskillStage.js +20 -0
  89. package/dist/courseFormat/hyperskill/HyperskillTaskType.d.ts +4 -0
  90. package/dist/courseFormat/hyperskill/HyperskillTaskType.js +26 -0
  91. package/dist/courseFormat/hyperskill/HyperskillTopic.d.ts +5 -0
  92. package/dist/courseFormat/hyperskill/HyperskillTopic.js +11 -0
  93. package/dist/courseFormat/loggerUtils.d.ts +1 -0
  94. package/dist/courseFormat/loggerUtils.js +6 -0
  95. package/dist/courseFormat/stepik/StepikCourse.d.ts +5 -0
  96. package/dist/courseFormat/stepik/StepikCourse.js +15 -0
  97. package/dist/courseFormat/stepik/StepikLesson.d.ts +6 -0
  98. package/dist/courseFormat/stepik/StepikLesson.js +16 -0
  99. package/dist/courseFormat/tasks/AnswerTask.d.ts +8 -0
  100. package/dist/courseFormat/tasks/AnswerTask.js +11 -0
  101. package/dist/courseFormat/tasks/CodeTask.d.ts +12 -0
  102. package/dist/courseFormat/tasks/CodeTask.js +21 -0
  103. package/dist/courseFormat/tasks/DataTask.d.ts +18 -0
  104. package/dist/courseFormat/tasks/DataTask.js +32 -0
  105. package/dist/courseFormat/tasks/EduTask.d.ts +12 -0
  106. package/dist/courseFormat/tasks/EduTask.js +22 -0
  107. package/dist/courseFormat/tasks/IdeTask.d.ts +9 -0
  108. package/dist/courseFormat/tasks/IdeTask.js +14 -0
  109. package/dist/courseFormat/tasks/NumberTask.d.ts +9 -0
  110. package/dist/courseFormat/tasks/NumberTask.js +14 -0
  111. package/dist/courseFormat/tasks/OutputTask.d.ts +10 -0
  112. package/dist/courseFormat/tasks/OutputTask.js +18 -0
  113. package/dist/courseFormat/tasks/OutputTaskBase.d.ts +14 -0
  114. package/dist/courseFormat/tasks/OutputTaskBase.js +19 -0
  115. package/dist/courseFormat/tasks/RemoteEduTask.d.ts +9 -0
  116. package/dist/courseFormat/tasks/RemoteEduTask.js +15 -0
  117. package/dist/courseFormat/tasks/StringTask.d.ts +9 -0
  118. package/dist/courseFormat/tasks/StringTask.js +14 -0
  119. package/dist/courseFormat/tasks/TableTask.d.ts +17 -0
  120. package/dist/courseFormat/tasks/TableTask.js +43 -0
  121. package/dist/courseFormat/tasks/Task.d.ts +45 -0
  122. package/dist/courseFormat/tasks/Task.js +155 -0
  123. package/dist/courseFormat/tasks/TheoryTask.d.ts +10 -0
  124. package/dist/courseFormat/tasks/TheoryTask.js +15 -0
  125. package/dist/courseFormat/tasks/UnsupportedTask.d.ts +9 -0
  126. package/dist/courseFormat/tasks/UnsupportedTask.js +14 -0
  127. package/dist/courseFormat/tasks/choice/ChoiceOption.d.ts +10 -0
  128. package/dist/courseFormat/tasks/choice/ChoiceOption.js +33 -0
  129. package/dist/courseFormat/tasks/choice/ChoiceOptionStatus.d.ts +5 -0
  130. package/dist/courseFormat/tasks/choice/ChoiceOptionStatus.js +9 -0
  131. package/dist/courseFormat/tasks/choice/ChoiceTask.d.ts +23 -0
  132. package/dist/courseFormat/tasks/choice/ChoiceTask.js +47 -0
  133. package/dist/courseFormat/tasks/matching/MatchingTask.d.ts +10 -0
  134. package/dist/courseFormat/tasks/matching/MatchingTask.js +15 -0
  135. package/dist/courseFormat/tasks/matching/SortingBasedTask.d.ts +16 -0
  136. package/dist/courseFormat/tasks/matching/SortingBasedTask.js +50 -0
  137. package/dist/courseFormat/tasks/matching/SortingTask.d.ts +9 -0
  138. package/dist/courseFormat/tasks/matching/SortingTask.js +14 -0
  139. package/dist/courseFormat/uiMessages.d.ts +3 -0
  140. package/dist/courseFormat/uiMessages.js +14 -0
  141. package/dist/disk-loader.d.ts +4 -0
  142. package/dist/disk-loader.js +389 -0
  143. package/dist/index.d.ts +31 -0
  144. package/dist/index.js +64 -0
  145. package/dist/loader.d.ts +7 -0
  146. package/dist/loader.js +435 -0
  147. package/dist/models.d.ts +49 -0
  148. package/dist/models.js +2 -0
  149. package/dist/zip-loader.d.ts +4 -0
  150. package/dist/zip-loader.js +431 -0
  151. package/example-course-project/course-info.yaml +15 -0
  152. package/example-course-project/lesson1/lesson-info.yaml +3 -0
  153. package/example-course-project/lesson1/lesson-remote-info.yaml +1 -0
  154. package/example-course-project/lesson1/task1/Task.txt +1 -0
  155. package/example-course-project/lesson1/task1/task-info.yaml +12 -0
  156. package/example-course-project/lesson1/task1/task-remote-info.yaml +1 -0
  157. package/example-course-project/lesson1/task1/task.md +47 -0
  158. package/example-course-project/lesson1/task1/tests/Tests.txt +0 -0
  159. package/example-course-project/lesson1/task2/Task.txt +1 -0
  160. package/example-course-project/lesson1/task2/task-info.yaml +12 -0
  161. package/example-course-project/lesson1/task2/task-remote-info.yaml +1 -0
  162. package/example-course-project/lesson1/task2/task.md +47 -0
  163. package/example-course-project/lesson1/task2/tests/Tests.txt +0 -0
  164. package/package.json +19 -0
  165. package/src/@types/mime-types.d.ts +3 -0
  166. package/src/courseFormat/AnswerPlaceholder.ts +121 -0
  167. package/src/courseFormat/AnswerPlaceholderComparator.ts +7 -0
  168. package/src/courseFormat/AnswerPlaceholderDependency.ts +122 -0
  169. package/src/courseFormat/CheckFeedback.ts +71 -0
  170. package/src/courseFormat/CheckResult.ts +92 -0
  171. package/src/courseFormat/CheckResultSeverity.ts +13 -0
  172. package/src/courseFormat/CheckStatus.ts +5 -0
  173. package/src/courseFormat/Course.ts +201 -0
  174. package/src/courseFormat/CourseMode.ts +4 -0
  175. package/src/courseFormat/CourseVisibility.ts +4 -0
  176. package/src/courseFormat/CourseraCourse.ts +10 -0
  177. package/src/courseFormat/DescriptionFormat.ts +5 -0
  178. package/src/courseFormat/EduCourse.ts +41 -0
  179. package/src/courseFormat/EduFile.ts +133 -0
  180. package/src/courseFormat/EduFileErrorHighlightLevel.ts +5 -0
  181. package/src/courseFormat/EduFormatNames.ts +95 -0
  182. package/src/courseFormat/EduTestInfo.ts +87 -0
  183. package/src/courseFormat/EduVersions.ts +2 -0
  184. package/src/courseFormat/FileContents.ts +97 -0
  185. package/src/courseFormat/FileContentsFactory.ts +19 -0
  186. package/src/courseFormat/FrameworkLesson.ts +29 -0
  187. package/src/courseFormat/ItemContainer.ts +47 -0
  188. package/src/courseFormat/JBAccountUserInfo.ts +21 -0
  189. package/src/courseFormat/Language.ts +31 -0
  190. package/src/courseFormat/Lesson.ts +69 -0
  191. package/src/courseFormat/LessonContainer.ts +65 -0
  192. package/src/courseFormat/PluginInfo.ts +15 -0
  193. package/src/courseFormat/Section.ts +29 -0
  194. package/src/courseFormat/StudyItem.ts +55 -0
  195. package/src/courseFormat/Tags.ts +45 -0
  196. package/src/courseFormat/TaskFile.ts +88 -0
  197. package/src/courseFormat/UserInfo.ts +3 -0
  198. package/src/courseFormat/Vendor.ts +15 -0
  199. package/src/courseFormat/attempts/Attempt.ts +28 -0
  200. package/src/courseFormat/attempts/AttemptBase.ts +24 -0
  201. package/src/courseFormat/attempts/DataTaskAttempt.ts +19 -0
  202. package/src/courseFormat/attempts/Dataset.ts +13 -0
  203. package/src/courseFormat/fileUtils.ts +31 -0
  204. package/src/courseFormat/hyperskill/HyperskillCourse.ts +24 -0
  205. package/src/courseFormat/hyperskill/HyperskillProject.ts +10 -0
  206. package/src/courseFormat/hyperskill/HyperskillStage.ts +15 -0
  207. package/src/courseFormat/hyperskill/HyperskillTaskType.ts +23 -0
  208. package/src/courseFormat/hyperskill/HyperskillTopic.ts +5 -0
  209. package/src/courseFormat/loggerUtils.ts +3 -0
  210. package/src/courseFormat/stepik/StepikCourse.ts +10 -0
  211. package/src/courseFormat/stepik/StepikLesson.ts +11 -0
  212. package/src/courseFormat/tasks/AnswerTask.ts +13 -0
  213. package/src/courseFormat/tasks/CodeTask.ts +42 -0
  214. package/src/courseFormat/tasks/DataTask.ts +37 -0
  215. package/src/courseFormat/tasks/EduTask.ts +26 -0
  216. package/src/courseFormat/tasks/IdeTask.ts +17 -0
  217. package/src/courseFormat/tasks/NumberTask.ts +17 -0
  218. package/src/courseFormat/tasks/OutputTask.ts +21 -0
  219. package/src/courseFormat/tasks/OutputTaskBase.ts +23 -0
  220. package/src/courseFormat/tasks/RemoteEduTask.ts +18 -0
  221. package/src/courseFormat/tasks/StringTask.ts +17 -0
  222. package/src/courseFormat/tasks/TableTask.ts +51 -0
  223. package/src/courseFormat/tasks/Task.ts +181 -0
  224. package/src/courseFormat/tasks/TheoryTask.ts +19 -0
  225. package/src/courseFormat/tasks/UnsupportedTask.ts +17 -0
  226. package/src/courseFormat/tasks/choice/ChoiceOption.ts +37 -0
  227. package/src/courseFormat/tasks/choice/ChoiceOptionStatus.ts +5 -0
  228. package/src/courseFormat/tasks/choice/ChoiceTask.ts +57 -0
  229. package/src/courseFormat/tasks/matching/MatchingTask.ts +19 -0
  230. package/src/courseFormat/tasks/matching/SortingBasedTask.ts +59 -0
  231. package/src/courseFormat/tasks/matching/SortingTask.ts +17 -0
  232. package/src/courseFormat/uiMessages.ts +12 -0
  233. package/src/disk-loader.ts +463 -0
  234. package/src/index.ts +33 -0
  235. package/src/models.ts +54 -0
  236. package/src/zip-loader.ts +583 -0
  237. package/test/load-course.test.js +279 -0
  238. package/test/load-zip-course.test.js +73 -0
  239. package/tsconfig.json +15 -0
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChoiceTask = void 0;
4
+ const CheckStatus_1 = require("../../CheckStatus");
5
+ const uiMessages_1 = require("../../uiMessages");
6
+ const Task_1 = require("../Task");
7
+ class ChoiceTask extends Task_1.Task {
8
+ constructor(name, id, position, updateDate, status) {
9
+ super(name, id, position, updateDate, status);
10
+ this.choiceOptions = [];
11
+ this.isMultipleChoice = false;
12
+ this.selectedVariants = [];
13
+ this.messageCorrect = (0, uiMessages_1.message)("check.correct.solution");
14
+ this.messageIncorrect = (0, uiMessages_1.message)("check.incorrect.solution");
15
+ this.canCheckLocally = true;
16
+ }
17
+ get itemType() {
18
+ return ChoiceTask.CHOICE_TASK_TYPE;
19
+ }
20
+ get isPluginTaskType() {
21
+ return false;
22
+ }
23
+ get isChangedOnFailed() {
24
+ return !this.canCheckLocally;
25
+ }
26
+ get isToSubmitToRemote() {
27
+ return this.status !== CheckStatus_1.CheckStatus.Unchecked;
28
+ }
29
+ get presentableQuizHeader() {
30
+ if (this.quizHeader)
31
+ return this.quizHeader;
32
+ return this.isMultipleChoice
33
+ ? (0, uiMessages_1.message)("course.creator.create.choice.task.multiple.label")
34
+ : (0, uiMessages_1.message)("course.creator.create.choice.task.single.label");
35
+ }
36
+ addSelectedVariant(variant) {
37
+ this.selectedVariants.push(variant);
38
+ }
39
+ removeSelectedVariant(variant) {
40
+ this.selectedVariants = this.selectedVariants.filter((value) => value !== variant);
41
+ }
42
+ clearSelectedVariants() {
43
+ this.selectedVariants = [];
44
+ }
45
+ }
46
+ exports.ChoiceTask = ChoiceTask;
47
+ ChoiceTask.CHOICE_TASK_TYPE = "choice";
@@ -0,0 +1,10 @@
1
+ import { CheckStatus } from "../../CheckStatus";
2
+ import { SortingBasedTask } from "./SortingBasedTask";
3
+ export declare class MatchingTask extends SortingBasedTask {
4
+ captions: string[];
5
+ constructor();
6
+ constructor(name: string);
7
+ constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus);
8
+ get itemType(): string;
9
+ static MATCHING_TASK_TYPE: string;
10
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MatchingTask = void 0;
4
+ const SortingBasedTask_1 = require("./SortingBasedTask");
5
+ class MatchingTask extends SortingBasedTask_1.SortingBasedTask {
6
+ constructor(name, id, position, updateDate, status) {
7
+ super(name, id, position, updateDate, status);
8
+ this.captions = [];
9
+ }
10
+ get itemType() {
11
+ return MatchingTask.MATCHING_TASK_TYPE;
12
+ }
13
+ }
14
+ exports.MatchingTask = MatchingTask;
15
+ MatchingTask.MATCHING_TASK_TYPE = "matching";
@@ -0,0 +1,16 @@
1
+ import { CheckStatus } from "../../CheckStatus";
2
+ import { Task } from "../Task";
3
+ export declare abstract class SortingBasedTask extends Task {
4
+ private _options;
5
+ ordering: number[];
6
+ get options(): string[];
7
+ set options(value: string[]);
8
+ constructor();
9
+ constructor(name: string);
10
+ constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus);
11
+ getOrderedOptions(): string[];
12
+ moveOptionUp(index: number): void;
13
+ moveOptionDown(index: number): void;
14
+ swapOptions(firstColumnIndex: number, secondColumnIndex: number): void;
15
+ restoreInitialOrdering(): void;
16
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SortingBasedTask = void 0;
4
+ const loggerUtils_1 = require("../../loggerUtils");
5
+ const Task_1 = require("../Task");
6
+ class SortingBasedTask extends Task_1.Task {
7
+ get options() {
8
+ return this._options;
9
+ }
10
+ set options(value) {
11
+ this.ordering = value.map((_, index) => index);
12
+ this._options = value;
13
+ }
14
+ constructor(name, id, position, updateDate, status) {
15
+ super(name, id, position, updateDate, status);
16
+ this._options = [];
17
+ this.ordering = [];
18
+ }
19
+ getOrderedOptions() {
20
+ return this.options.map((_, index) => this.options[this.ordering[index]]);
21
+ }
22
+ moveOptionUp(index) {
23
+ const targetIndex = index - 1;
24
+ if (targetIndex < 0) {
25
+ const message = "There was an attempt to move the option up out of bounds";
26
+ (0, loggerUtils_1.logger)("SortingBasedTask").error(message);
27
+ throw new Error(message);
28
+ }
29
+ this.swapOptions(index, targetIndex);
30
+ }
31
+ moveOptionDown(index) {
32
+ const targetIndex = index + 1;
33
+ if (targetIndex === this.options.length) {
34
+ const message = "There was an attempt to move the option down out of bounds";
35
+ (0, loggerUtils_1.logger)("SortingBasedTask").error(message);
36
+ throw new Error(message);
37
+ }
38
+ this.swapOptions(index, targetIndex);
39
+ }
40
+ swapOptions(firstColumnIndex, secondColumnIndex) {
41
+ const firstOptionIndex = this.ordering[firstColumnIndex];
42
+ const secondOptionIndex = this.ordering[secondColumnIndex];
43
+ this.ordering[firstColumnIndex] = secondOptionIndex;
44
+ this.ordering[secondColumnIndex] = firstOptionIndex;
45
+ }
46
+ restoreInitialOrdering() {
47
+ this.ordering = this.options.map((_, index) => index);
48
+ }
49
+ }
50
+ exports.SortingBasedTask = SortingBasedTask;
@@ -0,0 +1,9 @@
1
+ import { CheckStatus } from "../../CheckStatus";
2
+ import { SortingBasedTask } from "./SortingBasedTask";
3
+ export declare class SortingTask extends SortingBasedTask {
4
+ constructor();
5
+ constructor(name: string);
6
+ constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus);
7
+ get itemType(): string;
8
+ static SORTING_TASK_TYPE: string;
9
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SortingTask = void 0;
4
+ const SortingBasedTask_1 = require("./SortingBasedTask");
5
+ class SortingTask extends SortingBasedTask_1.SortingBasedTask {
6
+ constructor(name, id, position, updateDate, status) {
7
+ super(name, id, position, updateDate, status);
8
+ }
9
+ get itemType() {
10
+ return SortingTask.SORTING_TASK_TYPE;
11
+ }
12
+ }
13
+ exports.SortingTask = SortingTask;
14
+ SortingTask.SORTING_TASK_TYPE = "sorting";
@@ -0,0 +1,3 @@
1
+ declare const FORMAT_BUNDLE = "messages.EduFormatBundle";
2
+ export declare function message(key: string, ...params: Array<string | number>): string;
3
+ export { FORMAT_BUNDLE };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FORMAT_BUNDLE = void 0;
4
+ exports.message = message;
5
+ const FORMAT_BUNDLE = "messages.EduFormatBundle";
6
+ exports.FORMAT_BUNDLE = FORMAT_BUNDLE;
7
+ function message(key, ...params) {
8
+ if (params.length === 0) {
9
+ return key;
10
+ }
11
+ return params.reduce((result, param, index) => {
12
+ return result.replace(new RegExp(`\\{${index}\\}`, "g"), String(param));
13
+ }, key);
14
+ }
@@ -0,0 +1,4 @@
1
+ import { Course } from "./courseFormat/Course";
2
+ export declare function loadCourseProject(projectPath: string, options?: {
3
+ aesKey?: string;
4
+ }): Promise<Course>;
@@ -0,0 +1,389 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.loadCourseProject = loadCourseProject;
16
+ const node_fs_1 = require("node:fs");
17
+ const node_fs_2 = require("node:fs");
18
+ const node_path_1 = __importDefault(require("node:path"));
19
+ const node_crypto_1 = __importDefault(require("node:crypto"));
20
+ const yaml_1 = require("yaml");
21
+ const CheckStatus_1 = require("./courseFormat/CheckStatus");
22
+ const CourseMode_1 = require("./courseFormat/CourseMode");
23
+ const Lesson_1 = require("./courseFormat/Lesson");
24
+ const EduCourse_1 = require("./courseFormat/EduCourse");
25
+ const CourseraCourse_1 = require("./courseFormat/CourseraCourse");
26
+ const HyperskillCourse_1 = require("./courseFormat/hyperskill/HyperskillCourse");
27
+ const StepikCourse_1 = require("./courseFormat/stepik/StepikCourse");
28
+ const StepikLesson_1 = require("./courseFormat/stepik/StepikLesson");
29
+ const EduTask_1 = require("./courseFormat/tasks/EduTask");
30
+ const CodeTask_1 = require("./courseFormat/tasks/CodeTask");
31
+ const NumberTask_1 = require("./courseFormat/tasks/NumberTask");
32
+ const StringTask_1 = require("./courseFormat/tasks/StringTask");
33
+ const OutputTask_1 = require("./courseFormat/tasks/OutputTask");
34
+ const DataTask_1 = require("./courseFormat/tasks/DataTask");
35
+ const TableTask_1 = require("./courseFormat/tasks/TableTask");
36
+ const TheoryTask_1 = require("./courseFormat/tasks/TheoryTask");
37
+ const IdeTask_1 = require("./courseFormat/tasks/IdeTask");
38
+ const UnsupportedTask_1 = require("./courseFormat/tasks/UnsupportedTask");
39
+ const RemoteEduTask_1 = require("./courseFormat/tasks/RemoteEduTask");
40
+ const ChoiceTask_1 = require("./courseFormat/tasks/choice/ChoiceTask");
41
+ const ChoiceOption_1 = require("./courseFormat/tasks/choice/ChoiceOption");
42
+ const ChoiceOptionStatus_1 = require("./courseFormat/tasks/choice/ChoiceOptionStatus");
43
+ const MatchingTask_1 = require("./courseFormat/tasks/matching/MatchingTask");
44
+ const SortingTask_1 = require("./courseFormat/tasks/matching/SortingTask");
45
+ const TaskFile_1 = require("./courseFormat/TaskFile");
46
+ const COURSE_CONFIG = "course-info.yaml";
47
+ const LESSON_CONFIG = "lesson-info.yaml";
48
+ const TASK_CONFIG = "task-info.yaml";
49
+ const TEST_AES_KEY = "DFC929E375655998A34E56A21C98651C";
50
+ function createCourse(type) {
51
+ switch (type) {
52
+ case "hyperskill":
53
+ return new HyperskillCourse_1.HyperskillCourse();
54
+ case "coursera":
55
+ return new CourseraCourse_1.CourseraCourse();
56
+ case "stepik":
57
+ return new StepikCourse_1.StepikCourse();
58
+ default:
59
+ const course = new EduCourse_1.EduCourse();
60
+ return course;
61
+ }
62
+ }
63
+ function hydrateCourse(course, yaml) {
64
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
65
+ course.name = (_a = yaml.title) !== null && _a !== void 0 ? _a : "";
66
+ course.description = (_b = yaml.summary) !== null && _b !== void 0 ? _b : "";
67
+ course.programmingLanguage = (_c = yaml.programming_language) !== null && _c !== void 0 ? _c : "";
68
+ course.languageVersion = yaml.programming_language_version;
69
+ course.environment = (_d = yaml.environment) !== null && _d !== void 0 ? _d : course.environment;
70
+ course.solutionsHidden = (_e = yaml.solutions_hidden) !== null && _e !== void 0 ? _e : course.solutionsHidden;
71
+ course.environmentSettings = (_f = yaml.environment_settings) !== null && _f !== void 0 ? _f : course.environmentSettings;
72
+ course.customContentPath = (_g = yaml.custom_content_path) !== null && _g !== void 0 ? _g : course.customContentPath;
73
+ course.disabledFeatures = (_h = yaml.disabled_features) !== null && _h !== void 0 ? _h : course.disabledFeatures;
74
+ course.vendor = (_j = yaml.vendor) !== null && _j !== void 0 ? _j : course.vendor;
75
+ if (yaml.is_private !== undefined)
76
+ course.isMarketplacePrivate = yaml.is_private;
77
+ if (yaml.mode) {
78
+ course.courseMode = CourseMode_1.CourseMode.STUDENT;
79
+ }
80
+ else {
81
+ course.courseMode = CourseMode_1.CourseMode.EDUCATOR;
82
+ }
83
+ }
84
+ function loadCourseProject(projectPath_1) {
85
+ return __awaiter(this, arguments, void 0, function* (projectPath, options = {}) {
86
+ var _a;
87
+ const courseConfigPath = node_path_1.default.join(projectPath, COURSE_CONFIG);
88
+ const courseYaml = yield readRawYamlFile(courseConfigPath);
89
+ if (!courseYaml.title) {
90
+ throw new Error(`Missing 'title' in ${courseConfigPath}`);
91
+ }
92
+ if (!courseYaml.language) {
93
+ throw new Error(`Missing 'language' in ${courseConfigPath}`);
94
+ }
95
+ if (!courseYaml.programming_language) {
96
+ throw new Error(`Missing 'programming_language' in ${courseConfigPath}`);
97
+ }
98
+ const contentNames = ensureNamedContent(courseYaml.content, courseConfigPath);
99
+ const aesKey = (_a = options.aesKey) !== null && _a !== void 0 ? _a : getAesKey();
100
+ const course = createCourse(courseYaml.type);
101
+ hydrateCourse(course, courseYaml);
102
+ course.languageCode = courseYaml.language;
103
+ const lessons = yield Promise.all(contentNames.map((lessonName) => loadLesson(projectPath, lessonName, aesKey, courseYaml.type)));
104
+ for (const lesson of lessons) {
105
+ course.addLesson(lesson);
106
+ }
107
+ return course;
108
+ });
109
+ }
110
+ function createLesson(courseType) {
111
+ if (courseType === "stepik") {
112
+ return new StepikLesson_1.StepikLesson();
113
+ }
114
+ return new Lesson_1.Lesson();
115
+ }
116
+ function hydrateLesson(lesson, lessonName, yaml) {
117
+ lesson.name = lessonName;
118
+ if (yaml.custom_name) {
119
+ lesson.customPresentableName = yaml.custom_name;
120
+ }
121
+ if (yaml.tags) {
122
+ lesson.contentTags = yaml.tags;
123
+ }
124
+ }
125
+ function loadLesson(coursePath, lessonName, aesKey, courseType) {
126
+ return __awaiter(this, void 0, void 0, function* () {
127
+ const lessonPath = node_path_1.default.join(coursePath, lessonName);
128
+ const lessonConfigPath = node_path_1.default.join(lessonPath, LESSON_CONFIG);
129
+ const lessonYaml = yield readRawYamlFile(lessonConfigPath);
130
+ const taskNames = ensureNamedContent(lessonYaml.content, lessonConfigPath);
131
+ const tasks = yield Promise.all(taskNames.map((taskName) => loadTask(lessonPath, taskName, aesKey)));
132
+ const lesson = createLesson(courseType);
133
+ hydrateLesson(lesson, lessonName, lessonYaml);
134
+ for (const task of tasks) {
135
+ lesson.addTask(task);
136
+ }
137
+ return lesson;
138
+ });
139
+ }
140
+ function createTask(taskType) {
141
+ switch (taskType) {
142
+ case "edu":
143
+ case "pycharm":
144
+ return new EduTask_1.EduTask();
145
+ case "code":
146
+ return new CodeTask_1.CodeTask();
147
+ case "number":
148
+ return new NumberTask_1.NumberTask();
149
+ case "string":
150
+ return new StringTask_1.StringTask();
151
+ case "output":
152
+ return new OutputTask_1.OutputTask();
153
+ case "dataset":
154
+ return new DataTask_1.DataTask();
155
+ case "table":
156
+ return new TableTask_1.TableTask();
157
+ case "theory":
158
+ return new TheoryTask_1.TheoryTask();
159
+ case "ide":
160
+ return new IdeTask_1.IdeTask();
161
+ case "unsupported":
162
+ return new UnsupportedTask_1.UnsupportedTask();
163
+ case "remote_edu":
164
+ return new RemoteEduTask_1.RemoteEduTask();
165
+ case "choice":
166
+ return new ChoiceTask_1.ChoiceTask();
167
+ case "matching":
168
+ return new MatchingTask_1.MatchingTask();
169
+ case "sorting":
170
+ return new SortingTask_1.SortingTask();
171
+ default:
172
+ return null;
173
+ }
174
+ }
175
+ function hydrateTask(task, taskName, yaml) {
176
+ var _a;
177
+ task.name = taskName;
178
+ if (yaml.status !== undefined && yaml.status !== null) {
179
+ const statusStr = String(yaml.status);
180
+ const statusMap = {
181
+ Unchecked: CheckStatus_1.CheckStatus.Unchecked,
182
+ Solved: CheckStatus_1.CheckStatus.Solved,
183
+ Failed: CheckStatus_1.CheckStatus.Failed,
184
+ };
185
+ task.status = (_a = statusMap[statusStr]) !== null && _a !== void 0 ? _a : CheckStatus_1.CheckStatus.Unchecked;
186
+ }
187
+ if (typeof yaml.record === "number") {
188
+ task.record = yaml.record;
189
+ }
190
+ if (yaml.feedback_link !== undefined) {
191
+ task.feedbackLink = String(yaml.feedback_link);
192
+ }
193
+ if (yaml.solution_hidden !== undefined) {
194
+ task.solutionHidden = Boolean(yaml.solution_hidden);
195
+ }
196
+ if (Array.isArray(yaml.tags)) {
197
+ task.contentTags = yaml.tags.map(String);
198
+ }
199
+ }
200
+ function hydrateChoiceTask(task, yaml) {
201
+ if (yaml.is_multiple_choice !== undefined) {
202
+ task.isMultipleChoice = Boolean(yaml.is_multiple_choice);
203
+ }
204
+ if (Array.isArray(yaml.options)) {
205
+ task.choiceOptions = yaml.options.map((opt) => {
206
+ var _a;
207
+ const option = new ChoiceOption_1.ChoiceOption();
208
+ option.text = String((_a = opt.text) !== null && _a !== void 0 ? _a : "");
209
+ if (opt.is_correct === true) {
210
+ option.status = ChoiceOptionStatus_1.ChoiceOptionStatus.CORRECT;
211
+ }
212
+ else if (opt.is_correct === false) {
213
+ option.status = ChoiceOptionStatus_1.ChoiceOptionStatus.INCORRECT;
214
+ }
215
+ return option;
216
+ });
217
+ }
218
+ }
219
+ function hydrateMatchingTask(task, yaml) {
220
+ if (Array.isArray(yaml.captions)) {
221
+ const captions = yaml.captions;
222
+ task.captions = captions.map((c) => {
223
+ var _a, _b;
224
+ const first = String((_a = c.first) !== null && _a !== void 0 ? _a : "");
225
+ const second = String((_b = c.second) !== null && _b !== void 0 ? _b : "");
226
+ return `${first} : ${second}`;
227
+ });
228
+ }
229
+ if (Array.isArray(yaml.options)) {
230
+ const opts = yaml.options;
231
+ task.options = opts.map(String);
232
+ }
233
+ }
234
+ function hydrateSortingTask(task, yaml) {
235
+ if (Array.isArray(yaml.options)) {
236
+ const opts = yaml.options;
237
+ task.options = opts.map(String);
238
+ }
239
+ }
240
+ function hydrateTableTask(task, yaml) {
241
+ if (yaml.is_multiple_choice !== undefined) {
242
+ task.isMultipleChoice = Boolean(yaml.is_multiple_choice);
243
+ }
244
+ if (Array.isArray(yaml.rows)) {
245
+ task.rows = yaml.rows.map(String);
246
+ }
247
+ if (Array.isArray(yaml.columns)) {
248
+ task.columns = yaml.columns.map(String);
249
+ }
250
+ if (Array.isArray(yaml.selected)) {
251
+ const sel = yaml.selected;
252
+ task.selected = sel.map((row) => row.map(Boolean));
253
+ }
254
+ }
255
+ function loadTask(lessonPath, taskName, aesKey) {
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ const taskPath = node_path_1.default.join(lessonPath, taskName);
258
+ const taskConfigPath = node_path_1.default.join(taskPath, TASK_CONFIG);
259
+ const rawYaml = yield readRawYamlFile(taskConfigPath);
260
+ if (!rawYaml.type) {
261
+ throw new Error(`Missing 'type' in ${taskConfigPath}`);
262
+ }
263
+ const task = createTask(rawYaml.type);
264
+ if (!task) {
265
+ throw new Error(`Unknown task type '${rawYaml.type}' in ${taskConfigPath}`);
266
+ }
267
+ hydrateTask(task, taskName, rawYaml);
268
+ const files = rawYaml.files
269
+ ? yield Promise.all(rawYaml.files.map((file) => loadTaskFile(taskPath, file, aesKey)))
270
+ : [];
271
+ for (const taskFile of files) {
272
+ task.addTaskFileInstance(taskFile);
273
+ }
274
+ // Hydrate task-specific fields
275
+ if (task instanceof ChoiceTask_1.ChoiceTask) {
276
+ hydrateChoiceTask(task, rawYaml);
277
+ }
278
+ else if (task instanceof MatchingTask_1.MatchingTask) {
279
+ hydrateMatchingTask(task, rawYaml);
280
+ }
281
+ else if (task instanceof SortingTask_1.SortingTask) {
282
+ hydrateSortingTask(task, rawYaml);
283
+ }
284
+ else if (task instanceof TableTask_1.TableTask) {
285
+ hydrateTableTask(task, rawYaml);
286
+ }
287
+ return task;
288
+ });
289
+ }
290
+ function loadTaskFile(ownerPath, fileYaml, aesKey) {
291
+ return __awaiter(this, void 0, void 0, function* () {
292
+ var _a, _b, _c, _d, _e;
293
+ if (!fileYaml.name) {
294
+ throw new Error(`Task file without name in ${ownerPath}`);
295
+ }
296
+ const isBinary = (_a = fileYaml.is_binary) !== null && _a !== void 0 ? _a : false;
297
+ const text = yield resolveTaskFileText(ownerPath, fileYaml, aesKey, isBinary);
298
+ const taskFile = new TaskFile_1.TaskFile();
299
+ taskFile.name = fileYaml.name;
300
+ taskFile.text = text !== null && text !== void 0 ? text : "";
301
+ taskFile.isVisible = (_b = fileYaml.visible) !== null && _b !== void 0 ? _b : true;
302
+ taskFile.isEditable = (_c = fileYaml.editable) !== null && _c !== void 0 ? _c : true;
303
+ taskFile.isPropagatable = (_d = fileYaml.propagatable) !== null && _d !== void 0 ? _d : true;
304
+ taskFile.isLearnerCreated = (_e = fileYaml.learner_created) !== null && _e !== void 0 ? _e : false;
305
+ return taskFile;
306
+ });
307
+ }
308
+ function resolveTaskFileText(ownerPath, fileYaml, aesKey, isBinary) {
309
+ return __awaiter(this, void 0, void 0, function* () {
310
+ if (fileYaml.encrypted_text) {
311
+ let decryptedText;
312
+ try {
313
+ decryptedText = decryptText(fileYaml.encrypted_text, aesKey);
314
+ }
315
+ catch (_a) {
316
+ decryptedText = undefined;
317
+ }
318
+ if (decryptedText && decryptedText.length > 0) {
319
+ return decryptedText;
320
+ }
321
+ const fileText = yield readTaskFileFromDisk(ownerPath, fileYaml.name, isBinary);
322
+ return fileText !== null && fileText !== void 0 ? fileText : decryptedText;
323
+ }
324
+ if (fileYaml.text !== undefined) {
325
+ return fileYaml.text;
326
+ }
327
+ return readTaskFileFromDisk(ownerPath, fileYaml.name, isBinary);
328
+ });
329
+ }
330
+ function readTaskFileFromDisk(ownerPath, name, isBinary) {
331
+ return __awaiter(this, void 0, void 0, function* () {
332
+ if (!name)
333
+ return undefined;
334
+ const filePath = node_path_1.default.join(ownerPath, name);
335
+ try {
336
+ const buffer = yield node_fs_1.promises.readFile(filePath);
337
+ return isBinary ? buffer.toString("base64") : buffer.toString("utf8");
338
+ }
339
+ catch (_a) {
340
+ return undefined;
341
+ }
342
+ });
343
+ }
344
+ function ensureNamedContent(content, configPath) {
345
+ if (!content)
346
+ return [];
347
+ return content.map((name, index) => {
348
+ if (!name) {
349
+ throw new Error(`Unnamed item at position ${index + 1} in ${configPath}`);
350
+ }
351
+ return name;
352
+ });
353
+ }
354
+ function readRawYamlFile(filePath) {
355
+ return __awaiter(this, void 0, void 0, function* () {
356
+ const text = yield node_fs_1.promises.readFile(filePath, "utf8");
357
+ return (0, yaml_1.parse)(text);
358
+ });
359
+ }
360
+ function decryptText(encryptedText, aesKey) {
361
+ const key = Buffer.from(aesKey, "utf8");
362
+ const iv = Buffer.from(aesKey.slice(0, 16), "utf8");
363
+ const decipher = node_crypto_1.default.createDecipheriv("aes-256-cbc", key, iv);
364
+ const decrypted = Buffer.concat([
365
+ decipher.update(Buffer.from(encryptedText, "base64")),
366
+ decipher.final(),
367
+ ]);
368
+ return decrypted.toString("utf8");
369
+ }
370
+ function getAesKey() {
371
+ const keyFromFile = readAesKeyFromResources();
372
+ if (keyFromFile && keyFromFile.length === 32) {
373
+ return keyFromFile;
374
+ }
375
+ return TEST_AES_KEY;
376
+ }
377
+ function readAesKeyFromResources() {
378
+ const resourcePath = node_path_1.default.resolve(process.cwd(), "edu-format", "resources", "aes", "aes.properties");
379
+ try {
380
+ const data = (0, node_fs_2.readFileSync)(resourcePath, "utf8");
381
+ const match = data.split(/\r?\n/).find((line) => line.startsWith("aesKey="));
382
+ if (!match)
383
+ return null;
384
+ return match.slice("aesKey=".length).trim() || null;
385
+ }
386
+ catch (_a) {
387
+ return null;
388
+ }
389
+ }
@@ -0,0 +1,31 @@
1
+ export { loadCourseProject } from "./disk-loader";
2
+ export { loadCourseProjectFromZip } from "./zip-loader";
3
+ export { EduCourse } from "./courseFormat/EduCourse";
4
+ export { CourseraCourse } from "./courseFormat/CourseraCourse";
5
+ export { HyperskillCourse } from "./courseFormat/hyperskill/HyperskillCourse";
6
+ export { StepikCourse } from "./courseFormat/stepik/StepikCourse";
7
+ export { Course } from "./courseFormat/Course";
8
+ export { CourseMode } from "./courseFormat/CourseMode";
9
+ export { Lesson } from "./courseFormat/Lesson";
10
+ export { StepikLesson } from "./courseFormat/stepik/StepikLesson";
11
+ export { FrameworkLesson } from "./courseFormat/FrameworkLesson";
12
+ export { Section } from "./courseFormat/Section";
13
+ export { TaskFile } from "./courseFormat/TaskFile";
14
+ export { Task } from "./courseFormat/tasks/Task";
15
+ export { EduTask } from "./courseFormat/tasks/EduTask";
16
+ export { CodeTask } from "./courseFormat/tasks/CodeTask";
17
+ export { AnswerTask } from "./courseFormat/tasks/AnswerTask";
18
+ export { NumberTask } from "./courseFormat/tasks/NumberTask";
19
+ export { StringTask } from "./courseFormat/tasks/StringTask";
20
+ export { OutputTask } from "./courseFormat/tasks/OutputTask";
21
+ export { DataTask } from "./courseFormat/tasks/DataTask";
22
+ export { TableTask } from "./courseFormat/tasks/TableTask";
23
+ export { TheoryTask } from "./courseFormat/tasks/TheoryTask";
24
+ export { IdeTask } from "./courseFormat/tasks/IdeTask";
25
+ export { UnsupportedTask } from "./courseFormat/tasks/UnsupportedTask";
26
+ export { RemoteEduTask } from "./courseFormat/tasks/RemoteEduTask";
27
+ export { ChoiceTask } from "./courseFormat/tasks/choice/ChoiceTask";
28
+ export { MatchingTask } from "./courseFormat/tasks/matching/MatchingTask";
29
+ export { SortingTask } from "./courseFormat/tasks/matching/SortingTask";
30
+ export { Vendor } from "./models";
31
+ export { CheckStatus } from "./courseFormat/CheckStatus";