@mathscan/math-exercise-engine 1.0.1 → 1.0.3
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 +56 -41
- package/dist/index.d.ts +228 -159
- package/dist/index.js +413 -222
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +413 -222
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +241 -60
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -15,26 +15,27 @@ A TypeScript DSL parser for mathematical exercises. Parse exercise definitions i
|
|
|
15
15
|
## 📦 Installation
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm install math-exercise-engine
|
|
18
|
+
npm install @mathscan/math-exercise-engine
|
|
19
19
|
# or
|
|
20
|
-
pnpm add math-exercise-engine
|
|
20
|
+
pnpm add @mathscan/math-exercise-engine
|
|
21
21
|
# or
|
|
22
|
-
yarn add math-exercise-engine
|
|
22
|
+
yarn add @mathscan/math-exercise-engine
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## 🚀 Quick Start
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
|
-
import { compile, validate, ExerciseRenderer } from 'math-exercise-engine';
|
|
28
|
+
import { compile, validate, ExerciseRenderer } from '@mathscan/math-exercise-engine';
|
|
29
29
|
|
|
30
30
|
// Compile a DSL exercise to JSON
|
|
31
31
|
const json = compile(`
|
|
32
|
-
|
|
32
|
+
QUESTION_TEXT["What is 25 + 5?"]
|
|
33
|
+
25 + NUMERIC_INPUT[name="x", digits=2, answer="5"] = 30
|
|
33
34
|
WIDGET_ANSWER[type=simple]
|
|
34
35
|
`);
|
|
35
36
|
|
|
36
37
|
// Render in React
|
|
37
|
-
import 'math-exercise-engine/style.css'; // Opt-in: import minimal default styles
|
|
38
|
+
import '@mathscan/math-exercise-engine/style.css'; // Opt-in: import minimal default styles
|
|
38
39
|
|
|
39
40
|
// Option 1: Use built-in submit button
|
|
40
41
|
<ExerciseRenderer
|
|
@@ -88,7 +89,7 @@ const exerciseRef = useRef<ExerciseRendererRef>(null);
|
|
|
88
89
|
When using `ref` for custom button styling, you get full programmatic control:
|
|
89
90
|
|
|
90
91
|
```typescript
|
|
91
|
-
import type { ExerciseRendererRef } from 'math-exercise-engine';
|
|
92
|
+
import type { ExerciseRendererRef } from '@mathscan/math-exercise-engine';
|
|
92
93
|
|
|
93
94
|
const exerciseRef = useRef<ExerciseRendererRef>(null);
|
|
94
95
|
|
|
@@ -108,21 +109,37 @@ exerciseRef.current?.focusFirstInput(); // Focus first input field
|
|
|
108
109
|
|
|
109
110
|
## 📝 DSL Syntax
|
|
110
111
|
|
|
111
|
-
###
|
|
112
|
+
### Input Widgets
|
|
113
|
+
|
|
114
|
+
The DSL supports both legacy short names and modern readable aliases:
|
|
115
|
+
|
|
116
|
+
#### Numeric Input Widget
|
|
112
117
|
|
|
113
118
|
```
|
|
114
119
|
W_N_I[name=a, digits=2]
|
|
120
|
+
// or use the readable alias
|
|
121
|
+
NUMERIC_INPUT[name=a, digits=2]
|
|
115
122
|
```
|
|
116
123
|
|
|
117
124
|
Creates an input field for numbers with up to 2 digits.
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
#### String Input Widget
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
W_S_I[name=x, length=5]
|
|
130
|
+
// or use the readable alias
|
|
131
|
+
STRING_INPUT[name=x, length=5]
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Creates an input field for text with up to 5 characters.
|
|
135
|
+
|
|
136
|
+
### Text Highlighter
|
|
120
137
|
|
|
121
138
|
```
|
|
122
|
-
|
|
139
|
+
TEXT_HIGHLIGHTER[value="123456", start=2, end=3]
|
|
123
140
|
```
|
|
124
141
|
|
|
125
|
-
|
|
142
|
+
Displays text with specific characters highlighted (useful for highlighting digits in numbers).
|
|
126
143
|
|
|
127
144
|
### Validators
|
|
128
145
|
|
|
@@ -140,25 +157,27 @@ WIDGET_ANSWER[type=expression, expr="(a * b) + (c * d) == 1200"]
|
|
|
140
157
|
|
|
141
158
|
## 📚 Examples
|
|
142
159
|
|
|
143
|
-
### Example 1:
|
|
160
|
+
### Example 1: Math Expression (using readable aliases)
|
|
144
161
|
|
|
145
162
|
```
|
|
146
|
-
|
|
147
|
-
WIDGET_ANSWER[type=
|
|
163
|
+
(NUMERIC_INPUT[name=a, digits=2] × NUMERIC_INPUT[name=b, digits=2]) + (NUMERIC_INPUT[name=c, digits=2] × NUMERIC_INPUT[name=d, digits=2]) = 1200
|
|
164
|
+
WIDGET_ANSWER[type=expression, expr="(a * b) + (c * d) == 1200"]
|
|
148
165
|
```
|
|
149
166
|
|
|
150
|
-
### Example 2:
|
|
167
|
+
### Example 2: Simple Addition
|
|
151
168
|
|
|
152
169
|
```
|
|
153
|
-
|
|
154
|
-
WIDGET_ANSWER[type=expression, expr="
|
|
170
|
+
NUMERIC_INPUT[name=x, digits=2] + NUMERIC_INPUT[name=y, digits=2] = 100
|
|
171
|
+
WIDGET_ANSWER[type=expression, expr="x + y == 100"]
|
|
155
172
|
```
|
|
156
173
|
|
|
157
|
-
### Example 3:
|
|
174
|
+
### Example 3: Text Highlighter
|
|
158
175
|
|
|
159
176
|
```
|
|
160
|
-
|
|
161
|
-
|
|
177
|
+
QUESTION_TEXT["What digit is highlighted?"]
|
|
178
|
+
The number TEXT_HIGHLIGHTER[value="123456", start=2, end=3] has a highlighted digit
|
|
179
|
+
STRING_INPUT[name=answer, length=1, answer="3"]
|
|
180
|
+
WIDGET_ANSWER[type=simple]
|
|
162
181
|
```
|
|
163
182
|
|
|
164
183
|
## 🔧 API Reference
|
|
@@ -166,7 +185,7 @@ WIDGET_ANSWER[type=expression, expr="x + y == 100"]
|
|
|
166
185
|
### Parsing
|
|
167
186
|
|
|
168
187
|
```typescript
|
|
169
|
-
import { compile, tokenize, parse, toAST, toJSON } from 'math-exercise-engine';
|
|
188
|
+
import { compile, tokenize, parse, toAST, toJSON } from '@mathscan/math-exercise-engine';
|
|
170
189
|
|
|
171
190
|
// Full pipeline (recommended)
|
|
172
191
|
const json = compile(dslText);
|
|
@@ -184,7 +203,7 @@ const { ast, json } = compileWithAST(dslText);
|
|
|
184
203
|
### Validation
|
|
185
204
|
|
|
186
205
|
```typescript
|
|
187
|
-
import { validate, validateSimple, validateExpression } from 'math-exercise-engine';
|
|
206
|
+
import { validate, validateSimple, validateExpression } from '@mathscan/math-exercise-engine';
|
|
188
207
|
|
|
189
208
|
// Auto-detect validation type
|
|
190
209
|
const result = validate(exerciseJSON, userInputs);
|
|
@@ -203,7 +222,7 @@ import type {
|
|
|
203
222
|
ValidationResult,
|
|
204
223
|
WidgetJSON,
|
|
205
224
|
ExerciseRendererRef
|
|
206
|
-
} from 'math-exercise-engine';
|
|
225
|
+
} from '@mathscan/math-exercise-engine';
|
|
207
226
|
|
|
208
227
|
// ExerciseRendererRef interface:
|
|
209
228
|
interface ExerciseRendererRef {
|
|
@@ -222,47 +241,43 @@ All layout items include unique `id` fields for React/JSX rendering:
|
|
|
222
241
|
{
|
|
223
242
|
"version": "2.0",
|
|
224
243
|
"layout": [
|
|
225
|
-
{ "id": "text_1", "type": "text", "value": "
|
|
226
|
-
{ "id": "
|
|
227
|
-
{ "id": "
|
|
244
|
+
{ "id": "text_1", "type": "text", "value": "25" },
|
|
245
|
+
{ "id": "operator_2", "type": "operator", "operator": "+" },
|
|
246
|
+
{ "id": "widget-ref_3", "type": "widget-ref", "widgetId": "x" },
|
|
247
|
+
{ "id": "operator_4", "type": "operator", "operator": "=" },
|
|
248
|
+
{ "id": "text_5", "type": "text", "value": "30" }
|
|
228
249
|
],
|
|
229
250
|
"widgets": {
|
|
230
|
-
"
|
|
231
|
-
"type": "
|
|
232
|
-
"id": "
|
|
251
|
+
"x": {
|
|
252
|
+
"type": "numeric-input",
|
|
253
|
+
"id": "x",
|
|
233
254
|
"config": {
|
|
234
|
-
"
|
|
235
|
-
"
|
|
255
|
+
"name": "x",
|
|
256
|
+
"digits": 2
|
|
236
257
|
}
|
|
237
258
|
}
|
|
238
259
|
},
|
|
239
260
|
"validation": {
|
|
240
261
|
"mode": "simple",
|
|
241
262
|
"answers": {
|
|
242
|
-
"
|
|
263
|
+
"x": "5"
|
|
243
264
|
}
|
|
244
265
|
}
|
|
245
266
|
}
|
|
246
267
|
```
|
|
247
268
|
|
|
248
|
-
> 💡 **New:** Layout items now include unique IDs perfect for React keys. [Learn more](docs/LAYOUT_IDS.md)
|
|
249
|
-
|
|
250
269
|
## ✅ Testing
|
|
251
270
|
|
|
252
271
|
```bash
|
|
253
|
-
pnpm test
|
|
272
|
+
pnpm test:run
|
|
254
273
|
```
|
|
255
274
|
|
|
256
|
-
All 83 tests passing ✅
|
|
257
|
-
|
|
258
275
|
## 📄 License
|
|
259
276
|
|
|
260
|
-
|
|
277
|
+
mathscan
|
|
261
278
|
|
|
262
279
|
## 👥 Authors
|
|
263
280
|
|
|
264
|
-
|
|
281
|
+
mathscan
|
|
265
282
|
|
|
266
283
|
---
|
|
267
|
-
|
|
268
|
-
**Status**: Production ready. All tests passing.
|