@khanacademy/perseus-score 4.0.0 → 4.0.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/dist/index.js CHANGED
@@ -508,48 +508,63 @@ const KhanAnswerTypes = {
508
508
  guess: guess
509
509
  };
510
510
 
511
- // iterate over all the acceptable forms, and if one of the
512
- // answers is correct, return true
513
- acceptableForms.forEach(form => {
514
- const transformed = forms[form](guess);
515
- for (let j = 0, l = transformed.length; j < l; j++) {
516
- const val = transformed[j].value;
517
- const exact = transformed[j].exact;
518
- const piApprox = transformed[j].piApprox;
519
- // If a string was returned, and it exactly matches,
520
- // return true
521
- if (predicate(val, options.maxError)) {
522
- // If the exact correct number was returned,
511
+ // Iterate over all the acceptable forms
512
+ // and exit if one of the answers is correct.
513
+ //
514
+ // HACK: This function is a bug fix from LEMS-2962;
515
+ // after a transition from jQuery's `each` to JS's `forEach`
516
+ // we realized this code was banking on the ability to:
517
+ // 1. exit early from nested loops (can be tricky outside of functions)
518
+ // 2. mutate external variables (score)
519
+ // Could probably be refactored to be a pure function that
520
+ // returns a score, but this code is poorly tested and prone to break.
521
+ const findCorrectAnswer = () => {
522
+ // WARNING: Don't use `forEach` without additional refactoring
523
+ // because code needs to be able to exit early
524
+ for (const form of acceptableForms) {
525
+ const transformed = forms[form](guess);
526
+ for (let j = 0, l = transformed.length; j < l; j++) {
527
+ const val = transformed[j].value;
528
+ const exact = transformed[j].exact;
529
+ const piApprox = transformed[j].piApprox;
530
+ // If a string was returned, and it exactly matches,
523
531
  // return true
524
- if (exact || options.simplify === "optional") {
525
- score.correct = true;
526
- score.message = options.message || null;
527
- // If the answer is correct, don't say it's
528
- // empty. This happens, for example, with the
529
- // coefficient type where guess === "" but is
530
- // interpreted as "1" which is correct.
531
- score.empty = false;
532
- } else if (form === "percent") {
533
- // Otherwise, an error was returned
534
- score.empty = true;
535
- score.message = ErrorCodes.MISSING_PERCENT_ERROR;
536
- } else {
537
- if (options.simplify !== "enforced") {
532
+ if (predicate(val, options.maxError)) {
533
+ // If the exact correct number was returned,
534
+ // return true
535
+ if (exact || options.simplify === "optional") {
536
+ score.correct = true;
537
+ score.message = options.message || null;
538
+ // If the answer is correct, don't say it's
539
+ // empty. This happens, for example, with the
540
+ // coefficient type where guess === "" but is
541
+ // interpreted as "1" which is correct.
542
+ score.empty = false;
543
+ } else if (form === "percent") {
544
+ // Otherwise, an error was returned
538
545
  score.empty = true;
546
+ score.message = ErrorCodes.MISSING_PERCENT_ERROR;
547
+ } else {
548
+ if (options.simplify !== "enforced") {
549
+ score.empty = true;
550
+ }
551
+ score.message = ErrorCodes.NEEDS_TO_BE_SIMPLIFIED_ERROR;
539
552
  }
540
- score.message = ErrorCodes.NEEDS_TO_BE_SIMPLIFIED_ERROR;
553
+ // HACK: The return false below stops the looping of the
554
+ // callback since predicate check succeeded.
555
+ // No more forms to look to verify the user guess.
556
+ return false;
557
+ }
558
+ if (piApprox && predicate(val, Math.abs(val * 0.001))) {
559
+ score.empty = true;
560
+ score.message = ErrorCodes.APPROXIMATED_PI_ERROR;
541
561
  }
542
- // The return false below stops the looping of the
543
- // callback since predicate check succeeded.
544
- // No more forms to look to verify the user guess.
545
- return false;
546
- }
547
- if (piApprox && predicate(val, Math.abs(val * 0.001))) {
548
- score.empty = true;
549
- score.message = ErrorCodes.APPROXIMATED_PI_ERROR;
550
562
  }
551
563
  }
552
- });
564
+ };
565
+
566
+ // mutates `score`
567
+ findCorrectAnswer();
553
568
  if (score.correct === false) {
554
569
  let interpretedGuess = false;
555
570
  ___default.default.each(forms, function (form) {