@khanacademy/perseus 19.1.4 → 19.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/graphie.d.ts +9 -1
- package/dist/es/index.js +255 -122
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +261 -126
- package/dist/index.js.map +1 -1
- package/dist/interactive2/interactive-util.d.ts +1 -1
- package/dist/interactive2/movable-point-options.d.ts +5 -4
- package/dist/interactive2/movable.d.ts +90 -13
- package/dist/interactive2/types.d.ts +6 -0
- package/dist/util/graphie.d.ts +5 -0
- package/dist/widgets/expression.d.ts +4 -4
- package/package.json +11 -8
- package/.babelrc.js +0 -8
- package/.eslintrc.js +0 -12
- package/CHANGELOG.md +0 -1422
- package/src/__stories__/article-renderer.stories.tsx +0 -100
- package/src/__stories__/hints-renderer.stories.tsx +0 -55
- package/src/__stories__/server-item-renderer.stories.tsx +0 -44
- package/src/__testdata__/article-renderer.testdata.ts +0 -212
- package/src/__testdata__/graphie.testdata.ts +0 -51
- package/src/__testdata__/renderer.testdata.ts +0 -274
- package/src/__testdata__/server-item-renderer.testdata.ts +0 -171
- package/src/__tests__/__snapshots__/perseus-markdown.test.ts.snap +0 -507
- package/src/__tests__/__snapshots__/renderer.test.tsx.snap +0 -525
- package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +0 -285
- package/src/__tests__/a11y.test.ts +0 -303
- package/src/__tests__/article-renderer.test.tsx +0 -130
- package/src/__tests__/error-boundary.test.tsx +0 -76
- package/src/__tests__/extract-perseus-data.test.ts +0 -1027
- package/src/__tests__/init.test.ts +0 -10
- package/src/__tests__/jipt-paragraphs.test.ts +0 -32
- package/src/__tests__/mock-asset-loading-widget.tsx +0 -53
- package/src/__tests__/mock-widget.tsx +0 -33
- package/src/__tests__/perseus-markdown.test.ts +0 -764
- package/src/__tests__/renderability.test.ts +0 -480
- package/src/__tests__/renderer-api.test.tsx +0 -302
- package/src/__tests__/renderer.test.tsx +0 -1816
- package/src/__tests__/server-item-renderer.test.tsx +0 -582
- package/src/__tests__/test-items/image-item.ts +0 -24
- package/src/__tests__/test-items/input-number-1-item.ts +0 -26
- package/src/__tests__/test-items/input-number-2-item.ts +0 -38
- package/src/__tests__/test-items/table-item.ts +0 -29
- package/src/__tests__/tex-wrangler.test.ts +0 -82
- package/src/__tests__/util.test.ts +0 -40
- package/src/__tests__/widget-container.test.tsx +0 -126
- package/src/__tests__/widgets.test.ts +0 -91
- package/src/a11y.ts +0 -45
- package/src/all-widgets.ts +0 -9
- package/src/article-renderer.tsx +0 -237
- package/src/asset-context.ts +0 -30
- package/src/basic-widgets.ts +0 -16
- package/src/components/__stories__/button-group.stories.tsx +0 -55
- package/src/components/__stories__/fixed-to-responsive.stories.tsx +0 -141
- package/src/components/__stories__/graph.stories.tsx +0 -28
- package/src/components/__stories__/graphie.stories.tsx +0 -33
- package/src/components/__stories__/hud.stories.tsx +0 -35
- package/src/components/__stories__/icon.stories.tsx +0 -63
- package/src/components/__stories__/image-loader.stories.tsx +0 -63
- package/src/components/__stories__/info-tip.stories.tsx +0 -31
- package/src/components/__stories__/inline-icon.stories.tsx +0 -40
- package/src/components/__stories__/input-with-examples.stories.tsx +0 -53
- package/src/components/__stories__/lint.stories.tsx +0 -86
- package/src/components/__stories__/math-input.stories.tsx +0 -43
- package/src/components/__stories__/math-output.stories.tsx +0 -23
- package/src/components/__stories__/multi-button-group.stories.tsx +0 -66
- package/src/components/__stories__/number-input.stories.tsx +0 -41
- package/src/components/__stories__/prop-check-box.stories.tsx +0 -65
- package/src/components/__stories__/range-input.stories.tsx +0 -29
- package/src/components/__stories__/simple-keypad-input.stories.tsx +0 -27
- package/src/components/__stories__/sortable.stories.tsx +0 -77
- package/src/components/__stories__/stub-tag-editor.stories.tsx +0 -45
- package/src/components/__stories__/svg-image.stories.tsx +0 -74
- package/src/components/__stories__/tex.stories.tsx +0 -23
- package/src/components/__stories__/text-input.stories.tsx +0 -33
- package/src/components/__stories__/text-list-editor.stories.tsx +0 -32
- package/src/components/__stories__/tooltip.stories.tsx +0 -52
- package/src/components/__stories__/zoomable-tex.stories.tsx +0 -41
- package/src/components/__stories__/zoomable.stories.tsx +0 -49
- package/src/components/__testdata__/sorter.testdata.ts +0 -19
- package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +0 -163
- package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +0 -265
- package/src/components/__tests__/math-input.test.tsx +0 -147
- package/src/components/__tests__/number-input.test.tsx +0 -128
- package/src/components/__tests__/sortable.test.tsx +0 -269
- package/src/components/__tests__/sorter.test.tsx +0 -114
- package/src/components/__tests__/zoomable.test.tsx +0 -399
- package/src/components/button-group.tsx +0 -130
- package/src/components/constants.ts +0 -14
- package/src/components/fixed-to-responsive.tsx +0 -169
- package/src/components/graph.tsx +0 -444
- package/src/components/graphie-classes.ts +0 -153
- package/src/components/graphie-movables.ts +0 -338
- package/src/components/graphie.tsx +0 -392
- package/src/components/highlighting/highlightable-content.tsx +0 -240
- package/src/components/highlighting/highlights.ts +0 -207
- package/src/components/highlighting/ranges.ts +0 -304
- package/src/components/highlighting/types.ts +0 -73
- package/src/components/highlighting/ui/highlight-renderer.tsx +0 -172
- package/src/components/highlighting/ui/highlight-set-renderer.tsx +0 -185
- package/src/components/highlighting/ui/highlight-tooltip.tsx +0 -141
- package/src/components/highlighting/ui/highlighting-ui.tsx +0 -143
- package/src/components/highlighting/ui/selection-tracker.tsx +0 -186
- package/src/components/highlighting/ui/types.ts +0 -21
- package/src/components/highlighting/ui/util.ts +0 -165
- package/src/components/highlighting/word-indexer.tsx +0 -152
- package/src/components/hud.tsx +0 -167
- package/src/components/icon.tsx +0 -141
- package/src/components/image-loader.tsx +0 -177
- package/src/components/info-tip/info-tip.tsx +0 -144
- package/src/components/info-tip.tsx +0 -39
- package/src/components/inline-icon.tsx +0 -60
- package/src/components/input-with-examples.tsx +0 -249
- package/src/components/lint.tsx +0 -459
- package/src/components/math-input.tsx +0 -474
- package/src/components/math-output.tsx +0 -134
- package/src/components/multi-button-group.tsx +0 -135
- package/src/components/number-input.tsx +0 -249
- package/src/components/prop-check-box.tsx +0 -79
- package/src/components/range-input.tsx +0 -60
- package/src/components/simple-keypad-input.tsx +0 -88
- package/src/components/sortable.tsx +0 -958
- package/src/components/stub-tag-editor.tsx +0 -53
- package/src/components/svg-image.tsx +0 -779
- package/src/components/tex.tsx +0 -67
- package/src/components/text-input.tsx +0 -129
- package/src/components/text-list-editor.tsx +0 -166
- package/src/components/tooltip.tsx +0 -410
- package/src/components/visibility-observer/__stories__/visibility-observer.stories.tsx +0 -141
- package/src/components/visibility-observer/create-visibility-observer.ts +0 -108
- package/src/components/visibility-observer/get-scroll-parent.ts +0 -46
- package/src/components/visibility-observer/visibility-observer.tsx +0 -124
- package/src/components/zoomable-tex.tsx +0 -78
- package/src/components/zoomable.tsx +0 -304
- package/src/components.ts +0 -15
- package/src/definition-context.tsx +0 -59
- package/src/dependencies.ts +0 -40
- package/src/error-boundary.tsx +0 -70
- package/src/extra-widgets.ts +0 -75
- package/src/hint-renderer.tsx +0 -151
- package/src/hints-renderer.tsx +0 -372
- package/src/icon-paths.ts +0 -119
- package/src/index.ts +0 -171
- package/src/init.ts +0 -56
- package/src/interaction-tracker.ts +0 -62
- package/src/interactive2/__tests__/movable-mock.ts +0 -43
- package/src/interactive2/__tests__/movable-point.test.ts +0 -144
- package/src/interactive2/__tests__/movable.test.ts +0 -157
- package/src/interactive2/interactive-util.test.ts +0 -93
- package/src/interactive2/interactive-util.ts +0 -159
- package/src/interactive2/movable-helper-methods.ts +0 -166
- package/src/interactive2/movable-line-options.ts +0 -419
- package/src/interactive2/movable-line.ts +0 -307
- package/src/interactive2/movable-point-options.ts +0 -212
- package/src/interactive2/movable-point.tsx +0 -585
- package/src/interactive2/movable-polygon-options.ts +0 -389
- package/src/interactive2/movable-polygon.ts +0 -360
- package/src/interactive2/movable.ts +0 -279
- package/src/interactive2/objective_.ts +0 -79
- package/src/interactive2/types.ts +0 -2
- package/src/interactive2/wrapped-defaults.ts +0 -87
- package/src/interactive2/wrapped-ellipse.ts +0 -94
- package/src/interactive2/wrapped-line.ts +0 -116
- package/src/interactive2/wrapped-path.ts +0 -51
- package/src/interactive2.ts +0 -70
- package/src/item-version.ts +0 -10
- package/src/jipt-paragraphs.ts +0 -49
- package/src/jquery.mobile.vmouse.js +0 -545
- package/src/loading-context.ts +0 -21
- package/src/logging/log.test.ts +0 -39
- package/src/logging/log.ts +0 -97
- package/src/mixins/__tests__/widget-prop-denylist.test.ts +0 -21
- package/src/mixins/changeable.ts +0 -133
- package/src/mixins/editor-jsonify.ts +0 -13
- package/src/mixins/widget-jsonify-deprecated.ts +0 -23
- package/src/mixins/widget-prop-denylist.ts +0 -48
- package/src/multi-items/__stories__/multi-renderer.stories.tsx +0 -83
- package/src/multi-items/__testdata__/multi-renderer.testdata.ts +0 -172
- package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +0 -1164
- package/src/multi-items/__tests__/items.test.ts +0 -240
- package/src/multi-items/__tests__/multi-renderer.test.tsx +0 -914
- package/src/multi-items/__tests__/prop-type-builders.test.ts +0 -133
- package/src/multi-items/__tests__/shapes.test.ts +0 -43
- package/src/multi-items/__tests__/trees.test.ts +0 -317
- package/src/multi-items/item-types.ts +0 -56
- package/src/multi-items/items.ts +0 -176
- package/src/multi-items/multi-renderer.tsx +0 -569
- package/src/multi-items/prop-type-builders.ts +0 -106
- package/src/multi-items/shape-types.ts +0 -52
- package/src/multi-items/shapes.ts +0 -52
- package/src/multi-items/tree-types.ts +0 -47
- package/src/multi-items/trees.ts +0 -360
- package/src/multi-items.ts +0 -75
- package/src/perseus-api.tsx +0 -188
- package/src/perseus-env.ts +0 -27
- package/src/perseus-error.ts +0 -17
- package/src/perseus-markdown.tsx +0 -405
- package/src/perseus-types.ts +0 -1366
- package/src/perseus-version.ts +0 -9
- package/src/question-paragraph.tsx +0 -34
- package/src/renderability.ts +0 -109
- package/src/renderer.tsx +0 -2000
- package/src/server-item-renderer.tsx +0 -495
- package/src/sigfigs.ts +0 -490
- package/src/styles/articles.less +0 -749
- package/src/styles/constants.ts +0 -94
- package/src/styles/global-constants.ts +0 -343
- package/src/styles/global-styles.ts +0 -306
- package/src/styles/khan-exercise.css +0 -1468
- package/src/styles/media-queries.ts +0 -47
- package/src/styles/perseus-renderer.less +0 -732
- package/src/styles/shared.ts +0 -130
- package/src/styles/util.less +0 -47
- package/src/styles/variables.boostrap.less +0 -277
- package/src/styles/variables.less +0 -56
- package/src/styles/variables.shared.less +0 -340
- package/src/styles/widgets/categorizer.less +0 -38
- package/src/styles/widgets/dropdown.less +0 -3
- package/src/styles/widgets/expression.less +0 -65
- package/src/styles/widgets/graded-group.less +0 -36
- package/src/styles/widgets/grapher.less +0 -12
- package/src/styles/widgets/group.less +0 -19
- package/src/styles/widgets/image.less +0 -54
- package/src/styles/widgets/interactive-graph.less +0 -64
- package/src/styles/widgets/label-image.less +0 -57
- package/src/styles/widgets/matcher.less +0 -8
- package/src/styles/widgets/matrix.less +0 -126
- package/src/styles/widgets/measurer.less +0 -20
- package/src/styles/widgets/orderer.less +0 -98
- package/src/styles/widgets/passage.less +0 -154
- package/src/styles/widgets/plotter.less +0 -31
- package/src/styles/widgets/radio.less +0 -58
- package/src/styles/widgets/reaction-diagram.less +0 -35
- package/src/styles/widgets/sequence.less +0 -5
- package/src/styles/widgets/sortable.less +0 -113
- package/src/styles/widgets/table.less +0 -57
- package/src/styles/widgets/unit.less +0 -15
- package/src/tex-wrangler.ts +0 -182
- package/src/translation-linter.ts +0 -126
- package/src/traversal.ts +0 -138
- package/src/types.ts +0 -513
- package/src/util/a11y.ts +0 -23
- package/src/util/answer-types.test.ts +0 -114
- package/src/util/answer-types.ts +0 -876
- package/src/util/colors.ts +0 -93
- package/src/util/drawing-transform.test.ts +0 -67
- package/src/util/drawing-transform.ts +0 -102
- package/src/util/extract-perseus-data.ts +0 -539
- package/src/util/fix-passage-refs.ts +0 -121
- package/src/util/geometry.test.ts +0 -75
- package/src/util/geometry.ts +0 -312
- package/src/util/graph-bounds.ts +0 -23
- package/src/util/graph-utils.ts +0 -15
- package/src/util/graphie.test.ts +0 -1277
- package/src/util/graphie.ts +0 -1566
- package/src/util/interactive.ts +0 -4172
- package/src/util/interval.ts +0 -4
- package/src/util/katex-preprocess.ts +0 -14
- package/src/util/math.test.ts +0 -11
- package/src/util/math.ts +0 -294
- package/src/util/mobile-native-utils.test.ts +0 -22
- package/src/util/mobile-native-utils.ts +0 -12
- package/src/util/parse-perseus-json.test.ts +0 -10
- package/src/util/parse-perseus-json.ts +0 -13
- package/src/util/react-render.tsx +0 -27
- package/src/util/register-all-widgets-for-testing.ts +0 -13
- package/src/util/scroll-utils.ts +0 -155
- package/src/util/sizing-utils.ts +0 -46
- package/src/util/tex.ts +0 -73
- package/src/util/url-utils.ts +0 -34
- package/src/util.graphie.test.ts +0 -45
- package/src/util.graphie.ts +0 -59
- package/src/util.ts +0 -966
- package/src/version.ts +0 -10
- package/src/widget-container.tsx +0 -199
- package/src/widgets/__stories__/categorizer.stories.tsx +0 -14
- package/src/widgets/__stories__/cs-program.stories.tsx +0 -14
- package/src/widgets/__stories__/definition.stories.tsx +0 -114
- package/src/widgets/__stories__/dropdown.stories.tsx +0 -14
- package/src/widgets/__stories__/explanation.stories.tsx +0 -18
- package/src/widgets/__stories__/expression.stories.tsx +0 -145
- package/src/widgets/__stories__/graded-group-set.stories.tsx +0 -31
- package/src/widgets/__stories__/graded-group.stories.tsx +0 -31
- package/src/widgets/__stories__/grapher.stories.tsx +0 -46
- package/src/widgets/__stories__/group.stories.tsx +0 -14
- package/src/widgets/__stories__/iframe.stories.tsx +0 -14
- package/src/widgets/__stories__/image.stories.tsx +0 -85
- package/src/widgets/__stories__/input-number.stories.tsx +0 -101
- package/src/widgets/__stories__/interaction.stories.tsx +0 -14
- package/src/widgets/__stories__/interactive-graph.stories.tsx +0 -60
- package/src/widgets/__stories__/label-image.stories.tsx +0 -130
- package/src/widgets/__stories__/matcher.stories.tsx +0 -14
- package/src/widgets/__stories__/matrix.stories.tsx +0 -14
- package/src/widgets/__stories__/number-line.stories.tsx +0 -14
- package/src/widgets/__stories__/numeric-input.stories.tsx +0 -105
- package/src/widgets/__stories__/orderer.stories.tsx +0 -18
- package/src/widgets/__stories__/passage-ref.stories.tsx +0 -33
- package/src/widgets/__stories__/passage.stories.tsx +0 -39
- package/src/widgets/__stories__/plotter.stories.tsx +0 -27
- package/src/widgets/__stories__/radio.stories.tsx +0 -86
- package/src/widgets/__stories__/random-widgets.stories.tsx +0 -59
- package/src/widgets/__stories__/sorter.stories.tsx +0 -14
- package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +0 -66
- package/src/widgets/__stories__/unit.stories.tsx +0 -28
- package/src/widgets/__stories__/video-transcript-link.stories.tsx +0 -23
- package/src/widgets/__stories__/video.stories.tsx +0 -22
- package/src/widgets/__testdata__/base-radio.testdata.ts +0 -21
- package/src/widgets/__testdata__/categorizer.testdata.ts +0 -89
- package/src/widgets/__testdata__/cs-program.testdata.ts +0 -27
- package/src/widgets/__testdata__/dropdown.testdata.ts +0 -71
- package/src/widgets/__testdata__/explanation.testdata.ts +0 -85
- package/src/widgets/__testdata__/expression.testdata.ts +0 -198
- package/src/widgets/__testdata__/graded-group-set.testdata.ts +0 -356
- package/src/widgets/__testdata__/graded-group.testdata.ts +0 -77
- package/src/widgets/__testdata__/grapher.testdata.ts +0 -374
- package/src/widgets/__testdata__/group.testdata.ts +0 -153
- package/src/widgets/__testdata__/iframe.testdata.ts +0 -35
- package/src/widgets/__testdata__/image.testdata.ts +0 -36
- package/src/widgets/__testdata__/input-number.testdata.ts +0 -72
- package/src/widgets/__testdata__/interaction.testdata.ts +0 -262
- package/src/widgets/__testdata__/interactive-graph-random.testdata.ts +0 -269
- package/src/widgets/__testdata__/interactive-graph.testdata.ts +0 -644
- package/src/widgets/__testdata__/label-image.testdata.ts +0 -308
- package/src/widgets/__testdata__/matcher.testdata.ts +0 -33
- package/src/widgets/__testdata__/matrix.testdata.ts +0 -28
- package/src/widgets/__testdata__/number-line.testdata.ts +0 -30
- package/src/widgets/__testdata__/numeric-input.testdata.ts +0 -265
- package/src/widgets/__testdata__/orderer.testdata.ts +0 -123
- package/src/widgets/__testdata__/passage-ref.testdata.ts +0 -101
- package/src/widgets/__testdata__/passage.testdata.ts +0 -95
- package/src/widgets/__testdata__/plotter.testdata.ts +0 -36
- package/src/widgets/__testdata__/radio.testdata.ts +0 -324
- package/src/widgets/__testdata__/randomizers.ts +0 -51
- package/src/widgets/__testdata__/sorter.testdata.ts +0 -19
- package/src/widgets/__testdata__/video.testdata.ts +0 -61
- package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +0 -940
- package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +0 -67
- package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +0 -97
- package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +0 -133
- package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +0 -425
- package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +0 -729
- package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +0 -339
- package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +0 -801
- package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +0 -2673
- package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +0 -1211
- package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +0 -61
- package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +0 -378
- package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +0 -495
- package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +0 -292
- package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +0 -2889
- package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +0 -883
- package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +0 -514
- package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +0 -814
- package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +0 -470
- package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +0 -243
- package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +0 -434
- package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +0 -1956
- package/src/widgets/__tests__/__snapshots__/plotter.test.tsx.snap +0 -827
- package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +0 -4237
- package/src/widgets/__tests__/__snapshots__/unit.test.tsx.snap +0 -20
- package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +0 -153
- package/src/widgets/__tests__/categorizer.test.ts +0 -203
- package/src/widgets/__tests__/cs-program.test.ts +0 -43
- package/src/widgets/__tests__/definition.test.ts +0 -136
- package/src/widgets/__tests__/dropdown.test.ts +0 -105
- package/src/widgets/__tests__/explanation.test.ts +0 -198
- package/src/widgets/__tests__/expression-mobile.test.tsx +0 -363
- package/src/widgets/__tests__/expression.test.tsx +0 -484
- package/src/widgets/__tests__/graded-group-set-jipt.test.ts +0 -30
- package/src/widgets/__tests__/graded-group-set.test.ts +0 -288
- package/src/widgets/__tests__/graded-group.test.ts +0 -232
- package/src/widgets/__tests__/grapher.cypress.ts +0 -576
- package/src/widgets/__tests__/grapher.test.ts +0 -33
- package/src/widgets/__tests__/group.test.tsx +0 -510
- package/src/widgets/__tests__/iframe.test.ts +0 -45
- package/src/widgets/__tests__/image.test.ts +0 -62
- package/src/widgets/__tests__/input-number.test.ts +0 -354
- package/src/widgets/__tests__/interaction.test.ts +0 -31
- package/src/widgets/__tests__/interactive-graph.cypress.ts +0 -815
- package/src/widgets/__tests__/interactive-graph.test.ts +0 -106
- package/src/widgets/__tests__/matcher.test.tsx +0 -176
- package/src/widgets/__tests__/matrix.test.ts +0 -82
- package/src/widgets/__tests__/number-line.test.ts +0 -79
- package/src/widgets/__tests__/numeric-input.test.ts +0 -575
- package/src/widgets/__tests__/orderer.test.ts +0 -73
- package/src/widgets/__tests__/passage-ref.test.ts +0 -168
- package/src/widgets/__tests__/passage.test.tsx +0 -224
- package/src/widgets/__tests__/plotter.test.tsx +0 -69
- package/src/widgets/__tests__/radio/base-radio.test.tsx +0 -470
- package/src/widgets/__tests__/radio/choice-icon.test.tsx +0 -90
- package/src/widgets/__tests__/radio/choice.test.tsx +0 -310
- package/src/widgets/__tests__/radio/focus-ring.test.tsx +0 -22
- package/src/widgets/__tests__/radio/option-status.test.tsx +0 -77
- package/src/widgets/__tests__/radio.test.ts +0 -807
- package/src/widgets/__tests__/randomizers.test.ts +0 -53
- package/src/widgets/__tests__/renderQuestion.tsx +0 -101
- package/src/widgets/__tests__/unit.test.tsx +0 -168
- package/src/widgets/__tests__/video.test.ts +0 -69
- package/src/widgets/categorizer.tsx +0 -344
- package/src/widgets/cs-program.tsx +0 -227
- package/src/widgets/definition.tsx +0 -121
- package/src/widgets/deprecated-standin/__stories__/deprecated-standin.stories.tsx +0 -30
- package/src/widgets/deprecated-standin/__tests__/__snapshots__/deprecated-standin.test.ts.snap +0 -70
- package/src/widgets/deprecated-standin/__tests__/deprecated-standin.test.ts +0 -93
- package/src/widgets/deprecated-standin/index.tsx +0 -58
- package/src/widgets/dropdown.tsx +0 -142
- package/src/widgets/explanation.tsx +0 -317
- package/src/widgets/expression.tsx +0 -707
- package/src/widgets/graded-group-answer-bar.tsx +0 -142
- package/src/widgets/graded-group-set.tsx +0 -338
- package/src/widgets/graded-group.tsx +0 -471
- package/src/widgets/grapher/util.tsx +0 -799
- package/src/widgets/grapher.tsx +0 -660
- package/src/widgets/group.tsx +0 -195
- package/src/widgets/iframe.tsx +0 -195
- package/src/widgets/image.tsx +0 -312
- package/src/widgets/input-number.tsx +0 -412
- package/src/widgets/interaction/arrow-picker.tsx +0 -38
- package/src/widgets/interaction/color-picker.tsx +0 -69
- package/src/widgets/interaction/dash-picker.tsx +0 -45
- package/src/widgets/interaction/element-container.tsx +0 -100
- package/src/widgets/interaction.tsx +0 -826
- package/src/widgets/interactive-graph.tsx +0 -2597
- package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -91
- package/src/widgets/label-image/__stories__/answer-pill.stories.tsx +0 -62
- package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -171
- package/src/widgets/label-image/__tests__/answer-pill.test.tsx +0 -75
- package/src/widgets/label-image/__tests__/hide-answers-toggle.test.tsx +0 -39
- package/src/widgets/label-image/answer-choices.tsx +0 -88
- package/src/widgets/label-image/answer-pill.tsx +0 -103
- package/src/widgets/label-image/hide-answers-toggle.tsx +0 -40
- package/src/widgets/label-image/marker.tsx +0 -268
- package/src/widgets/label-image/strings.ts +0 -5
- package/src/widgets/label-image/types.ts +0 -27
- package/src/widgets/label-image.test.ts +0 -928
- package/src/widgets/label-image.tsx +0 -819
- package/src/widgets/lights-puzzle.tsx +0 -359
- package/src/widgets/matcher.tsx +0 -298
- package/src/widgets/matrix.tsx +0 -634
- package/src/widgets/measurer.tsx +0 -222
- package/src/widgets/molecule/__tests__/layout.test.ts +0 -162
- package/src/widgets/molecule/__tests__/parser.test.ts +0 -155
- package/src/widgets/molecule/molecule-drawing.ts +0 -173
- package/src/widgets/molecule/molecule-layout.ts +0 -362
- package/src/widgets/molecule/smiles-parser.ts +0 -296
- package/src/widgets/molecule.tsx +0 -172
- package/src/widgets/number-line.tsx +0 -862
- package/src/widgets/numeric-input.tsx +0 -576
- package/src/widgets/orderer.tsx +0 -786
- package/src/widgets/passage/__tests__/passage-markdown.test.ts +0 -376
- package/src/widgets/passage/passage-markdown.tsx +0 -475
- package/src/widgets/passage-ref-target.tsx +0 -76
- package/src/widgets/passage-ref.tsx +0 -213
- package/src/widgets/passage.tsx +0 -582
- package/src/widgets/plotter.tsx +0 -1194
- package/src/widgets/radio/__stories__/base-radio.stories.tsx +0 -196
- package/src/widgets/radio/__stories__/choice-icon.stories.tsx +0 -166
- package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +0 -40
- package/src/widgets/radio/__stories__/choice.stories.tsx +0 -137
- package/src/widgets/radio/__stories__/focus-ring.stories.tsx +0 -43
- package/src/widgets/radio/__stories__/option-status.stories.tsx +0 -103
- package/src/widgets/radio/base-radio.tsx +0 -511
- package/src/widgets/radio/choice-a11y-text.ts +0 -61
- package/src/widgets/radio/choice-icon/choice-icon.tsx +0 -218
- package/src/widgets/radio/choice-icon/cross-out-line.tsx +0 -51
- package/src/widgets/radio/choice-icon/shared-styles.ts +0 -15
- package/src/widgets/radio/choice-none-above.tsx +0 -56
- package/src/widgets/radio/choice.jsx.fixture.ts +0 -45
- package/src/widgets/radio/choice.tsx +0 -359
- package/src/widgets/radio/focus-ring.tsx +0 -57
- package/src/widgets/radio/option-status.tsx +0 -98
- package/src/widgets/radio/util.test.ts +0 -18
- package/src/widgets/radio/util.ts +0 -31
- package/src/widgets/radio/widget.tsx +0 -520
- package/src/widgets/radio.ts +0 -157
- package/src/widgets/reaction-diagram.tsx +0 -144
- package/src/widgets/sequence.tsx +0 -142
- package/src/widgets/simulator.tsx +0 -829
- package/src/widgets/sorter.tsx +0 -155
- package/src/widgets/table.tsx +0 -393
- package/src/widgets/unit.tsx +0 -374
- package/src/widgets/video-transcript-link.test.tsx +0 -213
- package/src/widgets/video-transcript-link.tsx +0 -84
- package/src/widgets/video.tsx +0 -135
- package/src/widgets.ts +0 -489
- package/src/zoom.ts +0 -555
- package/tsconfig-build.json +0 -26
- package/tsconfig-build.tsbuildinfo +0 -1
package/src/util/answer-types.ts
DELETED
|
@@ -1,876 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-useless-escape */
|
|
2
|
-
import * as KAS from "@khanacademy/kas";
|
|
3
|
-
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
4
|
-
import $ from "jquery";
|
|
5
|
-
import _ from "underscore";
|
|
6
|
-
|
|
7
|
-
import {Errors} from "../logging/log";
|
|
8
|
-
import {PerseusError} from "../perseus-error";
|
|
9
|
-
|
|
10
|
-
import KhanMath from "./math";
|
|
11
|
-
|
|
12
|
-
const MAXERROR_EPSILON = Math.pow(2, -42);
|
|
13
|
-
|
|
14
|
-
type Guess = any;
|
|
15
|
-
type Predicate = any;
|
|
16
|
-
|
|
17
|
-
// TOOD(kevinb): Figure out how this relates to KEScore in
|
|
18
|
-
// perseus-all-package/types.js and see if there's a way to
|
|
19
|
-
// unify these types.
|
|
20
|
-
type Score = {
|
|
21
|
-
empty: boolean;
|
|
22
|
-
correct: boolean;
|
|
23
|
-
message: string | null | undefined;
|
|
24
|
-
suppressAlmostThere?: boolean | null | undefined;
|
|
25
|
-
guess: Guess;
|
|
26
|
-
// It would be nice if we could ungraded required
|
|
27
|
-
ungraded?: boolean;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const errors = {
|
|
31
|
-
APPROXIMATED_PI_ERROR: i18n._(
|
|
32
|
-
"Your answer is close, but you may " +
|
|
33
|
-
"have approximated pi. Enter your " +
|
|
34
|
-
"answer as a multiple of pi, like " +
|
|
35
|
-
"<code>12\\ \\text{pi}</code> or " +
|
|
36
|
-
"<code>2/3\\ \\text{pi}</code>",
|
|
37
|
-
) as string,
|
|
38
|
-
EXTRA_SYMBOLS_ERROR: i18n._(
|
|
39
|
-
"We could not understand your " +
|
|
40
|
-
"answer. Please check your answer for extra " +
|
|
41
|
-
"text or symbols.",
|
|
42
|
-
) as string,
|
|
43
|
-
NEEDS_TO_BE_SIMPLFIED_ERROR: i18n._(
|
|
44
|
-
"Your answer is almost correct, " + "but it needs to be simplified.",
|
|
45
|
-
) as string,
|
|
46
|
-
MISSING_PERCENT_ERROR: i18n._(
|
|
47
|
-
"Your answer is almost correct, " +
|
|
48
|
-
"but it is missing a " +
|
|
49
|
-
"<code>\\%</code> at the end.",
|
|
50
|
-
) as string,
|
|
51
|
-
MULTIPLICATION_SIGN_ERROR: i18n._(
|
|
52
|
-
"I'm a computer. I only understand " +
|
|
53
|
-
"multiplication if you use an asterisk " +
|
|
54
|
-
"(*) as the multiplication sign.",
|
|
55
|
-
) as string,
|
|
56
|
-
WRONG_CASE_ERROR: i18n._(
|
|
57
|
-
"Your answer includes use of a variable with the wrong case.",
|
|
58
|
-
) as string,
|
|
59
|
-
WRONG_LETTER_ERROR: i18n._(
|
|
60
|
-
"Your answer includes a wrong variable letter.",
|
|
61
|
-
) as string,
|
|
62
|
-
} as const;
|
|
63
|
-
|
|
64
|
-
/*
|
|
65
|
-
* Answer types
|
|
66
|
-
*
|
|
67
|
-
* Utility for creating answerable questions displayed in exercises
|
|
68
|
-
*
|
|
69
|
-
* Different answer types produce different kinds of input displays, and do
|
|
70
|
-
* different kinds of checking on the solutions.
|
|
71
|
-
*
|
|
72
|
-
* Each of the objects contain two functions, setup and createValidator.
|
|
73
|
-
*
|
|
74
|
-
* The setup function takes a solutionarea and solution, and performs setup
|
|
75
|
-
* within the solutionarea, and then returns an object which contains:
|
|
76
|
-
*
|
|
77
|
-
* answer: a function which, when called, will retrieve the current answer from
|
|
78
|
-
* the solutionarea, which can then be validated using the validator
|
|
79
|
-
* function
|
|
80
|
-
* validator: a function returned from the createValidator function (defined
|
|
81
|
-
* below)
|
|
82
|
-
* solution: the correct answer to the problem
|
|
83
|
-
* showGuess: a function which, when given a guess, shows the guess within the
|
|
84
|
-
* provided solutionarea
|
|
85
|
-
* showGuessCustom: a function which displays parts of a guess that are not
|
|
86
|
-
* within the solutionarea; currently only used for custom
|
|
87
|
-
* answers
|
|
88
|
-
*
|
|
89
|
-
* The createValidator function only takes a solution, and it returns a
|
|
90
|
-
* function which can be used to validate an answer.
|
|
91
|
-
*
|
|
92
|
-
* The resulting validator function returns:
|
|
93
|
-
* - true: if the answer is fully correct
|
|
94
|
-
* - false: if the answer is incorrect
|
|
95
|
-
* - "" (the empty string): if no answer has been provided (e.g. the answer box
|
|
96
|
-
* is left unfilled)
|
|
97
|
-
* - a string: if there is some slight error
|
|
98
|
-
*
|
|
99
|
-
* In most cases, setup and createValidator don't really need the solution DOM
|
|
100
|
-
* element so we have setupFunctional and createValidatorFunctional for them
|
|
101
|
-
* which take only $solution.text() and $solution.data(). This makes it easier
|
|
102
|
-
* to reuse specific answer types.
|
|
103
|
-
*
|
|
104
|
-
* TODO(alpert): Think of a less-absurd name for createValidatorFunctional.
|
|
105
|
-
*
|
|
106
|
-
*/
|
|
107
|
-
|
|
108
|
-
const KhanAnswerTypes = {
|
|
109
|
-
/*
|
|
110
|
-
* predicate answer type
|
|
111
|
-
*
|
|
112
|
-
* performs simple predicate-based checking of a numeric solution, with
|
|
113
|
-
* different kinds of number formats
|
|
114
|
-
*
|
|
115
|
-
* Uses the data-forms option on the solution to choose which number formats
|
|
116
|
-
* are acceptable. Available data-forms:
|
|
117
|
-
*
|
|
118
|
-
* - integer: 3
|
|
119
|
-
* - proper: 3/5
|
|
120
|
-
* - improper: 5/3
|
|
121
|
-
* - pi: 3 pi
|
|
122
|
-
* - log: log(5)
|
|
123
|
-
* - percent: 15%
|
|
124
|
-
* - mixed: 1 1/3
|
|
125
|
-
* - decimal: 1.7
|
|
126
|
-
*
|
|
127
|
-
* The solution should be a predicate of the form:
|
|
128
|
-
*
|
|
129
|
-
* function(guess, maxError) {
|
|
130
|
-
* return abs(guess - 3) < maxError;
|
|
131
|
-
* }
|
|
132
|
-
*
|
|
133
|
-
*/
|
|
134
|
-
predicate: {
|
|
135
|
-
defaultForms: "integer, proper, improper, mixed, decimal",
|
|
136
|
-
createValidatorFunctional: function (
|
|
137
|
-
predicate: Predicate,
|
|
138
|
-
options: any,
|
|
139
|
-
): (arg1: Guess) => Score {
|
|
140
|
-
// Extract the options from the given solution object
|
|
141
|
-
options = _.extend(
|
|
142
|
-
{
|
|
143
|
-
simplify: "required",
|
|
144
|
-
ratio: false,
|
|
145
|
-
forms: KhanAnswerTypes.predicate.defaultForms,
|
|
146
|
-
},
|
|
147
|
-
options,
|
|
148
|
-
);
|
|
149
|
-
let acceptableForms;
|
|
150
|
-
// this is maintaining backwards compatibility
|
|
151
|
-
// TODO(merlob) fix all places that depend on this, then delete
|
|
152
|
-
if (!_.isArray(options.forms)) {
|
|
153
|
-
acceptableForms = options.forms.split(/\s*,\s*/);
|
|
154
|
-
} else {
|
|
155
|
-
acceptableForms = options.forms;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// TODO(jack): remove options.inexact in favor of options.maxError
|
|
159
|
-
if (options.inexact === undefined) {
|
|
160
|
-
// If we aren't allowing inexact, ensure that we don't have a
|
|
161
|
-
// large maxError as well.
|
|
162
|
-
options.maxError = 0;
|
|
163
|
-
}
|
|
164
|
-
// Allow a small tolerance on maxError, to avoid numerical
|
|
165
|
-
// representation issues (2.3 should be correct for a solution of
|
|
166
|
-
// 2.45 with maxError=0.15).
|
|
167
|
-
options.maxError = +options.maxError + MAXERROR_EPSILON;
|
|
168
|
-
|
|
169
|
-
// If percent is an acceptable form, make sure it's the last one
|
|
170
|
-
// in the list so we don't prematurely complain about not having
|
|
171
|
-
// a percent sign when the user entered the correct answer in a
|
|
172
|
-
// different form (such as a decimal or fraction)
|
|
173
|
-
if (_.contains(acceptableForms, "percent")) {
|
|
174
|
-
acceptableForms = _.without(acceptableForms, "percent");
|
|
175
|
-
acceptableForms.push("percent");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Take text looking like a fraction, and turn it into a number
|
|
179
|
-
const fractionTransformer = function (text) {
|
|
180
|
-
text = text
|
|
181
|
-
// Replace unicode minus sign with hyphen
|
|
182
|
-
.replace(/\u2212/, "-")
|
|
183
|
-
// Remove space after +, -
|
|
184
|
-
.replace(/([+-])\s+/g, "$1")
|
|
185
|
-
// Remove leading/trailing whitespace
|
|
186
|
-
.replace(/(^\s*)|(\s*$)/gi, "");
|
|
187
|
-
|
|
188
|
-
// Extract numerator and denominator
|
|
189
|
-
const match = text.match(/^([+-]?\d+)\s*\/\s*([+-]?\d+)$/);
|
|
190
|
-
// Fractions are represented as "-\frac{numerator}{denominator}"
|
|
191
|
-
// in Mobile device input instead of "numerator/denominator" as
|
|
192
|
-
// in web-browser.
|
|
193
|
-
const mobileDeviceMatch = text.match(
|
|
194
|
-
/^([+-]?)\\frac\{([+-]?\d+)\}\{([+-]?\d+)\}$/,
|
|
195
|
-
);
|
|
196
|
-
const parsedInt = parseInt(text, 10);
|
|
197
|
-
if (match || mobileDeviceMatch) {
|
|
198
|
-
let num;
|
|
199
|
-
let denom;
|
|
200
|
-
let simplified = true;
|
|
201
|
-
if (match) {
|
|
202
|
-
num = parseFloat(match[1]);
|
|
203
|
-
denom = parseFloat(match[2]);
|
|
204
|
-
} else {
|
|
205
|
-
num = parseFloat(mobileDeviceMatch[2]);
|
|
206
|
-
if (mobileDeviceMatch[1] === "-") {
|
|
207
|
-
if (num < 0) {
|
|
208
|
-
simplified = false;
|
|
209
|
-
}
|
|
210
|
-
num = -num;
|
|
211
|
-
}
|
|
212
|
-
denom = parseFloat(mobileDeviceMatch[3]);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
simplified =
|
|
216
|
-
simplified &&
|
|
217
|
-
denom > 0 &&
|
|
218
|
-
(options.ratio || denom !== 1) &&
|
|
219
|
-
KhanMath.getGCD(num, denom) === 1;
|
|
220
|
-
return [
|
|
221
|
-
{
|
|
222
|
-
value: num / denom,
|
|
223
|
-
exact: simplified,
|
|
224
|
-
},
|
|
225
|
-
];
|
|
226
|
-
}
|
|
227
|
-
if (!isNaN(parsedInt) && "" + parsedInt === text) {
|
|
228
|
-
return [
|
|
229
|
-
{
|
|
230
|
-
value: parsedInt,
|
|
231
|
-
exact: true,
|
|
232
|
-
},
|
|
233
|
-
];
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return [];
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
/*
|
|
240
|
-
* Different forms of numbers
|
|
241
|
-
*
|
|
242
|
-
* Each function returns a list of objects of the form:
|
|
243
|
-
*
|
|
244
|
-
* {
|
|
245
|
-
* value: numerical value,
|
|
246
|
-
* exact: true/false
|
|
247
|
-
* }
|
|
248
|
-
*/
|
|
249
|
-
const forms = {
|
|
250
|
-
// integer, which is encompassed by decimal
|
|
251
|
-
integer: function (text) {
|
|
252
|
-
// Compare the decimal form to the decimal form rounded to
|
|
253
|
-
// an integer. Only accept if the user actually entered an
|
|
254
|
-
// integer.
|
|
255
|
-
const decimal = forms.decimal(text);
|
|
256
|
-
const rounded = forms.decimal(text, 1);
|
|
257
|
-
if (
|
|
258
|
-
(decimal[0].value != null &&
|
|
259
|
-
decimal[0].value === rounded[0].value) ||
|
|
260
|
-
(decimal[1].value != null &&
|
|
261
|
-
decimal[1].value === rounded[1].value)
|
|
262
|
-
) {
|
|
263
|
-
return decimal;
|
|
264
|
-
}
|
|
265
|
-
return [];
|
|
266
|
-
},
|
|
267
|
-
|
|
268
|
-
// A proper fraction
|
|
269
|
-
proper: function (text) {
|
|
270
|
-
return $.map(fractionTransformer(text), function (o) {
|
|
271
|
-
// All fractions that are less than 1
|
|
272
|
-
if (Math.abs(o.value) < 1) {
|
|
273
|
-
return [o];
|
|
274
|
-
}
|
|
275
|
-
return [];
|
|
276
|
-
});
|
|
277
|
-
},
|
|
278
|
-
|
|
279
|
-
// an improper fraction
|
|
280
|
-
improper: function (text) {
|
|
281
|
-
return $.map(fractionTransformer(text), function (o) {
|
|
282
|
-
// All fractions that are greater than 1
|
|
283
|
-
if (Math.abs(o.value) >= 1) {
|
|
284
|
-
return [o];
|
|
285
|
-
}
|
|
286
|
-
return [];
|
|
287
|
-
});
|
|
288
|
-
},
|
|
289
|
-
|
|
290
|
-
// pi-like numbers
|
|
291
|
-
pi: function (text) {
|
|
292
|
-
let match;
|
|
293
|
-
let possibilities: any[] = [];
|
|
294
|
-
|
|
295
|
-
// Replace unicode minus sign with hyphen
|
|
296
|
-
text = text.replace(/\u2212/, "-");
|
|
297
|
-
|
|
298
|
-
// - pi
|
|
299
|
-
// (Note: we also support \pi (for TeX), p, tau (and \tau,
|
|
300
|
-
// and t), pau.)
|
|
301
|
-
if (
|
|
302
|
-
(match = text.match(
|
|
303
|
-
/^([+-]?)\s*(\\?pi|p|\u03c0|\\?tau|t|\u03c4|pau)$/i,
|
|
304
|
-
))
|
|
305
|
-
) {
|
|
306
|
-
possibilities = [
|
|
307
|
-
{
|
|
308
|
-
value: parseFloat(match[1] + "1"),
|
|
309
|
-
exact: true,
|
|
310
|
-
},
|
|
311
|
-
];
|
|
312
|
-
|
|
313
|
-
// 5 / 6 pi
|
|
314
|
-
} else if (
|
|
315
|
-
(match = text.match(
|
|
316
|
-
/^([+-]?\s*\d+\s*(?:\/\s*[+-]?\s*\d+)?)\s*\*?\s*(\\?pi|p|\u03c0|\\?tau|t|\u03c4|pau)$/i,
|
|
317
|
-
))
|
|
318
|
-
) {
|
|
319
|
-
possibilities = fractionTransformer(match[1]);
|
|
320
|
-
|
|
321
|
-
// 4 5 / 6 pi
|
|
322
|
-
} else if (
|
|
323
|
-
(match = text.match(
|
|
324
|
-
/^([+-]?)\s*(\d+)\s*([+-]?\d+)\s*\/\s*([+-]?\d+)\s*\*?\s*(\\?pi|p|\u03c0|\\?tau|t|\u03c4|pau)$/i,
|
|
325
|
-
))
|
|
326
|
-
) {
|
|
327
|
-
const sign = parseFloat(match[1] + "1");
|
|
328
|
-
const integ = parseFloat(match[2]);
|
|
329
|
-
const num = parseFloat(match[3]);
|
|
330
|
-
const denom = parseFloat(match[4]);
|
|
331
|
-
const simplified =
|
|
332
|
-
num < denom && KhanMath.getGCD(num, denom) === 1;
|
|
333
|
-
|
|
334
|
-
possibilities = [
|
|
335
|
-
{
|
|
336
|
-
value: sign * (integ + num / denom),
|
|
337
|
-
exact: simplified,
|
|
338
|
-
},
|
|
339
|
-
];
|
|
340
|
-
|
|
341
|
-
// 5 pi / 6
|
|
342
|
-
} else if (
|
|
343
|
-
(match = text.match(
|
|
344
|
-
/^([+-]?\s*\d+)\s*\*?\s*(\\?pi|p|\u03c0|\\?tau|t|\u03c4|pau)\s*(?:\/\s*([+-]?\s*\d+))?$/i,
|
|
345
|
-
))
|
|
346
|
-
) {
|
|
347
|
-
possibilities = fractionTransformer(
|
|
348
|
-
match[1] + "/" + match[3],
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
// - pi / 4
|
|
352
|
-
} else if (
|
|
353
|
-
(match = text.match(
|
|
354
|
-
/^([+-]?)\s*\*?\s*(\\?pi|p|\u03c0|\\?tau|t|\u03c4|pau)\s*(?:\/\s*([+-]?\d+))?$/i,
|
|
355
|
-
))
|
|
356
|
-
) {
|
|
357
|
-
possibilities = fractionTransformer(
|
|
358
|
-
match[1] + "1/" + match[3],
|
|
359
|
-
);
|
|
360
|
-
|
|
361
|
-
// 0
|
|
362
|
-
} else if (text === "0") {
|
|
363
|
-
possibilities = [{value: 0, exact: true}];
|
|
364
|
-
|
|
365
|
-
// 0.5 pi (fallback)
|
|
366
|
-
} else if (
|
|
367
|
-
(match = text.match(
|
|
368
|
-
/^(.+)\s*\*?\s*(\\?pi|p|\u03c0|\\?tau|t|\u03c4|pau)$/i,
|
|
369
|
-
))
|
|
370
|
-
) {
|
|
371
|
-
possibilities = forms.decimal(match[1]);
|
|
372
|
-
} else {
|
|
373
|
-
possibilities = _.reduce(
|
|
374
|
-
KhanAnswerTypes.predicate.defaultForms.split(
|
|
375
|
-
/\s*,\s*/,
|
|
376
|
-
),
|
|
377
|
-
function (memo, form) {
|
|
378
|
-
return memo.concat(forms[form](text));
|
|
379
|
-
},
|
|
380
|
-
[],
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
// If the answer is a floating point number that's
|
|
384
|
-
// near a multiple of pi, mark is as being possibly
|
|
385
|
-
// an approximation of pi. We actually check if
|
|
386
|
-
// it's a plausible approximation of pi/12, since
|
|
387
|
-
// sometimes the correct answer is like pi/3 or pi/4.
|
|
388
|
-
// We also say it's a pi-approximation if it involves
|
|
389
|
-
// x/7 (since 22/7 is an approximation of pi.)
|
|
390
|
-
// Never mark an integer as being an approximation
|
|
391
|
-
// of pi.
|
|
392
|
-
let approximatesPi = false;
|
|
393
|
-
const number = parseFloat(text);
|
|
394
|
-
if (!isNaN(number) && number !== parseInt(text)) {
|
|
395
|
-
const piMult = Math.PI / 12;
|
|
396
|
-
const roundedNumber =
|
|
397
|
-
piMult * Math.round(number / piMult);
|
|
398
|
-
if (Math.abs(number - roundedNumber) < 0.01) {
|
|
399
|
-
approximatesPi = true;
|
|
400
|
-
}
|
|
401
|
-
} else if (text.match(/\/\s*7/)) {
|
|
402
|
-
approximatesPi = true;
|
|
403
|
-
}
|
|
404
|
-
if (approximatesPi) {
|
|
405
|
-
_.each(possibilities, function (possibility) {
|
|
406
|
-
possibility.piApprox = true;
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
return possibilities;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
let multiplier = Math.PI;
|
|
413
|
-
if (text.match(/\\?tau|t|\u03c4/)) {
|
|
414
|
-
multiplier = Math.PI * 2;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// We're taking an early stand along side xkcd in the
|
|
418
|
-
// inevitable ti vs. pau debate... http://xkcd.com/1292
|
|
419
|
-
if (text.match(/pau/)) {
|
|
420
|
-
multiplier = Math.PI * 1.5;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
$.each(possibilities, function (ix, possibility) {
|
|
424
|
-
possibility.value *= multiplier;
|
|
425
|
-
});
|
|
426
|
-
return possibilities;
|
|
427
|
-
},
|
|
428
|
-
|
|
429
|
-
// Converts '' to 1 and '-' to -1 so you can write "[___] x"
|
|
430
|
-
// and accept sane things
|
|
431
|
-
coefficient: function (text) {
|
|
432
|
-
let possibilities:
|
|
433
|
-
| Array<never>
|
|
434
|
-
| Array<{
|
|
435
|
-
exact: boolean;
|
|
436
|
-
value: number;
|
|
437
|
-
}> = [];
|
|
438
|
-
|
|
439
|
-
// Replace unicode minus sign with hyphen
|
|
440
|
-
text = text.replace(/\u2212/, "-");
|
|
441
|
-
|
|
442
|
-
if (text === "") {
|
|
443
|
-
possibilities = [{value: 1, exact: true}];
|
|
444
|
-
} else if (text === "-") {
|
|
445
|
-
possibilities = [{value: -1, exact: true}];
|
|
446
|
-
}
|
|
447
|
-
return possibilities;
|
|
448
|
-
},
|
|
449
|
-
|
|
450
|
-
// simple log(c) form
|
|
451
|
-
log: function (text) {
|
|
452
|
-
let match;
|
|
453
|
-
let possibilities = [];
|
|
454
|
-
|
|
455
|
-
// Replace unicode minus sign with hyphen
|
|
456
|
-
text = text.replace(/\u2212/, "-");
|
|
457
|
-
text = text.replace(/[ \(\)]/g, "");
|
|
458
|
-
|
|
459
|
-
if ((match = text.match(/^log\s*(\S+)\s*$/i))) {
|
|
460
|
-
// @ts-expect-error - TS2322 - Type '{ value: number | undefined; exact: boolean; }[]' is not assignable to type 'never[]'.
|
|
461
|
-
possibilities = forms.decimal(match[1]);
|
|
462
|
-
} else if (text === "0") {
|
|
463
|
-
// @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'never'. | TS2322 - Type 'boolean' is not assignable to type 'never'.
|
|
464
|
-
possibilities = [{value: 0, exact: true}];
|
|
465
|
-
}
|
|
466
|
-
return possibilities;
|
|
467
|
-
},
|
|
468
|
-
|
|
469
|
-
// Numbers with percent signs
|
|
470
|
-
percent: function (text) {
|
|
471
|
-
text = $.trim(text);
|
|
472
|
-
// store whether or not there is a percent sign
|
|
473
|
-
let hasPercentSign = false;
|
|
474
|
-
|
|
475
|
-
if (text.indexOf("%") === text.length - 1) {
|
|
476
|
-
text = $.trim(text.substring(0, text.length - 1));
|
|
477
|
-
hasPercentSign = true;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
const transformed = forms.decimal(text);
|
|
481
|
-
$.each(transformed, function (ix, t) {
|
|
482
|
-
t.exact = hasPercentSign;
|
|
483
|
-
// @ts-expect-error - TS2532 - Object is possibly 'undefined'.
|
|
484
|
-
t.value = t.value / 100;
|
|
485
|
-
});
|
|
486
|
-
return transformed;
|
|
487
|
-
},
|
|
488
|
-
|
|
489
|
-
// Mixed numbers, like 1 3/4
|
|
490
|
-
mixed: function (text) {
|
|
491
|
-
const match = text
|
|
492
|
-
// Replace unicode minus sign with hyphen
|
|
493
|
-
.replace(/\u2212/, "-")
|
|
494
|
-
// Remove space after +, -
|
|
495
|
-
.replace(/([+-])\s+/g, "$1")
|
|
496
|
-
// Extract integer, numerator and denominator
|
|
497
|
-
.match(/^([+-]?)(\d+)\s+(\d+)\s*\/\s*(\d+)$/);
|
|
498
|
-
|
|
499
|
-
if (match) {
|
|
500
|
-
const sign = parseFloat(match[1] + "1");
|
|
501
|
-
const integ = parseFloat(match[2]);
|
|
502
|
-
const num = parseFloat(match[3]);
|
|
503
|
-
const denom = parseFloat(match[4]);
|
|
504
|
-
const simplified =
|
|
505
|
-
num < denom && KhanMath.getGCD(num, denom) === 1;
|
|
506
|
-
|
|
507
|
-
return [
|
|
508
|
-
{
|
|
509
|
-
value: sign * (integ + num / denom),
|
|
510
|
-
exact: simplified,
|
|
511
|
-
},
|
|
512
|
-
];
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
return [];
|
|
516
|
-
},
|
|
517
|
-
|
|
518
|
-
// Decimal numbers -- compare entered text rounded to
|
|
519
|
-
// 'precision' Reciprical of the precision against the correct
|
|
520
|
-
// answer. We round to 1/1e10 by default, which is healthily
|
|
521
|
-
// less than machine epsilon but should be more than any real
|
|
522
|
-
// decimal answer would use. (The 'integer' answer type uses
|
|
523
|
-
// precision == 1.)
|
|
524
|
-
decimal: function (text: string, precision = 1e10) {
|
|
525
|
-
const normal = function (text) {
|
|
526
|
-
text = $.trim(text);
|
|
527
|
-
|
|
528
|
-
const match = text
|
|
529
|
-
// Replace unicode minus sign with hyphen
|
|
530
|
-
.replace(/\u2212/, "-")
|
|
531
|
-
// Remove space after +, -
|
|
532
|
-
.replace(/([+-])\s+/g, "$1")
|
|
533
|
-
// Extract integer, numerator and denominator. If
|
|
534
|
-
// commas or spaces are used, they must be in the
|
|
535
|
-
// "correct" places
|
|
536
|
-
.match(
|
|
537
|
-
/^([+-]?(?:\d{1,3}(?:[, ]?\d{3})*\.?|\d{0,3}(?:[, ]?\d{3})*\.(?:\d{3}[, ]?)*\d{1,3}))$/,
|
|
538
|
-
);
|
|
539
|
-
|
|
540
|
-
// You can't start a number with `0,`, to prevent us
|
|
541
|
-
// interpeting '0.342' as correct for '342'
|
|
542
|
-
const badLeadingZero = text.match(/^0[0,]*,/);
|
|
543
|
-
|
|
544
|
-
if (match && !badLeadingZero) {
|
|
545
|
-
let x = parseFloat(match[1].replace(/[, ]/g, ""));
|
|
546
|
-
|
|
547
|
-
if (options.inexact === undefined) {
|
|
548
|
-
x = Math.round(x * precision) / precision;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
return x;
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
const commas = function (text: string) {
|
|
556
|
-
text = text.replace(/([\.,])/g, function (_, c) {
|
|
557
|
-
return c === "." ? "," : ".";
|
|
558
|
-
});
|
|
559
|
-
return normal(text);
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
return [
|
|
563
|
-
{value: normal(text), exact: true},
|
|
564
|
-
{value: commas(text), exact: true},
|
|
565
|
-
];
|
|
566
|
-
},
|
|
567
|
-
} as const;
|
|
568
|
-
|
|
569
|
-
// validator function
|
|
570
|
-
return function (guess: Guess): Score {
|
|
571
|
-
// The fallback variable is used in place of the answer, if no
|
|
572
|
-
// answer is provided (i.e. the field is left blank)
|
|
573
|
-
const fallback =
|
|
574
|
-
options.fallback != null ? "" + options.fallback : "";
|
|
575
|
-
|
|
576
|
-
guess = $.trim(guess) || fallback;
|
|
577
|
-
|
|
578
|
-
const score: Score = {
|
|
579
|
-
empty: guess === "",
|
|
580
|
-
correct: false,
|
|
581
|
-
message: null as string | null | undefined,
|
|
582
|
-
guess: guess,
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
// iterate over all the acceptable forms, and if one of the
|
|
586
|
-
// answers is correct, return true
|
|
587
|
-
$.each(acceptableForms, function (i, form) {
|
|
588
|
-
const transformed = forms[form](guess);
|
|
589
|
-
for (let j = 0, l = transformed.length; j < l; j++) {
|
|
590
|
-
const val = transformed[j].value;
|
|
591
|
-
const exact = transformed[j].exact;
|
|
592
|
-
const piApprox = transformed[j].piApprox;
|
|
593
|
-
// If a string was returned, and it exactly matches,
|
|
594
|
-
// return true
|
|
595
|
-
if (predicate(val, options.maxError)) {
|
|
596
|
-
// If the exact correct number was returned,
|
|
597
|
-
// return true
|
|
598
|
-
if (exact || options.simplify === "optional") {
|
|
599
|
-
score.correct = true;
|
|
600
|
-
score.message = options.message || null;
|
|
601
|
-
// If the answer is correct, don't say it's
|
|
602
|
-
// empty. This happens, for example, with the
|
|
603
|
-
// coefficient type where guess === "" but is
|
|
604
|
-
// interpreted as "1" which is correct.
|
|
605
|
-
score.empty = false;
|
|
606
|
-
} else if (form === "percent") {
|
|
607
|
-
// Otherwise, an error was returned
|
|
608
|
-
score.empty = true;
|
|
609
|
-
score.message = errors.MISSING_PERCENT_ERROR;
|
|
610
|
-
} else {
|
|
611
|
-
if (options.simplify !== "enforced") {
|
|
612
|
-
score.empty = true;
|
|
613
|
-
}
|
|
614
|
-
score.message =
|
|
615
|
-
errors.NEEDS_TO_BE_SIMPLFIED_ERROR;
|
|
616
|
-
}
|
|
617
|
-
// The return false below stops the looping of the
|
|
618
|
-
// callback since predicate check succeeded.
|
|
619
|
-
// No more forms to look to verify the user guess.
|
|
620
|
-
return false;
|
|
621
|
-
}
|
|
622
|
-
if (piApprox && predicate(val, Math.abs(val * 0.001))) {
|
|
623
|
-
score.empty = true;
|
|
624
|
-
score.message = errors.APPROXIMATED_PI_ERROR;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
});
|
|
628
|
-
|
|
629
|
-
if (score.correct === false) {
|
|
630
|
-
let interpretedGuess = false;
|
|
631
|
-
_.each(forms, function (form) {
|
|
632
|
-
const anyAreNaN = _.any(form(guess), function (t) {
|
|
633
|
-
return t.value != null && !_.isNaN(t.value);
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
if (anyAreNaN) {
|
|
637
|
-
interpretedGuess = true;
|
|
638
|
-
}
|
|
639
|
-
});
|
|
640
|
-
if (!interpretedGuess) {
|
|
641
|
-
score.empty = true;
|
|
642
|
-
score.message = errors.EXTRA_SYMBOLS_ERROR;
|
|
643
|
-
return score;
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
return score;
|
|
648
|
-
};
|
|
649
|
-
},
|
|
650
|
-
},
|
|
651
|
-
|
|
652
|
-
/*
|
|
653
|
-
* number answer type
|
|
654
|
-
*
|
|
655
|
-
* wraps the predicate answer type to performs simple number-based checking
|
|
656
|
-
* of a solution
|
|
657
|
-
*/
|
|
658
|
-
number: {
|
|
659
|
-
convertToPredicate: function (
|
|
660
|
-
correctAnswer: string,
|
|
661
|
-
options: any,
|
|
662
|
-
): Predicate {
|
|
663
|
-
const correctFloat = parseFloat(correctAnswer);
|
|
664
|
-
|
|
665
|
-
return [
|
|
666
|
-
function (guess: Predicate, maxError: Predicate) {
|
|
667
|
-
return Math.abs(guess - correctFloat) < maxError;
|
|
668
|
-
},
|
|
669
|
-
$.extend({}, options, {type: "predicate"}),
|
|
670
|
-
];
|
|
671
|
-
},
|
|
672
|
-
createValidatorFunctional: function (
|
|
673
|
-
correctAnswer: string,
|
|
674
|
-
options: any,
|
|
675
|
-
): (arg1: Guess) => Score {
|
|
676
|
-
return KhanAnswerTypes.predicate.createValidatorFunctional(
|
|
677
|
-
// @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
678
|
-
...KhanAnswerTypes.number.convertToPredicate(
|
|
679
|
-
correctAnswer,
|
|
680
|
-
options,
|
|
681
|
-
),
|
|
682
|
-
);
|
|
683
|
-
},
|
|
684
|
-
},
|
|
685
|
-
|
|
686
|
-
/*
|
|
687
|
-
* The expression answer type parses a given expression or equation
|
|
688
|
-
* and semantically compares it to the solution. In addition, instant
|
|
689
|
-
* feedback is provided by rendering the last answer that fully parsed.
|
|
690
|
-
*
|
|
691
|
-
* Parsing options:
|
|
692
|
-
* functions (e.g. data-functions="f g h")
|
|
693
|
-
* A space or comma separated list of single-letter variables that
|
|
694
|
-
* should be interpreted as functions. Case sensitive. "e" and "i"
|
|
695
|
-
* are reserved.
|
|
696
|
-
*
|
|
697
|
-
* no functions specified: f(x+y) == fx + fy
|
|
698
|
-
* with "f" as a function: f(x+y) != fx + fy
|
|
699
|
-
*
|
|
700
|
-
* Comparison options:
|
|
701
|
-
* same-form (e.g. data-same-form)
|
|
702
|
-
* If present, the answer must match the solution's structure in
|
|
703
|
-
* addition to evaluating the same. Commutativity and excess negation
|
|
704
|
-
* are ignored, but all other changes will trigger a rejection. Useful
|
|
705
|
-
* for requiring a particular form of an equation, or if the answer
|
|
706
|
-
* must be factored.
|
|
707
|
-
*
|
|
708
|
-
* example question: Factor x^2 + x - 2
|
|
709
|
-
* example solution: (x-1)(x+2)
|
|
710
|
-
* accepted answers: (x-1)(x+2), (x+2)(x-1), ---(-x-2)(-1+x), etc.
|
|
711
|
-
* rejected answers: x^2+x-2, x*x+x-2, x(x+1)-2, (x-1)(x+2)^1, etc.
|
|
712
|
-
* rejection message: Your answer is not in the correct form
|
|
713
|
-
*
|
|
714
|
-
* simplify (e.g. data-simplify)
|
|
715
|
-
* If present, the answer must be fully expanded and simplified. Use
|
|
716
|
-
* carefully - simplification is hard and there may be bugs, or you
|
|
717
|
-
* might not agree on the definition of "simplified" used. You will
|
|
718
|
-
* get an error if the provided solution is not itself fully expanded
|
|
719
|
-
* and simplified.
|
|
720
|
-
*
|
|
721
|
-
* example question: Simplify ((n*x^5)^5) / (n^(-2)*x^2)^-3
|
|
722
|
-
* example solution: x^31 / n
|
|
723
|
-
* accepted answers: x^31 / n, x^31 / n^1, x^31 * n^(-1), etc.
|
|
724
|
-
* rejected answers: (x^25 * n^5) / (x^(-6) * n^6), etc.
|
|
725
|
-
* rejection message: Your answer is not fully expanded and simplified
|
|
726
|
-
*
|
|
727
|
-
* Rendering options:
|
|
728
|
-
* times (e.g. data-times)
|
|
729
|
-
* If present, explicit multiplication (such as between numbers) will
|
|
730
|
-
* be rendered with a cross/x symbol (TeX: \times) instead of the usual
|
|
731
|
-
* center dot (TeX: \cdot).
|
|
732
|
-
*
|
|
733
|
-
* normal rendering: 2 * 3^x -> 2 \cdot 3^{x}
|
|
734
|
-
* but with "times": 2 * 3^x -> 2 \times 3^{x}
|
|
735
|
-
*/
|
|
736
|
-
expression: {
|
|
737
|
-
parseSolution: function (solutionString: string, options: any): any {
|
|
738
|
-
let solution = KAS.parse(solutionString, options);
|
|
739
|
-
if (!solution.parsed) {
|
|
740
|
-
throw new PerseusError(
|
|
741
|
-
"The provided solution (" +
|
|
742
|
-
solutionString +
|
|
743
|
-
") didn't parse.",
|
|
744
|
-
Errors.InvalidInput,
|
|
745
|
-
);
|
|
746
|
-
} else if (options.simplified && !solution.expr.isSimplified()) {
|
|
747
|
-
throw new PerseusError(
|
|
748
|
-
"The provided solution (" +
|
|
749
|
-
solutionString +
|
|
750
|
-
") isn't fully expanded and simplified.",
|
|
751
|
-
Errors.InvalidInput,
|
|
752
|
-
);
|
|
753
|
-
} else {
|
|
754
|
-
solution = solution.expr;
|
|
755
|
-
}
|
|
756
|
-
return solution;
|
|
757
|
-
},
|
|
758
|
-
|
|
759
|
-
createValidatorFunctional: function (
|
|
760
|
-
solution: any,
|
|
761
|
-
options: any,
|
|
762
|
-
): (arg1: Guess) => Score {
|
|
763
|
-
return function (guess: Guess): Score {
|
|
764
|
-
const score = {
|
|
765
|
-
empty: false,
|
|
766
|
-
correct: false,
|
|
767
|
-
message: null as string | null | undefined,
|
|
768
|
-
guess: guess,
|
|
769
|
-
// Setting `ungraded` to true indicates that if the
|
|
770
|
-
// guess doesn't match any of the solutions, the guess
|
|
771
|
-
// shouldn't be marked as incorrect; instead, `message`
|
|
772
|
-
// should be shown to the user. This is different from
|
|
773
|
-
// setting `empty` to true, since the behavior of `empty`
|
|
774
|
-
// is that `message` only will be shown if the guess is
|
|
775
|
-
// graded as empty for every solution.
|
|
776
|
-
ungraded: false,
|
|
777
|
-
} as const;
|
|
778
|
-
|
|
779
|
-
// Don't bother parsing an empty input
|
|
780
|
-
if (!guess) {
|
|
781
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'empty' because it is a read-only property.
|
|
782
|
-
score.empty = true;
|
|
783
|
-
return score;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
const answer = KAS.parse(guess, options);
|
|
787
|
-
|
|
788
|
-
// An unsuccessful parse doesn't count as wrong
|
|
789
|
-
if (!answer.parsed) {
|
|
790
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'empty' because it is a read-only property.
|
|
791
|
-
score.empty = true;
|
|
792
|
-
return score;
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
// Solution will need to be parsed again if we're creating
|
|
796
|
-
// this from a multiple question type
|
|
797
|
-
if (typeof solution === "string") {
|
|
798
|
-
solution = KhanAnswerTypes.expression.parseSolution(
|
|
799
|
-
solution,
|
|
800
|
-
options,
|
|
801
|
-
);
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
const result = KAS.compare(answer.expr, solution, options);
|
|
805
|
-
|
|
806
|
-
if (result.equal) {
|
|
807
|
-
// Correct answer
|
|
808
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'correct' because it is a read-only property.
|
|
809
|
-
score.correct = true;
|
|
810
|
-
} else if (
|
|
811
|
-
result.wrongVariableNames ||
|
|
812
|
-
result.wrongVariableCase
|
|
813
|
-
) {
|
|
814
|
-
// We don't want to give people an error for getting the
|
|
815
|
-
// variable names or the variable case wrong.
|
|
816
|
-
// TODO(aasmund): This should ideally have been handled
|
|
817
|
-
// under the `result.message` condition, but the
|
|
818
|
-
// KAS messages currently aren't translatable.
|
|
819
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'ungraded' because it is a read-only property.
|
|
820
|
-
score.ungraded = true;
|
|
821
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
822
|
-
score.message = result.wrongVariableCase
|
|
823
|
-
? errors.WRONG_CASE_ERROR
|
|
824
|
-
: errors.WRONG_LETTER_ERROR;
|
|
825
|
-
// Don't tell the use they're "almost there" in this case, that may not be true and isn't helpful.
|
|
826
|
-
// @ts-expect-error - TS2339 - Property 'suppressAlmostThere' does not exist on type '{ readonly empty: false; readonly correct: false; readonly message: string | null | undefined; readonly guess: any; readonly ungraded: false; }'.
|
|
827
|
-
score.suppressAlmostThere = true;
|
|
828
|
-
} else if (result.message) {
|
|
829
|
-
// Nearly correct answer
|
|
830
|
-
// TODO(aasmund): This message also isn't translatable;
|
|
831
|
-
// need to fix that in KAS
|
|
832
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
833
|
-
score.message = result.message;
|
|
834
|
-
} else {
|
|
835
|
-
// Replace x with * and see if it would have been correct
|
|
836
|
-
// TODO(aasmund): I think this branch is effectively dead,
|
|
837
|
-
// because the replacement will only work in situations
|
|
838
|
-
// where the variables are wrong (except if the variable
|
|
839
|
-
// is x, in which case the replacement won't work either),
|
|
840
|
-
// which is handled by another branch. When we implement a
|
|
841
|
-
// more sophisticated variable check, revive this or
|
|
842
|
-
// remove it completely if it will never come into play.
|
|
843
|
-
const answerX = KAS.parse(
|
|
844
|
-
guess.replace(/[xX]/g, "*"),
|
|
845
|
-
options,
|
|
846
|
-
);
|
|
847
|
-
if (answerX.parsed) {
|
|
848
|
-
const resultX = KAS.compare(
|
|
849
|
-
answerX.expr,
|
|
850
|
-
solution,
|
|
851
|
-
options,
|
|
852
|
-
);
|
|
853
|
-
if (resultX.equal) {
|
|
854
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'ungraded' because it is a read-only property.
|
|
855
|
-
score.ungraded = true;
|
|
856
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
857
|
-
score.message = errors.MULTIPLICATION_SIGN_ERROR;
|
|
858
|
-
} else if (resultX.message) {
|
|
859
|
-
// TODO(aasmund): I18nize `score.message`
|
|
860
|
-
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
861
|
-
score.message =
|
|
862
|
-
resultX.message +
|
|
863
|
-
" Also, I'm a computer. I only understand " +
|
|
864
|
-
"multiplication if you use an " +
|
|
865
|
-
"asterisk (*) as the multiplication " +
|
|
866
|
-
"sign.";
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return score;
|
|
871
|
-
};
|
|
872
|
-
},
|
|
873
|
-
},
|
|
874
|
-
} as const;
|
|
875
|
-
|
|
876
|
-
export default KhanAnswerTypes;
|