@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 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
- COMPARISON[350158 ? 2334443, answer="<"]
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
- ### Numeric Input Widget
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
- ### Comparison Widget
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
- COMPARISON[350158 ? 2334443, answer="<"]
139
+ TEXT_HIGHLIGHTER[value="123456", start=2, end=3]
123
140
  ```
124
141
 
125
- Student must choose `<`, `>`, or `=` to compare two numbers.
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: Simple Comparison
160
+ ### Example 1: Math Expression (using readable aliases)
144
161
 
145
162
  ```
146
- COMPARISON[350158 ? 2334443, answer="<"]
147
- WIDGET_ANSWER[type=simple]
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: Math Expression
167
+ ### Example 2: Simple Addition
151
168
 
152
169
  ```
153
- (W_N_I[name=a, digits=2] × W_N_I[name=b, digits=2]) + (W_N_I[name=c, digits=2] × W_N_I[name=d, digits=2]) = 1200
154
- WIDGET_ANSWER[type=expression, expr="(a * b) + (c * d) == 1200"]
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: Simple Addition
174
+ ### Example 3: Text Highlighter
158
175
 
159
176
  ```
160
- W_N_I[name=x, digits=2] + W_N_I[name=y, digits=2] = 100
161
- WIDGET_ANSWER[type=expression, expr="x + y == 100"]
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": "350158" },
226
- { "id": "widget-ref_2", "type": "widget-ref", "widgetId": "comparison_1" },
227
- { "id": "text_3", "type": "text", "value": "2334443" }
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
- "comparison_1": {
231
- "type": "comparison",
232
- "id": "comparison_1",
251
+ "x": {
252
+ "type": "numeric-input",
253
+ "id": "x",
233
254
  "config": {
234
- "left": 350158,
235
- "right": 2334443
255
+ "name": "x",
256
+ "digits": 2
236
257
  }
237
258
  }
238
259
  },
239
260
  "validation": {
240
261
  "mode": "simple",
241
262
  "answers": {
242
- "comparison_1": "<"
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
- [Your License]
277
+ mathscan
261
278
 
262
279
  ## 👥 Authors
263
280
 
264
- [Your Name]
281
+ mathscan
265
282
 
266
283
  ---
267
-
268
- **Status**: Production ready. All tests passing.