@mathscan/math-exercise-engine 1.0.5 → 1.0.7
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 +2860 -999
- package/dist/index.js +362 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +362 -29
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +34 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -27,6 +27,12 @@ const AST_TYPES = {
|
|
|
27
27
|
TEXT_BLOCK: "TextBlock",
|
|
28
28
|
/** Line containing inline elements */
|
|
29
29
|
LINE_BLOCK: "LineBlock",
|
|
30
|
+
/** Table layout block */
|
|
31
|
+
TABLE_BLOCK: "TableBlock",
|
|
32
|
+
/** Row within a table */
|
|
33
|
+
TABLE_ROW: "TableRow",
|
|
34
|
+
/** Cell within a table row */
|
|
35
|
+
TABLE_CELL: "TableCell",
|
|
30
36
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
31
37
|
// Tools
|
|
32
38
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -71,6 +77,12 @@ const JSON_TYPES = {
|
|
|
71
77
|
GROUP: "group",
|
|
72
78
|
/** Operator symbol */
|
|
73
79
|
OPERATOR: "operator",
|
|
80
|
+
/** Table layout block */
|
|
81
|
+
TABLE: "table",
|
|
82
|
+
/** Row within a table */
|
|
83
|
+
TABLE_ROW: "table-row",
|
|
84
|
+
/** Cell within a table */
|
|
85
|
+
TABLE_CELL: "table-cell",
|
|
74
86
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
75
87
|
// Widget Types
|
|
76
88
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -162,6 +174,18 @@ const NUMERIC_INPUT = createToken({
|
|
|
162
174
|
name: "NUMERIC_INPUT",
|
|
163
175
|
pattern: /NUMERIC_INPUT/
|
|
164
176
|
});
|
|
177
|
+
const TABLE = createToken({
|
|
178
|
+
name: "TABLE",
|
|
179
|
+
pattern: /TABLE/
|
|
180
|
+
});
|
|
181
|
+
const ROW = createToken({
|
|
182
|
+
name: "ROW",
|
|
183
|
+
pattern: /ROW/
|
|
184
|
+
});
|
|
185
|
+
const CELL = createToken({
|
|
186
|
+
name: "CELL",
|
|
187
|
+
pattern: /CELL/
|
|
188
|
+
});
|
|
165
189
|
const NumberLiteral = createToken({
|
|
166
190
|
name: "NumberLiteral",
|
|
167
191
|
pattern: /-?\d+(\.\d+)?/
|
|
@@ -229,9 +253,17 @@ const Comma = createToken({
|
|
|
229
253
|
name: "Comma",
|
|
230
254
|
pattern: /,/
|
|
231
255
|
});
|
|
256
|
+
const LBrace = createToken({
|
|
257
|
+
name: "LBrace",
|
|
258
|
+
pattern: /\{/
|
|
259
|
+
});
|
|
260
|
+
const RBrace = createToken({
|
|
261
|
+
name: "RBrace",
|
|
262
|
+
pattern: /\}/
|
|
263
|
+
});
|
|
232
264
|
const FreeText = createToken({
|
|
233
265
|
name: "FreeText",
|
|
234
|
-
pattern: /(?:[^A-Z\n\r \t+\-−×*÷/=<>?()\[\],]|(?![A-Z_]
|
|
266
|
+
pattern: /(?:[^A-Z\n\r \t+\-−×*÷/=<>?()\[\],{}]|(?![A-Z_]+[\[{])[A-Z])+/,
|
|
235
267
|
line_breaks: false
|
|
236
268
|
});
|
|
237
269
|
const allTokens = [
|
|
@@ -255,6 +287,9 @@ const allTokens = [
|
|
|
255
287
|
WIDGET_ANSWER,
|
|
256
288
|
W_N_I,
|
|
257
289
|
NUMERIC_INPUT,
|
|
290
|
+
TABLE,
|
|
291
|
+
ROW,
|
|
292
|
+
CELL,
|
|
258
293
|
// Literals
|
|
259
294
|
NumberLiteral,
|
|
260
295
|
StringLiteral,
|
|
@@ -275,6 +310,8 @@ const allTokens = [
|
|
|
275
310
|
LBracket,
|
|
276
311
|
RBracket,
|
|
277
312
|
Comma,
|
|
313
|
+
LBrace,
|
|
314
|
+
RBrace,
|
|
278
315
|
// FreeText - LAST (fallback for natural text)
|
|
279
316
|
FreeText
|
|
280
317
|
];
|
|
@@ -369,7 +406,7 @@ class MathExerciseParser extends CstParser {
|
|
|
369
406
|
this.SUBRULE(this.question);
|
|
370
407
|
});
|
|
371
408
|
this.MANY2(() => {
|
|
372
|
-
this.SUBRULE(this.
|
|
409
|
+
this.SUBRULE(this.contentBlock);
|
|
373
410
|
});
|
|
374
411
|
this.MANY3(() => {
|
|
375
412
|
this.SUBRULE(this.tool);
|
|
@@ -394,6 +431,116 @@ class MathExerciseParser extends CstParser {
|
|
|
394
431
|
]);
|
|
395
432
|
});
|
|
396
433
|
});
|
|
434
|
+
this.contentBlock = this.RULE("contentBlock", () => {
|
|
435
|
+
this.OR([
|
|
436
|
+
{
|
|
437
|
+
GATE: this.BACKTRACK(this.table),
|
|
438
|
+
ALT: () => this.SUBRULE(this.table)
|
|
439
|
+
},
|
|
440
|
+
{ ALT: () => this.SUBRULE(this.line) }
|
|
441
|
+
]);
|
|
442
|
+
});
|
|
443
|
+
this.table = this.RULE("table", () => {
|
|
444
|
+
this.MANY(() => {
|
|
445
|
+
this.OR2([
|
|
446
|
+
{ ALT: () => this.CONSUME(Space) },
|
|
447
|
+
{ ALT: () => this.CONSUME(Newline) }
|
|
448
|
+
]);
|
|
449
|
+
});
|
|
450
|
+
this.CONSUME(TABLE);
|
|
451
|
+
this.CONSUME(LBracket);
|
|
452
|
+
this.SUBRULE(this.parameterList);
|
|
453
|
+
this.CONSUME(RBracket);
|
|
454
|
+
this.MANY2(() => {
|
|
455
|
+
this.OR3([
|
|
456
|
+
{ ALT: () => this.CONSUME2(Space) },
|
|
457
|
+
{ ALT: () => this.CONSUME2(Newline) }
|
|
458
|
+
]);
|
|
459
|
+
});
|
|
460
|
+
this.CONSUME(LBrace);
|
|
461
|
+
this.MANY3(() => {
|
|
462
|
+
this.OR4([
|
|
463
|
+
{ ALT: () => this.CONSUME3(Space) },
|
|
464
|
+
{ ALT: () => this.CONSUME3(Newline) }
|
|
465
|
+
]);
|
|
466
|
+
});
|
|
467
|
+
this.AT_LEAST_ONE(() => {
|
|
468
|
+
this.SUBRULE(this.row);
|
|
469
|
+
});
|
|
470
|
+
this.CONSUME(RBrace);
|
|
471
|
+
this.MANY4(() => {
|
|
472
|
+
this.OR5([
|
|
473
|
+
{ ALT: () => this.CONSUME4(Newline) },
|
|
474
|
+
{ ALT: () => this.CONSUME4(Space) }
|
|
475
|
+
]);
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
this.row = this.RULE("row", () => {
|
|
479
|
+
this.MANY(() => {
|
|
480
|
+
this.OR([
|
|
481
|
+
{ ALT: () => this.CONSUME(Space) },
|
|
482
|
+
{ ALT: () => this.CONSUME(Newline) }
|
|
483
|
+
]);
|
|
484
|
+
});
|
|
485
|
+
this.CONSUME(ROW);
|
|
486
|
+
this.MANY2(() => {
|
|
487
|
+
this.OR2([
|
|
488
|
+
{ ALT: () => this.CONSUME2(Space) },
|
|
489
|
+
{ ALT: () => this.CONSUME2(Newline) }
|
|
490
|
+
]);
|
|
491
|
+
});
|
|
492
|
+
this.CONSUME(LBrace);
|
|
493
|
+
this.MANY3(() => {
|
|
494
|
+
this.OR3([
|
|
495
|
+
{ ALT: () => this.CONSUME3(Space) },
|
|
496
|
+
{ ALT: () => this.CONSUME3(Newline) }
|
|
497
|
+
]);
|
|
498
|
+
});
|
|
499
|
+
this.AT_LEAST_ONE(() => {
|
|
500
|
+
this.SUBRULE(this.cell);
|
|
501
|
+
});
|
|
502
|
+
this.CONSUME(RBrace);
|
|
503
|
+
this.MANY4(() => {
|
|
504
|
+
this.OR4([
|
|
505
|
+
{ ALT: () => this.CONSUME4(Space) },
|
|
506
|
+
{ ALT: () => this.CONSUME4(Newline) }
|
|
507
|
+
]);
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
this.cell = this.RULE("cell", () => {
|
|
511
|
+
this.MANY(() => {
|
|
512
|
+
this.OR([
|
|
513
|
+
{ ALT: () => this.CONSUME(Space) },
|
|
514
|
+
{ ALT: () => this.CONSUME(Newline) }
|
|
515
|
+
]);
|
|
516
|
+
});
|
|
517
|
+
this.CONSUME(CELL);
|
|
518
|
+
this.OPTION(() => {
|
|
519
|
+
this.CONSUME(LBracket);
|
|
520
|
+
this.SUBRULE(this.parameterList);
|
|
521
|
+
this.CONSUME(RBracket);
|
|
522
|
+
});
|
|
523
|
+
this.MANY2(() => {
|
|
524
|
+
this.OR2([
|
|
525
|
+
{ ALT: () => this.CONSUME2(Space) },
|
|
526
|
+
{ ALT: () => this.CONSUME2(Newline) }
|
|
527
|
+
]);
|
|
528
|
+
});
|
|
529
|
+
this.CONSUME(LBrace);
|
|
530
|
+
this.MANY3(() => {
|
|
531
|
+
this.OR3([
|
|
532
|
+
{ ALT: () => this.SUBRULE(this.inlineElement) },
|
|
533
|
+
{ ALT: () => this.CONSUME3(Newline) }
|
|
534
|
+
]);
|
|
535
|
+
});
|
|
536
|
+
this.CONSUME(RBrace);
|
|
537
|
+
this.MANY4(() => {
|
|
538
|
+
this.OR4([
|
|
539
|
+
{ ALT: () => this.CONSUME4(Space) },
|
|
540
|
+
{ ALT: () => this.CONSUME4(Newline) }
|
|
541
|
+
]);
|
|
542
|
+
});
|
|
543
|
+
});
|
|
397
544
|
this.line = this.RULE("line", () => {
|
|
398
545
|
this.MANY(() => {
|
|
399
546
|
this.CONSUME(Space);
|
|
@@ -731,6 +878,40 @@ function isTextBlock(value) {
|
|
|
731
878
|
function isLineBlock(value) {
|
|
732
879
|
return LineBlockSchema.safeParse(value).success;
|
|
733
880
|
}
|
|
881
|
+
const TableCellSchema = z.object({
|
|
882
|
+
type: z.literal(AST_TYPES.TABLE_CELL),
|
|
883
|
+
colspan: z.number().int().positive().optional(),
|
|
884
|
+
inlines: z.array(InlineNodeSchema)
|
|
885
|
+
});
|
|
886
|
+
function createTableCell(inlines, colspan) {
|
|
887
|
+
return TableCellSchema.parse({
|
|
888
|
+
type: AST_TYPES.TABLE_CELL,
|
|
889
|
+
colspan,
|
|
890
|
+
inlines
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
const TableRowSchema = z.object({
|
|
894
|
+
type: z.literal(AST_TYPES.TABLE_ROW),
|
|
895
|
+
cells: z.array(TableCellSchema).min(1)
|
|
896
|
+
});
|
|
897
|
+
function createTableRow(cells) {
|
|
898
|
+
return TableRowSchema.parse({
|
|
899
|
+
type: AST_TYPES.TABLE_ROW,
|
|
900
|
+
cells
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
const TableBlockSchema = z.object({
|
|
904
|
+
type: z.literal(AST_TYPES.TABLE_BLOCK),
|
|
905
|
+
cols: z.number().int().positive(),
|
|
906
|
+
rows: z.array(TableRowSchema).min(1)
|
|
907
|
+
});
|
|
908
|
+
function createTableBlock(cols, rows) {
|
|
909
|
+
return TableBlockSchema.parse({
|
|
910
|
+
type: AST_TYPES.TABLE_BLOCK,
|
|
911
|
+
cols,
|
|
912
|
+
rows
|
|
913
|
+
});
|
|
914
|
+
}
|
|
734
915
|
const DragOptionsToolSchema = z.object({
|
|
735
916
|
type: z.literal(AST_TYPES.DRAG_OPTIONS),
|
|
736
917
|
options: z.array(z.string()).min(1)
|
|
@@ -797,10 +978,11 @@ function isExpressionValidation(value) {
|
|
|
797
978
|
function isValidationNode(value) {
|
|
798
979
|
return ValidationNodeSchema.safeParse(value).success;
|
|
799
980
|
}
|
|
981
|
+
const ContentBlockSchema = z.union([LineBlockSchema, TableBlockSchema]);
|
|
800
982
|
const ExerciseDocumentSchema = z.object({
|
|
801
983
|
type: z.literal(AST_TYPES.EXERCISE_DOCUMENT),
|
|
802
984
|
question: TextBlockSchema.optional(),
|
|
803
|
-
lines: z.array(
|
|
985
|
+
lines: z.array(ContentBlockSchema),
|
|
804
986
|
tools: z.array(ToolNodeSchema).optional(),
|
|
805
987
|
validation: ValidationNodeSchema
|
|
806
988
|
});
|
|
@@ -827,10 +1009,10 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
827
1009
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
828
1010
|
exerciseDocument(ctx) {
|
|
829
1011
|
const question = ctx.question ? this.visit(ctx.question) : void 0;
|
|
830
|
-
const
|
|
1012
|
+
const contentBlocks = ctx.contentBlock ? ctx.contentBlock.map((cb) => this.visit(cb)) : [];
|
|
831
1013
|
const tools = ctx.tool ? ctx.tool.map((t) => this.visit(t)) : [];
|
|
832
1014
|
const validation = this.visit(ctx.validation);
|
|
833
|
-
return createExerciseDocument(question,
|
|
1015
|
+
return createExerciseDocument(question, contentBlocks, validation, tools);
|
|
834
1016
|
}
|
|
835
1017
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
836
1018
|
// Question Block
|
|
@@ -841,6 +1023,33 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
841
1023
|
return createTextBlock(value);
|
|
842
1024
|
}
|
|
843
1025
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1026
|
+
// Content Block
|
|
1027
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1028
|
+
contentBlock(ctx) {
|
|
1029
|
+
if (ctx.table) return this.visit(ctx.table);
|
|
1030
|
+
if (ctx.line) return this.visit(ctx.line);
|
|
1031
|
+
throw new Error("Unknown content block");
|
|
1032
|
+
}
|
|
1033
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1034
|
+
// Table Block
|
|
1035
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1036
|
+
table(ctx) {
|
|
1037
|
+
const params = this.visit(ctx.parameterList);
|
|
1038
|
+
const cols = params.cols;
|
|
1039
|
+
const rows = ctx.row.map((r) => this.visit(r));
|
|
1040
|
+
return createTableBlock(cols, rows);
|
|
1041
|
+
}
|
|
1042
|
+
row(ctx) {
|
|
1043
|
+
const cells = ctx.cell.map((c) => this.visit(c));
|
|
1044
|
+
return createTableRow(cells);
|
|
1045
|
+
}
|
|
1046
|
+
cell(ctx) {
|
|
1047
|
+
const params = ctx.parameterList ? this.visit(ctx.parameterList) : {};
|
|
1048
|
+
const colspan = params.colspan;
|
|
1049
|
+
const inlines = ctx.inlineElement ? ctx.inlineElement.map((elem) => this.visit(elem)) : [];
|
|
1050
|
+
return createTableCell(inlines, colspan);
|
|
1051
|
+
}
|
|
1052
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
844
1053
|
// Line Block
|
|
845
1054
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
846
1055
|
line(ctx) {
|
|
@@ -1112,6 +1321,10 @@ const BoldTextSchema = z.object({
|
|
|
1112
1321
|
value: z.string(),
|
|
1113
1322
|
highlight: z.tuple([z.number(), z.number()]).optional()
|
|
1114
1323
|
});
|
|
1324
|
+
const SpaceItemSchema = z.object({
|
|
1325
|
+
id: z.string(),
|
|
1326
|
+
type: z.literal(JSON_TYPES.SPACE)
|
|
1327
|
+
});
|
|
1115
1328
|
const LinebreakSchema = z.object({
|
|
1116
1329
|
id: z.string(),
|
|
1117
1330
|
type: z.literal(JSON_TYPES.LINEBREAK)
|
|
@@ -1130,9 +1343,11 @@ const LayoutItemSchema = z.lazy(
|
|
|
1130
1343
|
HighlightedTextSchema,
|
|
1131
1344
|
ColorTextSchema,
|
|
1132
1345
|
BoldTextSchema,
|
|
1346
|
+
SpaceItemSchema,
|
|
1133
1347
|
LinebreakSchema,
|
|
1134
1348
|
GroupItemSchema,
|
|
1135
|
-
OperatorItemSchema
|
|
1349
|
+
OperatorItemSchema,
|
|
1350
|
+
TableItemSchema
|
|
1136
1351
|
])
|
|
1137
1352
|
);
|
|
1138
1353
|
const GroupItemSchema = z.object({
|
|
@@ -1140,6 +1355,23 @@ const GroupItemSchema = z.object({
|
|
|
1140
1355
|
type: z.literal(JSON_TYPES.GROUP),
|
|
1141
1356
|
items: z.array(LayoutItemSchema)
|
|
1142
1357
|
});
|
|
1358
|
+
const TableCellItemSchema = z.object({
|
|
1359
|
+
id: z.string(),
|
|
1360
|
+
type: z.literal(JSON_TYPES.TABLE_CELL),
|
|
1361
|
+
colspan: z.number().int().positive().optional(),
|
|
1362
|
+
items: z.array(LayoutItemSchema)
|
|
1363
|
+
});
|
|
1364
|
+
const TableRowItemSchema = z.object({
|
|
1365
|
+
id: z.string(),
|
|
1366
|
+
type: z.literal(JSON_TYPES.TABLE_ROW),
|
|
1367
|
+
cells: z.array(TableCellItemSchema)
|
|
1368
|
+
});
|
|
1369
|
+
const TableItemSchema = z.object({
|
|
1370
|
+
id: z.string(),
|
|
1371
|
+
type: z.literal(JSON_TYPES.TABLE),
|
|
1372
|
+
cols: z.number().int().positive(),
|
|
1373
|
+
rows: z.array(TableRowItemSchema)
|
|
1374
|
+
});
|
|
1143
1375
|
const StringInputJSONSchema = z.object({
|
|
1144
1376
|
type: z.literal(JSON_TYPES.INLINE_INPUT),
|
|
1145
1377
|
inputType: z.literal(INPUT_TYPES.STRING),
|
|
@@ -1218,6 +1450,9 @@ function isColorText(item) {
|
|
|
1218
1450
|
function isBoldText(item) {
|
|
1219
1451
|
return item.type === JSON_TYPES.BOLD_TEXT;
|
|
1220
1452
|
}
|
|
1453
|
+
function isSpaceItem(item) {
|
|
1454
|
+
return item.type === JSON_TYPES.SPACE;
|
|
1455
|
+
}
|
|
1221
1456
|
function isLinebreak(item) {
|
|
1222
1457
|
return item.type === JSON_TYPES.LINEBREAK;
|
|
1223
1458
|
}
|
|
@@ -1227,6 +1462,15 @@ function isGroupItem(item) {
|
|
|
1227
1462
|
function isOperatorItem(item) {
|
|
1228
1463
|
return item.type === JSON_TYPES.OPERATOR;
|
|
1229
1464
|
}
|
|
1465
|
+
function isTableItem(item) {
|
|
1466
|
+
return item.type === JSON_TYPES.TABLE;
|
|
1467
|
+
}
|
|
1468
|
+
function isTableRowItem(item) {
|
|
1469
|
+
return item.type === JSON_TYPES.TABLE_ROW;
|
|
1470
|
+
}
|
|
1471
|
+
function isTableCellItem(item) {
|
|
1472
|
+
return item.type === JSON_TYPES.TABLE_CELL;
|
|
1473
|
+
}
|
|
1230
1474
|
function isInlineInputJSON(widget) {
|
|
1231
1475
|
return widget.type === JSON_TYPES.INLINE_INPUT;
|
|
1232
1476
|
}
|
|
@@ -1257,31 +1501,34 @@ function toJSON(ast) {
|
|
|
1257
1501
|
value: ast.question.value
|
|
1258
1502
|
});
|
|
1259
1503
|
}
|
|
1260
|
-
for (const
|
|
1261
|
-
|
|
1262
|
-
|
|
1504
|
+
for (const block of ast.lines) {
|
|
1505
|
+
if (block.type === AST_TYPES.TABLE_BLOCK) {
|
|
1506
|
+
layout.push(transformTable(block, idGenerator));
|
|
1507
|
+
} else {
|
|
1508
|
+
const lineItems = transformLine(block, idGenerator);
|
|
1509
|
+
layout.push(...lineItems);
|
|
1510
|
+
}
|
|
1263
1511
|
}
|
|
1264
1512
|
const widgets = {};
|
|
1265
1513
|
const answers = {};
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
}
|
|
1514
|
+
const allInlines = collectAllInlines(ast.lines);
|
|
1515
|
+
for (const inline of allInlines) {
|
|
1516
|
+
if (inline.type === AST_TYPES.INLINE_INPUT) {
|
|
1517
|
+
if (inline.inputType === INPUT_TYPES.STRING) {
|
|
1518
|
+
widgets[inline.name] = {
|
|
1519
|
+
type: JSON_TYPES.INLINE_INPUT,
|
|
1520
|
+
inputType: INPUT_TYPES.STRING,
|
|
1521
|
+
length: inline.length
|
|
1522
|
+
};
|
|
1523
|
+
} else {
|
|
1524
|
+
widgets[inline.name] = {
|
|
1525
|
+
type: JSON_TYPES.INLINE_INPUT,
|
|
1526
|
+
inputType: INPUT_TYPES.NUMERIC,
|
|
1527
|
+
digits: inline.digits
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
if (inline.answer !== void 0) {
|
|
1531
|
+
answers[inline.name] = inline.answer;
|
|
1285
1532
|
}
|
|
1286
1533
|
}
|
|
1287
1534
|
}
|
|
@@ -1310,6 +1557,48 @@ function toJSON(ast) {
|
|
|
1310
1557
|
validation
|
|
1311
1558
|
};
|
|
1312
1559
|
}
|
|
1560
|
+
function collectAllInlines(blocks) {
|
|
1561
|
+
const result = [];
|
|
1562
|
+
for (const block of blocks) {
|
|
1563
|
+
if (block.type === AST_TYPES.LINE_BLOCK) {
|
|
1564
|
+
result.push(...block.inlines);
|
|
1565
|
+
} else if (block.type === AST_TYPES.TABLE_BLOCK) {
|
|
1566
|
+
for (const row of block.rows) {
|
|
1567
|
+
for (const cell of row.cells) {
|
|
1568
|
+
result.push(...cell.inlines);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
return result;
|
|
1574
|
+
}
|
|
1575
|
+
function transformTable(table, idGenerator) {
|
|
1576
|
+
const rows = table.rows.map((row) => {
|
|
1577
|
+
const cells = row.cells.map((cell) => {
|
|
1578
|
+
const items = cell.inlines.map((inline) => transformInline(inline, idGenerator));
|
|
1579
|
+
const cellItem = {
|
|
1580
|
+
id: idGenerator.generate(JSON_TYPES.TABLE_CELL),
|
|
1581
|
+
type: JSON_TYPES.TABLE_CELL,
|
|
1582
|
+
items
|
|
1583
|
+
};
|
|
1584
|
+
if (cell.colspan !== void 0) {
|
|
1585
|
+
cellItem.colspan = cell.colspan;
|
|
1586
|
+
}
|
|
1587
|
+
return cellItem;
|
|
1588
|
+
});
|
|
1589
|
+
return {
|
|
1590
|
+
id: idGenerator.generate(JSON_TYPES.TABLE_ROW),
|
|
1591
|
+
type: JSON_TYPES.TABLE_ROW,
|
|
1592
|
+
cells
|
|
1593
|
+
};
|
|
1594
|
+
});
|
|
1595
|
+
return {
|
|
1596
|
+
id: idGenerator.generate(JSON_TYPES.TABLE),
|
|
1597
|
+
type: JSON_TYPES.TABLE,
|
|
1598
|
+
cols: table.cols,
|
|
1599
|
+
rows
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1313
1602
|
function transformLine(line, idGenerator) {
|
|
1314
1603
|
const items = [];
|
|
1315
1604
|
for (const inline of line.inlines) {
|
|
@@ -5981,7 +6270,7 @@ function itemContainsLatin(item) {
|
|
|
5981
6270
|
return false;
|
|
5982
6271
|
}
|
|
5983
6272
|
function isTextItem(item) {
|
|
5984
|
-
return item.type === JSON_TYPES.TEXT || item.type === JSON_TYPES.HIGHLIGHTED_TEXT || item.type === JSON_TYPES.OPERATOR || item.type === JSON_TYPES.SPACE || item.type === JSON_TYPES.GROUP;
|
|
6273
|
+
return item.type === JSON_TYPES.TEXT || item.type === JSON_TYPES.HIGHLIGHTED_TEXT || item.type === JSON_TYPES.BOLD_TEXT || item.type === JSON_TYPES.COLOR_TEXT || item.type === JSON_TYPES.OPERATOR || item.type === JSON_TYPES.SPACE || item.type === JSON_TYPES.GROUP;
|
|
5985
6274
|
}
|
|
5986
6275
|
function groupLineItems(items) {
|
|
5987
6276
|
const groups = [];
|
|
@@ -6096,6 +6385,27 @@ const LayoutRenderer = ({
|
|
|
6096
6385
|
},
|
|
6097
6386
|
subItem.id
|
|
6098
6387
|
)) });
|
|
6388
|
+
case JSON_TYPES.TABLE:
|
|
6389
|
+
return /* @__PURE__ */ jsx("div", { className: "exercise-table-container", children: /* @__PURE__ */ jsx("table", { className: "exercise-table", children: /* @__PURE__ */ jsx("tbody", { children: item.rows.map((row) => /* @__PURE__ */ jsx("tr", { className: "exercise-table-row", children: row.cells.map((cell) => /* @__PURE__ */ jsx(
|
|
6390
|
+
"td",
|
|
6391
|
+
{
|
|
6392
|
+
className: "exercise-table-cell",
|
|
6393
|
+
colSpan: cell.colspan || 1,
|
|
6394
|
+
children: cell.items.map((subItem) => /* @__PURE__ */ jsx(
|
|
6395
|
+
LayoutRenderer,
|
|
6396
|
+
{
|
|
6397
|
+
item: subItem,
|
|
6398
|
+
widgets,
|
|
6399
|
+
values,
|
|
6400
|
+
droppedInputs,
|
|
6401
|
+
onChange,
|
|
6402
|
+
onInputFocus
|
|
6403
|
+
},
|
|
6404
|
+
subItem.id
|
|
6405
|
+
))
|
|
6406
|
+
},
|
|
6407
|
+
cell.id
|
|
6408
|
+
)) }, row.id)) }) }) });
|
|
6099
6409
|
default:
|
|
6100
6410
|
return null;
|
|
6101
6411
|
}
|
|
@@ -6169,6 +6479,20 @@ const ExerciseRenderer = forwardRef(({
|
|
|
6169
6479
|
});
|
|
6170
6480
|
continue;
|
|
6171
6481
|
}
|
|
6482
|
+
if (item.type === JSON_TYPES.TABLE) {
|
|
6483
|
+
if (currentGroup.length > 0) {
|
|
6484
|
+
const hasArabic = currentGroup.some((item2) => itemContainsArabic(item2));
|
|
6485
|
+
const subGroups = groupLineItems(currentGroup);
|
|
6486
|
+
groups.push({ items: currentGroup, hasArabic, subGroups });
|
|
6487
|
+
currentGroup = [];
|
|
6488
|
+
}
|
|
6489
|
+
groups.push({
|
|
6490
|
+
items: [item],
|
|
6491
|
+
hasArabic: false,
|
|
6492
|
+
subGroups: []
|
|
6493
|
+
});
|
|
6494
|
+
continue;
|
|
6495
|
+
}
|
|
6172
6496
|
if (item.type === JSON_TYPES.LINEBREAK) {
|
|
6173
6497
|
if (currentGroup.length > 0) {
|
|
6174
6498
|
const hasArabic = currentGroup.some((item2) => itemContainsArabic(item2));
|
|
@@ -38292,6 +38616,7 @@ export {
|
|
|
38292
38616
|
BoldTextSchema,
|
|
38293
38617
|
ColorTextInlineSchema,
|
|
38294
38618
|
ColorTextSchema,
|
|
38619
|
+
ContentBlockSchema,
|
|
38295
38620
|
DragOptionsJSONSchema,
|
|
38296
38621
|
DragOptionsToolSchema,
|
|
38297
38622
|
EngineError,
|
|
@@ -38321,6 +38646,10 @@ export {
|
|
|
38321
38646
|
QuestionTextSchema,
|
|
38322
38647
|
SimpleValidationSchema,
|
|
38323
38648
|
SpaceInlineSchema,
|
|
38649
|
+
SpaceItemSchema,
|
|
38650
|
+
TableCellItemSchema,
|
|
38651
|
+
TableItemSchema,
|
|
38652
|
+
TableRowItemSchema,
|
|
38324
38653
|
TextBlockSchema,
|
|
38325
38654
|
TextItemSchema,
|
|
38326
38655
|
ToolNodeSchema,
|
|
@@ -38371,6 +38700,10 @@ export {
|
|
|
38371
38700
|
isQuestionText,
|
|
38372
38701
|
isSimpleValidation,
|
|
38373
38702
|
isSpace,
|
|
38703
|
+
isSpaceItem,
|
|
38704
|
+
isTableCellItem,
|
|
38705
|
+
isTableItem,
|
|
38706
|
+
isTableRowItem,
|
|
38374
38707
|
isTextBlock,
|
|
38375
38708
|
isTextItem$1 as isTextItem,
|
|
38376
38709
|
isToolNode,
|