@mathscan/math-exercise-engine 1.0.9 → 1.0.11
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/dist/index.d.ts +67 -63
- package/dist/index.js +24 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +24 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -191,12 +191,6 @@ export declare function compile(dsl: string): ExerciseJSON;
|
|
|
191
191
|
*/
|
|
192
192
|
export declare function compileWithAST(dsl: string): {
|
|
193
193
|
ast: {
|
|
194
|
-
validation: {
|
|
195
|
-
type: "SimpleValidation";
|
|
196
|
-
} | {
|
|
197
|
-
expression: string;
|
|
198
|
-
type: "ExpressionValidation";
|
|
199
|
-
};
|
|
200
194
|
type: "ExerciseDocument";
|
|
201
195
|
lines: ({
|
|
202
196
|
type: "LineBlock";
|
|
@@ -324,6 +318,12 @@ export declare function compileWithAST(dsl: string): {
|
|
|
324
318
|
value: string;
|
|
325
319
|
type: "TextBlock";
|
|
326
320
|
} | undefined;
|
|
321
|
+
validation?: {
|
|
322
|
+
type: "SimpleValidation";
|
|
323
|
+
} | {
|
|
324
|
+
expression: string;
|
|
325
|
+
type: "ExpressionValidation";
|
|
326
|
+
} | undefined;
|
|
327
327
|
tools?: ({
|
|
328
328
|
type: "DragOptions";
|
|
329
329
|
options: string[];
|
|
@@ -334,12 +334,6 @@ export declare function compileWithAST(dsl: string): {
|
|
|
334
334
|
})[] | undefined;
|
|
335
335
|
};
|
|
336
336
|
json: {
|
|
337
|
-
validation: {
|
|
338
|
-
mode: "simple" | "expression";
|
|
339
|
-
expression?: string | undefined;
|
|
340
|
-
answers?: Record<string, string | number> | undefined;
|
|
341
|
-
variables?: string[] | undefined;
|
|
342
|
-
};
|
|
343
337
|
version: "2.0";
|
|
344
338
|
layout: any[];
|
|
345
339
|
widgets: Record<string, {
|
|
@@ -361,6 +355,12 @@ export declare function compileWithAST(dsl: string): {
|
|
|
361
355
|
includeOperators?: boolean | undefined;
|
|
362
356
|
includeDecimal?: boolean | undefined;
|
|
363
357
|
}>;
|
|
358
|
+
validation?: {
|
|
359
|
+
mode: "simple" | "expression";
|
|
360
|
+
expression?: string | undefined;
|
|
361
|
+
answers?: Record<string, string | number> | undefined;
|
|
362
|
+
variables?: string[] | undefined;
|
|
363
|
+
} | undefined;
|
|
364
364
|
id?: string | undefined;
|
|
365
365
|
meta?: {
|
|
366
366
|
createdAt?: string | undefined;
|
|
@@ -1314,7 +1314,7 @@ export declare function createDragOptions(options: string[]): DragOptionsTool;
|
|
|
1314
1314
|
/**
|
|
1315
1315
|
* Create an exercise document
|
|
1316
1316
|
*/
|
|
1317
|
-
export declare function createExerciseDocument(question: z.infer<typeof TextBlockSchema> | undefined, lines: ContentBlock[], validation
|
|
1317
|
+
export declare function createExerciseDocument(question: z.infer<typeof TextBlockSchema> | undefined, lines: ContentBlock[], validation?: z.infer<typeof ValidationNodeSchema>, tools?: z.infer<typeof ToolNodeSchema>[]): ExerciseDocument;
|
|
1318
1318
|
|
|
1319
1319
|
/**
|
|
1320
1320
|
* Create an expression validation node
|
|
@@ -2415,7 +2415,7 @@ export declare const ExerciseDocumentSchema: z.ZodObject<{
|
|
|
2415
2415
|
includeOperators?: boolean | undefined;
|
|
2416
2416
|
includeDecimal?: boolean | undefined;
|
|
2417
2417
|
}>]>, "many">>;
|
|
2418
|
-
validation: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
2418
|
+
validation: z.ZodOptional<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
2419
2419
|
type: z.ZodLiteral<"SimpleValidation">;
|
|
2420
2420
|
}, "strip", z.ZodTypeAny, {
|
|
2421
2421
|
type: "SimpleValidation";
|
|
@@ -2430,14 +2430,8 @@ export declare const ExerciseDocumentSchema: z.ZodObject<{
|
|
|
2430
2430
|
}, {
|
|
2431
2431
|
expression: string;
|
|
2432
2432
|
type: "ExpressionValidation";
|
|
2433
|
-
}>]
|
|
2433
|
+
}>]>>;
|
|
2434
2434
|
}, "strip", z.ZodTypeAny, {
|
|
2435
|
-
validation: {
|
|
2436
|
-
type: "SimpleValidation";
|
|
2437
|
-
} | {
|
|
2438
|
-
expression: string;
|
|
2439
|
-
type: "ExpressionValidation";
|
|
2440
|
-
};
|
|
2441
2435
|
type: "ExerciseDocument";
|
|
2442
2436
|
lines: ({
|
|
2443
2437
|
type: "LineBlock";
|
|
@@ -2565,6 +2559,12 @@ export declare const ExerciseDocumentSchema: z.ZodObject<{
|
|
|
2565
2559
|
value: string;
|
|
2566
2560
|
type: "TextBlock";
|
|
2567
2561
|
} | undefined;
|
|
2562
|
+
validation?: {
|
|
2563
|
+
type: "SimpleValidation";
|
|
2564
|
+
} | {
|
|
2565
|
+
expression: string;
|
|
2566
|
+
type: "ExpressionValidation";
|
|
2567
|
+
} | undefined;
|
|
2568
2568
|
tools?: ({
|
|
2569
2569
|
type: "DragOptions";
|
|
2570
2570
|
options: string[];
|
|
@@ -2574,12 +2574,6 @@ export declare const ExerciseDocumentSchema: z.ZodObject<{
|
|
|
2574
2574
|
includeDecimal?: boolean | undefined;
|
|
2575
2575
|
})[] | undefined;
|
|
2576
2576
|
}, {
|
|
2577
|
-
validation: {
|
|
2578
|
-
type: "SimpleValidation";
|
|
2579
|
-
} | {
|
|
2580
|
-
expression: string;
|
|
2581
|
-
type: "ExpressionValidation";
|
|
2582
|
-
};
|
|
2583
2577
|
type: "ExerciseDocument";
|
|
2584
2578
|
lines: ({
|
|
2585
2579
|
type: "LineBlock";
|
|
@@ -2707,6 +2701,12 @@ export declare const ExerciseDocumentSchema: z.ZodObject<{
|
|
|
2707
2701
|
value: string;
|
|
2708
2702
|
type: "TextBlock";
|
|
2709
2703
|
} | undefined;
|
|
2704
|
+
validation?: {
|
|
2705
|
+
type: "SimpleValidation";
|
|
2706
|
+
} | {
|
|
2707
|
+
expression: string;
|
|
2708
|
+
type: "ExpressionValidation";
|
|
2709
|
+
} | undefined;
|
|
2710
2710
|
tools?: ({
|
|
2711
2711
|
type: "DragOptions";
|
|
2712
2712
|
options: string[];
|
|
@@ -2778,7 +2778,7 @@ export declare const ExerciseJSONSchema: z.ZodObject<{
|
|
|
2778
2778
|
includeOperators?: boolean | undefined;
|
|
2779
2779
|
includeDecimal?: boolean | undefined;
|
|
2780
2780
|
}>]>>;
|
|
2781
|
-
validation: z.ZodObject<{
|
|
2781
|
+
validation: z.ZodOptional<z.ZodObject<{
|
|
2782
2782
|
mode: z.ZodEnum<["simple", "expression"]>;
|
|
2783
2783
|
answers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber]>>>;
|
|
2784
2784
|
expression: z.ZodOptional<z.ZodString>;
|
|
@@ -2793,7 +2793,7 @@ export declare const ExerciseJSONSchema: z.ZodObject<{
|
|
|
2793
2793
|
expression?: string | undefined;
|
|
2794
2794
|
answers?: Record<string, string | number> | undefined;
|
|
2795
2795
|
variables?: string[] | undefined;
|
|
2796
|
-
}
|
|
2796
|
+
}>>;
|
|
2797
2797
|
meta: z.ZodOptional<z.ZodObject<{
|
|
2798
2798
|
createdAt: z.ZodOptional<z.ZodString>;
|
|
2799
2799
|
author: z.ZodOptional<z.ZodString>;
|
|
@@ -2811,12 +2811,6 @@ export declare const ExerciseJSONSchema: z.ZodObject<{
|
|
|
2811
2811
|
difficulty?: number | undefined;
|
|
2812
2812
|
}>>;
|
|
2813
2813
|
}, "strip", z.ZodTypeAny, {
|
|
2814
|
-
validation: {
|
|
2815
|
-
mode: "simple" | "expression";
|
|
2816
|
-
expression?: string | undefined;
|
|
2817
|
-
answers?: Record<string, string | number> | undefined;
|
|
2818
|
-
variables?: string[] | undefined;
|
|
2819
|
-
};
|
|
2820
2814
|
version: "2.0";
|
|
2821
2815
|
layout: any[];
|
|
2822
2816
|
widgets: Record<string, {
|
|
@@ -2838,6 +2832,12 @@ export declare const ExerciseJSONSchema: z.ZodObject<{
|
|
|
2838
2832
|
includeOperators?: boolean | undefined;
|
|
2839
2833
|
includeDecimal?: boolean | undefined;
|
|
2840
2834
|
}>;
|
|
2835
|
+
validation?: {
|
|
2836
|
+
mode: "simple" | "expression";
|
|
2837
|
+
expression?: string | undefined;
|
|
2838
|
+
answers?: Record<string, string | number> | undefined;
|
|
2839
|
+
variables?: string[] | undefined;
|
|
2840
|
+
} | undefined;
|
|
2841
2841
|
id?: string | undefined;
|
|
2842
2842
|
meta?: {
|
|
2843
2843
|
createdAt?: string | undefined;
|
|
@@ -2846,12 +2846,6 @@ export declare const ExerciseJSONSchema: z.ZodObject<{
|
|
|
2846
2846
|
difficulty?: number | undefined;
|
|
2847
2847
|
} | undefined;
|
|
2848
2848
|
}, {
|
|
2849
|
-
validation: {
|
|
2850
|
-
mode: "simple" | "expression";
|
|
2851
|
-
expression?: string | undefined;
|
|
2852
|
-
answers?: Record<string, string | number> | undefined;
|
|
2853
|
-
variables?: string[] | undefined;
|
|
2854
|
-
};
|
|
2855
2849
|
version: "2.0";
|
|
2856
2850
|
layout: any[];
|
|
2857
2851
|
widgets: Record<string, {
|
|
@@ -2873,6 +2867,12 @@ export declare const ExerciseJSONSchema: z.ZodObject<{
|
|
|
2873
2867
|
includeOperators?: boolean | undefined;
|
|
2874
2868
|
includeDecimal?: boolean | undefined;
|
|
2875
2869
|
}>;
|
|
2870
|
+
validation?: {
|
|
2871
|
+
mode: "simple" | "expression";
|
|
2872
|
+
expression?: string | undefined;
|
|
2873
|
+
answers?: Record<string, string | number> | undefined;
|
|
2874
|
+
variables?: string[] | undefined;
|
|
2875
|
+
} | undefined;
|
|
2876
2876
|
id?: string | undefined;
|
|
2877
2877
|
meta?: {
|
|
2878
2878
|
createdAt?: string | undefined;
|
|
@@ -4944,6 +4944,10 @@ export declare function validate(exercise: ExerciseJSON, userInputs: Record<stri
|
|
|
4944
4944
|
*/
|
|
4945
4945
|
export declare function validateBooleanExpression(expression: string): string | null;
|
|
4946
4946
|
|
|
4947
|
+
declare type ValidatedExerciseJSON = ExerciseJSON & {
|
|
4948
|
+
validation: ValidationJSON;
|
|
4949
|
+
};
|
|
4950
|
+
|
|
4947
4951
|
/**
|
|
4948
4952
|
* Validate an exercise JSON object at runtime
|
|
4949
4953
|
*
|
|
@@ -4962,12 +4966,6 @@ export declare function validateBooleanExpression(expression: string): string |
|
|
|
4962
4966
|
* ```
|
|
4963
4967
|
*/
|
|
4964
4968
|
export declare function validateExerciseJSON(data: unknown): {
|
|
4965
|
-
validation: {
|
|
4966
|
-
mode: "simple" | "expression";
|
|
4967
|
-
expression?: string | undefined;
|
|
4968
|
-
answers?: Record<string, string | number> | undefined;
|
|
4969
|
-
variables?: string[] | undefined;
|
|
4970
|
-
};
|
|
4971
4969
|
version: "2.0";
|
|
4972
4970
|
layout: any[];
|
|
4973
4971
|
widgets: Record<string, {
|
|
@@ -4989,6 +4987,12 @@ export declare function validateExerciseJSON(data: unknown): {
|
|
|
4989
4987
|
includeOperators?: boolean | undefined;
|
|
4990
4988
|
includeDecimal?: boolean | undefined;
|
|
4991
4989
|
}>;
|
|
4990
|
+
validation?: {
|
|
4991
|
+
mode: "simple" | "expression";
|
|
4992
|
+
expression?: string | undefined;
|
|
4993
|
+
answers?: Record<string, string | number> | undefined;
|
|
4994
|
+
variables?: string[] | undefined;
|
|
4995
|
+
} | undefined;
|
|
4992
4996
|
id?: string | undefined;
|
|
4993
4997
|
meta?: {
|
|
4994
4998
|
createdAt?: string | undefined;
|
|
@@ -5015,12 +5019,6 @@ export declare function validateExerciseJSON(data: unknown): {
|
|
|
5015
5019
|
* ```
|
|
5016
5020
|
*/
|
|
5017
5021
|
export declare function validateExerciseJSONSafe(data: unknown): z.SafeParseReturnType<{
|
|
5018
|
-
validation: {
|
|
5019
|
-
mode: "simple" | "expression";
|
|
5020
|
-
expression?: string | undefined;
|
|
5021
|
-
answers?: Record<string, string | number> | undefined;
|
|
5022
|
-
variables?: string[] | undefined;
|
|
5023
|
-
};
|
|
5024
5022
|
version: "2.0";
|
|
5025
5023
|
layout: any[];
|
|
5026
5024
|
widgets: Record<string, {
|
|
@@ -5042,6 +5040,12 @@ export declare function validateExerciseJSONSafe(data: unknown): z.SafeParseRetu
|
|
|
5042
5040
|
includeOperators?: boolean | undefined;
|
|
5043
5041
|
includeDecimal?: boolean | undefined;
|
|
5044
5042
|
}>;
|
|
5043
|
+
validation?: {
|
|
5044
|
+
mode: "simple" | "expression";
|
|
5045
|
+
expression?: string | undefined;
|
|
5046
|
+
answers?: Record<string, string | number> | undefined;
|
|
5047
|
+
variables?: string[] | undefined;
|
|
5048
|
+
} | undefined;
|
|
5045
5049
|
id?: string | undefined;
|
|
5046
5050
|
meta?: {
|
|
5047
5051
|
createdAt?: string | undefined;
|
|
@@ -5050,12 +5054,6 @@ export declare function validateExerciseJSONSafe(data: unknown): z.SafeParseRetu
|
|
|
5050
5054
|
difficulty?: number | undefined;
|
|
5051
5055
|
} | undefined;
|
|
5052
5056
|
}, {
|
|
5053
|
-
validation: {
|
|
5054
|
-
mode: "simple" | "expression";
|
|
5055
|
-
expression?: string | undefined;
|
|
5056
|
-
answers?: Record<string, string | number> | undefined;
|
|
5057
|
-
variables?: string[] | undefined;
|
|
5058
|
-
};
|
|
5059
5057
|
version: "2.0";
|
|
5060
5058
|
layout: any[];
|
|
5061
5059
|
widgets: Record<string, {
|
|
@@ -5077,6 +5075,12 @@ export declare function validateExerciseJSONSafe(data: unknown): z.SafeParseRetu
|
|
|
5077
5075
|
includeOperators?: boolean | undefined;
|
|
5078
5076
|
includeDecimal?: boolean | undefined;
|
|
5079
5077
|
}>;
|
|
5078
|
+
validation?: {
|
|
5079
|
+
mode: "simple" | "expression";
|
|
5080
|
+
expression?: string | undefined;
|
|
5081
|
+
answers?: Record<string, string | number> | undefined;
|
|
5082
|
+
variables?: string[] | undefined;
|
|
5083
|
+
} | undefined;
|
|
5080
5084
|
id?: string | undefined;
|
|
5081
5085
|
meta?: {
|
|
5082
5086
|
createdAt?: string | undefined;
|
|
@@ -5089,11 +5093,11 @@ export declare function validateExerciseJSONSafe(data: unknown): z.SafeParseRetu
|
|
|
5089
5093
|
/**
|
|
5090
5094
|
* Validate using expression mode
|
|
5091
5095
|
*
|
|
5092
|
-
* @param exercise - The exercise JSON
|
|
5096
|
+
* @param exercise - The exercise JSON (with validation present)
|
|
5093
5097
|
* @param userInputs - User's answers keyed by widget ID (variable names)
|
|
5094
5098
|
* @returns Validation result
|
|
5095
5099
|
*/
|
|
5096
|
-
export declare function validateExpression(exercise:
|
|
5100
|
+
export declare function validateExpression(exercise: ValidatedExerciseJSON, userInputs: Record<string, string | number>): ValidationResult;
|
|
5097
5101
|
|
|
5098
5102
|
/**
|
|
5099
5103
|
* Check if user inputs are valid (proper format, etc.)
|
|
@@ -5108,11 +5112,11 @@ export declare function validateInputFormats(exercise: ExerciseJSON, userInputs:
|
|
|
5108
5112
|
/**
|
|
5109
5113
|
* Validate using simple mode (predetermined answers)
|
|
5110
5114
|
*
|
|
5111
|
-
* @param exercise - The exercise JSON
|
|
5115
|
+
* @param exercise - The exercise JSON (with validation present)
|
|
5112
5116
|
* @param userInputs - User's answers keyed by widget ID
|
|
5113
5117
|
* @returns Validation result
|
|
5114
5118
|
*/
|
|
5115
|
-
export declare function validateSimple(exercise:
|
|
5119
|
+
export declare function validateSimple(exercise: ValidatedExerciseJSON, userInputs: Record<string, string | number>): ValidationResult;
|
|
5116
5120
|
|
|
5117
5121
|
/**
|
|
5118
5122
|
* Validate a widget JSON object at runtime
|
package/dist/index.js
CHANGED
|
@@ -439,13 +439,16 @@ class MathExerciseParser extends chevrotain.CstParser {
|
|
|
439
439
|
this.OPTION(() => {
|
|
440
440
|
this.SUBRULE(this.question);
|
|
441
441
|
});
|
|
442
|
-
this.MANY2(
|
|
443
|
-
this.
|
|
442
|
+
this.MANY2({
|
|
443
|
+
GATE: this.BACKTRACK(this.contentBlock),
|
|
444
|
+
DEF: () => this.SUBRULE(this.contentBlock)
|
|
444
445
|
});
|
|
445
446
|
this.MANY3(() => {
|
|
446
447
|
this.SUBRULE(this.tool);
|
|
447
448
|
});
|
|
448
|
-
this.
|
|
449
|
+
this.OPTION2(() => {
|
|
450
|
+
this.SUBRULE(this.validation);
|
|
451
|
+
});
|
|
449
452
|
this.MANY4(() => {
|
|
450
453
|
this.OR2([
|
|
451
454
|
{ ALT: () => this.CONSUME2(Newline) },
|
|
@@ -666,7 +669,7 @@ class MathExerciseParser extends chevrotain.CstParser {
|
|
|
666
669
|
this.MANY2(() => {
|
|
667
670
|
this.CONSUME2(Space);
|
|
668
671
|
});
|
|
669
|
-
this.
|
|
672
|
+
this.MANY3(() => {
|
|
670
673
|
this.CONSUME(Newline);
|
|
671
674
|
});
|
|
672
675
|
});
|
|
@@ -1203,7 +1206,7 @@ const ExerciseDocumentSchema = zod.z.object({
|
|
|
1203
1206
|
question: TextBlockSchema.optional(),
|
|
1204
1207
|
lines: zod.z.array(ContentBlockSchema),
|
|
1205
1208
|
tools: zod.z.array(ToolNodeSchema).optional(),
|
|
1206
|
-
validation: ValidationNodeSchema
|
|
1209
|
+
validation: ValidationNodeSchema.optional()
|
|
1207
1210
|
});
|
|
1208
1211
|
function createExerciseDocument(question, lines, validation, tools) {
|
|
1209
1212
|
return ExerciseDocumentSchema.parse({
|
|
@@ -1230,7 +1233,7 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
1230
1233
|
const question = ctx.question ? this.visit(ctx.question) : void 0;
|
|
1231
1234
|
const contentBlocks = ctx.contentBlock ? ctx.contentBlock.map((cb) => this.visit(cb)) : [];
|
|
1232
1235
|
const tools = ctx.tool ? ctx.tool.map((t) => this.visit(t)) : [];
|
|
1233
|
-
const validation = this.visit(ctx.validation);
|
|
1236
|
+
const validation = ctx.validation ? this.visit(ctx.validation) : void 0;
|
|
1234
1237
|
return createExerciseDocument(question, contentBlocks, validation, tools);
|
|
1235
1238
|
}
|
|
1236
1239
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1695,7 +1698,7 @@ const ExerciseJSONSchema = zod.z.object({
|
|
|
1695
1698
|
id: zod.z.string().optional(),
|
|
1696
1699
|
layout: zod.z.array(LayoutItemSchema),
|
|
1697
1700
|
widgets: zod.z.record(WidgetJSONSchema),
|
|
1698
|
-
validation: ValidationJSONSchema,
|
|
1701
|
+
validation: ValidationJSONSchema.optional(),
|
|
1699
1702
|
meta: ExerciseMetaSchema.optional()
|
|
1700
1703
|
});
|
|
1701
1704
|
function validateExerciseJSON(data) {
|
|
@@ -1852,13 +1855,12 @@ function toJSON(ast) {
|
|
|
1852
1855
|
}
|
|
1853
1856
|
}
|
|
1854
1857
|
}
|
|
1855
|
-
const validation = transformValidation(ast.validation, answers, widgets);
|
|
1856
1858
|
return {
|
|
1857
1859
|
version: "2.0",
|
|
1858
1860
|
// Natural DSL version
|
|
1859
1861
|
layout,
|
|
1860
1862
|
widgets,
|
|
1861
|
-
validation
|
|
1863
|
+
...ast.validation ? { validation: transformValidation(ast.validation, answers, widgets) } : {}
|
|
1862
1864
|
};
|
|
1863
1865
|
}
|
|
1864
1866
|
function collectAllInlines(blocks) {
|
|
@@ -2329,11 +2331,18 @@ function findValidCombination(expression, ranges) {
|
|
|
2329
2331
|
return null;
|
|
2330
2332
|
}
|
|
2331
2333
|
function validate(exercise, userInputs) {
|
|
2332
|
-
|
|
2334
|
+
if (!exercise.validation) {
|
|
2335
|
+
return {
|
|
2336
|
+
isCorrect: true,
|
|
2337
|
+
details: {}
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
const validatedExercise = exercise;
|
|
2341
|
+
switch (validatedExercise.validation.mode) {
|
|
2333
2342
|
case VALIDATION_MODES.SIMPLE:
|
|
2334
|
-
return validateSimple(
|
|
2343
|
+
return validateSimple(validatedExercise, userInputs);
|
|
2335
2344
|
case VALIDATION_MODES.EXPRESSION:
|
|
2336
|
-
return validateExpression(
|
|
2345
|
+
return validateExpression(validatedExercise, userInputs);
|
|
2337
2346
|
default:
|
|
2338
2347
|
return {
|
|
2339
2348
|
isCorrect: false,
|
|
@@ -2344,6 +2353,9 @@ function validate(exercise, userInputs) {
|
|
|
2344
2353
|
}
|
|
2345
2354
|
function getMissingInputs(exercise, userInputs) {
|
|
2346
2355
|
const missing = [];
|
|
2356
|
+
if (!exercise.validation) {
|
|
2357
|
+
return missing;
|
|
2358
|
+
}
|
|
2347
2359
|
if (exercise.validation.mode === VALIDATION_MODES.SIMPLE && exercise.validation.answers) {
|
|
2348
2360
|
for (const widgetId of Object.keys(exercise.validation.answers)) {
|
|
2349
2361
|
if (!(widgetId in userInputs) || userInputs[widgetId] === "") {
|