Skip to content

Delete most InputNumber code, replace with NumericInput#3760

Open
benchristel wants to merge 26 commits into
mainfrom
benc/input-number-v2-take-3
Open

Delete most InputNumber code, replace with NumericInput#3760
benchristel wants to merge 26 commits into
mainfrom
benc/input-number-v2-take-3

[benc/input-number-v2-take-3] Delete unused test data file

2f62c39
Select commit
Loading
Failed to load commit list.
Sign in for the full log view
GitHub Actions / PR Comparison: Item Splitting succeeded Jun 11, 2026 in 0s

PR Comparison: Item Splitting: Changes Acknowledged ✅

Acknowledged via the item-splitting-change-ack label. Remove the label to require re-acknowledgement.

View diff
diff --unified /home/github/work/_temp/branch-compare/base/item-splitting.bundle.js /home/github/work/_temp/branch-compare/pr/item-splitting.bundle.js
--- /home/github/work/_temp/branch-compare/base/item-splitting.bundle.js	2026-06-11 18:46:56.975788949 +0000
+++ /home/github/work/_temp/branch-compare/pr/item-splitting.bundle.js	2026-06-11 18:46:53.975789066 +0000
@@ -6383,13 +6383,54 @@
 );
 
 // packages/perseus-core/src/parse-perseus-json/perseus-parsers/input-number-widget.ts
-var booleanToString = (rawValue, ctx) => {
+var booleanToZero = (rawValue, ctx) => {
   if (typeof rawValue === "boolean") {
-    return ctx.success(String(rawValue));
+    return ctx.success(0);
   }
   return ctx.failure("boolean", rawValue);
 };
-var parseInputNumberWidget = parseWidget(
+var parseMathFormat = enumeration(
+  "integer",
+  "mixed",
+  "improper",
+  "proper",
+  "decimal",
+  "percent",
+  "pi"
+);
+var parseInputNumberWidgetV1 = parseWidgetWithVersion(
+  object({ major: constant(1), minor: number }),
+  constant("input-number"),
+  object({
+    size: string,
+    coefficient: boolean,
+    labelText: optional(string),
+    rightAlign: optional(boolean),
+    answers: array(
+      object({
+        value: optional(nullable(number)),
+        status: string,
+        message: string,
+        answerForms: optional(array(parseMathFormat)),
+        // FIXME: confirm that we need the default on `strict`.
+        // cribbed from numeric-input-widget.ts.
+        strict: defaulted(boolean, () => false),
+        maxError: optional(nullable(number)),
+        simplify: enumeration("required", "enforced", "optional")
+      })
+    )
+  })
+);
+function migrateV0ToV12(v0) {
+  const v1Options = convertInputNumberOptionsToNumericInput(v0.options);
+  return {
+    ...v0,
+    version: { major: 1, minor: 0 },
+    options: v1Options
+  };
+}
+var parseInputNumberWidgetV0 = parseWidgetWithVersion(
+  optional(object({ major: constant(0), minor: number })),
   constant("input-number"),
   object({
     answerType: optional(
@@ -6414,11 +6455,66 @@
     // those content items are actually published anywhere, and consider
     // updating them.
     value: defaulted(
-      union(number).or(string).or(booleanToString).parser,
+      union(number).or(string).or(booleanToZero).parser,
       () => 0
     )
   })
 );
+function convertInputNumberOptionsToNumericInput(inputNumberOptions) {
+  return {
+    coefficient: false,
+    rightAlign: inputNumberOptions.rightAlign,
+    size: inputNumberOptions.size,
+    answers: [
+      {
+        status: "correct",
+        value: Number(inputNumberOptions.value),
+        simplify: inputNumberOptions.simplify,
+        message: "",
+        maxError: getMaxError(inputNumberOptions),
+        strict: true,
+        answerForms: getAnswerForms(inputNumberOptions)
+      }
+    ]
+  };
+}
+function getMaxError(inputNumberOptions) {
+  if (!inputNumberOptions.inexact) {
+    return 0;
+  }
+  if (inputNumberOptions.maxError == null) {
+    return void 0;
+  }
+  return Number(inputNumberOptions.maxError);
+}
+var mathFormatsForAnswerType = {
+  number: [],
+  decimal: ["decimal"],
+  integer: ["integer"],
+  rational: ["integer", "proper", "improper", "mixed"],
+  improper: ["integer", "proper", "improper"],
+  mixed: ["integer", "proper", "mixed"],
+  percent: ["integer", "decimal", "proper", "improper", "mixed", "percent"],
+  pi: ["pi"]
+};
+function getAnswerForms(options) {
+  const value = Number(options.value);
+  const { inexact } = options;
+  const precision = 1e10;
+  const rounded = Math.round(value * precision) / precision;
+  const answerType = options.answerType ?? "number";
+  if (answerType === "number" && !inexact && !equalFloats(rounded, value)) {
+    return ["proper", "improper", "mixed"];
+  }
+  return mathFormatsForAnswerType[answerType];
+}
+function equalFloats(a, b) {
+  return Math.abs(a - b) < Math.pow(2, -42);
+}
+var parseInputNumberWidget = versionedWidgetOptions(
+  1,
+  parseInputNumberWidgetV1
+).withMigrationFrom(0, parseInputNumberWidgetV0, migrateV0ToV12).parser;
 
 // packages/perseus-core/src/parse-perseus-json/perseus-parsers/interaction-widget.ts
 var pairOfNumbers3 = pair(number, number);
@@ -7010,7 +7106,7 @@
 );
 
 // packages/perseus-core/src/parse-perseus-json/perseus-parsers/numeric-input-widget.ts
-var parseMathFormat = enumeration(
+var parseMathFormat2 = enumeration(
   "integer",
   "mixed",
   "improper",
@@ -7048,7 +7144,7 @@
         value: optional(nullable(number)),
         status: string,
         answerForms: defaulted(
-          optional(array(parseMathFormat)),
+          optional(array(parseMathFormat2)),
           () => void 0
         ),
         strict: defaulted(boolean, () => false),
@@ -7330,7 +7426,7 @@
     }
   };
 }
-function migrateV0ToV12(widget) {
+function migrateV0ToV13(widget) {
   const { options } = widget;
   const { noneOfTheAbove: _5, ...rest } = options;
   return {
@@ -7343,7 +7439,7 @@
     }
   };
 }
-var parseRadioWidget = versionedWidgetOptions(3, parseRadioWidgetV3).withMigrationFrom(2, parseRadioWidgetV2, migrateV2toV3).withMigrationFrom(1, parseRadioWidgetV1, migrateV1ToV22).withMigrationFrom(0, parseRadioWidgetV0, migrateV0ToV12).parser;
+var parseRadioWidget = versionedWidgetOptions(3, parseRadioWidgetV3).withMigrationFrom(2, parseRadioWidgetV2, migrateV2toV3).withMigrationFrom(1, parseRadioWidgetV1, migrateV1ToV22).withMigrationFrom(0, parseRadioWidgetV0, migrateV0ToV13).parser;
 
 // packages/perseus-core/src/parse-perseus-json/perseus-parsers/sorter-widget.ts
 var parseSorterWidget = parseWidget(