@telebort/question-banks 2.2.0 → 2.4.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.
- package/README.md +194 -27
- package/dist/{assessment-DnV2240e.d.cts → assessment-BhkjdWy1.d.cts} +38 -5
- package/dist/{assessment-DnV2240e.d.ts → assessment-BhkjdWy1.d.ts} +38 -5
- package/dist/cli/index.cjs +273 -72
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +273 -72
- package/dist/cli/index.js.map +1 -1
- package/dist/{course-CkP2VX_5.d.cts → course-DD94UGiI.d.cts} +329 -139
- package/dist/{course-CkP2VX_5.d.ts → course-DD94UGiI.d.ts} +329 -139
- package/dist/{index-DRVgW8qc.d.ts → index-B1r6pY_k.d.ts} +1 -1
- package/dist/{index-B-16Gs9R.d.cts → index-jb328lpu.d.cts} +1 -1
- package/dist/index.cjs +256 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -34
- package/dist/index.d.ts +61 -34
- package/dist/index.js +255 -60
- package/dist/index.js.map +1 -1
- package/dist/premium/index.d.cts +3 -3
- package/dist/premium/index.d.ts +3 -3
- package/dist/schemas/index.cjs +120 -58
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +2 -2
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/index.js +120 -59
- package/dist/schemas/index.js.map +1 -1
- package/dist/validation/index.cjs +119 -58
- package/dist/validation/index.cjs.map +1 -1
- package/dist/validation/index.d.cts +1 -1
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +119 -58
- package/dist/validation/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -19,22 +19,52 @@ var OptionSchema = zod.z.object({
|
|
|
19
19
|
text: zod.z.string().min(1),
|
|
20
20
|
isCorrect: zod.z.boolean(),
|
|
21
21
|
// v1.1 fields - optional for backward compatibility
|
|
22
|
-
misconceptionId: zod.z.string().
|
|
22
|
+
misconceptionId: zod.z.string().nullish(),
|
|
23
23
|
feedback: FeedbackSchema.optional()
|
|
24
24
|
});
|
|
25
25
|
var QuestionTypeSchema = zod.z.enum([
|
|
26
|
+
// Core assessment types (original v1.0)
|
|
26
27
|
"vocabulary",
|
|
27
28
|
"code_understanding",
|
|
28
29
|
"problem_solving",
|
|
29
30
|
"application",
|
|
30
|
-
"reflection"
|
|
31
|
+
"reflection",
|
|
32
|
+
// Code-focused types
|
|
33
|
+
"debugging",
|
|
34
|
+
"trace",
|
|
35
|
+
"predict",
|
|
36
|
+
// Higher-order thinking
|
|
37
|
+
"analyze",
|
|
38
|
+
"evaluation",
|
|
39
|
+
"synthesis",
|
|
40
|
+
"design",
|
|
41
|
+
"conceptual",
|
|
42
|
+
"explain",
|
|
43
|
+
// Domain-specific
|
|
44
|
+
"bebras",
|
|
45
|
+
"blockmodel",
|
|
46
|
+
"ethical_reasoning"
|
|
31
47
|
]);
|
|
32
48
|
var QuestionArchetypeSchema = zod.z.enum([
|
|
49
|
+
// Original archetypes (v1.1)
|
|
33
50
|
"vocabulary",
|
|
34
51
|
"trace",
|
|
35
52
|
"bebras",
|
|
36
53
|
"blockmodel",
|
|
37
|
-
"parsons"
|
|
54
|
+
"parsons",
|
|
55
|
+
// Assessment patterns
|
|
56
|
+
"application",
|
|
57
|
+
"problem_solving",
|
|
58
|
+
"debugging",
|
|
59
|
+
"predict",
|
|
60
|
+
"explain",
|
|
61
|
+
"evaluation",
|
|
62
|
+
"reflection",
|
|
63
|
+
"conceptual",
|
|
64
|
+
"analysis",
|
|
65
|
+
"design",
|
|
66
|
+
"synthesis",
|
|
67
|
+
"code"
|
|
38
68
|
]);
|
|
39
69
|
var DifficultySchema = zod.z.enum(["easy", "medium", "hard", "challenge"]);
|
|
40
70
|
var BloomsTaxonomySchema = zod.z.enum([
|
|
@@ -51,6 +81,10 @@ var QuestionMetadataSchema = zod.z.object({
|
|
|
51
81
|
// seconds
|
|
52
82
|
bloomsTaxonomy: BloomsTaxonomySchema,
|
|
53
83
|
tags: zod.z.array(zod.z.string()),
|
|
84
|
+
conceptTags: zod.z.array(zod.z.string()).optional(),
|
|
85
|
+
// mastery-relevant concept tags
|
|
86
|
+
metaTags: zod.z.array(zod.z.string()).optional(),
|
|
87
|
+
// Bloom's types, course codes, internal
|
|
54
88
|
source: zod.z.string().default("exit-ticket"),
|
|
55
89
|
version: zod.z.string().default("1.1"),
|
|
56
90
|
createdDate: zod.z.string().optional(),
|
|
@@ -58,8 +92,8 @@ var QuestionMetadataSchema = zod.z.object({
|
|
|
58
92
|
});
|
|
59
93
|
var QuestionSchema = zod.z.object({
|
|
60
94
|
// Identifiers
|
|
61
|
-
questionId: zod.z.string().regex(/^[a-z0-9-]
|
|
62
|
-
globalId: zod.z.string().regex(/^exit-ticket
|
|
95
|
+
questionId: zod.z.string().regex(/^[a-z0-9][-a-z0-9]*-(?:l\d+-)?q\d+$/),
|
|
96
|
+
globalId: zod.z.string().regex(/^exit-ticket-[a-z0-9][-a-z0-9]*$/),
|
|
63
97
|
questionNumber: zod.z.number().int().positive().max(5),
|
|
64
98
|
// Classification
|
|
65
99
|
questionType: QuestionTypeSchema,
|
|
@@ -93,58 +127,17 @@ QuestionSchema.omit({
|
|
|
93
127
|
})
|
|
94
128
|
).length(4)
|
|
95
129
|
});
|
|
96
|
-
var
|
|
97
|
-
|
|
98
|
-
"
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// Block-based Programming
|
|
108
|
-
"block_based",
|
|
109
|
-
"python_programming",
|
|
110
|
-
"design",
|
|
111
|
-
// Foundation
|
|
112
|
-
"foundation",
|
|
113
|
-
"creative_computing"
|
|
114
|
-
]);
|
|
115
|
-
var CourseTierSchema = zod.z.enum([
|
|
116
|
-
"foundation",
|
|
117
|
-
"intermediate",
|
|
118
|
-
"advanced"
|
|
119
|
-
]);
|
|
120
|
-
var LessonSchema = zod.z.object({
|
|
121
|
-
lessonId: zod.z.string(),
|
|
122
|
-
// e.g., "ai-1-lesson-1"
|
|
123
|
-
lessonNumber: zod.z.number().int().positive(),
|
|
124
|
-
lessonTitle: zod.z.string(),
|
|
125
|
-
lessonSlug: zod.z.string().optional(),
|
|
126
|
-
totalQuestions: zod.z.number().int().positive().default(5),
|
|
127
|
-
questions: zod.z.array(QuestionSchema)
|
|
128
|
-
});
|
|
129
|
-
var CourseSchema = zod.z.object({
|
|
130
|
-
courseId: zod.z.string(),
|
|
131
|
-
// e.g., "ai-1"
|
|
132
|
-
courseName: zod.z.string(),
|
|
133
|
-
// e.g., "AI-1 Data Analysis and Data Science"
|
|
134
|
-
courseCode: zod.z.string(),
|
|
135
|
-
// e.g., "AI1"
|
|
136
|
-
domain: CourseDomainSchema,
|
|
137
|
-
tier: CourseTierSchema,
|
|
138
|
-
difficulty: zod.z.number().int().min(1).max(5),
|
|
139
|
-
totalLessons: zod.z.number().int().positive(),
|
|
140
|
-
totalQuestions: zod.z.number().int().positive(),
|
|
141
|
-
sourceFile: zod.z.string().optional(),
|
|
142
|
-
lessons: zod.z.array(LessonSchema)
|
|
143
|
-
});
|
|
144
|
-
CourseSchema.omit({ lessons: true }).extend({
|
|
145
|
-
lessons: zod.z.array(
|
|
146
|
-
LessonSchema.omit({ questions: true })
|
|
147
|
-
).optional()
|
|
130
|
+
var AssessmentBlueprintSchema = zod.z.object({
|
|
131
|
+
assessmentId: zod.z.string(),
|
|
132
|
+
// e.g., "cs1-quiz-1"
|
|
133
|
+
title: zod.z.string(),
|
|
134
|
+
// e.g., "Quiz 1"
|
|
135
|
+
description: zod.z.string(),
|
|
136
|
+
lessonRange: zod.z.tuple([zod.z.number().int().positive(), zod.z.number().int().positive()]).refine(([start2, end2]) => start2 <= end2, { message: "lessonRange start must be <= end" }),
|
|
137
|
+
questionCount: zod.z.number().int().positive(),
|
|
138
|
+
passingScore: zod.z.number().min(0).max(100),
|
|
139
|
+
timeLimitMinutes: zod.z.number().int().positive().nullable(),
|
|
140
|
+
tags: zod.z.array(zod.z.string()).optional()
|
|
148
141
|
});
|
|
149
142
|
var UserResponseSchema = zod.z.object({
|
|
150
143
|
questionId: zod.z.string(),
|
|
@@ -185,7 +178,7 @@ var MisconceptionReportSchema = zod.z.object({
|
|
|
185
178
|
description: zod.z.string().optional()
|
|
186
179
|
});
|
|
187
180
|
zod.z.object({
|
|
188
|
-
assessmentId: zod.z.string()
|
|
181
|
+
assessmentId: zod.z.string(),
|
|
189
182
|
userId: zod.z.string().optional(),
|
|
190
183
|
courseId: zod.z.string(),
|
|
191
184
|
lessonId: zod.z.string().optional(),
|
|
@@ -221,6 +214,74 @@ zod.z.object({
|
|
|
221
214
|
questionCount: zod.z.number().int(),
|
|
222
215
|
answeredCount: zod.z.number().int()
|
|
223
216
|
});
|
|
217
|
+
|
|
218
|
+
// src/schemas/course.ts
|
|
219
|
+
var CourseDomainSchema = zod.z.enum([
|
|
220
|
+
// AI & Data Science
|
|
221
|
+
"ai_data_science",
|
|
222
|
+
"ai_ml_cv",
|
|
223
|
+
"ai_generative",
|
|
224
|
+
"ai_advanced",
|
|
225
|
+
"ai",
|
|
226
|
+
// Prompt Engineering (general AI)
|
|
227
|
+
// Web Development
|
|
228
|
+
"web_development",
|
|
229
|
+
// Mobile Development
|
|
230
|
+
"mobile_development",
|
|
231
|
+
"mobile",
|
|
232
|
+
// Block-based Programming
|
|
233
|
+
"block_based",
|
|
234
|
+
"python_programming",
|
|
235
|
+
"design",
|
|
236
|
+
"artificial_intelligence",
|
|
237
|
+
// Block-based AI courses (BBAI)
|
|
238
|
+
// Computer Science
|
|
239
|
+
"cs_foundations",
|
|
240
|
+
// CS1-CS4 courses
|
|
241
|
+
// Foundation
|
|
242
|
+
"foundation",
|
|
243
|
+
"creative_computing",
|
|
244
|
+
// Utility / Tools
|
|
245
|
+
"tools"
|
|
246
|
+
// IDE Setup, Git, Vibe Coding
|
|
247
|
+
]);
|
|
248
|
+
var CourseTierSchema = zod.z.enum([
|
|
249
|
+
"beginner",
|
|
250
|
+
// Block-based courses (BBW, BBP, BBD, BBAI)
|
|
251
|
+
"foundation",
|
|
252
|
+
"intermediate",
|
|
253
|
+
"advanced"
|
|
254
|
+
]);
|
|
255
|
+
var LessonSchema = zod.z.object({
|
|
256
|
+
lessonId: zod.z.string(),
|
|
257
|
+
// e.g., "ai-1-lesson-1"
|
|
258
|
+
lessonNumber: zod.z.number().int().positive(),
|
|
259
|
+
lessonTitle: zod.z.string(),
|
|
260
|
+
lessonSlug: zod.z.string().optional(),
|
|
261
|
+
totalQuestions: zod.z.number().int().positive().default(5),
|
|
262
|
+
questions: zod.z.array(QuestionSchema)
|
|
263
|
+
});
|
|
264
|
+
var CourseSchema = zod.z.object({
|
|
265
|
+
courseId: zod.z.string(),
|
|
266
|
+
// e.g., "ai-1"
|
|
267
|
+
courseName: zod.z.string(),
|
|
268
|
+
// e.g., "AI-1 Data Analysis and Data Science"
|
|
269
|
+
courseCode: zod.z.string(),
|
|
270
|
+
// e.g., "AI1"
|
|
271
|
+
domain: CourseDomainSchema,
|
|
272
|
+
tier: CourseTierSchema,
|
|
273
|
+
difficulty: zod.z.number().int().min(1).max(5),
|
|
274
|
+
totalLessons: zod.z.number().int().positive(),
|
|
275
|
+
totalQuestions: zod.z.number().int().positive(),
|
|
276
|
+
sourceFile: zod.z.string().optional(),
|
|
277
|
+
lessons: zod.z.array(LessonSchema),
|
|
278
|
+
assessments: zod.z.array(AssessmentBlueprintSchema).optional()
|
|
279
|
+
});
|
|
280
|
+
CourseSchema.omit({ lessons: true }).extend({
|
|
281
|
+
lessons: zod.z.array(
|
|
282
|
+
LessonSchema.omit({ questions: true })
|
|
283
|
+
).optional()
|
|
284
|
+
});
|
|
224
285
|
var CertificationProjectSchema = zod.z.object({
|
|
225
286
|
projectNumber: zod.z.number().int().positive(),
|
|
226
287
|
projectName: zod.z.string(),
|
|
@@ -508,6 +569,138 @@ ${green(bold("Valid!"))} File passed schema validation.
|
|
|
508
569
|
}
|
|
509
570
|
}
|
|
510
571
|
|
|
572
|
+
// src/core/assessment.ts
|
|
573
|
+
var SeededRandom = class {
|
|
574
|
+
constructor(seed) {
|
|
575
|
+
this.state = seed;
|
|
576
|
+
}
|
|
577
|
+
next() {
|
|
578
|
+
this.state = (this.state * 1103515245 + 12345) % 2147483648;
|
|
579
|
+
return this.state / 2147483648;
|
|
580
|
+
}
|
|
581
|
+
/** Fisher-Yates shuffle */
|
|
582
|
+
shuffle(array) {
|
|
583
|
+
const result = [...array];
|
|
584
|
+
for (let i3 = result.length - 1; i3 > 0; i3--) {
|
|
585
|
+
const j2 = Math.floor(this.next() * (i3 + 1));
|
|
586
|
+
const temp = result[i3];
|
|
587
|
+
result[i3] = result[j2];
|
|
588
|
+
result[j2] = temp;
|
|
589
|
+
}
|
|
590
|
+
return result;
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
function hashString(str) {
|
|
594
|
+
let hash = 0;
|
|
595
|
+
for (let i3 = 0; i3 < str.length; i3++) {
|
|
596
|
+
const char = str.charCodeAt(i3);
|
|
597
|
+
hash = (hash << 5) - hash + char;
|
|
598
|
+
hash = hash & hash;
|
|
599
|
+
}
|
|
600
|
+
return Math.abs(hash);
|
|
601
|
+
}
|
|
602
|
+
function createAssessmentModule(getCourse) {
|
|
603
|
+
return {
|
|
604
|
+
async getAssessments(courseId) {
|
|
605
|
+
const course = await getCourse(courseId);
|
|
606
|
+
return course?.assessments ?? [];
|
|
607
|
+
},
|
|
608
|
+
async buildAssessmentQuiz(courseId, assessmentId, seed) {
|
|
609
|
+
const course = await getCourse(courseId);
|
|
610
|
+
if (!course) throw new Error(`Course not found: ${courseId}`);
|
|
611
|
+
const blueprint = course.assessments?.find((a2) => a2.assessmentId === assessmentId);
|
|
612
|
+
if (!blueprint) throw new Error(`Assessment not found: ${assessmentId}`);
|
|
613
|
+
const [rangeStart, rangeEnd] = blueprint.lessonRange;
|
|
614
|
+
const pool = [];
|
|
615
|
+
for (const lesson of course.lessons) {
|
|
616
|
+
if (lesson.lessonNumber >= rangeStart && lesson.lessonNumber <= rangeEnd) {
|
|
617
|
+
pool.push(...lesson.questions);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (pool.length === 0) {
|
|
621
|
+
throw new Error(`No questions found for lessons ${rangeStart}-${rangeEnd} in ${courseId}`);
|
|
622
|
+
}
|
|
623
|
+
const seedValue = seed ? hashString(seed) : Date.now();
|
|
624
|
+
const rng = new SeededRandom(seedValue);
|
|
625
|
+
const shuffled = rng.shuffle(pool);
|
|
626
|
+
return shuffled.slice(0, Math.min(blueprint.questionCount, shuffled.length));
|
|
627
|
+
},
|
|
628
|
+
async gradeAssessment(courseId, assessmentId, responses, passingScore) {
|
|
629
|
+
const course = await getCourse(courseId);
|
|
630
|
+
if (!course) throw new Error(`Course not found: ${courseId}`);
|
|
631
|
+
const blueprint = course.assessments?.find((a2) => a2.assessmentId === assessmentId);
|
|
632
|
+
if (!blueprint) throw new Error(`Assessment not found: ${assessmentId}`);
|
|
633
|
+
const threshold = passingScore ?? blueprint.passingScore;
|
|
634
|
+
const questionMap = /* @__PURE__ */ new Map();
|
|
635
|
+
for (const lesson of course.lessons) {
|
|
636
|
+
for (const q of lesson.questions) {
|
|
637
|
+
questionMap.set(q.questionId, q);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const gradedResponses = [];
|
|
641
|
+
let correctCount = 0;
|
|
642
|
+
for (const response of responses) {
|
|
643
|
+
const question = questionMap.get(response.questionId);
|
|
644
|
+
if (!question) continue;
|
|
645
|
+
const selectedOption = question.options.find((o2) => o2.key === response.selectedAnswer);
|
|
646
|
+
const isCorrect = selectedOption?.isCorrect ?? false;
|
|
647
|
+
if (isCorrect) correctCount++;
|
|
648
|
+
gradedResponses.push({
|
|
649
|
+
questionId: response.questionId,
|
|
650
|
+
selectedAnswer: response.selectedAnswer,
|
|
651
|
+
correctAnswer: question.correctAnswer,
|
|
652
|
+
isCorrect,
|
|
653
|
+
misconceptionId: isCorrect ? null : selectedOption?.misconceptionId ?? null,
|
|
654
|
+
feedback: selectedOption?.feedback,
|
|
655
|
+
timeSpent: response.timeSpent
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
const totalQuestions = gradedResponses.length;
|
|
659
|
+
const score = totalQuestions > 0 ? Math.round(correctCount / totalQuestions * 100) : 0;
|
|
660
|
+
const misconceptionCounts = /* @__PURE__ */ new Map();
|
|
661
|
+
for (const gr of gradedResponses) {
|
|
662
|
+
if (gr.misconceptionId) {
|
|
663
|
+
const existing = misconceptionCounts.get(gr.misconceptionId);
|
|
664
|
+
if (existing) {
|
|
665
|
+
existing.count++;
|
|
666
|
+
existing.questionIds.push(gr.questionId);
|
|
667
|
+
} else {
|
|
668
|
+
misconceptionCounts.set(gr.misconceptionId, {
|
|
669
|
+
count: 1,
|
|
670
|
+
questionIds: [gr.questionId]
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
const misconceptions = Array.from(misconceptionCounts.entries()).map(([id, data]) => ({
|
|
676
|
+
misconceptionId: id,
|
|
677
|
+
count: data.count,
|
|
678
|
+
percentage: Math.round(data.count / totalQuestions * 100),
|
|
679
|
+
questionIds: data.questionIds
|
|
680
|
+
})).sort((a2, b) => b.count - a2.count);
|
|
681
|
+
if (totalQuestions === 0) {
|
|
682
|
+
throw new Error(`No valid questions matched for assessment ${assessmentId}. All ${responses.length} response(s) referenced unknown questionIds.`);
|
|
683
|
+
}
|
|
684
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
685
|
+
const generatedId = `grade-${courseId}-${assessmentId}-${hashString(now).toString(36)}`;
|
|
686
|
+
return {
|
|
687
|
+
assessmentId: generatedId,
|
|
688
|
+
courseId,
|
|
689
|
+
totalQuestions,
|
|
690
|
+
correctCount,
|
|
691
|
+
incorrectCount: totalQuestions - correctCount,
|
|
692
|
+
score,
|
|
693
|
+
passed: score >= threshold,
|
|
694
|
+
responses: gradedResponses,
|
|
695
|
+
misconceptions,
|
|
696
|
+
topMisconceptions: misconceptions.slice(0, 3).map((m3) => m3.misconceptionId),
|
|
697
|
+
submittedAt: now,
|
|
698
|
+
gradedAt: now
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
511
704
|
// src/knowledge/index.ts
|
|
512
705
|
function createLogger(config) {
|
|
513
706
|
return {
|
|
@@ -23249,6 +23442,7 @@ function createExitTicketsSDK(config) {
|
|
|
23249
23442
|
};
|
|
23250
23443
|
const malaysiaMath = createMalaysiaMathModule(malaysiaMathConfig);
|
|
23251
23444
|
const malaysiaMathTaxonomy = createMalaysiaMathTaxonomyModule(malaysiaMathConfig);
|
|
23445
|
+
const assessment = createAssessmentModule(data.getCourse);
|
|
23252
23446
|
return {
|
|
23253
23447
|
data,
|
|
23254
23448
|
query,
|
|
@@ -23259,7 +23453,8 @@ function createExitTicketsSDK(config) {
|
|
|
23259
23453
|
knowledge,
|
|
23260
23454
|
taxonomy,
|
|
23261
23455
|
malaysiaMath,
|
|
23262
|
-
malaysiaMathTaxonomy
|
|
23456
|
+
malaysiaMathTaxonomy,
|
|
23457
|
+
assessment
|
|
23263
23458
|
};
|
|
23264
23459
|
}
|
|
23265
23460
|
|
|
@@ -23428,26 +23623,32 @@ async function loadCourseData(filePath) {
|
|
|
23428
23623
|
}
|
|
23429
23624
|
function extractQuestions(courseData) {
|
|
23430
23625
|
const questions = [];
|
|
23626
|
+
const pushQuestion = (q) => {
|
|
23627
|
+
questions.push({
|
|
23628
|
+
questionId: q.questionId || q.globalId || `${courseData.courseId || "unknown"}-unknown`,
|
|
23629
|
+
prompt: q.prompt || "",
|
|
23630
|
+
options: (q.options || []).map((o2) => ({
|
|
23631
|
+
key: o2.key || "",
|
|
23632
|
+
text: o2.text || "",
|
|
23633
|
+
isCorrect: o2.isCorrect || false
|
|
23634
|
+
})),
|
|
23635
|
+
hasCodeBlock: q.hasCodeBlock || false,
|
|
23636
|
+
codeLanguage: q.codeLanguage || null,
|
|
23637
|
+
codeContent: q.codeContent || null
|
|
23638
|
+
});
|
|
23639
|
+
};
|
|
23431
23640
|
if (courseData.lessons) {
|
|
23432
23641
|
for (const lesson of courseData.lessons) {
|
|
23433
23642
|
if (lesson.questions) {
|
|
23434
23643
|
for (const q of lesson.questions) {
|
|
23435
|
-
|
|
23436
|
-
questionId: q.questionId || `${courseData.courseId}-unknown`,
|
|
23437
|
-
prompt: q.prompt || "",
|
|
23438
|
-
options: (q.options || []).map((o2) => ({
|
|
23439
|
-
key: o2.key || "",
|
|
23440
|
-
text: o2.text || "",
|
|
23441
|
-
isCorrect: o2.isCorrect || false
|
|
23442
|
-
})),
|
|
23443
|
-
// CS-specific fields for enhanced analysis
|
|
23444
|
-
hasCodeBlock: q.hasCodeBlock || false,
|
|
23445
|
-
codeLanguage: q.codeLanguage || null,
|
|
23446
|
-
codeContent: q.codeContent || null
|
|
23447
|
-
});
|
|
23644
|
+
pushQuestion(q);
|
|
23448
23645
|
}
|
|
23449
23646
|
}
|
|
23450
23647
|
}
|
|
23648
|
+
} else if (courseData.questions && Array.isArray(courseData.questions)) {
|
|
23649
|
+
for (const q of courseData.questions) {
|
|
23650
|
+
pushQuestion(q);
|
|
23651
|
+
}
|
|
23451
23652
|
}
|
|
23452
23653
|
return questions;
|
|
23453
23654
|
}
|