@mathscan/geometry-engine 0.1.0 → 0.1.1
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 +24 -7
- package/dist/core.cjs +1 -1
- package/dist/core.mjs +4 -4
- package/dist/entries/core.d.cts +1 -1
- package/dist/entries/core.d.ts +1 -1
- package/dist/entries/core.d.ts.map +1 -1
- package/dist/exercise.schema-Bma3qN9P.js +251 -0
- package/dist/exercise.schema-Bma3qN9P.js.map +1 -0
- package/dist/exercise.schema-Oj5ZH-yO.cjs +2 -0
- package/dist/exercise.schema-Oj5ZH-yO.cjs.map +1 -0
- package/dist/exerciseLoad-Db9Cigxi.cjs +2 -0
- package/dist/exerciseLoad-Db9Cigxi.cjs.map +1 -0
- package/dist/{geometryAttemptStatus-5L_q6-9l.js → exerciseLoad-DgeDXYbf.js} +84 -71
- package/dist/exerciseLoad-DgeDXYbf.js.map +1 -0
- package/dist/geometry/entities/angle.d.cts +56 -0
- package/dist/geometry/entities/angle.d.ts +57 -0
- package/dist/geometry/entities/angle.d.ts.map +1 -0
- package/dist/geometry/entities/circle.d.ts.map +1 -1
- package/dist/geometry/entities/index.d.cts +8 -4
- package/dist/geometry/entities/index.d.ts +8 -4
- package/dist/geometry/entities/index.d.ts.map +1 -1
- package/dist/geometry/entities/line.d.ts.map +1 -1
- package/dist/geometry/entities/point.d.ts.map +1 -1
- package/dist/geometry/entities/relations.d.cts +8 -1
- package/dist/geometry/entities/relations.d.ts +8 -1
- package/dist/geometry/entities/relations.d.ts.map +1 -1
- package/dist/geometry/entities/segment.d.ts.map +1 -1
- package/dist/geometry/entityModel.d.cts +21 -3
- package/dist/geometry/entityModel.d.ts +21 -3
- package/dist/geometry/entityModel.d.ts.map +1 -1
- package/dist/geometryState.schema-B5ccMKDa.cjs +2 -0
- package/dist/geometryState.schema-B5ccMKDa.cjs.map +1 -0
- package/dist/geometryState.schema-CKFPlX8j.js +1177 -0
- package/dist/geometryState.schema-CKFPlX8j.js.map +1 -0
- package/dist/goals-BlSeniyt.js +563 -0
- package/dist/goals-BlSeniyt.js.map +1 -0
- package/dist/goals-DLbmBZD8.cjs +2 -0
- package/dist/goals-DLbmBZD8.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +8 -8
- package/dist/measure/angleType.d.cts +2 -0
- package/dist/measure/angleType.d.ts +3 -0
- package/dist/measure/angleType.d.ts.map +1 -0
- package/dist/measure/geometryAdapter.d.cts +3 -0
- package/dist/measure/geometryAdapter.d.ts +3 -0
- package/dist/measure/geometryAdapter.d.ts.map +1 -1
- package/dist/react-B26_e52I.cjs +2 -0
- package/dist/react-B26_e52I.cjs.map +1 -0
- package/dist/{react-BEcdx1f6.js → react-B5cGaxH8.js} +738 -513
- package/dist/react-B5cGaxH8.js.map +1 -0
- package/dist/react.cjs +1 -1
- package/dist/react.mjs +1 -1
- package/dist/renderer/GeometryCanvas.d.ts.map +1 -1
- package/dist/renderer/StudentGeometryCanvas.d.ts.map +1 -1
- package/dist/renderer/Toolbar.d.ts.map +1 -1
- package/dist/renderer/angleMeasure.d.cts +14 -0
- package/dist/renderer/angleMeasure.d.ts +15 -0
- package/dist/renderer/angleMeasure.d.ts.map +1 -0
- package/dist/renderer/deriveRenderableGeometry.d.cts +1 -0
- package/dist/renderer/deriveRenderableGeometry.d.ts +1 -0
- package/dist/renderer/deriveRenderableGeometry.d.ts.map +1 -1
- package/dist/renderer/deriveSemanticScene.d.ts.map +1 -1
- package/dist/renderer/dragSnap.d.cts +14 -0
- package/dist/renderer/dragSnap.d.ts +15 -0
- package/dist/renderer/dragSnap.d.ts.map +1 -0
- package/dist/renderer/shapes/AngleShape.d.cts +19 -0
- package/dist/renderer/shapes/AngleShape.d.ts +20 -0
- package/dist/renderer/shapes/AngleShape.d.ts.map +1 -0
- package/dist/renderer/shapes/EntityLabel.d.cts +9 -1
- package/dist/renderer/shapes/EntityLabel.d.ts +9 -1
- package/dist/renderer/shapes/EntityLabel.d.ts.map +1 -1
- package/dist/renderer/shapes/EntityShape.d.cts +2 -1
- package/dist/renderer/shapes/EntityShape.d.ts +2 -1
- package/dist/renderer/shapes/EntityShape.d.ts.map +1 -1
- package/dist/renderer/useConnectionPreview.d.cts +12 -1
- package/dist/renderer/useConnectionPreview.d.ts +12 -1
- package/dist/renderer/useConnectionPreview.d.ts.map +1 -1
- package/dist/renderer/usePointerGestures.d.cts +1 -1
- package/dist/renderer/usePointerGestures.d.ts +1 -1
- package/dist/renderer/usePointerGestures.d.ts.map +1 -1
- package/dist/schemas/entityDefinition.schema.d.cts +7 -0
- package/dist/schemas/entityDefinition.schema.d.ts +7 -0
- package/dist/schemas/entityDefinition.schema.d.ts.map +1 -1
- package/dist/schemas/entityDocument.d.cts +34 -13
- package/dist/schemas/entityDocument.d.ts +34 -13
- package/dist/schemas/entityDocument.d.ts.map +1 -1
- package/dist/schemas/entityPresentation.schema.d.cts +3 -0
- package/dist/schemas/entityPresentation.schema.d.ts +3 -0
- package/dist/schemas/entityPresentation.schema.d.ts.map +1 -1
- package/dist/schemas/exercise.schema.d.cts +80 -2
- package/dist/schemas/exercise.schema.d.ts +80 -2
- package/dist/schemas/exercise.schema.d.ts.map +1 -1
- package/dist/schemas/exerciseV2.schema.d.cts +57 -0
- package/dist/schemas/exerciseV2.schema.d.ts +57 -0
- package/dist/schemas/exerciseV2.schema.d.ts.map +1 -1
- package/dist/schemas/exerciseV4.schema.d.cts +168 -0
- package/dist/schemas/exerciseV4.schema.d.ts +169 -0
- package/dist/schemas/exerciseV4.schema.d.ts.map +1 -0
- package/dist/schemas/geometryState.schema.d.cts +8 -0
- package/dist/schemas/geometryState.schema.d.ts +8 -0
- package/dist/schemas/geometryState.schema.d.ts.map +1 -1
- package/dist/schemas/goals/angleBisectorGoal.schema.d.cts +15 -0
- package/dist/schemas/goals/angleBisectorGoal.schema.d.ts +16 -0
- package/dist/schemas/goals/angleBisectorGoal.schema.d.ts.map +1 -0
- package/dist/schemas/goals/angleCriterion.schema.d.cts +28 -0
- package/dist/schemas/goals/angleCriterion.schema.d.ts +29 -0
- package/dist/schemas/goals/angleCriterion.schema.d.ts.map +1 -0
- package/dist/schemas/goals/angleMeasureGoal.schema.d.cts +26 -0
- package/dist/schemas/goals/angleMeasureGoal.schema.d.ts +27 -0
- package/dist/schemas/goals/angleMeasureGoal.schema.d.ts.map +1 -0
- package/dist/schemas/goals/createGoal.schema.d.cts +1 -0
- package/dist/schemas/goals/createGoal.schema.d.ts +1 -0
- package/dist/schemas/goals/createGoal.schema.d.ts.map +1 -1
- package/dist/schemas/goals/geometryGoal.schema.d.cts +61 -0
- package/dist/schemas/goals/geometryGoal.schema.d.ts +61 -0
- package/dist/schemas/goals/geometryGoal.schema.d.ts.map +1 -1
- package/dist/schemas/goals/givenAngleGoal.schema.d.cts +35 -0
- package/dist/schemas/goals/givenAngleGoal.schema.d.ts +36 -0
- package/dist/schemas/goals/givenAngleGoal.schema.d.ts.map +1 -0
- package/dist/schemas/goals/goalKindDeclaration.d.cts +7 -0
- package/dist/schemas/goals/goalKindDeclaration.d.ts +7 -0
- package/dist/schemas/goals/goalKindDeclaration.d.ts.map +1 -1
- package/dist/schemas/goals/parallelGoal.schema.d.cts +1 -0
- package/dist/schemas/goals/parallelGoal.schema.d.ts +1 -0
- package/dist/schemas/goals/parallelGoal.schema.d.ts.map +1 -1
- package/dist/schemas/goals/perpendicularGoal.schema.d.cts +1 -0
- package/dist/schemas/goals/perpendicularGoal.schema.d.ts +1 -0
- package/dist/schemas/goals/perpendicularGoal.schema.d.ts.map +1 -1
- package/dist/schemas/goals/throughPointsGoal.schema.d.cts +1 -0
- package/dist/schemas/goals/throughPointsGoal.schema.d.ts +1 -0
- package/dist/schemas/goals/throughPointsGoal.schema.d.ts.map +1 -1
- package/dist/schemas/objectTypeName.schema.d.cts +1 -0
- package/dist/schemas/objectTypeName.schema.d.ts +1 -0
- package/dist/schemas/objectTypeName.schema.d.ts.map +1 -1
- package/dist/schemas/v2ToV3.d.cts +15 -1
- package/dist/schemas/v2ToV3.d.ts +15 -1
- package/dist/schemas/v2ToV3.d.ts.map +1 -1
- package/dist/schemas/v3ToV4.d.cts +2 -1
- package/dist/schemas/v3ToV4.d.ts +2 -1
- package/dist/schemas/v3ToV4.d.ts.map +1 -1
- package/dist/schemas/v4ToV5.d.cts +7 -0
- package/dist/schemas/v4ToV5.d.ts +8 -0
- package/dist/schemas/v4ToV5.d.ts.map +1 -0
- package/dist/schemas.cjs +1 -1
- package/dist/schemas.mjs +3 -3
- package/dist/snapping/computeDragSnap.d.cts +30 -0
- package/dist/snapping/computeDragSnap.d.ts +31 -0
- package/dist/snapping/computeDragSnap.d.ts.map +1 -0
- package/dist/state/geometryContext.d.ts.map +1 -1
- package/dist/store/attemptChange.d.cts +1 -1
- package/dist/store/attemptChange.d.ts +1 -1
- package/dist/store/attemptChange.d.ts.map +1 -1
- package/dist/store/constructionCommand.d.cts +14 -2
- package/dist/store/constructionCommand.d.ts +14 -2
- package/dist/store/constructionCommand.d.ts.map +1 -1
- package/dist/store/constructionIdentity.d.cts +9 -0
- package/dist/store/constructionIdentity.d.ts +9 -0
- package/dist/store/constructionIdentity.d.ts.map +1 -1
- package/dist/store/studentStore.d.cts +7 -0
- package/dist/store/studentStore.d.ts +7 -0
- package/dist/store/studentStore.d.ts.map +1 -1
- package/dist/store/teacherStore.d.cts +16 -0
- package/dist/store/teacherStore.d.ts +16 -0
- package/dist/store/teacherStore.d.ts.map +1 -1
- package/dist/{studentStore-CEKTtMCh.js → studentStore-CyYa0N93.js} +502 -370
- package/dist/studentStore-CyYa0N93.js.map +1 -0
- package/dist/studentStore-ubldy4PJ.cjs +2 -0
- package/dist/studentStore-ubldy4PJ.cjs.map +1 -0
- package/dist/validation/getGeometryExerciseWarnings.d.cts +3 -2
- package/dist/validation/getGeometryExerciseWarnings.d.ts +3 -2
- package/dist/validation/getGeometryExerciseWarnings.d.ts.map +1 -1
- package/dist/validation/goals/angleBisector.d.cts +3 -0
- package/dist/validation/goals/angleBisector.d.ts +4 -0
- package/dist/validation/goals/angleBisector.d.ts.map +1 -0
- package/dist/validation/goals/angleCriterion.d.cts +12 -0
- package/dist/validation/goals/angleCriterion.d.ts +13 -0
- package/dist/validation/goals/angleCriterion.d.ts.map +1 -0
- package/dist/validation/goals/angleMeasure.d.cts +9 -0
- package/dist/validation/goals/angleMeasure.d.ts +10 -0
- package/dist/validation/goals/angleMeasure.d.ts.map +1 -0
- package/dist/validation/goals/create.d.cts +2 -2
- package/dist/validation/goals/create.d.ts +2 -2
- package/dist/validation/goals/create.d.ts.map +1 -1
- package/dist/validation/goals/givenAngle.d.cts +11 -0
- package/dist/validation/goals/givenAngle.d.ts +12 -0
- package/dist/validation/goals/givenAngle.d.ts.map +1 -0
- package/dist/validation/goals/goalKindHandler.d.cts +38 -1
- package/dist/validation/goals/goalKindHandler.d.ts +38 -1
- package/dist/validation/goals/goalKindHandler.d.ts.map +1 -1
- package/dist/validation/goals/index.d.cts +9 -2
- package/dist/validation/goals/index.d.ts +9 -2
- package/dist/validation/goals/index.d.ts.map +1 -1
- package/dist/validation/goals/midpoint.d.cts +2 -2
- package/dist/validation/goals/midpoint.d.ts +2 -2
- package/dist/validation/goals/midpoint.d.ts.map +1 -1
- package/dist/validation/goals/parallel.d.cts +2 -2
- package/dist/validation/goals/parallel.d.ts +2 -2
- package/dist/validation/goals/parallel.d.ts.map +1 -1
- package/dist/validation/goals/perpendicular.d.cts +2 -2
- package/dist/validation/goals/perpendicular.d.ts +2 -2
- package/dist/validation/goals/perpendicular.d.ts.map +1 -1
- package/dist/validation/goals/segmentLength.d.cts +2 -2
- package/dist/validation/goals/segmentLength.d.ts +2 -2
- package/dist/validation/goals/segmentLength.d.ts.map +1 -1
- package/dist/validation/goals/throughPoints.d.cts +2 -2
- package/dist/validation/goals/throughPoints.d.ts +2 -2
- package/dist/validation/goals/throughPoints.d.ts.map +1 -1
- package/dist/validation/types.d.cts +5 -1
- package/dist/validation/types.d.ts +5 -1
- package/dist/validation/types.d.ts.map +1 -1
- package/dist/validation/validateGeometryState.d.ts.map +1 -1
- package/dist/validation/validateGeometryStateInput.d.ts.map +1 -1
- package/dist/validation.cjs +1 -1
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.mjs +106 -85
- package/dist/validation.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/exercise.schema-BV2b7rtN.cjs +0 -2
- package/dist/exercise.schema-BV2b7rtN.cjs.map +0 -1
- package/dist/exercise.schema-ckVBW9XA.js +0 -212
- package/dist/exercise.schema-ckVBW9XA.js.map +0 -1
- package/dist/geometryAttemptStatus-5L_q6-9l.js.map +0 -1
- package/dist/geometryAttemptStatus-N_XHIkiS.cjs +0 -2
- package/dist/geometryAttemptStatus-N_XHIkiS.cjs.map +0 -1
- package/dist/geometryState.schema-D0ixyGYE.js +0 -955
- package/dist/geometryState.schema-D0ixyGYE.js.map +0 -1
- package/dist/geometryState.schema-DKQ-durx.cjs +0 -2
- package/dist/geometryState.schema-DKQ-durx.cjs.map +0 -1
- package/dist/goals-C3ZwbEh_.js +0 -451
- package/dist/goals-C3ZwbEh_.js.map +0 -1
- package/dist/goals-CxR5qPDC.cjs +0 -2
- package/dist/goals-CxR5qPDC.cjs.map +0 -1
- package/dist/react-BEcdx1f6.js.map +0 -1
- package/dist/react-Pp_VSk--.cjs +0 -2
- package/dist/react-Pp_VSk--.cjs.map +0 -1
- package/dist/studentStore-CEKTtMCh.js.map +0 -1
- package/dist/studentStore-DLftfFAl.cjs +0 -2
- package/dist/studentStore-DLftfFAl.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -147,7 +147,7 @@ This exercise asks the student to construct segment `AB`:
|
|
|
147
147
|
import type { GeometryExercise } from '@mathscan/geometry-engine'
|
|
148
148
|
|
|
149
149
|
const exercise: GeometryExercise = {
|
|
150
|
-
schemaVersion:
|
|
150
|
+
schemaVersion: 5,
|
|
151
151
|
id: 'segment-ab',
|
|
152
152
|
viewport: [0, 0, 10, 10],
|
|
153
153
|
showGrid: true,
|
|
@@ -181,12 +181,24 @@ const exercise: GeometryExercise = {
|
|
|
181
181
|
}
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
-
Supported objects are `point`, `segment`, `line`, and `
|
|
184
|
+
Supported objects are `point`, `segment`, `line`, `circle`, and `angle`. A circle is stored as
|
|
185
185
|
`{ id, type: 'circle', center, through }` — the id of its centre point and the id of a point it
|
|
186
186
|
passes through. Its radius is measured from those two on every evaluation and never stored, so
|
|
187
187
|
dragging either one changes the circle and everything built on it. There is no compass tool and no
|
|
188
188
|
circle goal kind yet: a circle can be authored as a given, persisted in an attempt, resolved,
|
|
189
|
-
intersected, snapped to and drawn, which is what M2.8 landed.
|
|
189
|
+
intersected, snapped to and drawn, which is what M2.8 landed.
|
|
190
|
+
|
|
191
|
+
An angle is stored as `{ kind: 'angle', parents: [arm, vertex, arm] }` — three point ids in the
|
|
192
|
+
order of ∠ABC. Its measure is derived on every evaluation as a **counter-clockwise sweep in turns**,
|
|
193
|
+
so reversing the arms gives exactly `1 − sweep`, 0° and 180° are ordinary angles, and a reflex angle
|
|
194
|
+
needs no flag; only an arm of zero length makes it degenerate. The curved mark is the entity, drawn
|
|
195
|
+
at a radius taken from the shorter arm, and **the arms a figure shows are ordinary segments over the
|
|
196
|
+
same points**, so dragging a shared arm point moves the arm and the mark together. Nothing meets an
|
|
197
|
+
angle and nothing lies on one: a point defined `on` an angle, or where an angle crosses something,
|
|
198
|
+
is refused when the document is parsed. A presentation entry may carry `measureLabel: 'degrees'`,
|
|
199
|
+
which only an angle may have. As with the circle there is no tool and no goal kind yet: an angle can
|
|
200
|
+
be authored as a given, persisted in an attempt, resolved, hit-tested, selected and drawn, which is
|
|
201
|
+
what M3.4 landed. Supported goal kinds are currently `create`, `throughPoints`, `perpendicular`, `parallel`, `segmentLength`, and `midpoint`.
|
|
190
202
|
|
|
191
203
|
A `perpendicular` or `parallel` goal names a reference object, a point the construction must pass through, and an angle tolerance in degrees. A `segmentLength` goal names a `targetLength`, and a `midpoint` goal names the reference segment; both take a `toleranceUnits` expressed in viewport units, not pixels. Because a parallel through a point that defines the reference is degenerate (redrawing the reference would be a correct answer), the exercise schema rejects that combination.
|
|
192
204
|
|
|
@@ -318,7 +330,7 @@ if (restored.success) {
|
|
|
318
330
|
|
|
319
331
|
### Versions and migration
|
|
320
332
|
|
|
321
|
-
**The two documents version independently.** The exercise is at version **
|
|
333
|
+
**The two documents version independently.** The exercise is at version **5** and the attempt is at version **2**. A v2 attempt is loaded and graded against a v5 exercise, and neither version implies the other. Version 3 exists for one optional field, `grading` (see [Strict grading](#strict-grading) below). Version 4 exists for one optional field, `solution`, the authored canonical attempt (see [Reveal answers](#reveal-answers)). Version 5 exists for the angle goals. An older exercise carrying a field added after its version is refused rather than promoted. An older reader rejects a newer exercise at its own version boundary rather than reading a field it does not understand.
|
|
322
334
|
|
|
323
335
|
Both stored documents carry a `schemaVersion`, and both are migrated the same way. An exercise migrates through `geometryExerciseMigrations` up to `latestGeometryExerciseVersion`; an attempt through `geometryStateMigrations` up to `latestGeometryStateVersion`. Each list holds one step per version hop, walked in chain order by `applyMigrations()`, so a document three versions old takes three steps and each step only has to know about its own neighbour.
|
|
324
336
|
|
|
@@ -742,7 +754,7 @@ The teacher store exposes actions for points, segments, lines, goals, tools, sel
|
|
|
742
754
|
|
|
743
755
|
## Reveal answers
|
|
744
756
|
|
|
745
|
-
An exercise at version 4 can embed its authored canonical answer as `solution`, an ordinary attempt document. `revealGeometryAttempt()` is synchronous, needs no DOM and accepts untrusted JSON. It returns that attempt only when the solution is valid and correct for the exercise, so the host can replace the student's value with it:
|
|
757
|
+
An exercise at version 4 or later can embed its authored canonical answer as `solution`, an ordinary attempt document. `revealGeometryAttempt()` is synchronous, needs no DOM and accepts untrusted JSON. It returns that attempt only when the solution is valid and correct for the exercise, so the host can replace the student's value with it:
|
|
746
758
|
|
|
747
759
|
```ts
|
|
748
760
|
import { revealGeometryAttempt } from '@mathscan/geometry-engine/validation'
|
|
@@ -860,7 +872,11 @@ and `StudentGeometryCanvas` at a **fixed 600x600 canvas over the viewport
|
|
|
860
872
|
`[-1, -1, 9, 9]`** — exactly 60 pixels per math unit, so every click a journey
|
|
861
873
|
makes is an integer pixel. The exercise comes from `?scenario=<name>`
|
|
862
874
|
(`tests/e2e/harness/scenarios.ts`); an unknown name throws rather than falling
|
|
863
|
-
back.
|
|
875
|
+
back. A scenario that embeds a `solution` is revealed by installing it as the
|
|
876
|
+
attempt, which is how a drag exercise is revealed (ADR 0016); a solution
|
|
877
|
+
`revealGeometryAttempt()` refuses changes nothing and is reported in the
|
|
878
|
+
`reveal-refused` alert, never replaced by a per-goal answer. A scenario with no
|
|
879
|
+
solution is revealed goal by goal. **`?canvas=WIDTHxHEIGHT`** and **`?projection=contain|stretch`** open that
|
|
864
880
|
scenario at another size or aspect ratio (M1b.4.d), and
|
|
865
881
|
`window.geometryHarness.resize()` changes it on a live page, which is what a
|
|
866
882
|
`ResizeObserver` does to a real embed. The dev page is deliberately not used: it sizes its canvas from a
|
|
@@ -1090,7 +1106,8 @@ both canvases were not edited.
|
|
|
1090
1106
|
|
|
1091
1107
|
## Known limitations
|
|
1092
1108
|
|
|
1093
|
-
- Object types are limited to points, segments, lines, and
|
|
1109
|
+
- Object types are limited to points, segments, lines, circles, and angles — no arcs or polygons yet.
|
|
1110
|
+
- An angle has no tool, no goal kind and no authoring UI: it can be authored in exercise JSON and persisted in an attempt, but a student cannot construct one, and nothing grades one. Its arms are not part of the entity — a figure draws them as segments over the same points — and the mark's radius fraction is provisional until the rendering work tunes it.
|
|
1094
1111
|
- A circle has no tool, no goal kind and no authoring UI: it can be authored in exercise JSON and persisted in an attempt, but a student cannot draw one. Only the centre-and-through-point construction exists — no radius provenance, no three-point circle.
|
|
1095
1112
|
- Goal kinds are limited to `create`, `throughPoints`, `perpendicular`, `parallel`, `segmentLength`, and `midpoint` (no angle-measure, area, or transformation goals yet).
|
|
1096
1113
|
- Instruments (`ruler`, `setSquare`, `protractor`) are visual aids only: draggable pictures with no mathematical effect. The engine can neither express nor verify that a student used one.
|
package/dist/core.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./geometryState.schema-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./geometryState.schema-B5ccMKDa.cjs"),t=require("./goals-DLbmBZD8.cjs"),n=require("./studentStore-ubldy4PJ.cjs");exports.CALCULATION_EPSILON=e.ct,exports.CONNECTION_SNAP_RADIUS_PX=e.lt,exports.COORDINATE_EPSILON=e.ut,exports.GRADING_BOUNDARY_EPSILON=e.dt,exports.PARAMETER_EPSILON=e.ft,exports.PLACEMENT_SNAP_RADIUS_PX=e.pt,exports.POINT_REUSE_EPSILON=e.mt,exports.RELATIVE_DEGENERACY_EPSILON=e.ht,exports.addGivenLine=n.S,exports.addGivenPoint=n.C,exports.addGivenSegment=n.w,exports.addGoal=n.T,exports.addStudentPoint=n.t,exports.approximatelyEqual=e.gt,exports.buildGeometryContext=t.f,exports.cancelGivenConstruction=n.E,exports.cancelStudentConstruction=n.n,exports.clipLineToViewport=n.at,exports.closestPointOnCircle=e.et,exports.closestPointOnLine=e.tt,exports.closestPointOnSegment=e.nt,exports.computePlacement=n.ot,exports.computeSnap=n.$,exports.coordinatesCoincide=e._t,exports.createStore=n.Q,exports.createStudentStore=n.r,exports.createTeacherStore=n.D,exports.deleteStudentObject=n.i,exports.distanceBetween=e.wt,exports.distancePointToCircle=e.rt,exports.distancePointToLine=e.it,exports.distancePointToSegment=e.at,exports.endGivenPointDrag=n.O,exports.endStudentPointDrag=n.a,exports.entryOf=e.M,exports.executeConstruction=n.o,exports.executeGivenConstruction=n.k,exports.firstHit=n.ut,exports.getGivenRemovalImpact=n.A,exports.getStudentRemovalImpact=n.s,exports.gridStep=n.nt,exports.gridSteps=n.rt,exports.hitTest=n.dt,exports.isCandidatePoint=t.p,exports.isDegenerateAtScale=e.vt,exports.isGivenPointDraggable=n.j,exports.isSameStoredPoint=e.yt,exports.isStudentOwned=n.c,exports.isStudentPointDraggable=n.l,exports.isWithinSegmentParameter=e.bt,exports.loadExercise=n.M,exports.mathToScreen=n.st,exports.midpointOf=e.Tt,exports.moveGivenPoint=n.N,exports.moveStudentPoint=n.u,exports.nearestGridPoint=n.it,exports.originForSnap=n.et,exports.parentsOfDefinition=e.z,exports.pickPointForPendingObject=n.P,exports.pickStudentPoint=n.d,exports.pixelRadiusToMathTolerance=e.xt,exports.pointAlong=e.ot,exports.projectionParameter=e.st,exports.promoteGivenEntity=n.F,exports.promoteGivenPoint=n.I,exports.promoteStudentPoint=n.f,exports.redoStudentChange=n.p,exports.redoTeacherChange=n.L,exports.removeGiven=n.R,exports.removeGoal=n.z,exports.replaceGoal=n.B,exports.replaceStudentAttempt=n.m,exports.replaceStudentSession=n.h,exports.resetStudentAttempt=n.g,exports.resolveAgainstPoints=e.B,exports.revealStudentAnswer=n._,exports.screenLengthToMath=n.ct,exports.screenToMath=n.lt,exports.selectGiven=n.V,exports.selectPendingObjectType=n.H,exports.selectStudentObject=n.v,exports.selectStudentObjectType=n.y,exports.setAllowedObjects=n.U,exports.setExtraObjectPolicy=n.W,exports.setGivenLabel=n.G,exports.setGivenMeasureLabel=n.K,exports.setGivenPointDraggable=n.q,exports.setShowGrid=n.J,exports.setStudentReadOnly=n.b,exports.setTools=n.Y,exports.setViewport=n.X,exports.snapPosition=n.tt,exports.undoStudentChange=n.x,exports.undoTeacherChange=n.Z,exports.withinAuthoredDeviation=e.St,exports.withinAuthoredTolerance=e.Ct;
|
package/dist/core.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { $ as j, A as M, B as N, C as P, D as F, E as I, F as L, G as R, H as z, I as B, J as V, K as H, L as U, M as W, N as G, O as K, P as q, Q as J, R as Y, S as X, T as Z, U as Q, V as $, W as ee, X as te, Y as ne, Z as re, _ as ie, a as ae, at as oe, b as se, c as ce, ct as le, d as ue,
|
|
4
|
-
export {
|
|
1
|
+
import { B as e, Ct as t, M as n, St as r, Tt as i, _t as a, at as o, bt as s, ct as c, dt as l, et as u, ft as d, gt as f, ht as p, it as m, lt as h, mt as g, nt as _, ot as v, pt as y, rt as b, st as x, tt as S, ut as C, vt as w, wt as T, xt as E, yt as D, z as O } from "./geometryState.schema-CKFPlX8j.js";
|
|
2
|
+
import { f as k, p as A } from "./goals-BlSeniyt.js";
|
|
3
|
+
import { $ as j, A as M, B as N, C as P, D as F, E as I, F as L, G as R, H as z, I as B, J as V, K as H, L as U, M as W, N as G, O as K, P as q, Q as J, R as Y, S as X, T as Z, U as Q, V as $, W as ee, X as te, Y as ne, Z as re, _ as ie, a as ae, at as oe, b as se, c as ce, ct as le, d as ue, dt as de, et as fe, f as pe, g as me, h as he, i as ge, it as _e, j as ve, k as ye, l as be, lt as xe, m as Se, n as Ce, nt as we, o as Te, ot as Ee, p as De, q as Oe, r as ke, rt as Ae, s as je, st as Me, t as Ne, tt as Pe, u as Fe, ut as Ie, v as Le, w as Re, x as ze, y as Be, z as Ve } from "./studentStore-CyYa0N93.js";
|
|
4
|
+
export { c as CALCULATION_EPSILON, h as CONNECTION_SNAP_RADIUS_PX, C as COORDINATE_EPSILON, l as GRADING_BOUNDARY_EPSILON, d as PARAMETER_EPSILON, y as PLACEMENT_SNAP_RADIUS_PX, g as POINT_REUSE_EPSILON, p as RELATIVE_DEGENERACY_EPSILON, X as addGivenLine, P as addGivenPoint, Re as addGivenSegment, Z as addGoal, Ne as addStudentPoint, f as approximatelyEqual, k as buildGeometryContext, I as cancelGivenConstruction, Ce as cancelStudentConstruction, oe as clipLineToViewport, u as closestPointOnCircle, S as closestPointOnLine, _ as closestPointOnSegment, Ee as computePlacement, j as computeSnap, a as coordinatesCoincide, J as createStore, ke as createStudentStore, F as createTeacherStore, ge as deleteStudentObject, T as distanceBetween, b as distancePointToCircle, m as distancePointToLine, o as distancePointToSegment, K as endGivenPointDrag, ae as endStudentPointDrag, n as entryOf, Te as executeConstruction, ye as executeGivenConstruction, Ie as firstHit, M as getGivenRemovalImpact, je as getStudentRemovalImpact, we as gridStep, Ae as gridSteps, de as hitTest, A as isCandidatePoint, w as isDegenerateAtScale, ve as isGivenPointDraggable, D as isSameStoredPoint, ce as isStudentOwned, be as isStudentPointDraggable, s as isWithinSegmentParameter, W as loadExercise, Me as mathToScreen, i as midpointOf, G as moveGivenPoint, Fe as moveStudentPoint, _e as nearestGridPoint, fe as originForSnap, O as parentsOfDefinition, q as pickPointForPendingObject, ue as pickStudentPoint, E as pixelRadiusToMathTolerance, v as pointAlong, x as projectionParameter, L as promoteGivenEntity, B as promoteGivenPoint, pe as promoteStudentPoint, De as redoStudentChange, U as redoTeacherChange, Y as removeGiven, Ve as removeGoal, N as replaceGoal, Se as replaceStudentAttempt, he as replaceStudentSession, me as resetStudentAttempt, e as resolveAgainstPoints, ie as revealStudentAnswer, le as screenLengthToMath, xe as screenToMath, $ as selectGiven, z as selectPendingObjectType, Le as selectStudentObject, Be as selectStudentObjectType, Q as setAllowedObjects, ee as setExtraObjectPolicy, R as setGivenLabel, H as setGivenMeasureLabel, Oe as setGivenPointDraggable, V as setShowGrid, se as setStudentReadOnly, ne as setTools, te as setViewport, Pe as snapPosition, ze as undoStudentChange, re as undoTeacherChange, r as withinAuthoredDeviation, t as withinAuthoredTolerance };
|
package/dist/entries/core.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { CircleDefinition, ConstructionOrigin, EntityCapabilities, EntityDefinition, EntityDefinitionOf, EntityId, EntityKind, EntityOperations, EntityPresentation, EntityRegistry, EntityRole, Evaluation, EvaluationIssue, EvaluationIssueLocation, FreeOrigin, FreePointDefinition, GeometryContext, IntersectionOrigin, IntersectionPointDefinition, LineDefinition, OnEntityOrigin, OnEntityPointDefinition, PointDefinition, ResolvedCircle, ResolvedEntity, ResolvedEntityOf, ResolvedLine, ResolvedPoint, ResolvedSegment, SegmentDefinition, ShapeDescriptor, } from '../geometry/entityModel.cjs';
|
|
1
|
+
export type { AngleDefinition, CircleDefinition, ConstructionOrigin, EntityCapabilities, EntityDefinition, EntityDefinitionOf, EntityId, EntityKind, EntityOperations, EntityPresentation, EntityRegistry, EntityRole, Evaluation, EvaluationIssue, EvaluationIssueLocation, FreeOrigin, FreePointDefinition, GeometryContext, IntersectionOrigin, IntersectionPointDefinition, LineDefinition, OnEntityOrigin, OnEntityPointDefinition, PointDefinition, ResolvedAngle, ResolvedCircle, ResolvedEntity, ResolvedEntityOf, ResolvedLine, ResolvedPoint, ResolvedSegment, SegmentDefinition, ShapeDescriptor, } from '../geometry/entityModel.cjs';
|
|
2
2
|
export { parentsOfDefinition, resolveAgainstPoints } from '../geometry/entities/index.cjs';
|
|
3
3
|
export { entryOf } from '../geometry/entityRecord.cjs';
|
|
4
4
|
export * from '../geometry/point.cjs';
|
package/dist/entries/core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { CircleDefinition, ConstructionOrigin, EntityCapabilities, EntityDefinition, EntityDefinitionOf, EntityId, EntityKind, EntityOperations, EntityPresentation, EntityRegistry, EntityRole, Evaluation, EvaluationIssue, EvaluationIssueLocation, FreeOrigin, FreePointDefinition, GeometryContext, IntersectionOrigin, IntersectionPointDefinition, LineDefinition, OnEntityOrigin, OnEntityPointDefinition, PointDefinition, ResolvedCircle, ResolvedEntity, ResolvedEntityOf, ResolvedLine, ResolvedPoint, ResolvedSegment, SegmentDefinition, ShapeDescriptor, } from '../geometry/entityModel.js';
|
|
1
|
+
export type { AngleDefinition, CircleDefinition, ConstructionOrigin, EntityCapabilities, EntityDefinition, EntityDefinitionOf, EntityId, EntityKind, EntityOperations, EntityPresentation, EntityRegistry, EntityRole, Evaluation, EvaluationIssue, EvaluationIssueLocation, FreeOrigin, FreePointDefinition, GeometryContext, IntersectionOrigin, IntersectionPointDefinition, LineDefinition, OnEntityOrigin, OnEntityPointDefinition, PointDefinition, ResolvedAngle, ResolvedCircle, ResolvedEntity, ResolvedEntityOf, ResolvedLine, ResolvedPoint, ResolvedSegment, SegmentDefinition, ShapeDescriptor, } from '../geometry/entityModel.js';
|
|
2
2
|
export { parentsOfDefinition, resolveAgainstPoints } from '../geometry/entities/index.js';
|
|
3
3
|
export { entryOf } from '../geometry/entityRecord.js';
|
|
4
4
|
export * from '../geometry/point.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/entries/core.ts"],"names":[],"mappings":"AAaA,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,UAAU,EACV,eAAe,EACf,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,2BAA2B,EAC3B,cAAc,EACd,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,yBAAyB,CAAA;AAKhC,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAMhF,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAGlD,cAAc,mBAAmB,CAAA;AACjC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AAGnC,cAAc,0BAA0B,CAAA;AAGxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AAGnC,cAAc,oBAAoB,CAAA;AAGlC,cAAc,yBAAyB,CAAA;AAKvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA"}
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/entries/core.ts"],"names":[],"mappings":"AAaA,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,UAAU,EACV,eAAe,EACf,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,2BAA2B,EAC3B,cAAc,EACd,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,yBAAyB,CAAA;AAKhC,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAMhF,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAGlD,cAAc,mBAAmB,CAAA;AACjC,cAAc,2BAA2B,CAAA;AACzC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AAGnC,cAAc,0BAA0B,CAAA;AAGxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AAGnC,cAAc,oBAAoB,CAAA;AAGlC,cAAc,yBAAyB,CAAA;AAKvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { A as e, C as t, D as n, M as r, O as i, S as a, _ as o, a as s, b as c, c as l, d as ee, g as u, h as d, j as f, k as p, m as te, n as m, o as h, s as g, u as _, v, x as y, y as ne } from "./geometryState.schema-CKFPlX8j.js";
|
|
2
|
+
import { z as b } from "zod";
|
|
3
|
+
//#region src/schemas/viewport.schema.ts
|
|
4
|
+
var x = b.number().finite().min(-100).max(100), S = b.tuple([
|
|
5
|
+
x,
|
|
6
|
+
x,
|
|
7
|
+
x,
|
|
8
|
+
x
|
|
9
|
+
]).refine(([e, t, n, r]) => e < n && t < r, { message: "viewport must satisfy xMin < xMax and yMin < yMax" }).refine(([e, , t]) => t - e >= 1 && t - e <= 100, { message: "viewport width must be between 1 and 100" }).refine(([, e, , t]) => t - e >= 1 && t - e <= 100, { message: "viewport height must be between 1 and 100" }), C = b.discriminatedUnion("type", [
|
|
10
|
+
c,
|
|
11
|
+
te,
|
|
12
|
+
u,
|
|
13
|
+
o,
|
|
14
|
+
d,
|
|
15
|
+
v,
|
|
16
|
+
y,
|
|
17
|
+
a,
|
|
18
|
+
ne
|
|
19
|
+
]), w = b.string().min(1).refine((e) => e === e.trim()), T = w, E = b.object({
|
|
20
|
+
x: b.number().finite(),
|
|
21
|
+
y: b.number().finite()
|
|
22
|
+
}).strict(), D = b.tuple([T, T]).readonly(), O = b.number().finite().min(-100).max(100), k = b.number().positive().finite(), re = b.tuple([
|
|
23
|
+
O,
|
|
24
|
+
O,
|
|
25
|
+
O,
|
|
26
|
+
O
|
|
27
|
+
]).refine(([e, t, n, r]) => e < n && t < r).refine(([e, , t]) => t - e >= 1 && t - e <= 100).refine(([, e, , t]) => t - e >= 1 && t - e <= 100), ie = [
|
|
28
|
+
"point",
|
|
29
|
+
"segment",
|
|
30
|
+
"line",
|
|
31
|
+
"circle"
|
|
32
|
+
], A = [
|
|
33
|
+
"point",
|
|
34
|
+
"segment",
|
|
35
|
+
"line",
|
|
36
|
+
"circle"
|
|
37
|
+
], j = [
|
|
38
|
+
"ruler",
|
|
39
|
+
"setSquare",
|
|
40
|
+
"protractor"
|
|
41
|
+
], M = [
|
|
42
|
+
"create",
|
|
43
|
+
"throughPoints",
|
|
44
|
+
"perpendicular",
|
|
45
|
+
"parallel",
|
|
46
|
+
"segmentLength",
|
|
47
|
+
"midpoint"
|
|
48
|
+
], N = ["role", "label"], P = b.enum(A), F = b.number().positive().max(90), I = [
|
|
49
|
+
b.object({
|
|
50
|
+
kind: b.literal("point"),
|
|
51
|
+
at: E
|
|
52
|
+
}).strict(),
|
|
53
|
+
b.object({
|
|
54
|
+
kind: b.literal("point"),
|
|
55
|
+
on: T,
|
|
56
|
+
t: b.number().finite()
|
|
57
|
+
}).strict(),
|
|
58
|
+
b.object({
|
|
59
|
+
kind: b.literal("point"),
|
|
60
|
+
intersectionOf: D,
|
|
61
|
+
which: b.union([b.literal(0), b.literal(1)]).optional()
|
|
62
|
+
}).strict(),
|
|
63
|
+
b.object({
|
|
64
|
+
kind: b.literal("segment"),
|
|
65
|
+
parents: D
|
|
66
|
+
}).strict(),
|
|
67
|
+
b.object({
|
|
68
|
+
kind: b.literal("line"),
|
|
69
|
+
parents: D
|
|
70
|
+
}).strict(),
|
|
71
|
+
b.object({
|
|
72
|
+
kind: b.literal("circle"),
|
|
73
|
+
parents: D
|
|
74
|
+
}).strict()
|
|
75
|
+
], L = b.union(I), R = {
|
|
76
|
+
create: { objectType: P },
|
|
77
|
+
throughPoints: {
|
|
78
|
+
objectType: P,
|
|
79
|
+
pointIds: b.array(T).min(1)
|
|
80
|
+
},
|
|
81
|
+
perpendicular: {
|
|
82
|
+
objectType: P,
|
|
83
|
+
referenceObjectId: T,
|
|
84
|
+
throughPointId: T,
|
|
85
|
+
toleranceDegrees: F
|
|
86
|
+
},
|
|
87
|
+
parallel: {
|
|
88
|
+
objectType: P,
|
|
89
|
+
referenceObjectId: T,
|
|
90
|
+
throughPointId: T,
|
|
91
|
+
toleranceDegrees: F
|
|
92
|
+
},
|
|
93
|
+
segmentLength: {
|
|
94
|
+
objectType: b.literal("segment"),
|
|
95
|
+
targetLength: k,
|
|
96
|
+
toleranceUnits: k
|
|
97
|
+
},
|
|
98
|
+
midpoint: {
|
|
99
|
+
objectType: b.literal("point"),
|
|
100
|
+
referenceObjectId: T,
|
|
101
|
+
toleranceUnits: k
|
|
102
|
+
}
|
|
103
|
+
}, z = b.union(M.map((e) => b.object({
|
|
104
|
+
id: T,
|
|
105
|
+
type: b.literal(e),
|
|
106
|
+
...R[e]
|
|
107
|
+
}).strict())), B = b.object({
|
|
108
|
+
schemaVersion: b.literal(2),
|
|
109
|
+
id: T,
|
|
110
|
+
viewport: re,
|
|
111
|
+
showGrid: b.boolean().optional(),
|
|
112
|
+
entities: p(L),
|
|
113
|
+
presentation: p(b.object({
|
|
114
|
+
role: b.enum(["implicit", "explicit"]),
|
|
115
|
+
label: b.string().min(1).optional()
|
|
116
|
+
}).strict()),
|
|
117
|
+
draggableEntityIds: b.array(T),
|
|
118
|
+
allowedObjects: b.array(P),
|
|
119
|
+
tools: b.array(b.enum(j)),
|
|
120
|
+
goals: b.array(z)
|
|
121
|
+
}).strict(), V = (e) => e;
|
|
122
|
+
function H(e) {
|
|
123
|
+
let t = e.flatMap((e) => e.code === "unrecognized_keys" && e.keys ? e.keys.map((t) => [...e.path, t].join(".")) : [e.path.join(".") || "the document"]);
|
|
124
|
+
return [...new Set(t)];
|
|
125
|
+
}
|
|
126
|
+
function U(e, t, n, r = {}) {
|
|
127
|
+
let i = e + 1, { frozen: a = V, next: o = V } = r;
|
|
128
|
+
return {
|
|
129
|
+
from: e,
|
|
130
|
+
to: i,
|
|
131
|
+
migrate: (r) => {
|
|
132
|
+
let s = t.safeParse(a(r));
|
|
133
|
+
if (!s.success && n.safeParse({
|
|
134
|
+
...o(r),
|
|
135
|
+
schemaVersion: i
|
|
136
|
+
}).success) throw Error(`a version ${e} exercise cannot carry ${H(s.error.issues).join(", ")}`);
|
|
137
|
+
return { ...r };
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function W(e) {
|
|
142
|
+
return U(2, B, e);
|
|
143
|
+
}
|
|
144
|
+
var G = B.extend({
|
|
145
|
+
schemaVersion: b.literal(3),
|
|
146
|
+
grading: b.object({ extraObjects: b.enum(["allow", "reject"]) }).strict().optional()
|
|
147
|
+
});
|
|
148
|
+
[...ie];
|
|
149
|
+
var K = [...A, "angle"];
|
|
150
|
+
[...N];
|
|
151
|
+
var q = G.extend({
|
|
152
|
+
schemaVersion: b.literal(4),
|
|
153
|
+
entities: p(b.union([...I, b.object({
|
|
154
|
+
kind: b.literal("angle"),
|
|
155
|
+
parents: b.tuple([
|
|
156
|
+
w,
|
|
157
|
+
w,
|
|
158
|
+
w
|
|
159
|
+
]).readonly()
|
|
160
|
+
}).strict()])),
|
|
161
|
+
presentation: p(b.object({
|
|
162
|
+
role: b.enum(["implicit", "explicit"]),
|
|
163
|
+
label: b.string().min(1).optional(),
|
|
164
|
+
measureLabel: b.enum(["degrees"]).optional()
|
|
165
|
+
}).strict()),
|
|
166
|
+
allowedObjects: b.array(b.enum(K)),
|
|
167
|
+
solution: b.unknown().optional()
|
|
168
|
+
});
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/schemas/v3ToV4.ts
|
|
171
|
+
function J(e = q) {
|
|
172
|
+
return U(3, G, e, { next: _ });
|
|
173
|
+
}
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/schemas/v4ToV5.ts
|
|
176
|
+
function ae(e) {
|
|
177
|
+
return U(4, q, e, {
|
|
178
|
+
frozen: _,
|
|
179
|
+
next: _
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/schemas/exercise.schema.ts
|
|
184
|
+
var Y = b.enum([
|
|
185
|
+
"ruler",
|
|
186
|
+
"setSquare",
|
|
187
|
+
"protractor"
|
|
188
|
+
]), oe = 5, X = b.enum(["allow", "reject"]), Z = b.object({ extraObjects: X }).strict(), Q = b.object({
|
|
189
|
+
schemaVersion: b.literal(5),
|
|
190
|
+
id: f,
|
|
191
|
+
viewport: S,
|
|
192
|
+
showGrid: b.boolean().optional(),
|
|
193
|
+
entities: p(l),
|
|
194
|
+
presentation: p(g),
|
|
195
|
+
draggableEntityIds: b.array(f),
|
|
196
|
+
allowedObjects: b.array(t),
|
|
197
|
+
tools: b.array(Y),
|
|
198
|
+
goals: b.array(C),
|
|
199
|
+
grading: Z.optional(),
|
|
200
|
+
solution: m.optional()
|
|
201
|
+
}).strict().superRefine((t, a) => {
|
|
202
|
+
for (let e of n(t, { parentsMustBeDeclared: !0 })) a.addIssue({
|
|
203
|
+
code: "custom",
|
|
204
|
+
path: e.path,
|
|
205
|
+
message: e.message
|
|
206
|
+
});
|
|
207
|
+
for (let e of i(t.draggableEntityIds, "draggableEntityIds", t, { pointsOnly: !0 })) a.addIssue({
|
|
208
|
+
code: "custom",
|
|
209
|
+
path: e.path,
|
|
210
|
+
message: e.message
|
|
211
|
+
});
|
|
212
|
+
let o = {
|
|
213
|
+
definitionOf: (e) => r(t.entities, e),
|
|
214
|
+
isStudentDraggable: (n) => e(t, n)
|
|
215
|
+
}, s = /* @__PURE__ */ new Set();
|
|
216
|
+
t.goals.forEach((e, t) => {
|
|
217
|
+
s.has(e.id) && a.addIssue({
|
|
218
|
+
code: "custom",
|
|
219
|
+
path: [
|
|
220
|
+
"goals",
|
|
221
|
+
t,
|
|
222
|
+
"id"
|
|
223
|
+
],
|
|
224
|
+
message: `duplicate goal id: ${e.id}`
|
|
225
|
+
}), s.add(e.id);
|
|
226
|
+
for (let n of ee(e).crossReferenceIssues(e, o)) a.addIssue({
|
|
227
|
+
code: "custom",
|
|
228
|
+
path: [
|
|
229
|
+
"goals",
|
|
230
|
+
t,
|
|
231
|
+
...n.path
|
|
232
|
+
],
|
|
233
|
+
message: n.message
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
}), $ = [
|
|
237
|
+
s,
|
|
238
|
+
W(G),
|
|
239
|
+
J(),
|
|
240
|
+
ae(Q)
|
|
241
|
+
];
|
|
242
|
+
function se(e) {
|
|
243
|
+
return Q.parse(e);
|
|
244
|
+
}
|
|
245
|
+
function ce(e) {
|
|
246
|
+
return h(e, $, 5);
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
249
|
+
export { oe as a, Y as c, Q as i, C as l, X as n, ce as o, $ as r, se as s, Z as t, S as u };
|
|
250
|
+
|
|
251
|
+
//# sourceMappingURL=exercise.schema-Bma3qN9P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exercise.schema-Bma3qN9P.js","names":[],"sources":["../src/schemas/viewport.schema.ts","../src/schemas/goals/geometryGoal.schema.ts","../src/schemas/exerciseV2.schema.ts","../src/schemas/v2ToV3.ts","../src/schemas/exerciseV3.schema.ts","../src/schemas/exerciseV4.schema.ts","../src/schemas/v3ToV4.ts","../src/schemas/v4ToV5.ts","../src/schemas/exercise.schema.ts"],"sourcesContent":["import { z } from 'zod'\n\nconst viewportCoordinateSchema = z.number().finite().min(-100).max(100)\n\nexport const mathViewportSchema = z\n .tuple([\n viewportCoordinateSchema,\n viewportCoordinateSchema,\n viewportCoordinateSchema,\n viewportCoordinateSchema,\n ])\n .refine(([xMin, yMin, xMax, yMax]) => xMin < xMax && yMin < yMax, {\n message: 'viewport must satisfy xMin < xMax and yMin < yMax',\n })\n .refine(([xMin, , xMax]) => xMax - xMin >= 1 && xMax - xMin <= 100, {\n message: 'viewport width must be between 1 and 100',\n })\n .refine(([, yMin, , yMax]) => yMax - yMin >= 1 && yMax - yMin <= 100, {\n message: 'viewport height must be between 1 and 100',\n })\n\nexport type MathViewport = z.infer<typeof mathViewportSchema>\n","import { z } from 'zod'\nimport { createGoalSchema } from './createGoal.schema'\nimport { throughPointsGoalSchema } from './throughPointsGoal.schema'\nimport { perpendicularGoalSchema } from './perpendicularGoal.schema'\nimport { parallelGoalSchema } from './parallelGoal.schema'\nimport { segmentLengthGoalSchema } from './segmentLengthGoal.schema'\nimport { midpointGoalSchema } from './midpointGoal.schema'\nimport { angleMeasureGoalSchema } from './angleMeasureGoal.schema'\nimport { angleBisectorGoalSchema } from './angleBisectorGoal.schema'\nimport { givenAngleGoalSchema } from './givenAngleGoal.schema'\n\nexport const geometryGoalSchema = z.discriminatedUnion('type', [\n createGoalSchema,\n throughPointsGoalSchema,\n perpendicularGoalSchema,\n parallelGoalSchema,\n segmentLengthGoalSchema,\n midpointGoalSchema,\n angleMeasureGoalSchema,\n angleBisectorGoalSchema,\n givenAngleGoalSchema,\n])\n\nexport type GeometryGoal = z.infer<typeof geometryGoalSchema>\n","import { z } from 'zod'\nimport { entityRecordSchema } from './entityDocument'\n\nexport const v2ExerciseSchemaVersion = 2\n\n/**\n * The exercise document ADR 0008 froze, transcribed **whole** so the v2 → v3\n * step can check what it was handed before promoting it (ADR 0013).\n *\n * Frozen means frozen: nothing below is imported from the current vocabulary.\n * An earlier version of this file reused `entityDefinitionSchema`,\n * `entityPresentationSchema`, `objectTypeNameSchema`, `toolNameSchema` and\n * `geometryGoalSchema`, which would have silently admitted every later addition\n * to them — the `angle` entity kind, `angleMeasure` / `angleBisector` goals and\n * the `measureLabel` presentation entry ADR 0010 already plans — into a document\n * claiming to be version 2. A union member or an enum value is as much a version\n * change as a new field, and a shared schema cannot tell two versions apart.\n *\n * What is deliberately shared is machinery rather than vocabulary:\n * `entityRecordSchema()` supplies the `__proto__` refusal (M2.G.1) and the\n * record's id-key rule. If those change they change for every version at once,\n * which is a decision of its own rather than a new document feature.\n *\n * Two things this schema is not. It carries **no cross-reference refinements**:\n * it answers \"could version 2 have said this?\", never \"is this exercise\n * coherent?\" — the migrated document is parsed by `geometryExerciseSchema`,\n * whose refinements report a dangling id or a duplicate goal id at its real\n * path. And it carries **no issue messages**: nothing renders them, because\n * `v2ToV3.ts` reports the offending *paths* and the surviving document is\n * described by the current schema.\n *\n * `tests/schemas/v2ToV3.test.ts` § \"the frozen v2 vocabulary\" fails the day the\n * current schemas gain a kind, goal, object type, tool or presentation field\n * this file does not list, so the freeze cannot rot quietly.\n */\n\n/** v2's id rule, shared with the later frozen transcriptions built on this one. */\nexport const v2IdSchema = z\n .string()\n .min(1)\n .refine((value) => value === value.trim())\nconst id = v2IdSchema\nconst point = z.object({ x: z.number().finite(), y: z.number().finite() }).strict()\nconst parents = z.tuple([id, id]).readonly()\nconst span = z.number().finite().min(-100).max(100)\nconst positive = z.number().positive().finite()\n\nconst viewport = z\n .tuple([span, span, span, span])\n .refine(([xMin, yMin, xMax, yMax]) => xMin < xMax && yMin < yMax)\n .refine(([xMin, , xMax]) => xMax - xMin >= 1 && xMax - xMin <= 100)\n .refine(([, yMin, , yMax]) => yMax - yMin >= 1 && yMax - yMin <= 100)\n\n/** v2's four entity kinds, its object types, its tools and its goal types. */\nexport const v2EntityKinds = ['point', 'segment', 'line', 'circle'] as const\nexport const v2ObjectTypeNames = ['point', 'segment', 'line', 'circle'] as const\nexport const v2ToolNames = ['ruler', 'setSquare', 'protractor'] as const\nexport const v2GoalTypes = [\n 'create',\n 'throughPoints',\n 'perpendicular',\n 'parallel',\n 'segmentLength',\n 'midpoint',\n] as const\n/** And the only two keys a v2 presentation entry had. */\nexport const v2PresentationKeys = ['role', 'label'] as const\n\nconst objectType = z.enum(v2ObjectTypeNames)\nconst angle = z.number().positive().max(90)\n\n/** v2's entity definitions, for the later frozen transcriptions to widen by name. */\nexport const v2EntityDefinitionMembers = [\n z.object({ kind: z.literal('point'), at: point }).strict(),\n z.object({ kind: z.literal('point'), on: id, t: z.number().finite() }).strict(),\n z\n .object({\n kind: z.literal('point'),\n intersectionOf: parents,\n which: z.union([z.literal(0), z.literal(1)]).optional(),\n })\n .strict(),\n z.object({ kind: z.literal('segment'), parents }).strict(),\n z.object({ kind: z.literal('line'), parents }).strict(),\n z.object({ kind: z.literal('circle'), parents }).strict(),\n] as const\nconst definition = z.union(v2EntityDefinitionMembers)\n\n// One row per v2 goal kind: the fields it carried beyond `id` and `type`.\nconst goalFields = {\n create: { objectType },\n throughPoints: { objectType, pointIds: z.array(id).min(1) },\n perpendicular: {\n objectType,\n referenceObjectId: id,\n throughPointId: id,\n toleranceDegrees: angle,\n },\n parallel: { objectType, referenceObjectId: id, throughPointId: id, toleranceDegrees: angle },\n segmentLength: {\n objectType: z.literal('segment'),\n targetLength: positive,\n toleranceUnits: positive,\n },\n midpoint: { objectType: z.literal('point'), referenceObjectId: id, toleranceUnits: positive },\n} as const\n\nconst goal = z.union(\n v2GoalTypes.map((type) => z.object({ id, type: z.literal(type), ...goalFields[type] }).strict()),\n)\n\nexport const geometryExerciseV2Schema = z\n .object({\n schemaVersion: z.literal(v2ExerciseSchemaVersion),\n id,\n viewport,\n showGrid: z.boolean().optional(),\n entities: entityRecordSchema(definition),\n presentation: entityRecordSchema(\n z\n .object({ role: z.enum(['implicit', 'explicit']), label: z.string().min(1).optional() })\n .strict(),\n ),\n draggableEntityIds: z.array(id),\n allowedObjects: z.array(objectType),\n tools: z.array(z.enum(v2ToolNames)),\n goals: z.array(goal),\n })\n .strict()\n","// The one-way v2 → v3 translation of a stored exercise (M3.H.6, ADR 0013).\n//\n// v3 adds one optional field, `grading`, and changes nothing else — so the\n// translation is the identity on every field a v2 document carries, and it\n// deliberately does **not** materialize a policy: absence means permissive,\n// and writing `{ extraObjects: 'allow' }` here would turn every historical\n// exercise into one that states a policy it never authored.\n//\n// The step does check its input, unlike `v1ToV2`'s translations, and for the\n// reason the human's version decision names: a v2 document carrying anything\n// version 2 could not say must be **rejected** rather than promoted into a\n// document where it is legal. Nothing downstream can catch that — after the hop\n// the vocabulary is the current one — so the gate has to be here. The v3 → v4\n// hop (ADR 0015) and the v4 → v5 hop (ADR 0019) are the same kind of step, so\n// all three are built by one factory.\nimport type { ZodType } from 'zod'\nimport type { MigrationStep } from './migrate'\nimport { geometryExerciseV2Schema } from './exerciseV2.schema'\n\n/** The version the step below produces. */\nexport const v3SchemaVersion = 3\n\n/**\n * Just enough of a schema for the gate: the next version's parser, passed in\n * rather than imported to keep this module free of a cycle with\n * `exercise.schema.ts` — and small enough that a test can substitute a laxer\n * one and watch the gate react.\n */\nexport interface DocumentGate {\n safeParse(input: unknown): { success: boolean }\n}\n\ntype Projection = (document: Record<string, unknown>) => Record<string, unknown>\n\n/**\n * What each side of a gate is asked about, identity by default. The hops after\n * version 3 ask without `solution`: it is an attempt document that migrates and\n * validates on its own path (ADR 0015), so whether a stored solution parses must\n * never decide whether the exercise around it is newer vocabulary.\n */\nexport interface ExerciseStepProjection {\n frozen?: Projection\n next?: Projection\n}\n\nconst identity: Projection = (document) => document\n\ninterface FrozenIssue {\n code: string\n path: PropertyKey[]\n keys?: string[]\n}\n\n/** What the document said that the version it claims has no way to express. */\nfunction offendingPaths(issues: readonly FrozenIssue[]): string[] {\n const named = issues.flatMap((issue) =>\n issue.code === 'unrecognized_keys' && issue.keys\n ? issue.keys.map((key) => [...issue.path, key].join('.'))\n : [issue.path.join('.') || 'the document'],\n )\n return [...new Set(named)]\n}\n\n/**\n * An exercise hop that adds vocabulary and changes nothing it already had. The\n * refusal rule, stated exactly: **a document that is invalid at `from` and\n * valid at `from + 1` is refused.** That is what silent promotion means, and it\n * covers every way the next version can be wider — a new field, a new entity\n * kind, a new goal type, a new `allowedObjects` member, a new presentation\n * entry, a loosened value — without the step having to enumerate them or read\n * issue codes to guess which is which.\n *\n * A document that is invalid at **both** versions passes through untouched, so\n * an ordinary fault (a bad viewport, a dangling parent) is still reported by\n * `geometryExerciseSchema` at its own document path rather than refiled here as\n * one message under `schemaVersion`. It is rejected either way; only the quality\n * of the error differs, and the path is the better answer.\n *\n * `frozenSchema` must be a transcription of version `from` and `nextSchema` the\n * parser of version `from + 1` — frozen as well unless that is the current one,\n * because a current schema's version literal would never accept the promotion.\n * `projection` says what each side is shown (ADR 0019); it only narrows the\n * question, and the document that travels on is always the input.\n */\nexport function createIdentityExerciseStep(\n from: number,\n frozenSchema: ZodType,\n nextSchema: DocumentGate,\n projection: ExerciseStepProjection = {},\n): MigrationStep {\n const to = from + 1\n const { frozen = identity, next = identity } = projection\n return {\n from,\n to,\n migrate: (document) => {\n const parsed = frozenSchema.safeParse(frozen(document))\n if (\n !parsed.success &&\n nextSchema.safeParse({ ...next(document), schemaVersion: to }).success\n ) {\n throw new Error(\n `a version ${from} exercise cannot carry ${offendingPaths(parsed.error.issues).join(', ')}`,\n )\n }\n // The input document, not a parsed copy: the shape is unchanged, so the\n // stored values travel on untouched and `applyMigrations()` stamps the new\n // version.\n return { ...document }\n },\n }\n}\n\n/** The v2 → v3 hop, gated against the version 3 schema it is given. */\nexport function createGeometryExerciseV2ToV3(v3ExerciseSchema: DocumentGate): MigrationStep {\n return createIdentityExerciseStep(2, geometryExerciseV2Schema, v3ExerciseSchema)\n}\n","import { z } from 'zod'\nimport { geometryExerciseV2Schema } from './exerciseV2.schema'\n\nexport const v3ExerciseSchemaVersion = 3\n\n/**\n * The exercise document ADR 0013 froze at version 3, so the v3 → v4 step can\n * check what it was handed before promoting it (ADR 0015) — and so the v2 → v3\n * step still has a version 3 to ask once the current schema has moved past it.\n *\n * Version 3 is version 2 plus `grading` and nothing else, so it is built on the\n * frozen v2 transcription rather than transcribed a second time. `grading` is\n * written out here with nothing imported from the current vocabulary, for the\n * reason `exerciseV2.schema.ts` gives: a shared schema admits every later\n * addition to it. Like that schema this one carries no cross-reference\n * refinements and no issue messages; it only answers \"could version 3 have\n * said this?\".\n */\nexport const geometryExerciseV3Schema = geometryExerciseV2Schema.extend({\n schemaVersion: z.literal(v3ExerciseSchemaVersion),\n grading: z\n .object({ extraObjects: z.enum(['allow', 'reject']) })\n .strict()\n .optional(),\n})\n","import { z } from 'zod'\nimport { entityRecordSchema } from './entityDocument'\nimport {\n v2EntityDefinitionMembers,\n v2EntityKinds,\n v2GoalTypes,\n v2IdSchema,\n v2ObjectTypeNames,\n v2PresentationKeys,\n v2ToolNames,\n} from './exerciseV2.schema'\nimport { geometryExerciseV3Schema } from './exerciseV3.schema'\n\nexport const v4ExerciseSchemaVersion = 4\n\n/** Version 4's vocabularies: version 2's plus the angle M3.4 added (ADR 0010). */\nexport const v4EntityKinds = [...v2EntityKinds, 'angle'] as const\nexport const v4ObjectTypeNames = [...v2ObjectTypeNames, 'angle'] as const\nexport const v4ToolNames = v2ToolNames\nexport const v4GoalTypes = v2GoalTypes\nexport const v4PresentationKeys = [...v2PresentationKeys, 'measureLabel'] as const\n\n/**\n * The exercise document at version 4 as M3.4 left it, frozen by ADR 0019 so the\n * v4 → v5 step can ask \"could version 4 have said this?\" once the angle goals\n * make the current schema wider — and so the v3 → v4 step still has a version 4\n * to ask.\n *\n * Version 4 is version 3 plus `solution` (ADR 0015) and the angle — one entity\n * kind, one object type, one presentation key — and no goal type, so it is built\n * on the frozen v3 transcription with those written out and nothing imported\n * from the current vocabulary (see `exerciseV2.schema.ts`).\n *\n * `solution` is admitted and never judged. It is an attempt document that\n * migrates and validates on its own path (ADR 0015), a malformed one does not\n * make the exercise unloadable, and both gates that ask this schema hand it the\n * solution-free projection anyway (ADR 0019).\n */\nexport const geometryExerciseV4Schema = geometryExerciseV3Schema.extend({\n schemaVersion: z.literal(v4ExerciseSchemaVersion),\n entities: entityRecordSchema(\n z.union([\n ...v2EntityDefinitionMembers,\n z\n .object({\n kind: z.literal('angle'),\n parents: z.tuple([v2IdSchema, v2IdSchema, v2IdSchema]).readonly(),\n })\n .strict(),\n ]),\n ),\n presentation: entityRecordSchema(\n z\n .object({\n role: z.enum(['implicit', 'explicit']),\n label: z.string().min(1).optional(),\n measureLabel: z.enum(['degrees']).optional(),\n })\n .strict(),\n ),\n allowedObjects: z.array(z.enum(v4ObjectTypeNames)),\n solution: z.unknown().optional(),\n})\n","// The one-way v3 → v4 translation of a stored exercise (M3.I.3, ADR 0015).\n//\n// v4 adds one optional field, `solution` — the authored canonical attempt — and\n// changes nothing else, so the translation is the identity plus a version and a\n// migrated v3 exercise simply has no solution. The gate is the v2 → v3 one a\n// version later: a v3 document carrying `solution`, or anything else version 3\n// could not say, is refused rather than promoted, because a v3 reader would\n// reject it too.\n//\n// The gate is asymmetric (ADR 0019). The v3 side parses the raw document,\n// because carrying `solution` at all is what version 3 cannot say, whatever the\n// solution contains. The v4 side asks the frozen v4 transcription without the\n// solution: asking with it would let a v3 document with a *malformed* solution\n// be invalid at both versions, pass through, and then load cleanly on the\n// solution-free path.\nimport type { MigrationStep } from './migrate'\nimport { withoutSolution } from './exerciseProjection'\nimport { geometryExerciseV3Schema } from './exerciseV3.schema'\nimport { geometryExerciseV4Schema } from './exerciseV4.schema'\nimport { createIdentityExerciseStep, type DocumentGate } from './v2ToV3'\n\n/** The v3 → v4 hop, gated against the frozen version 4 unless a test substitutes one. */\nexport function createGeometryExerciseV3ToV4(\n v4ExerciseSchema: DocumentGate = geometryExerciseV4Schema,\n): MigrationStep {\n return createIdentityExerciseStep(3, geometryExerciseV3Schema, v4ExerciseSchema, {\n next: withoutSolution,\n })\n}\n","// The one-way v4 → v5 translation of a stored exercise (M3.6.a, ADR 0019).\n//\n// v5 adds the angle goals — `angleMeasure`, `angleBisector`, `givenAngle` — and\n// changes nothing else, so the translation is the identity plus a version. The\n// gate refuses a v4 document carrying an angle goal, or anything else version 4\n// could not say, because a v4 reader would reject it too.\n//\n// **Both sides ask without the solution.** Version 4 already carries\n// `solution`, and the solution migrates and validates on its own path (ADR\n// 0015): a raw frozen-v4 parse would reject a v4 exercise whose solution is an\n// older attempt version or malformed, the solution-free v5 parse would accept\n// it, and the gate would misreport the document as v5 vocabulary.\nimport type { MigrationStep } from './migrate'\nimport { withoutSolution } from './exerciseProjection'\nimport { geometryExerciseV4Schema } from './exerciseV4.schema'\nimport { createIdentityExerciseStep, type DocumentGate } from './v2ToV3'\n\n/**\n * The v4 → v5 hop, gated against the version 5 schema it is given — the current\n * one, passed in to keep this module out of a cycle with `exercise.schema.ts`.\n */\nexport function createGeometryExerciseV4ToV5(v5ExerciseSchema: DocumentGate): MigrationStep {\n return createIdentityExerciseStep(4, geometryExerciseV4Schema, v5ExerciseSchema, {\n frozen: withoutSolution,\n next: withoutSolution,\n })\n}\n","import { z } from 'zod'\nimport { entryOf } from '../geometry/entityRecord'\nimport { geometryIdSchema } from './identifier.schema'\nimport { objectTypeNameSchema } from './objectTypeName.schema'\nimport { mathViewportSchema } from './viewport.schema'\nimport { entityDefinitionSchema } from './entityDefinition.schema'\nimport { entityPresentationSchema } from './entityPresentation.schema'\nimport {\n entityDocumentIssues,\n entityIdListIssues,\n entityRecordSchema,\n isStudentDraggableGiven,\n} from './entityDocument'\nimport { geometryGoalSchema } from './goals/geometryGoal.schema'\nimport { declarationFor, type GoalAuthoringContext } from './goals/goalKindDeclaration'\nimport { applyMigrations, type MigrationOutcome, type MigrationStep } from './migrate'\nimport { geometryExerciseV1ToV2 } from './v1ToV2'\nimport { createGeometryExerciseV2ToV3 } from './v2ToV3'\nimport { createGeometryExerciseV3ToV4 } from './v3ToV4'\nimport { createGeometryExerciseV4ToV5 } from './v4ToV5'\nimport { geometryExerciseV3Schema } from './exerciseV3.schema'\nimport { geometryStateSchema } from './geometryState.schema'\n\nexport const toolNameSchema = z.enum(['ruler', 'setSquare', 'protractor'])\nexport type ToolName = z.infer<typeof toolNameSchema>\n\n// An exercise is stored and reloaded exactly as an attempt is, so it versions\n// and migrates the same way (M2.6.b). Raised to 2 at M2.6.c.1, with the\n// consumers that read what the step below produces: a stored v1 exercise is now\n// migrated on the way in and no longer has a schema of its own, because nothing\n// parses a v1 exercise — `geometryExerciseV1ToV2` reads the raw JSON.\n//\n// Raised to 3 at M3.H.6 for `grading` (ADR 0013). The human rejected adding the\n// field to v2: an older reader claims to support version 2 and would reject the\n// document anyway, so the version says out loud what the field means. **The\n// attempt document stays at 2** — the two versions are independent, and a v2\n// attempt is graded against a v3 exercise.\n//\n// Raised to 4 at M3.I.3 for `solution` (ADR 0015), for the same reason: a v3\n// reader must not be handed a v3 document it would reject.\n//\n// Raised to 5 at M3.6.a for the angle goals (ADR 0019); the angle entity itself\n// stayed in version 4.\nexport const latestGeometryExerciseVersion = 5\n\n// How strictly an attempt is graded for answer entities no goal needed\n// (RFC 0004 § Decision 6). `allow` is what every exercise did before v3, so\n// **absence means `allow`** and nothing materializes a default: an exercise that\n// states no policy is indistinguishable from one migrated from v2.\nexport const extraObjectPolicySchema = z.enum(['allow', 'reject'])\nexport type ExtraObjectPolicy = z.infer<typeof extraObjectPolicySchema>\n\n// Strict and with `extraObjects` required when the object is present: a\n// `grading: {}` that silently meant \"allow\" would be a second way to say\n// nothing, and a misspelled key inside it would be read as permissive.\nexport const exerciseGradingSchema = z.object({ extraObjects: extraObjectPolicySchema }).strict()\nexport type ExerciseGrading = z.infer<typeof exerciseGradingSchema>\n\n// The exercise document ADR 0008 froze. `givens[]` became the same `entities`\n// record the attempt uses since M2.6.c.2, so a given segment and a student\n// segment are the same shape and only the document they live in distinguishes\n// them. `label` lives in the `presentation` record and `draggable` became\n// `draggableEntityIds` — a list on the exercise and unrepresentable in an\n// attempt, so a tampered attempt cannot declare a pinned given draggable and\n// move the reference its own goals are measured against.\n//\n// `id`, `viewport`, `showGrid`, `allowedObjects`, `tools` and `goals` are\n// unchanged from v1, and the goals array migrates by identity.\n//\n// v3 adds `grading` and nothing else. An attempt cannot carry it — the\n// strictness policy is the author's, not the student's — and it is optional, so\n// a migrated v2 exercise is a v3 exercise with the field absent.\nexport const geometryExerciseSchema = z\n .object({\n schemaVersion: z.literal(latestGeometryExerciseVersion),\n id: geometryIdSchema,\n viewport: mathViewportSchema,\n showGrid: z.boolean().optional(),\n entities: entityRecordSchema(entityDefinitionSchema),\n presentation: entityRecordSchema(entityPresentationSchema),\n draggableEntityIds: z.array(geometryIdSchema),\n allowedObjects: z.array(objectTypeNameSchema),\n tools: z.array(toolNameSchema),\n goals: z.array(geometryGoalSchema),\n grading: exerciseGradingSchema.optional(),\n // v4's authored canonical attempt (ADR 0015), a current-version attempt\n // document. The loaders never hand it to this schema raw: a stored solution\n // may be an older attempt version, so it is migrated and checked against the\n // exercise on its own (`validateEmbeddedSolution()`), and Check and the\n // student canvas load the solution-free projection instead, so a broken\n // authored answer never disables them (RFC 0005 § Decision 4, option C).\n solution: geometryStateSchema.optional(),\n })\n .strict()\n .superRefine((exercise, context) => {\n // An exercise is self-contained — nothing in it may name an id it does not\n // declare — which is the half of the staging an attempt cannot have.\n for (const issue of entityDocumentIssues(exercise, { parentsMustBeDeclared: true })) {\n context.addIssue({ code: 'custom', path: issue.path, message: issue.message })\n }\n // Only a point can be dragged: dragging a segment would have to decide what\n // happens to its endpoints, which is a command, not a stored capability.\n for (const issue of entityIdListIssues(\n exercise.draggableEntityIds,\n 'draggableEntityIds',\n exercise,\n { pointsOnly: true },\n )) {\n context.addIssue({ code: 'custom', path: issue.path, message: issue.message })\n }\n\n // Each goal kind's own cross-reference rules, from its declaration (M2.5),\n // so this refinement stays the exercise-wide part. The entity record *is*\n // the authoring context, so nothing translates.\n const authoring: GoalAuthoringContext = {\n definitionOf: (id) => entryOf(exercise.entities, id),\n // The document being parsed is the authority a figure goal's movability\n // rule reads (ADR 0016): both fields it needs are already on it.\n isStudentDraggable: (id) => isStudentDraggableGiven(exercise, id),\n }\n const goalIds = new Set<string>()\n exercise.goals.forEach((goal, index) => {\n if (goalIds.has(goal.id)) {\n context.addIssue({\n code: 'custom',\n path: ['goals', index, 'id'],\n message: `duplicate goal id: ${goal.id}`,\n })\n }\n goalIds.add(goal.id)\n for (const issue of declarationFor(goal).crossReferenceIssues(goal, authoring)) {\n context.addIssue({\n code: 'custom',\n path: ['goals', index, ...issue.path],\n message: issue.message,\n })\n }\n })\n })\n\nexport type GeometryExercise = z.infer<typeof geometryExerciseSchema>\n\n// One entry per version hop. Each gate asks the next version's schema whether\n// the document it is refusing would have been accepted there — the definition\n// of a silent promotion. For v2 → v3 and v3 → v4 that is a frozen schema,\n// because the current one only accepts version 5; for v4 → v5 it is the current\n// schema, declared above, and passing it in keeps `v4ToV5.ts` out of an import\n// cycle. The steps after version 3 decide for themselves what each side is\n// shown of `solution` (ADR 0019).\nexport const geometryExerciseMigrations: readonly MigrationStep[] = [\n geometryExerciseV1ToV2,\n createGeometryExerciseV2ToV3(geometryExerciseV3Schema),\n createGeometryExerciseV3ToV4(),\n createGeometryExerciseV4ToV5(geometryExerciseSchema),\n]\n\nexport function parseGeometryExercise(input: unknown): GeometryExercise {\n return geometryExerciseSchema.parse(input)\n}\n\n// Brings a stored exercise up to the current version, the counterpart of\n// `migrateGeometryState()`. Structure is checked afterwards by the schema; this\n// only moves the shape forward, and it never mutates its input.\nexport function migrateGeometryExercise(input: unknown): MigrationOutcome {\n return applyMigrations(input, geometryExerciseMigrations, latestGeometryExerciseVersion)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./geometryState.schema-B5ccMKDa.cjs");let t=require("zod");var n=t.z.number().finite().min(-100).max(100),r=t.z.tuple([n,n,n,n]).refine(([e,t,n,r])=>e<n&&t<r,{message:`viewport must satisfy xMin < xMax and yMin < yMax`}).refine(([e,,t])=>t-e>=1&&t-e<=100,{message:`viewport width must be between 1 and 100`}).refine(([,e,,t])=>t-e>=1&&t-e<=100,{message:`viewport height must be between 1 and 100`}),i=t.z.discriminatedUnion(`type`,[e.b,e.m,e.g,e._,e.h,e.v,e.x,e.S,e.y]),a=t.z.string().min(1).refine(e=>e===e.trim()),o=a,s=t.z.object({x:t.z.number().finite(),y:t.z.number().finite()}).strict(),c=t.z.tuple([o,o]).readonly(),l=t.z.number().finite().min(-100).max(100),u=t.z.number().positive().finite(),d=t.z.tuple([l,l,l,l]).refine(([e,t,n,r])=>e<n&&t<r).refine(([e,,t])=>t-e>=1&&t-e<=100).refine(([,e,,t])=>t-e>=1&&t-e<=100),f=[`point`,`segment`,`line`,`circle`],p=[`point`,`segment`,`line`,`circle`],m=[`ruler`,`setSquare`,`protractor`],h=[`create`,`throughPoints`,`perpendicular`,`parallel`,`segmentLength`,`midpoint`],g=[`role`,`label`],_=t.z.enum(p),v=t.z.number().positive().max(90),y=[t.z.object({kind:t.z.literal(`point`),at:s}).strict(),t.z.object({kind:t.z.literal(`point`),on:o,t:t.z.number().finite()}).strict(),t.z.object({kind:t.z.literal(`point`),intersectionOf:c,which:t.z.union([t.z.literal(0),t.z.literal(1)]).optional()}).strict(),t.z.object({kind:t.z.literal(`segment`),parents:c}).strict(),t.z.object({kind:t.z.literal(`line`),parents:c}).strict(),t.z.object({kind:t.z.literal(`circle`),parents:c}).strict()],b=t.z.union(y),x={create:{objectType:_},throughPoints:{objectType:_,pointIds:t.z.array(o).min(1)},perpendicular:{objectType:_,referenceObjectId:o,throughPointId:o,toleranceDegrees:v},parallel:{objectType:_,referenceObjectId:o,throughPointId:o,toleranceDegrees:v},segmentLength:{objectType:t.z.literal(`segment`),targetLength:u,toleranceUnits:u},midpoint:{objectType:t.z.literal(`point`),referenceObjectId:o,toleranceUnits:u}},S=t.z.union(h.map(e=>t.z.object({id:o,type:t.z.literal(e),...x[e]}).strict())),C=t.z.object({schemaVersion:t.z.literal(2),id:o,viewport:d,showGrid:t.z.boolean().optional(),entities:e.k(b),presentation:e.k(t.z.object({role:t.z.enum([`implicit`,`explicit`]),label:t.z.string().min(1).optional()}).strict()),draggableEntityIds:t.z.array(o),allowedObjects:t.z.array(_),tools:t.z.array(t.z.enum(m)),goals:t.z.array(S)}).strict(),w=e=>e;function T(e){let t=e.flatMap(e=>e.code===`unrecognized_keys`&&e.keys?e.keys.map(t=>[...e.path,t].join(`.`)):[e.path.join(`.`)||`the document`]);return[...new Set(t)]}function E(e,t,n,r={}){let i=e+1,{frozen:a=w,next:o=w}=r;return{from:e,to:i,migrate:r=>{let s=t.safeParse(a(r));if(!s.success&&n.safeParse({...o(r),schemaVersion:i}).success)throw Error(`a version ${e} exercise cannot carry ${T(s.error.issues).join(`, `)}`);return{...r}}}}function D(e){return E(2,C,e)}var O=C.extend({schemaVersion:t.z.literal(3),grading:t.z.object({extraObjects:t.z.enum([`allow`,`reject`])}).strict().optional()});[...f];var k=[...p,`angle`];[...g];var A=O.extend({schemaVersion:t.z.literal(4),entities:e.k(t.z.union([...y,t.z.object({kind:t.z.literal(`angle`),parents:t.z.tuple([a,a,a]).readonly()}).strict()])),presentation:e.k(t.z.object({role:t.z.enum([`implicit`,`explicit`]),label:t.z.string().min(1).optional(),measureLabel:t.z.enum([`degrees`]).optional()}).strict()),allowedObjects:t.z.array(t.z.enum(k)),solution:t.z.unknown().optional()});function j(t=A){return E(3,O,t,{next:e.u})}function M(t){return E(4,A,t,{frozen:e.u,next:e.u})}var N=t.z.enum([`ruler`,`setSquare`,`protractor`]),P=5,F=t.z.enum([`allow`,`reject`]),I=t.z.object({extraObjects:F}).strict(),L=t.z.object({schemaVersion:t.z.literal(5),id:e.j,viewport:r,showGrid:t.z.boolean().optional(),entities:e.k(e.c),presentation:e.k(e.s),draggableEntityIds:t.z.array(e.j),allowedObjects:t.z.array(e.C),tools:t.z.array(N),goals:t.z.array(i),grading:I.optional(),solution:e.n.optional()}).strict().superRefine((t,n)=>{for(let r of e.D(t,{parentsMustBeDeclared:!0}))n.addIssue({code:`custom`,path:r.path,message:r.message});for(let r of e.O(t.draggableEntityIds,`draggableEntityIds`,t,{pointsOnly:!0}))n.addIssue({code:`custom`,path:r.path,message:r.message});let r={definitionOf:n=>e.M(t.entities,n),isStudentDraggable:n=>e.A(t,n)},i=new Set;t.goals.forEach((t,a)=>{i.has(t.id)&&n.addIssue({code:`custom`,path:[`goals`,a,`id`],message:`duplicate goal id: ${t.id}`}),i.add(t.id);for(let i of e.d(t).crossReferenceIssues(t,r))n.addIssue({code:`custom`,path:[`goals`,a,...i.path],message:i.message})})}),R=[e.a,D(O),j(),M(L)];function z(e){return L.parse(e)}function B(t){return e.o(t,R,5)}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return I}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return r}});
|
|
2
|
+
//# sourceMappingURL=exercise.schema-Oj5ZH-yO.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exercise.schema-Oj5ZH-yO.cjs","names":[],"sources":["../src/schemas/viewport.schema.ts","../src/schemas/goals/geometryGoal.schema.ts","../src/schemas/exerciseV2.schema.ts","../src/schemas/v2ToV3.ts","../src/schemas/exerciseV3.schema.ts","../src/schemas/exerciseV4.schema.ts","../src/schemas/v3ToV4.ts","../src/schemas/v4ToV5.ts","../src/schemas/exercise.schema.ts"],"sourcesContent":["import { z } from 'zod'\n\nconst viewportCoordinateSchema = z.number().finite().min(-100).max(100)\n\nexport const mathViewportSchema = z\n .tuple([\n viewportCoordinateSchema,\n viewportCoordinateSchema,\n viewportCoordinateSchema,\n viewportCoordinateSchema,\n ])\n .refine(([xMin, yMin, xMax, yMax]) => xMin < xMax && yMin < yMax, {\n message: 'viewport must satisfy xMin < xMax and yMin < yMax',\n })\n .refine(([xMin, , xMax]) => xMax - xMin >= 1 && xMax - xMin <= 100, {\n message: 'viewport width must be between 1 and 100',\n })\n .refine(([, yMin, , yMax]) => yMax - yMin >= 1 && yMax - yMin <= 100, {\n message: 'viewport height must be between 1 and 100',\n })\n\nexport type MathViewport = z.infer<typeof mathViewportSchema>\n","import { z } from 'zod'\nimport { createGoalSchema } from './createGoal.schema'\nimport { throughPointsGoalSchema } from './throughPointsGoal.schema'\nimport { perpendicularGoalSchema } from './perpendicularGoal.schema'\nimport { parallelGoalSchema } from './parallelGoal.schema'\nimport { segmentLengthGoalSchema } from './segmentLengthGoal.schema'\nimport { midpointGoalSchema } from './midpointGoal.schema'\nimport { angleMeasureGoalSchema } from './angleMeasureGoal.schema'\nimport { angleBisectorGoalSchema } from './angleBisectorGoal.schema'\nimport { givenAngleGoalSchema } from './givenAngleGoal.schema'\n\nexport const geometryGoalSchema = z.discriminatedUnion('type', [\n createGoalSchema,\n throughPointsGoalSchema,\n perpendicularGoalSchema,\n parallelGoalSchema,\n segmentLengthGoalSchema,\n midpointGoalSchema,\n angleMeasureGoalSchema,\n angleBisectorGoalSchema,\n givenAngleGoalSchema,\n])\n\nexport type GeometryGoal = z.infer<typeof geometryGoalSchema>\n","import { z } from 'zod'\nimport { entityRecordSchema } from './entityDocument'\n\nexport const v2ExerciseSchemaVersion = 2\n\n/**\n * The exercise document ADR 0008 froze, transcribed **whole** so the v2 → v3\n * step can check what it was handed before promoting it (ADR 0013).\n *\n * Frozen means frozen: nothing below is imported from the current vocabulary.\n * An earlier version of this file reused `entityDefinitionSchema`,\n * `entityPresentationSchema`, `objectTypeNameSchema`, `toolNameSchema` and\n * `geometryGoalSchema`, which would have silently admitted every later addition\n * to them — the `angle` entity kind, `angleMeasure` / `angleBisector` goals and\n * the `measureLabel` presentation entry ADR 0010 already plans — into a document\n * claiming to be version 2. A union member or an enum value is as much a version\n * change as a new field, and a shared schema cannot tell two versions apart.\n *\n * What is deliberately shared is machinery rather than vocabulary:\n * `entityRecordSchema()` supplies the `__proto__` refusal (M2.G.1) and the\n * record's id-key rule. If those change they change for every version at once,\n * which is a decision of its own rather than a new document feature.\n *\n * Two things this schema is not. It carries **no cross-reference refinements**:\n * it answers \"could version 2 have said this?\", never \"is this exercise\n * coherent?\" — the migrated document is parsed by `geometryExerciseSchema`,\n * whose refinements report a dangling id or a duplicate goal id at its real\n * path. And it carries **no issue messages**: nothing renders them, because\n * `v2ToV3.ts` reports the offending *paths* and the surviving document is\n * described by the current schema.\n *\n * `tests/schemas/v2ToV3.test.ts` § \"the frozen v2 vocabulary\" fails the day the\n * current schemas gain a kind, goal, object type, tool or presentation field\n * this file does not list, so the freeze cannot rot quietly.\n */\n\n/** v2's id rule, shared with the later frozen transcriptions built on this one. */\nexport const v2IdSchema = z\n .string()\n .min(1)\n .refine((value) => value === value.trim())\nconst id = v2IdSchema\nconst point = z.object({ x: z.number().finite(), y: z.number().finite() }).strict()\nconst parents = z.tuple([id, id]).readonly()\nconst span = z.number().finite().min(-100).max(100)\nconst positive = z.number().positive().finite()\n\nconst viewport = z\n .tuple([span, span, span, span])\n .refine(([xMin, yMin, xMax, yMax]) => xMin < xMax && yMin < yMax)\n .refine(([xMin, , xMax]) => xMax - xMin >= 1 && xMax - xMin <= 100)\n .refine(([, yMin, , yMax]) => yMax - yMin >= 1 && yMax - yMin <= 100)\n\n/** v2's four entity kinds, its object types, its tools and its goal types. */\nexport const v2EntityKinds = ['point', 'segment', 'line', 'circle'] as const\nexport const v2ObjectTypeNames = ['point', 'segment', 'line', 'circle'] as const\nexport const v2ToolNames = ['ruler', 'setSquare', 'protractor'] as const\nexport const v2GoalTypes = [\n 'create',\n 'throughPoints',\n 'perpendicular',\n 'parallel',\n 'segmentLength',\n 'midpoint',\n] as const\n/** And the only two keys a v2 presentation entry had. */\nexport const v2PresentationKeys = ['role', 'label'] as const\n\nconst objectType = z.enum(v2ObjectTypeNames)\nconst angle = z.number().positive().max(90)\n\n/** v2's entity definitions, for the later frozen transcriptions to widen by name. */\nexport const v2EntityDefinitionMembers = [\n z.object({ kind: z.literal('point'), at: point }).strict(),\n z.object({ kind: z.literal('point'), on: id, t: z.number().finite() }).strict(),\n z\n .object({\n kind: z.literal('point'),\n intersectionOf: parents,\n which: z.union([z.literal(0), z.literal(1)]).optional(),\n })\n .strict(),\n z.object({ kind: z.literal('segment'), parents }).strict(),\n z.object({ kind: z.literal('line'), parents }).strict(),\n z.object({ kind: z.literal('circle'), parents }).strict(),\n] as const\nconst definition = z.union(v2EntityDefinitionMembers)\n\n// One row per v2 goal kind: the fields it carried beyond `id` and `type`.\nconst goalFields = {\n create: { objectType },\n throughPoints: { objectType, pointIds: z.array(id).min(1) },\n perpendicular: {\n objectType,\n referenceObjectId: id,\n throughPointId: id,\n toleranceDegrees: angle,\n },\n parallel: { objectType, referenceObjectId: id, throughPointId: id, toleranceDegrees: angle },\n segmentLength: {\n objectType: z.literal('segment'),\n targetLength: positive,\n toleranceUnits: positive,\n },\n midpoint: { objectType: z.literal('point'), referenceObjectId: id, toleranceUnits: positive },\n} as const\n\nconst goal = z.union(\n v2GoalTypes.map((type) => z.object({ id, type: z.literal(type), ...goalFields[type] }).strict()),\n)\n\nexport const geometryExerciseV2Schema = z\n .object({\n schemaVersion: z.literal(v2ExerciseSchemaVersion),\n id,\n viewport,\n showGrid: z.boolean().optional(),\n entities: entityRecordSchema(definition),\n presentation: entityRecordSchema(\n z\n .object({ role: z.enum(['implicit', 'explicit']), label: z.string().min(1).optional() })\n .strict(),\n ),\n draggableEntityIds: z.array(id),\n allowedObjects: z.array(objectType),\n tools: z.array(z.enum(v2ToolNames)),\n goals: z.array(goal),\n })\n .strict()\n","// The one-way v2 → v3 translation of a stored exercise (M3.H.6, ADR 0013).\n//\n// v3 adds one optional field, `grading`, and changes nothing else — so the\n// translation is the identity on every field a v2 document carries, and it\n// deliberately does **not** materialize a policy: absence means permissive,\n// and writing `{ extraObjects: 'allow' }` here would turn every historical\n// exercise into one that states a policy it never authored.\n//\n// The step does check its input, unlike `v1ToV2`'s translations, and for the\n// reason the human's version decision names: a v2 document carrying anything\n// version 2 could not say must be **rejected** rather than promoted into a\n// document where it is legal. Nothing downstream can catch that — after the hop\n// the vocabulary is the current one — so the gate has to be here. The v3 → v4\n// hop (ADR 0015) and the v4 → v5 hop (ADR 0019) are the same kind of step, so\n// all three are built by one factory.\nimport type { ZodType } from 'zod'\nimport type { MigrationStep } from './migrate'\nimport { geometryExerciseV2Schema } from './exerciseV2.schema'\n\n/** The version the step below produces. */\nexport const v3SchemaVersion = 3\n\n/**\n * Just enough of a schema for the gate: the next version's parser, passed in\n * rather than imported to keep this module free of a cycle with\n * `exercise.schema.ts` — and small enough that a test can substitute a laxer\n * one and watch the gate react.\n */\nexport interface DocumentGate {\n safeParse(input: unknown): { success: boolean }\n}\n\ntype Projection = (document: Record<string, unknown>) => Record<string, unknown>\n\n/**\n * What each side of a gate is asked about, identity by default. The hops after\n * version 3 ask without `solution`: it is an attempt document that migrates and\n * validates on its own path (ADR 0015), so whether a stored solution parses must\n * never decide whether the exercise around it is newer vocabulary.\n */\nexport interface ExerciseStepProjection {\n frozen?: Projection\n next?: Projection\n}\n\nconst identity: Projection = (document) => document\n\ninterface FrozenIssue {\n code: string\n path: PropertyKey[]\n keys?: string[]\n}\n\n/** What the document said that the version it claims has no way to express. */\nfunction offendingPaths(issues: readonly FrozenIssue[]): string[] {\n const named = issues.flatMap((issue) =>\n issue.code === 'unrecognized_keys' && issue.keys\n ? issue.keys.map((key) => [...issue.path, key].join('.'))\n : [issue.path.join('.') || 'the document'],\n )\n return [...new Set(named)]\n}\n\n/**\n * An exercise hop that adds vocabulary and changes nothing it already had. The\n * refusal rule, stated exactly: **a document that is invalid at `from` and\n * valid at `from + 1` is refused.** That is what silent promotion means, and it\n * covers every way the next version can be wider — a new field, a new entity\n * kind, a new goal type, a new `allowedObjects` member, a new presentation\n * entry, a loosened value — without the step having to enumerate them or read\n * issue codes to guess which is which.\n *\n * A document that is invalid at **both** versions passes through untouched, so\n * an ordinary fault (a bad viewport, a dangling parent) is still reported by\n * `geometryExerciseSchema` at its own document path rather than refiled here as\n * one message under `schemaVersion`. It is rejected either way; only the quality\n * of the error differs, and the path is the better answer.\n *\n * `frozenSchema` must be a transcription of version `from` and `nextSchema` the\n * parser of version `from + 1` — frozen as well unless that is the current one,\n * because a current schema's version literal would never accept the promotion.\n * `projection` says what each side is shown (ADR 0019); it only narrows the\n * question, and the document that travels on is always the input.\n */\nexport function createIdentityExerciseStep(\n from: number,\n frozenSchema: ZodType,\n nextSchema: DocumentGate,\n projection: ExerciseStepProjection = {},\n): MigrationStep {\n const to = from + 1\n const { frozen = identity, next = identity } = projection\n return {\n from,\n to,\n migrate: (document) => {\n const parsed = frozenSchema.safeParse(frozen(document))\n if (\n !parsed.success &&\n nextSchema.safeParse({ ...next(document), schemaVersion: to }).success\n ) {\n throw new Error(\n `a version ${from} exercise cannot carry ${offendingPaths(parsed.error.issues).join(', ')}`,\n )\n }\n // The input document, not a parsed copy: the shape is unchanged, so the\n // stored values travel on untouched and `applyMigrations()` stamps the new\n // version.\n return { ...document }\n },\n }\n}\n\n/** The v2 → v3 hop, gated against the version 3 schema it is given. */\nexport function createGeometryExerciseV2ToV3(v3ExerciseSchema: DocumentGate): MigrationStep {\n return createIdentityExerciseStep(2, geometryExerciseV2Schema, v3ExerciseSchema)\n}\n","import { z } from 'zod'\nimport { geometryExerciseV2Schema } from './exerciseV2.schema'\n\nexport const v3ExerciseSchemaVersion = 3\n\n/**\n * The exercise document ADR 0013 froze at version 3, so the v3 → v4 step can\n * check what it was handed before promoting it (ADR 0015) — and so the v2 → v3\n * step still has a version 3 to ask once the current schema has moved past it.\n *\n * Version 3 is version 2 plus `grading` and nothing else, so it is built on the\n * frozen v2 transcription rather than transcribed a second time. `grading` is\n * written out here with nothing imported from the current vocabulary, for the\n * reason `exerciseV2.schema.ts` gives: a shared schema admits every later\n * addition to it. Like that schema this one carries no cross-reference\n * refinements and no issue messages; it only answers \"could version 3 have\n * said this?\".\n */\nexport const geometryExerciseV3Schema = geometryExerciseV2Schema.extend({\n schemaVersion: z.literal(v3ExerciseSchemaVersion),\n grading: z\n .object({ extraObjects: z.enum(['allow', 'reject']) })\n .strict()\n .optional(),\n})\n","import { z } from 'zod'\nimport { entityRecordSchema } from './entityDocument'\nimport {\n v2EntityDefinitionMembers,\n v2EntityKinds,\n v2GoalTypes,\n v2IdSchema,\n v2ObjectTypeNames,\n v2PresentationKeys,\n v2ToolNames,\n} from './exerciseV2.schema'\nimport { geometryExerciseV3Schema } from './exerciseV3.schema'\n\nexport const v4ExerciseSchemaVersion = 4\n\n/** Version 4's vocabularies: version 2's plus the angle M3.4 added (ADR 0010). */\nexport const v4EntityKinds = [...v2EntityKinds, 'angle'] as const\nexport const v4ObjectTypeNames = [...v2ObjectTypeNames, 'angle'] as const\nexport const v4ToolNames = v2ToolNames\nexport const v4GoalTypes = v2GoalTypes\nexport const v4PresentationKeys = [...v2PresentationKeys, 'measureLabel'] as const\n\n/**\n * The exercise document at version 4 as M3.4 left it, frozen by ADR 0019 so the\n * v4 → v5 step can ask \"could version 4 have said this?\" once the angle goals\n * make the current schema wider — and so the v3 → v4 step still has a version 4\n * to ask.\n *\n * Version 4 is version 3 plus `solution` (ADR 0015) and the angle — one entity\n * kind, one object type, one presentation key — and no goal type, so it is built\n * on the frozen v3 transcription with those written out and nothing imported\n * from the current vocabulary (see `exerciseV2.schema.ts`).\n *\n * `solution` is admitted and never judged. It is an attempt document that\n * migrates and validates on its own path (ADR 0015), a malformed one does not\n * make the exercise unloadable, and both gates that ask this schema hand it the\n * solution-free projection anyway (ADR 0019).\n */\nexport const geometryExerciseV4Schema = geometryExerciseV3Schema.extend({\n schemaVersion: z.literal(v4ExerciseSchemaVersion),\n entities: entityRecordSchema(\n z.union([\n ...v2EntityDefinitionMembers,\n z\n .object({\n kind: z.literal('angle'),\n parents: z.tuple([v2IdSchema, v2IdSchema, v2IdSchema]).readonly(),\n })\n .strict(),\n ]),\n ),\n presentation: entityRecordSchema(\n z\n .object({\n role: z.enum(['implicit', 'explicit']),\n label: z.string().min(1).optional(),\n measureLabel: z.enum(['degrees']).optional(),\n })\n .strict(),\n ),\n allowedObjects: z.array(z.enum(v4ObjectTypeNames)),\n solution: z.unknown().optional(),\n})\n","// The one-way v3 → v4 translation of a stored exercise (M3.I.3, ADR 0015).\n//\n// v4 adds one optional field, `solution` — the authored canonical attempt — and\n// changes nothing else, so the translation is the identity plus a version and a\n// migrated v3 exercise simply has no solution. The gate is the v2 → v3 one a\n// version later: a v3 document carrying `solution`, or anything else version 3\n// could not say, is refused rather than promoted, because a v3 reader would\n// reject it too.\n//\n// The gate is asymmetric (ADR 0019). The v3 side parses the raw document,\n// because carrying `solution` at all is what version 3 cannot say, whatever the\n// solution contains. The v4 side asks the frozen v4 transcription without the\n// solution: asking with it would let a v3 document with a *malformed* solution\n// be invalid at both versions, pass through, and then load cleanly on the\n// solution-free path.\nimport type { MigrationStep } from './migrate'\nimport { withoutSolution } from './exerciseProjection'\nimport { geometryExerciseV3Schema } from './exerciseV3.schema'\nimport { geometryExerciseV4Schema } from './exerciseV4.schema'\nimport { createIdentityExerciseStep, type DocumentGate } from './v2ToV3'\n\n/** The v3 → v4 hop, gated against the frozen version 4 unless a test substitutes one. */\nexport function createGeometryExerciseV3ToV4(\n v4ExerciseSchema: DocumentGate = geometryExerciseV4Schema,\n): MigrationStep {\n return createIdentityExerciseStep(3, geometryExerciseV3Schema, v4ExerciseSchema, {\n next: withoutSolution,\n })\n}\n","// The one-way v4 → v5 translation of a stored exercise (M3.6.a, ADR 0019).\n//\n// v5 adds the angle goals — `angleMeasure`, `angleBisector`, `givenAngle` — and\n// changes nothing else, so the translation is the identity plus a version. The\n// gate refuses a v4 document carrying an angle goal, or anything else version 4\n// could not say, because a v4 reader would reject it too.\n//\n// **Both sides ask without the solution.** Version 4 already carries\n// `solution`, and the solution migrates and validates on its own path (ADR\n// 0015): a raw frozen-v4 parse would reject a v4 exercise whose solution is an\n// older attempt version or malformed, the solution-free v5 parse would accept\n// it, and the gate would misreport the document as v5 vocabulary.\nimport type { MigrationStep } from './migrate'\nimport { withoutSolution } from './exerciseProjection'\nimport { geometryExerciseV4Schema } from './exerciseV4.schema'\nimport { createIdentityExerciseStep, type DocumentGate } from './v2ToV3'\n\n/**\n * The v4 → v5 hop, gated against the version 5 schema it is given — the current\n * one, passed in to keep this module out of a cycle with `exercise.schema.ts`.\n */\nexport function createGeometryExerciseV4ToV5(v5ExerciseSchema: DocumentGate): MigrationStep {\n return createIdentityExerciseStep(4, geometryExerciseV4Schema, v5ExerciseSchema, {\n frozen: withoutSolution,\n next: withoutSolution,\n })\n}\n","import { z } from 'zod'\nimport { entryOf } from '../geometry/entityRecord'\nimport { geometryIdSchema } from './identifier.schema'\nimport { objectTypeNameSchema } from './objectTypeName.schema'\nimport { mathViewportSchema } from './viewport.schema'\nimport { entityDefinitionSchema } from './entityDefinition.schema'\nimport { entityPresentationSchema } from './entityPresentation.schema'\nimport {\n entityDocumentIssues,\n entityIdListIssues,\n entityRecordSchema,\n isStudentDraggableGiven,\n} from './entityDocument'\nimport { geometryGoalSchema } from './goals/geometryGoal.schema'\nimport { declarationFor, type GoalAuthoringContext } from './goals/goalKindDeclaration'\nimport { applyMigrations, type MigrationOutcome, type MigrationStep } from './migrate'\nimport { geometryExerciseV1ToV2 } from './v1ToV2'\nimport { createGeometryExerciseV2ToV3 } from './v2ToV3'\nimport { createGeometryExerciseV3ToV4 } from './v3ToV4'\nimport { createGeometryExerciseV4ToV5 } from './v4ToV5'\nimport { geometryExerciseV3Schema } from './exerciseV3.schema'\nimport { geometryStateSchema } from './geometryState.schema'\n\nexport const toolNameSchema = z.enum(['ruler', 'setSquare', 'protractor'])\nexport type ToolName = z.infer<typeof toolNameSchema>\n\n// An exercise is stored and reloaded exactly as an attempt is, so it versions\n// and migrates the same way (M2.6.b). Raised to 2 at M2.6.c.1, with the\n// consumers that read what the step below produces: a stored v1 exercise is now\n// migrated on the way in and no longer has a schema of its own, because nothing\n// parses a v1 exercise — `geometryExerciseV1ToV2` reads the raw JSON.\n//\n// Raised to 3 at M3.H.6 for `grading` (ADR 0013). The human rejected adding the\n// field to v2: an older reader claims to support version 2 and would reject the\n// document anyway, so the version says out loud what the field means. **The\n// attempt document stays at 2** — the two versions are independent, and a v2\n// attempt is graded against a v3 exercise.\n//\n// Raised to 4 at M3.I.3 for `solution` (ADR 0015), for the same reason: a v3\n// reader must not be handed a v3 document it would reject.\n//\n// Raised to 5 at M3.6.a for the angle goals (ADR 0019); the angle entity itself\n// stayed in version 4.\nexport const latestGeometryExerciseVersion = 5\n\n// How strictly an attempt is graded for answer entities no goal needed\n// (RFC 0004 § Decision 6). `allow` is what every exercise did before v3, so\n// **absence means `allow`** and nothing materializes a default: an exercise that\n// states no policy is indistinguishable from one migrated from v2.\nexport const extraObjectPolicySchema = z.enum(['allow', 'reject'])\nexport type ExtraObjectPolicy = z.infer<typeof extraObjectPolicySchema>\n\n// Strict and with `extraObjects` required when the object is present: a\n// `grading: {}` that silently meant \"allow\" would be a second way to say\n// nothing, and a misspelled key inside it would be read as permissive.\nexport const exerciseGradingSchema = z.object({ extraObjects: extraObjectPolicySchema }).strict()\nexport type ExerciseGrading = z.infer<typeof exerciseGradingSchema>\n\n// The exercise document ADR 0008 froze. `givens[]` became the same `entities`\n// record the attempt uses since M2.6.c.2, so a given segment and a student\n// segment are the same shape and only the document they live in distinguishes\n// them. `label` lives in the `presentation` record and `draggable` became\n// `draggableEntityIds` — a list on the exercise and unrepresentable in an\n// attempt, so a tampered attempt cannot declare a pinned given draggable and\n// move the reference its own goals are measured against.\n//\n// `id`, `viewport`, `showGrid`, `allowedObjects`, `tools` and `goals` are\n// unchanged from v1, and the goals array migrates by identity.\n//\n// v3 adds `grading` and nothing else. An attempt cannot carry it — the\n// strictness policy is the author's, not the student's — and it is optional, so\n// a migrated v2 exercise is a v3 exercise with the field absent.\nexport const geometryExerciseSchema = z\n .object({\n schemaVersion: z.literal(latestGeometryExerciseVersion),\n id: geometryIdSchema,\n viewport: mathViewportSchema,\n showGrid: z.boolean().optional(),\n entities: entityRecordSchema(entityDefinitionSchema),\n presentation: entityRecordSchema(entityPresentationSchema),\n draggableEntityIds: z.array(geometryIdSchema),\n allowedObjects: z.array(objectTypeNameSchema),\n tools: z.array(toolNameSchema),\n goals: z.array(geometryGoalSchema),\n grading: exerciseGradingSchema.optional(),\n // v4's authored canonical attempt (ADR 0015), a current-version attempt\n // document. The loaders never hand it to this schema raw: a stored solution\n // may be an older attempt version, so it is migrated and checked against the\n // exercise on its own (`validateEmbeddedSolution()`), and Check and the\n // student canvas load the solution-free projection instead, so a broken\n // authored answer never disables them (RFC 0005 § Decision 4, option C).\n solution: geometryStateSchema.optional(),\n })\n .strict()\n .superRefine((exercise, context) => {\n // An exercise is self-contained — nothing in it may name an id it does not\n // declare — which is the half of the staging an attempt cannot have.\n for (const issue of entityDocumentIssues(exercise, { parentsMustBeDeclared: true })) {\n context.addIssue({ code: 'custom', path: issue.path, message: issue.message })\n }\n // Only a point can be dragged: dragging a segment would have to decide what\n // happens to its endpoints, which is a command, not a stored capability.\n for (const issue of entityIdListIssues(\n exercise.draggableEntityIds,\n 'draggableEntityIds',\n exercise,\n { pointsOnly: true },\n )) {\n context.addIssue({ code: 'custom', path: issue.path, message: issue.message })\n }\n\n // Each goal kind's own cross-reference rules, from its declaration (M2.5),\n // so this refinement stays the exercise-wide part. The entity record *is*\n // the authoring context, so nothing translates.\n const authoring: GoalAuthoringContext = {\n definitionOf: (id) => entryOf(exercise.entities, id),\n // The document being parsed is the authority a figure goal's movability\n // rule reads (ADR 0016): both fields it needs are already on it.\n isStudentDraggable: (id) => isStudentDraggableGiven(exercise, id),\n }\n const goalIds = new Set<string>()\n exercise.goals.forEach((goal, index) => {\n if (goalIds.has(goal.id)) {\n context.addIssue({\n code: 'custom',\n path: ['goals', index, 'id'],\n message: `duplicate goal id: ${goal.id}`,\n })\n }\n goalIds.add(goal.id)\n for (const issue of declarationFor(goal).crossReferenceIssues(goal, authoring)) {\n context.addIssue({\n code: 'custom',\n path: ['goals', index, ...issue.path],\n message: issue.message,\n })\n }\n })\n })\n\nexport type GeometryExercise = z.infer<typeof geometryExerciseSchema>\n\n// One entry per version hop. Each gate asks the next version's schema whether\n// the document it is refusing would have been accepted there — the definition\n// of a silent promotion. For v2 → v3 and v3 → v4 that is a frozen schema,\n// because the current one only accepts version 5; for v4 → v5 it is the current\n// schema, declared above, and passing it in keeps `v4ToV5.ts` out of an import\n// cycle. The steps after version 3 decide for themselves what each side is\n// shown of `solution` (ADR 0019).\nexport const geometryExerciseMigrations: readonly MigrationStep[] = [\n geometryExerciseV1ToV2,\n createGeometryExerciseV2ToV3(geometryExerciseV3Schema),\n createGeometryExerciseV3ToV4(),\n createGeometryExerciseV4ToV5(geometryExerciseSchema),\n]\n\nexport function parseGeometryExercise(input: unknown): GeometryExercise {\n return geometryExerciseSchema.parse(input)\n}\n\n// Brings a stored exercise up to the current version, the counterpart of\n// `migrateGeometryState()`. Structure is checked afterwards by the schema; this\n// only moves the shape forward, and it never mutates its input.\nexport function migrateGeometryExercise(input: unknown): MigrationOutcome {\n return applyMigrations(input, geometryExerciseMigrations, latestGeometryExerciseVersion)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./geometryState.schema-B5ccMKDa.cjs"),t=require("./goals-DLbmBZD8.cjs"),n=require("./exercise.schema-Oj5ZH-yO.cjs");function r(t,n){let r=e=>Object.prototype.hasOwnProperty.call(n.entities,e),i=new Set;for(let[r,a]of Object.entries(t.entities)){let t=e.M(n.entities,r);t&&e.w(n,r,t,a)===`ignored`&&i.add(r)}let a=t.answerEntityIds.filter(e=>!r(e)),o=Object.keys(t.presentation);return i.size===0&&a.length===t.answerEntityIds.length&&!o.some(r)?t:{...t,entities:Object.fromEntries(Object.entries(t.entities).filter(([e])=>!i.has(e))),presentation:Object.fromEntries(Object.entries(t.presentation).filter(([e])=>!r(e))),answerEntityIds:a}}function i(t,n){let i=e.i(t);if(!i.success)return{success:!1,data:null,errors:[{path:[`schemaVersion`],message:i.message}]};let a=e.n.safeParse(i.data);if(!a.success)return{success:!1,data:null,errors:a.error.issues.map(e=>({path:e.path.map(e=>typeof e==`symbol`?e.toString():e),message:e.message}))};let o=[],s=a.data;if(n){s=r(s,n);for(let t of e.T(s,n))o.push(t);for(let t of e.E(s,n.entities))o.push(t);for(let[e,t]of Object.entries(s.entities))t.kind!==`point`&&(n.allowedObjects.includes(t.kind)||o.push({path:[`entities`,e],message:`${t.kind} is not allowed by this exercise`}))}return o.length>0?{success:!1,data:null,errors:o}:{success:!0,data:s,errors:[]}}function a(e,t){try{return i(JSON.parse(e),t)}catch(e){return{success:!1,data:null,errors:[{path:[],message:e instanceof Error?e.message:`Invalid JSON syntax`}]}}}function o(e){return JSON.stringify(e)}function s(t,n,r){let i=t?.goals.find(e=>e.id===r);if(!i)return{constructions:{},points:{}};let a=Object.fromEntries(i.constructionIds.map(e=>[e,i.status])),o=new Set(i.pointIds);for(let[t,r]of Object.entries(n.entities))if(r.kind!==`point`&&e.M(a,t))for(let t of e.z(r))o.add(t);return{constructions:a,points:Object.fromEntries([...o].map(e=>[e,i.status]))}}function c(e){if(Array.isArray(e))return`[${e.map(e=>e===void 0?`null`:c(e)).join(`,`)}]`;if(typeof e==`object`&&e){let t=e;return`{${Object.keys(t).sort().filter(e=>t[e]!==void 0).map(e=>`${JSON.stringify(e)}:${c(t[e])}`).join(`,`)}}`}return JSON.stringify(e)}function l(e){let t=3735928559,n=1103547991;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);t=Math.imul(t^i,2654435761),n=Math.imul(n^i,1597334677)}return t=Math.imul(t^t>>>16,2246822507),t^=Math.imul(n^n>>>13,3266489909),n=Math.imul(n^n>>>16,2246822507),n^=Math.imul(t^t>>>13,3266489909),`${(n>>>0).toString(16).padStart(8,`0`)}${(t>>>0).toString(16).padStart(8,`0`)}`}function u(t){return l(c(e.u(t)))}function d(e){return l(c(e))}function f(){return{schemaVersion:2,entities:{},presentation:{},answerEntityIds:[]}}function p(e){let t=i(e);return t.success&&Object.keys(t.data.entities).length>0}function m(e){let[t,n,r,i]=e.viewport,a=[];for(let[o,s]of Object.entries(e.entities)){if(s.kind!==`point`||!(`at`in s))continue;let{x:e,y:c}=s.at;e>=t&&e<=r&&c>=n&&c<=i||a.push({path:[`entities`,o],message:`point ${o} is outside the viewport`})}return a.push(...h(e)),a}function h(e){if(!e.goals.some(e=>t.t(e)!==null))return[];let n=t.f(e,f()),r={exercise:e,points:n.points,scene:n},i=[];return e.goals.forEach((e,n)=>{t.t(e)?.satisfiedByFigure(e,r)===!0&&i.push({path:[`goals`,n],message:`goal ${e.id} is already satisfied by the authored figure`})}),i}function g(e){return e.map(e=>typeof e==`symbol`?e.description??e.toString():e)}function _(t){let r=n.o(t);if(!r.success)return{success:!1,errors:[{path:[`schemaVersion`],message:r.message}]};let i=r.data,a=n.i.safeParse(e.u(i));return a.success?{success:!0,data:a.data,solution:i.solution,warnings:m(a.data)}:{success:!1,errors:a.error.issues.map(e=>({path:g(e.path),message:e.message}))}}function v(e,t){let n=i(e,t);return n.success?n:{...n,errors:n.errors.map(e=>({...e,path:[`solution`,...e.path]}))}}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return i}});
|
|
2
|
+
//# sourceMappingURL=exerciseLoad-Db9Cigxi.cjs.map
|