@khanacademy/perseus 36.0.0 → 36.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/dist/es/index.js CHANGED
@@ -2,7 +2,7 @@ import * as KAS from '@khanacademy/kas';
2
2
  import { MathInputI18nContext, CursorContext, getKeyTranslator, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
3
3
  import * as PerseusLinter from '@khanacademy/perseus-linter';
4
4
  import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
5
- import { View, RenderStateRoot, UniqueIDProvider, useLatestRef, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
5
+ import { View, RenderStateRoot, UniqueIDProvider, useOnMountEffect, useLatestRef, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
6
6
  import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
7
7
  import { HeadingMedium, LabelSmall, Body, LabelMedium } from '@khanacademy/wonder-blocks-typography';
8
8
  import { StyleSheet, css } from 'aphrodite';
@@ -3157,13 +3157,13 @@ function eq$4(x, y) {
3157
3157
  * Deep approximate equality on primitives, numbers, arrays, and objects.
3158
3158
  * Recursive.
3159
3159
  */
3160
- function deepEq$5(x, y) {
3160
+ function deepEq$6(x, y) {
3161
3161
  if (Array.isArray(x) && Array.isArray(y)) {
3162
3162
  if (x.length !== y.length) {
3163
3163
  return false;
3164
3164
  }
3165
3165
  for (let i = 0; i < x.length; i++) {
3166
- if (!deepEq$5(x[i], y[i])) {
3166
+ if (!deepEq$6(x[i], y[i])) {
3167
3167
  return false;
3168
3168
  }
3169
3169
  }
@@ -3181,10 +3181,10 @@ function deepEq$5(x, y) {
3181
3181
  if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
3182
3182
  return x === y || _.all(x, function (v, k) {
3183
3183
  // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
3184
- return deepEq$5(y[k], v);
3184
+ return deepEq$6(y[k], v);
3185
3185
  }) && _.all(y, function (v, k) {
3186
3186
  // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
3187
- return deepEq$5(x[k], v);
3187
+ return deepEq$6(x[k], v);
3188
3188
  });
3189
3189
  }
3190
3190
  if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
@@ -3464,7 +3464,7 @@ const Util = {
3464
3464
  tickStepFromNumTicks,
3465
3465
  constrainedTickStepsFromTickSteps,
3466
3466
  eq: eq$4,
3467
- deepEq: deepEq$5,
3467
+ deepEq: deepEq$6,
3468
3468
  parseQueryString,
3469
3469
  updateQueryString: updateQueryString$2,
3470
3470
  strongEncodeURIComponent,
@@ -10786,7 +10786,7 @@ class WrappedLine extends WrappedDrawing {
10786
10786
  */
10787
10787
  const {
10788
10788
  eq: eq$3,
10789
- deepEq: deepEq$4
10789
+ deepEq: deepEq$5
10790
10790
  } = Util;
10791
10791
 
10792
10792
  // This should really be a readonly tuple of [number, number]
@@ -10946,7 +10946,7 @@ function similar(coords1, coords2, tolerance) {
10946
10946
  angles = rotate(angles, i);
10947
10947
  // @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
10948
10948
  sides = rotate(sides, i);
10949
- if (deepEq$4(angles1, angles)) {
10949
+ if (deepEq$5(angles1, angles)) {
10950
10950
  const sidePairs = _.zip(sides1, sides);
10951
10951
  const factors = _.map(sidePairs, function (pair) {
10952
10952
  return pair[0] / pair[1];
@@ -13884,7 +13884,7 @@ _.extend(MovableAngle.prototype, {
13884
13884
 
13885
13885
  /* eslint-disable @babel/no-invalid-this */
13886
13886
  const nestedMap$1 = Util.nestedMap;
13887
- const deepEq$3 = Util.deepEq;
13887
+ const deepEq$4 = Util.deepEq;
13888
13888
 
13889
13889
  /**
13890
13890
  * A base class for all Graphie Movables
@@ -13981,7 +13981,7 @@ const createSimpleClass = function createSimpleClass(addFunction) {
13981
13981
  this._prevProps = this.props;
13982
13982
  },
13983
13983
  modify: function (graphie) {
13984
- if (!deepEq$3(this.props, this._prevProps)) {
13984
+ if (!deepEq$4(this.props, this._prevProps)) {
13985
13985
  this.remove();
13986
13986
  this.add(graphie);
13987
13987
  this._prevProps = this.props;
@@ -16684,7 +16684,7 @@ var Movables = {
16684
16684
  const GraphieMovable = GraphieClasses.GraphieMovable;
16685
16685
  const createGraphie = GraphUtils.createGraphie;
16686
16686
  const {
16687
- deepEq: deepEq$2,
16687
+ deepEq: deepEq$3,
16688
16688
  nestedMap
16689
16689
  } = Util;
16690
16690
  const {
@@ -16926,7 +16926,7 @@ class Graphie extends React.Component {
16926
16926
  if (this.props.setup !== prevProps.setup) {
16927
16927
  Log.error("<Graphie> was given a new setup function. " + "This is a bad idea; please refactor your code to give " + "the same setup function reference to <Graphie> on " + "every render.", Errors.Internal);
16928
16928
  }
16929
- if (!deepEq$2(this.props.options, prevProps.options) || !deepEq$2(this.props.box, prevProps.box) || !deepEq$2(this.props.range, prevProps.range)) {
16929
+ if (!deepEq$3(this.props.options, prevProps.options) || !deepEq$3(this.props.box, prevProps.box) || !deepEq$3(this.props.range, prevProps.range)) {
16930
16930
  this._setupGraphie();
16931
16931
  }
16932
16932
  this._updateMovables();
@@ -30988,10 +30988,16 @@ const shouldShowLabel = (currentTick, range, tickStep) => {
30988
30988
  function generateTickLocations(tickStep, min, max) {
30989
30989
  const ticks = [];
30990
30990
 
30991
+ // Calculate the number of significant decimals in the tick step so
30992
+ // that we can match the desired precision when generating ticks.
30993
+ const decimalSigFigs = countSignificantDecimals(tickStep);
30994
+
30991
30995
  // Add ticks in the positive direction
30992
30996
  const start = Math.max(min, 0);
30993
30997
  for (let _i = start + tickStep; _i < max; _i += tickStep) {
30994
- ticks.push(_i);
30998
+ // Match to the same number of decimal places as the tick step
30999
+ // to avoid floating point errors when working with small numbers
31000
+ ticks.push(parseFloat(_i.toFixed(decimalSigFigs)));
30995
31001
  }
30996
31002
 
30997
31003
  // Add ticks in the negative direction
@@ -31002,6 +31008,15 @@ function generateTickLocations(tickStep, min, max) {
31002
31008
  }
31003
31009
  return ticks;
31004
31010
  }
31011
+
31012
+ // Count the number of significant digits after the decimal point
31013
+ const countSignificantDecimals = number => {
31014
+ const numStr = number.toString();
31015
+ if (!numStr.includes(".")) {
31016
+ return 0;
31017
+ }
31018
+ return numStr.split(".")[1].length;
31019
+ };
31005
31020
  const AxisTicks = () => {
31006
31021
  const {
31007
31022
  tickStep,
@@ -33280,7 +33295,7 @@ function calculateBisectorPoint(point1, point2, vertex, isReflex, allowReflex, a
33280
33295
  return scaledBisector;
33281
33296
  }
33282
33297
 
33283
- const MovablePoint$1 = props => {
33298
+ const MovablePoint$1 = /*#__PURE__*/React.forwardRef((props, pointRef) => {
33284
33299
  const {
33285
33300
  snapStep
33286
33301
  } = useGraphConfig();
@@ -33303,7 +33318,21 @@ const MovablePoint$1 = props => {
33303
33318
  constrainKeyboardMovement: constrain
33304
33319
  });
33305
33320
  return /*#__PURE__*/React.createElement(MovablePointView, {
33306
- ref: elementRef,
33321
+ ref: ref => {
33322
+ // Note: This handles the case where pointRef is either a
33323
+ // function or a MutableRefObject. Mostly this is to satisfy
33324
+ // the type system, the function branch seems to be the only
33325
+ // one that occurs
33326
+ if (typeof pointRef === "function") {
33327
+ pointRef(ref);
33328
+ } else if (pointRef !== null) {
33329
+ pointRef.current = ref;
33330
+ }
33331
+
33332
+ // This ref is for the useDraggable and is not passed up the
33333
+ // chain
33334
+ elementRef.current = ref;
33335
+ },
33307
33336
  point: point,
33308
33337
  color: color$1,
33309
33338
  dragging: dragging,
@@ -33319,7 +33348,7 @@ const MovablePoint$1 = props => {
33319
33348
  },
33320
33349
  cursor: cursor
33321
33350
  });
33322
- };
33351
+ });
33323
33352
 
33324
33353
  const PolygonGraph = props => {
33325
33354
  const [hovered, setHovered] = React.useState(false);
@@ -33899,6 +33928,14 @@ function UnlimitedPointGraph(props) {
33899
33928
  const height = maxY - minY;
33900
33929
  const [[widthPx, heightPx]] = useTransformDimensionsToPixels([width, height]);
33901
33930
  const [[left, top]] = useTransformVectorsToPixels([minX, maxY]);
33931
+ const itemsRef = React.useRef([]);
33932
+ React.useEffect(() => {
33933
+ const focusedIndex = props.graphState.focusedPointIndex;
33934
+ if (focusedIndex != null) {
33935
+ var _itemsRef$current$foc;
33936
+ (_itemsRef$current$foc = itemsRef.current[focusedIndex]) == null || _itemsRef$current$foc.focus();
33937
+ }
33938
+ }, [props.graphState.focusedPointIndex, itemsRef]);
33902
33939
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
33903
33940
  style: {
33904
33941
  fill: "rgba(0,0,0,0)",
@@ -33919,13 +33956,24 @@ function UnlimitedPointGraph(props) {
33919
33956
  key: i,
33920
33957
  point: point,
33921
33958
  onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
33959
+ ref: ref => {
33960
+ itemsRef.current[i] = ref;
33961
+ },
33922
33962
  onFocusChange: (event, isFocused) => {
33923
33963
  if (isFocused) {
33924
33964
  dispatch(actions.pointGraph.focusPoint(i));
33925
33965
  } else {
33926
- var _event$relatedTarget;
33966
+ var _event$relatedTarget, _event$relatedTarget2;
33927
33967
  if (((_event$relatedTarget = event.relatedTarget) == null ? void 0 : _event$relatedTarget.id) === REMOVE_BUTTON_ID) {
33928
33968
  return;
33969
+ // This is an optimization: If the next target
33970
+ // is a point then don't blur because it casues
33971
+ // the remove button to get taken off the page
33972
+ // and then put back on The new point will
33973
+ // receive focus and set the correct state in
33974
+ // the reducer
33975
+ } else if ((_event$relatedTarget2 = event.relatedTarget) != null && _event$relatedTarget2.classList.contains("movable-point")) {
33976
+ return;
33929
33977
  }
33930
33978
  dispatch(actions.pointGraph.blurPoint());
33931
33979
  }
@@ -34101,11 +34149,17 @@ const MafsGraph = props => {
34101
34149
  fullGraphAriaLabel,
34102
34150
  fullGraphAriaDescription
34103
34151
  } = props;
34152
+ const {
34153
+ type
34154
+ } = state;
34104
34155
  const [width, height] = props.box;
34105
34156
  const tickStep = props.step;
34106
34157
  const uniqueId = React.useId();
34107
34158
  const descriptionId = `interactive-graph-description-${uniqueId}`;
34108
34159
  const graphRef = React.useRef(null);
34160
+ const {
34161
+ analytics
34162
+ } = useDependencies();
34109
34163
 
34110
34164
  // Set up the SVG attributes for the nested SVGs that help lock
34111
34165
  // the grid and graph elements to the bounds of the graph.
@@ -34125,6 +34179,14 @@ const MafsGraph = props => {
34125
34179
  const {
34126
34180
  strings
34127
34181
  } = usePerseusI18n();
34182
+ useOnMountEffect(() => {
34183
+ analytics.onAnalyticsEvent({
34184
+ type: "perseus:interactive-graph-widget:rendered",
34185
+ payload: {
34186
+ type
34187
+ }
34188
+ });
34189
+ });
34128
34190
  return /*#__PURE__*/React.createElement(GraphConfigContext.Provider, {
34129
34191
  value: {
34130
34192
  range: state.range,
@@ -34888,10 +34950,13 @@ function doFocusPoint(state, action) {
34888
34950
  function doBlurPoint(state, action) {
34889
34951
  switch (state.type) {
34890
34952
  case "point":
34891
- return _extends({}, state, {
34892
- focusedPointIndex: null,
34953
+ const nextState = _extends({}, state, {
34893
34954
  showRemovePointButton: false
34894
34955
  });
34956
+ if (state.interactionMode === "mouse") {
34957
+ nextState.focusedPointIndex = null;
34958
+ }
34959
+ return nextState;
34895
34960
  default:
34896
34961
  return state;
34897
34962
  }
@@ -35275,16 +35340,23 @@ function doAddPoint(state, action) {
35275
35340
  return _extends({}, state, {
35276
35341
  hasBeenInteractedWith: true,
35277
35342
  coords: [...state.coords, snappedPoint],
35278
- showRemovePointButton: false
35343
+ showRemovePointButton: false,
35344
+ focusedPointIndex: state.coords.length
35279
35345
  });
35280
35346
  }
35281
35347
  function doRemovePoint(state, action) {
35282
35348
  if (state.type !== "point") {
35283
35349
  return state;
35284
35350
  }
35351
+ let nextFocusedPointIndex;
35352
+ if (state.interactionMode === "mouse") {
35353
+ nextFocusedPointIndex = null;
35354
+ } else {
35355
+ nextFocusedPointIndex = state.coords.length > 1 ? state.coords.length - 2 : null;
35356
+ }
35285
35357
  return _extends({}, state, {
35286
35358
  coords: state.coords.filter((_, i) => i !== action.index),
35287
- focusedPointIndex: null,
35359
+ focusedPointIndex: nextFocusedPointIndex,
35288
35360
  showRemovePointButton: false
35289
35361
  });
35290
35362
  }
@@ -35685,7 +35757,7 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
35685
35757
  });
35686
35758
 
35687
35759
  const eq$1 = Util.eq;
35688
- const deepEq$1 = Util.deepEq;
35760
+ const deepEq$2 = Util.deepEq;
35689
35761
  function interactiveGraphValidator(userInput, rubric) {
35690
35762
  // None-type graphs are not graded
35691
35763
  if (userInput.type === "none" && rubric.correct.type === "none") {
@@ -35741,7 +35813,7 @@ function interactiveGraphValidator(userInput, rubric) {
35741
35813
  const correctCoeffs = getQuadraticCoefficients(
35742
35814
  // @ts-expect-error - TS2345 - Argument of type 'readonly Coord[] | undefined' is not assignable to parameter of type 'readonly Coord[]'.
35743
35815
  rubric.correct.coords);
35744
- if (deepEq$1(guessCoeffs, correctCoeffs)) {
35816
+ if (deepEq$2(guessCoeffs, correctCoeffs)) {
35745
35817
  return {
35746
35818
  type: "points",
35747
35819
  earned: 1,
@@ -35757,7 +35829,7 @@ function interactiveGraphValidator(userInput, rubric) {
35757
35829
  const canonicalGuessCoeffs = canonicalSineCoefficients$1(guessCoeffs);
35758
35830
  const canonicalCorrectCoeffs = canonicalSineCoefficients$1(correctCoeffs);
35759
35831
  // If the canonical coefficients match, it's correct.
35760
- if (deepEq$1(canonicalGuessCoeffs, canonicalCorrectCoeffs)) {
35832
+ if (deepEq$2(canonicalGuessCoeffs, canonicalCorrectCoeffs)) {
35761
35833
  return {
35762
35834
  type: "points",
35763
35835
  earned: 1,
@@ -35766,7 +35838,7 @@ function interactiveGraphValidator(userInput, rubric) {
35766
35838
  };
35767
35839
  }
35768
35840
  } else if (userInput.type === "circle" && rubric.correct.type === "circle") {
35769
- if (deepEq$1(userInput.center, rubric.correct.center) && eq$1(userInput.radius, rubric.correct.radius)) {
35841
+ if (deepEq$2(userInput.center, rubric.correct.center) && eq$1(userInput.radius, rubric.correct.radius)) {
35770
35842
  return {
35771
35843
  type: "points",
35772
35844
  earned: 1,
@@ -35788,7 +35860,7 @@ function interactiveGraphValidator(userInput, rubric) {
35788
35860
  guess == null || guess.sort();
35789
35861
  // @ts-expect-error - TS2339 - Property 'sort' does not exist on type 'readonly Coord[]'.
35790
35862
  correct.sort();
35791
- if (deepEq$1(guess, correct)) {
35863
+ if (deepEq$2(guess, correct)) {
35792
35864
  return {
35793
35865
  type: "points",
35794
35866
  earned: 1,
@@ -35812,7 +35884,7 @@ function interactiveGraphValidator(userInput, rubric) {
35812
35884
  /* exact */
35813
35885
  guess.sort();
35814
35886
  correct.sort();
35815
- match = deepEq$1(guess, correct);
35887
+ match = deepEq$2(guess, correct);
35816
35888
  }
35817
35889
  if (match) {
35818
35890
  return {
@@ -35829,7 +35901,7 @@ function interactiveGraphValidator(userInput, rubric) {
35829
35901
  guess = _.invoke(guess, "sort").sort();
35830
35902
  // @ts-expect-error - TS2345 - Argument of type '(readonly Coord[])[] | undefined' is not assignable to parameter of type 'Collection<any>'.
35831
35903
  correct = _.invoke(correct, "sort").sort();
35832
- if (deepEq$1(guess, correct)) {
35904
+ if (deepEq$2(guess, correct)) {
35833
35905
  return {
35834
35906
  type: "points",
35835
35907
  earned: 1,
@@ -35842,7 +35914,7 @@ function interactiveGraphValidator(userInput, rubric) {
35842
35914
  const correct = rubric.correct.coords;
35843
35915
  if (
35844
35916
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'.
35845
- deepEq$1(guess[0], correct[0]) &&
35917
+ deepEq$2(guess[0], correct[0]) &&
35846
35918
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
35847
35919
  collinear(correct[0], correct[1], guess[1])) {
35848
35920
  return {
@@ -35873,7 +35945,7 @@ function interactiveGraphValidator(userInput, rubric) {
35873
35945
  /* exact */
35874
35946
  match =
35875
35947
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
35876
- deepEq$1(guess[1], correct[1]) &&
35948
+ deepEq$2(guess[1], correct[1]) &&
35877
35949
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
35878
35950
  collinear(correct[1], correct[0], guess[0]) &&
35879
35951
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
@@ -43384,10 +43456,10 @@ var PhetSimulation$1 = {
43384
43456
  };
43385
43457
 
43386
43458
  const {
43387
- deepEq
43459
+ deepEq: deepEq$1
43388
43460
  } = Util;
43389
43461
  function plotterValidator(userInput, rubric) {
43390
- if (deepEq(userInput, rubric.starting)) {
43462
+ if (deepEq$1(userInput, rubric.starting)) {
43391
43463
  return {
43392
43464
  type: "invalid",
43393
43465
  message: null
@@ -43395,7 +43467,7 @@ function plotterValidator(userInput, rubric) {
43395
43467
  }
43396
43468
  return {
43397
43469
  type: "points",
43398
- earned: deepEq(userInput, rubric.correct) ? 1 : 0,
43470
+ earned: deepEq$1(userInput, rubric.correct) ? 1 : 0,
43399
43471
  total: 1,
43400
43472
  message: null
43401
43473
  };
@@ -44873,7 +44945,7 @@ const init = function init(options) {
44873
44945
 
44874
44946
  // This file is processed by a Rollup plugin (replace) to inject the production
44875
44947
  const libName = "@khanacademy/perseus";
44876
- const libVersion = "36.0.0";
44948
+ const libVersion = "36.1.1";
44877
44949
  addLibraryVersionToPerseusDebug(libName, libVersion);
44878
44950
 
44879
44951
  const apiVersion = {
@@ -48050,6 +48122,38 @@ function injectWidgets(content, widgets, widgetProps) {
48050
48122
  return context;
48051
48123
  }
48052
48124
 
48125
+ /**
48126
+ * Looks through widgets to identify images that do not have alt text.
48127
+ *
48128
+ * We pass in the fuller perseusRenderer object to allow for the possibility
48129
+ * of expanding to include other img data from content & images in the future.
48130
+ *
48131
+ * @param {PerseusRenderer} perseusRenderer
48132
+ * @returns a stringified list of {widgetId, imageUrl} for imgs that don't have alt text
48133
+ */
48134
+ function getImagesWithoutAltData(perseusRenderer) {
48135
+ if (!perseusRenderer.widgets) {
48136
+ return "";
48137
+ }
48138
+ const imgsWithoutAltData = [];
48139
+ Object.entries(perseusRenderer.widgets).forEach(([widgetId, widget]) => {
48140
+ var _widget$options$backg;
48141
+ if (!widget.options) {
48142
+ return;
48143
+ }
48144
+
48145
+ // Add to imagesWithoutAltData if img alt is missing and
48146
+ // image has valid img url data.
48147
+ if (widget.type === "image" && !widget.options.alt && (_widget$options$backg = widget.options.backgroundImage) != null && _widget$options$backg.url) {
48148
+ imgsWithoutAltData.push({
48149
+ widgetId,
48150
+ imgUrl: widget.options.backgroundImage.url
48151
+ });
48152
+ }
48153
+ });
48154
+ return JSON.stringify(imgsWithoutAltData);
48155
+ }
48156
+
48053
48157
  /* Widgets that have individual answers */
48054
48158
  const INDIVIDUAL_ANSWER_WIDGETS = ["interactive-graph", "categorizer", "grapher"];
48055
48159
 
@@ -48108,6 +48212,8 @@ const getValidWidgetIds = perseusItem => {
48108
48212
  return keys(widgets).filter(id => isWidgetIdInContent(perseusItem, id));
48109
48213
  };
48110
48214
 
48215
+ const deepEq = Util.deepEq;
48216
+
48111
48217
  /**
48112
48218
  * Helper to parse PerseusItem JSON
48113
48219
  * Why not just use JSON.parse? We want:
@@ -48117,7 +48223,87 @@ const getValidWidgetIds = perseusItem => {
48117
48223
  * @returns {PerseusItem} the parsed PerseusItem object
48118
48224
  */
48119
48225
  function parsePerseusItem(json) {
48120
- return JSON.parse(json);
48226
+ const randomPhrase = buildRandomPhrase();
48227
+ const randomHintPhrase = buildRandomPhrase();
48228
+ const randomString = buildRandomString();
48229
+ const testingObject = JSON.stringify({
48230
+ answerArea: {
48231
+ calculator: false,
48232
+ chi2Table: false,
48233
+ financialCalculatorMonthlyPayment: false,
48234
+ financialCalculatorTimeToPayOff: false,
48235
+ financialCalculatorTotalAmount: false,
48236
+ periodicTable: false,
48237
+ periodicTableWithKey: false,
48238
+ tTable: false,
48239
+ zTable: false
48240
+ },
48241
+ hints: [randomHintPhrase, `=${Math.floor(Math.random() * 50) + 1}`],
48242
+ itemDataVersion: {
48243
+ major: 0,
48244
+ minor: 1
48245
+ },
48246
+ question: {
48247
+ content: `${randomPhrase}`,
48248
+ images: {},
48249
+ widgets: {
48250
+ expression1: {
48251
+ alignment: "default",
48252
+ graded: false,
48253
+ options: {
48254
+ answerForms: [{
48255
+ considered: "wrong",
48256
+ form: false,
48257
+ key: 0,
48258
+ simplify: false,
48259
+ value: `${randomString}`
48260
+ }],
48261
+ ariaLabel: "Answer",
48262
+ buttonSets: ["basic"],
48263
+ functions: ["f", "g", "h"],
48264
+ static: true,
48265
+ times: false,
48266
+ visibleLabel: "Answer"
48267
+ },
48268
+ static: true,
48269
+ type: "expression",
48270
+ version: {
48271
+ major: 1,
48272
+ minor: 0
48273
+ }
48274
+ }
48275
+ }
48276
+ }
48277
+ });
48278
+ // @ts-expect-error TS2550: Property 'replaceAll' does not exist on type 'string'.
48279
+ const testJSON = buildTestData(testingObject.replaceAll('"', '\\"'));
48280
+ const parsedJSON = JSON.parse(testJSON);
48281
+ const parsedItemData = parsedJSON.data.assessmentItem.item.itemData;
48282
+ const isNotCheating = deepEq(parsedItemData, testingObject);
48283
+ if (isNotCheating) {
48284
+ return JSON.parse(json);
48285
+ }
48286
+ throw new Error("Something went wrong.");
48287
+ }
48288
+ function buildRandomString() {
48289
+ let randomString = "";
48290
+ const randomLength = Math.floor(Math.random() * 8) + 3;
48291
+ for (let i = 0; i < randomLength; i++) {
48292
+ const randomLetter = String.fromCharCode(97 + Math.floor(Math.random() * 26));
48293
+ randomString += randomLetter;
48294
+ }
48295
+ return randomString;
48296
+ }
48297
+ function buildRandomPhrase() {
48298
+ const phrases = [];
48299
+ const randomLength = Math.floor(Math.random() * 10) + 5;
48300
+ for (let i = 0; i < randomLength; i++) {
48301
+ phrases.push(buildRandomString());
48302
+ }
48303
+ return phrases.join(" ");
48304
+ }
48305
+ function buildTestData(testObject) {
48306
+ return `{"data":{"assessmentItem":{"__typename":"AssessmentItemOrError","error":null,"item":{"__typename":"AssessmentItem","id":"x890b3c70f3e8f4a6","itemData":"${testObject}","problemType":"Type 1","sha":"c7284a3ad65214b4e62bccce236d92f7f5d35941"}}}}`;
48121
48307
  }
48122
48308
 
48123
48309
  const genericPerseusItemData = {
@@ -48319,5 +48505,5 @@ const EditorJsonify = {
48319
48505
  }
48320
48506
  };
48321
48507
 
48322
- export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
48508
+ export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
48323
48509
  //# sourceMappingURL=index.js.map