@khanacademy/perseus 49.2.0 → 49.2.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.css +2 -1
- package/dist/es/index.js +141 -185
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +2 -2
- package/dist/es/strings.js.map +1 -1
- package/dist/index.css +2 -1
- package/dist/index.js +140 -176
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +9 -7
- package/dist/server-item-renderer.d.ts +1 -1
- package/dist/strings.js +2 -2
- package/dist/strings.js.map +1 -1
- package/dist/types.d.ts +2 -5
- package/dist/util/parse-perseus-json/general-purpose-parsers/discriminated-union.d.ts +18 -5
- package/dist/util/parse-perseus-json/general-purpose-parsers/discriminated-union.typetest.d.ts +1 -0
- package/dist/util/parse-perseus-json/perseus-parsers/versioned-widget-options.d.ts +12 -21
- package/dist/widgets/expression/expression.d.ts +2 -2
- package/dist/widgets/interactive-graphs/graph-locked-labels-layer.d.ts +1 -3
- package/dist/widgets/interactive-graphs/graph-locked-layer.d.ts +0 -2
- package/dist/widgets/interactive-graphs/locked-figures/locked-ellipse.d.ts +1 -5
- package/dist/widgets/interactive-graphs/locked-figures/locked-function.d.ts +1 -5
- package/dist/widgets/interactive-graphs/locked-figures/locked-line.d.ts +0 -2
- package/dist/widgets/interactive-graphs/locked-figures/locked-point.d.ts +1 -5
- package/dist/widgets/interactive-graphs/locked-figures/locked-polygon.d.ts +1 -5
- package/dist/widgets/interactive-graphs/locked-figures/locked-vector.d.ts +1 -5
- package/package.json +1 -1
package/dist/es/index.js
CHANGED
|
@@ -32370,7 +32370,7 @@ const LegacyGrid = ({
|
|
|
32370
32370
|
* "new-awesomeness": MyAwesomeNewWidget;
|
|
32371
32371
|
*
|
|
32372
32372
|
* // A deprecated widget
|
|
32373
|
-
* "super-old-widget":
|
|
32373
|
+
* "super-old-widget": DeprecatedStandinWidget;
|
|
32374
32374
|
* }
|
|
32375
32375
|
* }
|
|
32376
32376
|
*
|
|
@@ -32564,46 +32564,28 @@ function LockedLabel(props) {
|
|
|
32564
32564
|
|
|
32565
32565
|
function GraphLockedLabelsLayer(props) {
|
|
32566
32566
|
const {
|
|
32567
|
-
flags,
|
|
32568
32567
|
lockedFigures
|
|
32569
32568
|
} = props;
|
|
32570
32569
|
return lockedFigures.map((figure, i) => {
|
|
32571
|
-
var
|
|
32570
|
+
var _figure$labels, _figure$points$0$labe, _figure$points$1$labe;
|
|
32572
32571
|
if (figure.type === "label") {
|
|
32573
32572
|
return /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
32574
32573
|
key: `label-${i}`
|
|
32575
32574
|
}, figure));
|
|
32576
32575
|
}
|
|
32577
|
-
|
|
32578
|
-
|
|
32579
|
-
|
|
32580
|
-
|
|
32581
|
-
|
|
32582
|
-
|
|
32583
|
-
|
|
32584
|
-
|
|
32585
|
-
|
|
32586
|
-
// Polygon flag + polygon type
|
|
32587
|
-
flags != null && (_flags$mafs5 = flags["mafs"]) != null && _flags$mafs5["locked-polygon-labels"] && figure.type === "polygon" ||
|
|
32588
|
-
// Function flag + function type
|
|
32589
|
-
flags != null && (_flags$mafs6 = flags["mafs"]) != null && _flags$mafs6["locked-function-labels"] && figure.type === "function") {
|
|
32590
|
-
var _figure$labels, _figure$points$0$labe, _figure$points$1$labe;
|
|
32591
|
-
return /*#__PURE__*/React.createElement(React.Fragment, {
|
|
32592
|
-
key: i
|
|
32593
|
-
}, (_figure$labels = figure.labels) == null ? void 0 : _figure$labels.map((label, j) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
32594
|
-
key: `${i}-label-${j}`
|
|
32595
|
-
}, label))), figure.type === "line" && /*#__PURE__*/React.createElement(React.Fragment, null, (_figure$points$0$labe = figure.points[0].labels) == null ? void 0 : _figure$points$0$labe.map((label, k) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
32596
|
-
key: `locked-figure-${i}-point-1-label-${k}`
|
|
32597
|
-
}, label))), (_figure$points$1$labe = figure.points[1].labels) == null ? void 0 : _figure$points$1$labe.map((label, k) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
32598
|
-
key: `locked-figure-${i}-point-2-label-${k}`
|
|
32599
|
-
}, label)))));
|
|
32600
|
-
}
|
|
32601
|
-
return null;
|
|
32576
|
+
return /*#__PURE__*/React.createElement(React.Fragment, {
|
|
32577
|
+
key: i
|
|
32578
|
+
}, (_figure$labels = figure.labels) == null ? void 0 : _figure$labels.map((label, j) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
32579
|
+
key: `${i}-label-${j}`
|
|
32580
|
+
}, label))), figure.type === "line" && /*#__PURE__*/React.createElement(React.Fragment, null, (_figure$points$0$labe = figure.points[0].labels) == null ? void 0 : _figure$points$0$labe.map((label, k) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
32581
|
+
key: `locked-figure-${i}-point-1-label-${k}`
|
|
32582
|
+
}, label))), (_figure$points$1$labe = figure.points[1].labels) == null ? void 0 : _figure$points$1$labe.map((label, k) => /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
32583
|
+
key: `locked-figure-${i}-point-2-label-${k}`
|
|
32584
|
+
}, label)))));
|
|
32602
32585
|
});
|
|
32603
32586
|
}
|
|
32604
32587
|
|
|
32605
32588
|
const LockedEllipse = props => {
|
|
32606
|
-
var _flags$mafs;
|
|
32607
32589
|
const {
|
|
32608
32590
|
center,
|
|
32609
32591
|
radius,
|
|
@@ -32611,10 +32593,9 @@ const LockedEllipse = props => {
|
|
|
32611
32593
|
color: color$1,
|
|
32612
32594
|
fillStyle,
|
|
32613
32595
|
strokeStyle,
|
|
32614
|
-
ariaLabel
|
|
32615
|
-
flags
|
|
32596
|
+
ariaLabel
|
|
32616
32597
|
} = props;
|
|
32617
|
-
const hasAria = ariaLabel
|
|
32598
|
+
const hasAria = !!ariaLabel;
|
|
32618
32599
|
return /*#__PURE__*/React.createElement("g", {
|
|
32619
32600
|
className: "locked-ellipse",
|
|
32620
32601
|
"aria-label": hasAria ? ariaLabel : undefined,
|
|
@@ -32639,7 +32620,6 @@ const LockedEllipse = props => {
|
|
|
32639
32620
|
};
|
|
32640
32621
|
|
|
32641
32622
|
const LockedFunction = props => {
|
|
32642
|
-
var _props$flags;
|
|
32643
32623
|
const [equation, setEquation] = useState();
|
|
32644
32624
|
const {
|
|
32645
32625
|
color,
|
|
@@ -32652,7 +32632,7 @@ const LockedFunction = props => {
|
|
|
32652
32632
|
style: strokeStyle,
|
|
32653
32633
|
domain
|
|
32654
32634
|
};
|
|
32655
|
-
const hasAria = props.ariaLabel
|
|
32635
|
+
const hasAria = !!props.ariaLabel;
|
|
32656
32636
|
useEffect(() => {
|
|
32657
32637
|
// Parsing the equation in a "useEffect" hook saves about 2ms each frame
|
|
32658
32638
|
// when the learner is interacting with the graph (i.e. moving points).
|
|
@@ -32768,7 +32748,6 @@ function getArrayWithoutDuplicates(array) {
|
|
|
32768
32748
|
}
|
|
32769
32749
|
|
|
32770
32750
|
const LockedLine = props => {
|
|
32771
|
-
var _flags$mafs;
|
|
32772
32751
|
const {
|
|
32773
32752
|
color: color$1,
|
|
32774
32753
|
lineStyle,
|
|
@@ -32777,11 +32756,10 @@ const LockedLine = props => {
|
|
|
32777
32756
|
showPoint1,
|
|
32778
32757
|
showPoint2,
|
|
32779
32758
|
ariaLabel,
|
|
32780
|
-
flags,
|
|
32781
32759
|
range
|
|
32782
32760
|
} = props;
|
|
32783
32761
|
const [point1, point2] = points;
|
|
32784
|
-
const hasAria = ariaLabel
|
|
32762
|
+
const hasAria = !!ariaLabel;
|
|
32785
32763
|
let line;
|
|
32786
32764
|
if (kind === "ray") {
|
|
32787
32765
|
// Rays extend to the end of the graph in one direction.
|
|
@@ -32848,16 +32826,14 @@ const LockedLine = props => {
|
|
|
32848
32826
|
};
|
|
32849
32827
|
|
|
32850
32828
|
const LockedPoint = props => {
|
|
32851
|
-
var _flags$mafs;
|
|
32852
32829
|
const {
|
|
32853
|
-
flags,
|
|
32854
32830
|
color: color$1,
|
|
32855
32831
|
coord,
|
|
32856
32832
|
filled,
|
|
32857
32833
|
ariaLabel
|
|
32858
32834
|
} = props;
|
|
32859
32835
|
const [x, y] = coord;
|
|
32860
|
-
const hasAria = ariaLabel
|
|
32836
|
+
const hasAria = !!ariaLabel;
|
|
32861
32837
|
return /*#__PURE__*/React.createElement("g", {
|
|
32862
32838
|
className: "locked-point",
|
|
32863
32839
|
"aria-label": hasAria ? ariaLabel : undefined,
|
|
@@ -32876,7 +32852,6 @@ const LockedPoint = props => {
|
|
|
32876
32852
|
};
|
|
32877
32853
|
|
|
32878
32854
|
const LockedPolygon = props => {
|
|
32879
|
-
var _props$flags;
|
|
32880
32855
|
const {
|
|
32881
32856
|
points,
|
|
32882
32857
|
color: color$1,
|
|
@@ -32884,7 +32859,7 @@ const LockedPolygon = props => {
|
|
|
32884
32859
|
fillStyle,
|
|
32885
32860
|
strokeStyle
|
|
32886
32861
|
} = props;
|
|
32887
|
-
const hasAria = props.ariaLabel
|
|
32862
|
+
const hasAria = !!props.ariaLabel;
|
|
32888
32863
|
return /*#__PURE__*/React.createElement("g", {
|
|
32889
32864
|
className: "locked-polygon",
|
|
32890
32865
|
"aria-label": hasAria ? props.ariaLabel : undefined,
|
|
@@ -32912,15 +32887,13 @@ const LockedPolygon = props => {
|
|
|
32912
32887
|
};
|
|
32913
32888
|
|
|
32914
32889
|
const LockedVector = props => {
|
|
32915
|
-
var _flags$mafs;
|
|
32916
32890
|
const {
|
|
32917
32891
|
color,
|
|
32918
32892
|
points,
|
|
32919
|
-
ariaLabel
|
|
32920
|
-
flags
|
|
32893
|
+
ariaLabel
|
|
32921
32894
|
} = props;
|
|
32922
32895
|
const [tail, tip] = points;
|
|
32923
|
-
const hasAria = ariaLabel
|
|
32896
|
+
const hasAria = !!ariaLabel;
|
|
32924
32897
|
return /*#__PURE__*/React.createElement("g", {
|
|
32925
32898
|
className: "locked-vector",
|
|
32926
32899
|
"aria-label": hasAria ? ariaLabel : undefined,
|
|
@@ -32934,7 +32907,6 @@ const LockedVector = props => {
|
|
|
32934
32907
|
|
|
32935
32908
|
const GraphLockedLayer = props => {
|
|
32936
32909
|
const {
|
|
32937
|
-
flags,
|
|
32938
32910
|
lockedFigures
|
|
32939
32911
|
} = props;
|
|
32940
32912
|
return /*#__PURE__*/React.createElement(React.Fragment, null, lockedFigures.map((figure, index) => {
|
|
@@ -32942,40 +32914,28 @@ const GraphLockedLayer = props => {
|
|
|
32942
32914
|
case "point":
|
|
32943
32915
|
return /*#__PURE__*/React.createElement(LockedPoint, _extends({
|
|
32944
32916
|
key: `point-${index}`
|
|
32945
|
-
}, figure
|
|
32946
|
-
flags: flags
|
|
32947
|
-
}));
|
|
32917
|
+
}, figure));
|
|
32948
32918
|
case "line":
|
|
32949
32919
|
return /*#__PURE__*/React.createElement(LockedLine, _extends({
|
|
32950
32920
|
key: `line-${index}`,
|
|
32951
32921
|
range: props.range
|
|
32952
|
-
}, figure
|
|
32953
|
-
flags: flags
|
|
32954
|
-
}));
|
|
32922
|
+
}, figure));
|
|
32955
32923
|
case "vector":
|
|
32956
32924
|
return /*#__PURE__*/React.createElement(LockedVector, _extends({
|
|
32957
32925
|
key: `vector-${index}`
|
|
32958
|
-
}, figure
|
|
32959
|
-
flags: flags
|
|
32960
|
-
}));
|
|
32926
|
+
}, figure));
|
|
32961
32927
|
case "ellipse":
|
|
32962
32928
|
return /*#__PURE__*/React.createElement(LockedEllipse, _extends({
|
|
32963
32929
|
key: `ellipse-${index}`
|
|
32964
|
-
}, figure
|
|
32965
|
-
flags: flags
|
|
32966
|
-
}));
|
|
32930
|
+
}, figure));
|
|
32967
32931
|
case "polygon":
|
|
32968
32932
|
return /*#__PURE__*/React.createElement(LockedPolygon, _extends({
|
|
32969
32933
|
key: `polygon-${index}`
|
|
32970
|
-
}, figure
|
|
32971
|
-
flags: flags
|
|
32972
|
-
}));
|
|
32934
|
+
}, figure));
|
|
32973
32935
|
case "function":
|
|
32974
32936
|
return /*#__PURE__*/React.createElement(LockedFunction, _extends({
|
|
32975
32937
|
key: `function-${index}`
|
|
32976
|
-
}, figure
|
|
32977
|
-
flags: flags
|
|
32978
|
-
}));
|
|
32938
|
+
}, figure));
|
|
32979
32939
|
case "label":
|
|
32980
32940
|
// This is rendered outside the SVG element, since
|
|
32981
32941
|
// TeX cannot be rendered inside an SVG.
|
|
@@ -35446,7 +35406,6 @@ function useDraggablePx(args) {
|
|
|
35446
35406
|
* - Interactive Graph Elements
|
|
35447
35407
|
*/
|
|
35448
35408
|
const MafsGraph = props => {
|
|
35449
|
-
var _props$flags;
|
|
35450
35409
|
const {
|
|
35451
35410
|
state,
|
|
35452
35411
|
dispatch,
|
|
@@ -35583,11 +35542,9 @@ const MafsGraph = props => {
|
|
|
35583
35542
|
})),
|
|
35584
35543
|
// Only render the axis ticks and arrows if the markings are set to a full "graph"
|
|
35585
35544
|
props.markings === "graph" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisTicks, null), /*#__PURE__*/React.createElement(AxisArrows, null)), /*#__PURE__*/React.createElement("svg", nestedSVGAttributes, props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLayer, {
|
|
35586
|
-
flags: props.flags,
|
|
35587
35545
|
lockedFigures: props.lockedFigures,
|
|
35588
35546
|
range: state.range
|
|
35589
|
-
}))),
|
|
35590
|
-
flags: props.flags,
|
|
35547
|
+
}))), props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLabelsLayer, {
|
|
35591
35548
|
lockedFigures: props.lockedFigures
|
|
35592
35549
|
}), /*#__PURE__*/React.createElement(View, {
|
|
35593
35550
|
style: {
|
|
@@ -45560,7 +45517,7 @@ const init = function init() {
|
|
|
45560
45517
|
|
|
45561
45518
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45562
45519
|
const libName = "@khanacademy/perseus";
|
|
45563
|
-
const libVersion = "49.2.
|
|
45520
|
+
const libVersion = "49.2.1";
|
|
45564
45521
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45565
45522
|
|
|
45566
45523
|
const apiVersion = {
|
|
@@ -47845,10 +47802,10 @@ class UnionBuilder {
|
|
|
47845
47802
|
this.parser = parser;
|
|
47846
47803
|
}
|
|
47847
47804
|
or(newBranch) {
|
|
47848
|
-
return new UnionBuilder(either
|
|
47805
|
+
return new UnionBuilder(either(this.parser, newBranch));
|
|
47849
47806
|
}
|
|
47850
47807
|
}
|
|
47851
|
-
function either
|
|
47808
|
+
function either(parseA, parseB) {
|
|
47852
47809
|
return (rawValue, ctx) => {
|
|
47853
47810
|
const resultA = parseA(rawValue, ctx);
|
|
47854
47811
|
if (isSuccess(resultA)) {
|
|
@@ -47901,9 +47858,9 @@ function parseWidgetWithVersion(parseVersion, parseType, parseOptions) {
|
|
|
47901
47858
|
const parseCategorizerWidget = parseWidget(constant("categorizer"), object({
|
|
47902
47859
|
items: array(string),
|
|
47903
47860
|
categories: array(string),
|
|
47904
|
-
randomizeItems: boolean,
|
|
47861
|
+
randomizeItems: defaulted(boolean, () => false),
|
|
47905
47862
|
static: defaulted(boolean, () => false),
|
|
47906
|
-
values: array(number),
|
|
47863
|
+
values: array(defaulted(number, () => 0)),
|
|
47907
47864
|
highlightLint: optional(boolean),
|
|
47908
47865
|
linterContext: optional(object({
|
|
47909
47866
|
contentType: string,
|
|
@@ -47923,7 +47880,7 @@ const parseCSProgramWidget = parseWidget(constant("cs-program"), object({
|
|
|
47923
47880
|
showButtons: boolean,
|
|
47924
47881
|
width: number,
|
|
47925
47882
|
height: number,
|
|
47926
|
-
static: boolean
|
|
47883
|
+
static: defaulted(boolean, () => false)
|
|
47927
47884
|
}));
|
|
47928
47885
|
|
|
47929
47886
|
const parseDefinitionWidget = parseWidget(constant("definition"), object({
|
|
@@ -47933,7 +47890,7 @@ const parseDefinitionWidget = parseWidget(constant("definition"), object({
|
|
|
47933
47890
|
}));
|
|
47934
47891
|
|
|
47935
47892
|
const parseDropdownWidget = parseWidget(constant("dropdown"), object({
|
|
47936
|
-
placeholder: string,
|
|
47893
|
+
placeholder: defaulted(string, () => ""),
|
|
47937
47894
|
ariaLabel: optional(string),
|
|
47938
47895
|
visibleLabel: optional(string),
|
|
47939
47896
|
static: defaulted(boolean, () => false),
|
|
@@ -47966,60 +47923,63 @@ function convert(f) {
|
|
|
47966
47923
|
* data does not match any of the versions.
|
|
47967
47924
|
*
|
|
47968
47925
|
* @example
|
|
47969
|
-
* const parseOptions = versionedWidgetOptions(parseOptionsV3)
|
|
47970
|
-
* .withMigrationFrom(parseOptionsV2, migrateV2ToV3)
|
|
47971
|
-
* .withMigrationFrom(parseOptionsV1, migrateV1ToV2)
|
|
47972
|
-
* .withMigrationFrom(parseOptionsV0, migrateV0ToV1)
|
|
47926
|
+
* const parseOptions = versionedWidgetOptions(3, parseOptionsV3)
|
|
47927
|
+
* .withMigrationFrom(2, parseOptionsV2, migrateV2ToV3)
|
|
47928
|
+
* .withMigrationFrom(1, parseOptionsV1, migrateV1ToV2)
|
|
47929
|
+
* .withMigrationFrom(0, parseOptionsV0, migrateV0ToV1)
|
|
47973
47930
|
* .parser;
|
|
47974
47931
|
*
|
|
47932
|
+
* @param latestMajorVersion the latest major version of the widget options.
|
|
47975
47933
|
* @param parseLatest a {@link Parser} for the latest version of the widget
|
|
47976
|
-
* options.
|
|
47977
|
-
* version.
|
|
47934
|
+
* options.
|
|
47978
47935
|
* @returns a builder object, to which migrations from earlier versions can be
|
|
47979
47936
|
* added. Migrations must be added in "reverse chronological" order as in the
|
|
47980
47937
|
* example above.
|
|
47981
47938
|
*/
|
|
47982
|
-
function versionedWidgetOptions(parseLatest) {
|
|
47983
|
-
return new VersionedWidgetOptionsParserBuilder(parseLatest, latest => latest);
|
|
47939
|
+
function versionedWidgetOptions(latestMajorVersion, parseLatest) {
|
|
47940
|
+
return new VersionedWidgetOptionsParserBuilder(latestMajorVersion, parseLatest, latest => latest, (raw, ctx) => ctx.failure("widget options with a known version number", raw));
|
|
47984
47941
|
}
|
|
47985
47942
|
class VersionedWidgetOptionsParserBuilder {
|
|
47986
|
-
constructor(
|
|
47987
|
-
this.parser =
|
|
47988
|
-
this.
|
|
47943
|
+
constructor(majorVersion, parseThisVersion, migrateToLatest, parseOtherVersions) {
|
|
47944
|
+
this.parser = void 0;
|
|
47945
|
+
this.migrateToLatest = migrateToLatest;
|
|
47946
|
+
this.parseOtherVersions = parseOtherVersions;
|
|
47947
|
+
const parseThisVersionAndMigrateToLatest = pipeParsers(parseThisVersion).then(convert(this.migrateToLatest)).parser;
|
|
47948
|
+
this.parser = (raw, ctx) => {
|
|
47949
|
+
if (!isObject(raw)) {
|
|
47950
|
+
return ctx.failure("object", raw);
|
|
47951
|
+
}
|
|
47952
|
+
const versionParseResult = parseVersionedObject(raw, ctx);
|
|
47953
|
+
if (isFailure(versionParseResult)) {
|
|
47954
|
+
return versionParseResult;
|
|
47955
|
+
}
|
|
47956
|
+
if (versionParseResult.value.version.major !== majorVersion) {
|
|
47957
|
+
return this.parseOtherVersions(raw, ctx);
|
|
47958
|
+
}
|
|
47959
|
+
return parseThisVersionAndMigrateToLatest(raw, ctx);
|
|
47960
|
+
};
|
|
47989
47961
|
}
|
|
47990
47962
|
|
|
47991
47963
|
/**
|
|
47992
47964
|
* Add a migration from an old version of the widget options.
|
|
47993
|
-
*
|
|
47994
|
-
* @returns a VersionedWidgetOptionsParserBuilder whose `parser` function
|
|
47995
|
-
* is capable of migrating the old version to the latest version. The parser
|
|
47996
|
-
* will always return the latest version of the widget options on a
|
|
47997
|
-
* successful parse.
|
|
47998
|
-
* @param parseOldVersion should be a {@link Parser} for the old options
|
|
47999
|
-
* type. It should fail if version.major isn't correct.
|
|
48000
|
-
* @param migrateToNextVersion should migrate the `Old` data to the
|
|
48001
|
-
* `Migratable` version of the current VersionedWidgetOptionsParserBuilder.
|
|
48002
|
-
* Usually, this means migrating to the next major version.
|
|
48003
47965
|
*/
|
|
48004
|
-
withMigrationFrom(parseOldVersion, migrateToNextVersion) {
|
|
48005
|
-
const
|
|
48006
|
-
const migrateToLatest = old => this.
|
|
48007
|
-
return new VersionedWidgetOptionsParserBuilder(
|
|
48008
|
-
const resultOfParsingLatest = parseLatestVersion(raw, ctx);
|
|
48009
|
-
if (isSuccess(resultOfParsingLatest)) {
|
|
48010
|
-
return resultOfParsingLatest;
|
|
48011
|
-
}
|
|
48012
|
-
const resultOfParsingOld = parseOldVersion(raw, ctx);
|
|
48013
|
-
if (isSuccess(resultOfParsingOld)) {
|
|
48014
|
-
return success(migrateToLatest(resultOfParsingOld.value));
|
|
48015
|
-
}
|
|
48016
|
-
|
|
48017
|
-
// If we're here, neither parse succeeded. Return the failure.
|
|
48018
|
-
return resultOfParsingOld;
|
|
48019
|
-
}, migrateToLatest);
|
|
47966
|
+
withMigrationFrom(majorVersion, parseOldVersion, migrateToNextVersion) {
|
|
47967
|
+
const parseOtherVersions = this.parser;
|
|
47968
|
+
const migrateToLatest = old => this.migrateToLatest(migrateToNextVersion(old));
|
|
47969
|
+
return new VersionedWidgetOptionsParserBuilder(majorVersion, parseOldVersion, migrateToLatest, parseOtherVersions);
|
|
48020
47970
|
}
|
|
48021
47971
|
}
|
|
47972
|
+
const parseVersionedObject = object({
|
|
47973
|
+
version: defaulted(object({
|
|
47974
|
+
major: number,
|
|
47975
|
+
minor: number
|
|
47976
|
+
}), () => ({
|
|
47977
|
+
major: 0,
|
|
47978
|
+
minor: 0
|
|
47979
|
+
}))
|
|
47980
|
+
});
|
|
48022
47981
|
|
|
47982
|
+
const stringOrNumberOrNullOrUndefined = union(string).or(number).or(constant(null)).or(constant(undefined)).parser;
|
|
48023
47983
|
const parsePossiblyInvalidAnswerForm = object({
|
|
48024
47984
|
// `value` is the possibly invalid part of this. It should always be a
|
|
48025
47985
|
// string, but some answer forms don't have it. The Expression widget
|
|
@@ -48028,7 +47988,7 @@ const parsePossiblyInvalidAnswerForm = object({
|
|
|
48028
47988
|
form: defaulted(boolean, () => false),
|
|
48029
47989
|
simplify: defaulted(boolean, () => false),
|
|
48030
47990
|
considered: enumeration("correct", "wrong", "ungraded"),
|
|
48031
|
-
key: pipeParsers(
|
|
47991
|
+
key: pipeParsers(stringOrNumberOrNullOrUndefined).then(convert(String)).parser
|
|
48032
47992
|
});
|
|
48033
47993
|
function removeInvalidAnswerForms(possiblyInvalid) {
|
|
48034
47994
|
const valid = [];
|
|
@@ -48045,6 +48005,11 @@ function removeInvalidAnswerForms(possiblyInvalid) {
|
|
|
48045
48005
|
}
|
|
48046
48006
|
return valid;
|
|
48047
48007
|
}
|
|
48008
|
+
|
|
48009
|
+
// NOTE(benchristel): I copied the default buttonSets from
|
|
48010
|
+
// expression.tsx. See the parse-perseus-json/README.md for
|
|
48011
|
+
// an explanation of why we want to duplicate the default here.
|
|
48012
|
+
const parseButtonSets = defaulted(array(enumeration("basic", "basic+div", "trig", "prealgebra", "logarithms", "basic relations", "advanced relations")), () => ["basic", "trig", "prealgebra", "logarithms"]);
|
|
48048
48013
|
const version1 = object({
|
|
48049
48014
|
major: constant(1),
|
|
48050
48015
|
minor: number
|
|
@@ -48055,7 +48020,7 @@ const parseExpressionWidgetV1 = parseWidgetWithVersion(version1, constant("expre
|
|
|
48055
48020
|
times: boolean,
|
|
48056
48021
|
visibleLabel: optional(string),
|
|
48057
48022
|
ariaLabel: optional(string),
|
|
48058
|
-
buttonSets:
|
|
48023
|
+
buttonSets: parseButtonSets,
|
|
48059
48024
|
buttonsVisible: optional(enumeration("always", "never", "focused"))
|
|
48060
48025
|
}));
|
|
48061
48026
|
const version0 = optional(object({
|
|
@@ -48070,7 +48035,7 @@ const parseExpressionWidgetV0 = parseWidgetWithVersion(version0, constant("expre
|
|
|
48070
48035
|
form: boolean,
|
|
48071
48036
|
simplify: boolean,
|
|
48072
48037
|
value: string,
|
|
48073
|
-
buttonSets:
|
|
48038
|
+
buttonSets: parseButtonSets,
|
|
48074
48039
|
buttonsVisible: optional(enumeration("always", "never", "focused"))
|
|
48075
48040
|
}));
|
|
48076
48041
|
function migrateV0ToV1(widget) {
|
|
@@ -48098,7 +48063,7 @@ function migrateV0ToV1(widget) {
|
|
|
48098
48063
|
}
|
|
48099
48064
|
});
|
|
48100
48065
|
}
|
|
48101
|
-
const parseExpressionWidget = versionedWidgetOptions(parseExpressionWidgetV1).withMigrationFrom(parseExpressionWidgetV0, migrateV0ToV1).parser;
|
|
48066
|
+
const parseExpressionWidget = versionedWidgetOptions(1, parseExpressionWidgetV1).withMigrationFrom(0, parseExpressionWidgetV0, migrateV0ToV1).parser;
|
|
48102
48067
|
|
|
48103
48068
|
const parsePerseusRenderer = defaulted(object({
|
|
48104
48069
|
// TODO(benchristel): content is also defaulted to empty string in
|
|
@@ -48119,13 +48084,14 @@ const parsePerseusRenderer = defaulted(object({
|
|
|
48119
48084
|
images: {}
|
|
48120
48085
|
}));
|
|
48121
48086
|
|
|
48087
|
+
const falseToNull = pipeParsers(constant(false)).then(convert(() => null)).parser;
|
|
48122
48088
|
const parseGradedGroupWidgetOptions = object({
|
|
48123
48089
|
title: defaulted(string, () => ""),
|
|
48124
48090
|
hasHint: optional(nullable(boolean)),
|
|
48125
48091
|
// This module has an import cycle with parsePerseusRenderer.
|
|
48126
48092
|
// The anonymous function below ensures that we don't try to access
|
|
48127
48093
|
// parsePerseusRenderer before it's defined.
|
|
48128
|
-
hint:
|
|
48094
|
+
hint: union(falseToNull).or(constant(null)).or(constant(undefined)).or((rawVal, ctx) => parsePerseusRenderer(rawVal, ctx)).parser,
|
|
48129
48095
|
content: string,
|
|
48130
48096
|
// This module has an import cycle with parseWidgetsMap.
|
|
48131
48097
|
// The anonymous function below ensures that we don't try to access
|
|
@@ -48144,28 +48110,41 @@ const parseGradedGroupSetWidget = parseWidget(constant("graded-group-set"), obje
|
|
|
48144
48110
|
gradedGroups: array(parseGradedGroupWidgetOptions)
|
|
48145
48111
|
}));
|
|
48146
48112
|
|
|
48147
|
-
|
|
48148
|
-
|
|
48149
|
-
|
|
48150
|
-
|
|
48151
|
-
|
|
48152
|
-
|
|
48153
|
-
|
|
48113
|
+
/**
|
|
48114
|
+
* discriminatedUnion() should be preferred over union() when parsing a
|
|
48115
|
+
* discriminated union type, because discriminatedUnion() produces more
|
|
48116
|
+
* understandable failure messages. It takes the discriminant as the source of
|
|
48117
|
+
* truth for which variant is to be parsed, and expects the other data to match
|
|
48118
|
+
* that variant.
|
|
48119
|
+
*/
|
|
48120
|
+
function discriminatedUnionOn(discriminantKey) {
|
|
48121
|
+
const noMoreBranches = (raw, ctx) => {
|
|
48122
|
+
if (!isObject(raw)) {
|
|
48123
|
+
return ctx.failure("object", raw);
|
|
48124
|
+
}
|
|
48125
|
+
return ctx.forSubtree(discriminantKey).failure("a valid value", raw[discriminantKey]);
|
|
48126
|
+
};
|
|
48127
|
+
return new DiscriminatedUnionBuilder(discriminantKey, noMoreBranches);
|
|
48154
48128
|
}
|
|
48155
48129
|
class DiscriminatedUnionBuilder {
|
|
48156
|
-
constructor(parser) {
|
|
48130
|
+
constructor(discriminantKey, parser) {
|
|
48131
|
+
this.discriminantKey = discriminantKey;
|
|
48157
48132
|
this.parser = parser;
|
|
48158
48133
|
}
|
|
48159
|
-
|
|
48160
|
-
|
|
48134
|
+
withBranch(discriminantValue, parseNewVariant) {
|
|
48135
|
+
const parseNewBranch = discriminatedUnionBranch(this.discriminantKey, discriminantValue, parseNewVariant, this.parser);
|
|
48136
|
+
return new DiscriminatedUnionBuilder(this.discriminantKey, parseNewBranch);
|
|
48161
48137
|
}
|
|
48162
48138
|
}
|
|
48163
|
-
function
|
|
48164
|
-
return (
|
|
48165
|
-
if (
|
|
48166
|
-
return
|
|
48139
|
+
function discriminatedUnionBranch(discriminantKey, discriminantValue, parseVariant, parseOtherBranches) {
|
|
48140
|
+
return (raw, ctx) => {
|
|
48141
|
+
if (!isObject(raw)) {
|
|
48142
|
+
return ctx.failure("object", raw);
|
|
48167
48143
|
}
|
|
48168
|
-
|
|
48144
|
+
if (raw[discriminantKey] === discriminantValue) {
|
|
48145
|
+
return parseVariant(raw, ctx);
|
|
48146
|
+
}
|
|
48147
|
+
return parseOtherBranches(raw, ctx);
|
|
48169
48148
|
};
|
|
48170
48149
|
}
|
|
48171
48150
|
|
|
@@ -48173,41 +48152,27 @@ const pairOfNumbers$3 = pair(number, number);
|
|
|
48173
48152
|
const pairOfPoints = pair(pairOfNumbers$3, pairOfNumbers$3);
|
|
48174
48153
|
const parseGrapherWidget = parseWidget(constant("grapher"), object({
|
|
48175
48154
|
availableTypes: array(enumeration("absolute_value", "exponential", "linear", "logarithm", "quadratic", "sinusoid", "tangent")),
|
|
48176
|
-
correct:
|
|
48177
|
-
type: constant("absolute_value")
|
|
48178
|
-
}), object({
|
|
48155
|
+
correct: discriminatedUnionOn("type").withBranch("absolute_value", object({
|
|
48179
48156
|
type: constant("absolute_value"),
|
|
48180
48157
|
coords: pairOfPoints
|
|
48181
|
-
})).
|
|
48182
|
-
type: constant("exponential")
|
|
48183
|
-
}), object({
|
|
48158
|
+
})).withBranch("exponential", object({
|
|
48184
48159
|
type: constant("exponential"),
|
|
48185
48160
|
asymptote: pairOfPoints,
|
|
48186
48161
|
coords: pairOfPoints
|
|
48187
|
-
})).
|
|
48188
|
-
type: constant("linear")
|
|
48189
|
-
}), object({
|
|
48162
|
+
})).withBranch("linear", object({
|
|
48190
48163
|
type: constant("linear"),
|
|
48191
|
-
coords: pairOfPoints
|
|
48192
|
-
})).
|
|
48193
|
-
type: constant("logarithm")
|
|
48194
|
-
}), object({
|
|
48164
|
+
coords: defaulted(pairOfPoints, () => [[-5, 5], [5, 5]])
|
|
48165
|
+
})).withBranch("logarithm", object({
|
|
48195
48166
|
type: constant("logarithm"),
|
|
48196
48167
|
asymptote: pairOfPoints,
|
|
48197
48168
|
coords: pairOfPoints
|
|
48198
|
-
})).
|
|
48199
|
-
type: constant("quadratic")
|
|
48200
|
-
}), object({
|
|
48169
|
+
})).withBranch("quadratic", object({
|
|
48201
48170
|
type: constant("quadratic"),
|
|
48202
48171
|
coords: pairOfPoints
|
|
48203
|
-
})).
|
|
48204
|
-
type: constant("sinusoid")
|
|
48205
|
-
}), object({
|
|
48172
|
+
})).withBranch("sinusoid", object({
|
|
48206
48173
|
type: constant("sinusoid"),
|
|
48207
48174
|
coords: pairOfPoints
|
|
48208
|
-
})).
|
|
48209
|
-
type: constant("tangent")
|
|
48210
|
-
}), object({
|
|
48175
|
+
})).withBranch("tangent", object({
|
|
48211
48176
|
type: constant("tangent"),
|
|
48212
48177
|
coords: pairOfPoints
|
|
48213
48178
|
})).parser,
|
|
@@ -48455,23 +48420,7 @@ const parseInteractionWidget = parseWidget(constant("interaction"), object({
|
|
|
48455
48420
|
rulerTicks: optional(number),
|
|
48456
48421
|
tickStep: pairOfNumbers$1
|
|
48457
48422
|
}),
|
|
48458
|
-
elements: array(
|
|
48459
|
-
type: parseFunctionType
|
|
48460
|
-
}), parseFunctionElement).or(object({
|
|
48461
|
-
type: parseLabelType
|
|
48462
|
-
}), parseLabelElement).or(object({
|
|
48463
|
-
type: parseLineType
|
|
48464
|
-
}), parseLineElement).or(object({
|
|
48465
|
-
type: parseMovableLineType
|
|
48466
|
-
}), parseMovableLineElement).or(object({
|
|
48467
|
-
type: parseMovablePointType
|
|
48468
|
-
}), parseMovablePointElement).or(object({
|
|
48469
|
-
type: parseParametricType
|
|
48470
|
-
}), parseParametricElement).or(object({
|
|
48471
|
-
type: parsePointType
|
|
48472
|
-
}), parsePointElement).or(object({
|
|
48473
|
-
type: parseRectangleType
|
|
48474
|
-
}), parseRectangleElement).parser)
|
|
48423
|
+
elements: array(discriminatedUnionOn("type").withBranch("function", parseFunctionElement).withBranch("label", parseLabelElement).withBranch("line", parseLineElement).withBranch("movable-line", parseMovableLineElement).withBranch("movable-point", parseMovablePointElement).withBranch("parametric", parseParametricElement).withBranch("point", parsePointElement).withBranch("rectangle", parseRectangleElement).parser)
|
|
48475
48424
|
}));
|
|
48476
48425
|
|
|
48477
48426
|
// Used to represent 2-D points and ranges
|
|
@@ -48529,7 +48478,7 @@ const parsePerseusGraphTypePolygon = object({
|
|
|
48529
48478
|
showAngles: optional(boolean),
|
|
48530
48479
|
showSides: optional(boolean),
|
|
48531
48480
|
snapTo: optional(enumeration("grid", "angles", "sides")),
|
|
48532
|
-
match: optional(enumeration("similar", "congruent", "approx")),
|
|
48481
|
+
match: optional(enumeration("similar", "congruent", "approx", "exact")),
|
|
48533
48482
|
startCoords: optional(array(pairOfNumbers)),
|
|
48534
48483
|
// TODO: remove coord? it's legacy.
|
|
48535
48484
|
coord: optional(pairOfNumbers)
|
|
@@ -48564,7 +48513,7 @@ const parsePerseusGraphTypeSinusoid = object({
|
|
|
48564
48513
|
// TODO: remove coord? it's legacy.
|
|
48565
48514
|
coord: optional(pairOfNumbers)
|
|
48566
48515
|
});
|
|
48567
|
-
const parsePerseusGraphType =
|
|
48516
|
+
const parsePerseusGraphType = discriminatedUnionOn("type").withBranch("angle", parsePerseusGraphTypeAngle).withBranch("circle", parsePerseusGraphTypeCircle).withBranch("linear", parsePerseusGraphTypeLinear).withBranch("linear-system", parsePerseusGraphTypeLinearSystem).withBranch("none", parsePerseusGraphTypeNone).withBranch("point", parsePerseusGraphTypePoint).withBranch("polygon", parsePerseusGraphTypePolygon).withBranch("quadratic", parsePerseusGraphTypeQuadratic).withBranch("ray", parsePerseusGraphTypeRay).withBranch("segment", parsePerseusGraphTypeSegment).withBranch("sinusoid", parsePerseusGraphTypeSinusoid).parser;
|
|
48568
48517
|
const parseLockedFigureColor = enumeration(...lockedFigureColorNames);
|
|
48569
48518
|
const parseLockedFigureFillType = enumeration("none", "white", "translucent", "solid");
|
|
48570
48519
|
const parseLockedLineStyle = enumeration("solid", "dashed");
|
|
@@ -48683,7 +48632,7 @@ const parseLabelImageWidget = parseWidget(constant("label-image"), object({
|
|
|
48683
48632
|
})),
|
|
48684
48633
|
hideChoicesFromInstructions: boolean,
|
|
48685
48634
|
multipleAnswers: boolean,
|
|
48686
|
-
static: boolean
|
|
48635
|
+
static: defaulted(boolean, () => false)
|
|
48687
48636
|
}));
|
|
48688
48637
|
|
|
48689
48638
|
const parseMatcherWidget = parseWidget(constant("matcher"), object({
|
|
@@ -48694,7 +48643,8 @@ const parseMatcherWidget = parseWidget(constant("matcher"), object({
|
|
|
48694
48643
|
padding: boolean
|
|
48695
48644
|
}));
|
|
48696
48645
|
|
|
48697
|
-
const
|
|
48646
|
+
const numberOrString = union(number).or(string).parser;
|
|
48647
|
+
const numeric = pipeParsers(defaulted(numberOrString, () => NaN)).then(stringToNumber).parser;
|
|
48698
48648
|
const parseMatrixWidget = parseWidget(defaulted(constant("matrix"), () => "matrix"), object({
|
|
48699
48649
|
prefix: optional(string),
|
|
48700
48650
|
suffix: optional(string),
|
|
@@ -48713,7 +48663,8 @@ const parseMeasurerWidget = parseWidget(constant("measurer"), object({
|
|
|
48713
48663
|
rulerPixels: number,
|
|
48714
48664
|
rulerLength: number,
|
|
48715
48665
|
box: pair(number, number),
|
|
48716
|
-
|
|
48666
|
+
// TODO(benchristel): static is not used. Remove it?
|
|
48667
|
+
static: defaulted(boolean, () => false)
|
|
48717
48668
|
}));
|
|
48718
48669
|
|
|
48719
48670
|
const parseMoleculeRendererWidget = parseWidget(constant("molecule-renderer"), object({
|
|
@@ -48722,9 +48673,10 @@ const parseMoleculeRendererWidget = parseWidget(constant("molecule-renderer"), o
|
|
|
48722
48673
|
smiles: optional(string)
|
|
48723
48674
|
}));
|
|
48724
48675
|
|
|
48676
|
+
const emptyStringToNull = pipeParsers(constant("")).then(convert(() => null)).parser;
|
|
48725
48677
|
const parseNumberLineWidget = parseWidget(constant("number-line"), object({
|
|
48726
48678
|
range: array(number),
|
|
48727
|
-
labelRange: array(nullable(number)),
|
|
48679
|
+
labelRange: array(nullable(union(number).or(emptyStringToNull).parser)),
|
|
48728
48680
|
labelStyle: string,
|
|
48729
48681
|
labelTicks: boolean,
|
|
48730
48682
|
isTickCtrl: optional(nullable(boolean)),
|
|
@@ -48736,10 +48688,10 @@ const parseNumberLineWidget = parseWidget(constant("number-line"), object({
|
|
|
48736
48688
|
snapDivisions: defaulted(number, () => 2),
|
|
48737
48689
|
tickStep: optional(nullable(number)),
|
|
48738
48690
|
correctRel: optional(nullable(string)),
|
|
48739
|
-
correctX: number,
|
|
48691
|
+
correctX: nullable(number),
|
|
48740
48692
|
initialX: optional(nullable(number)),
|
|
48741
48693
|
showTooltip: optional(boolean),
|
|
48742
|
-
static: boolean
|
|
48694
|
+
static: defaulted(boolean, () => false)
|
|
48743
48695
|
}));
|
|
48744
48696
|
|
|
48745
48697
|
const parseMathFormat = enumeration("integer", "mixed", "improper", "proper", "decimal", "percent", "pi");
|
|
@@ -48754,14 +48706,14 @@ const parseNumericInputWidget = parseWidget(constant("numeric-input"), object({
|
|
|
48754
48706
|
answerForms: optional(array(parseMathFormat)),
|
|
48755
48707
|
strict: boolean,
|
|
48756
48708
|
maxError: optional(nullable(number)),
|
|
48757
|
-
// TODO(benchristel): simplify should never be
|
|
48709
|
+
// TODO(benchristel): simplify should never be a boolean, but we
|
|
48758
48710
|
// have some content where it is anyway. If we ever backfill
|
|
48759
48711
|
// the data, we should simplify `simplify`.
|
|
48760
|
-
simplify: optional(nullable(union(string).or(pipeParsers(
|
|
48712
|
+
simplify: optional(nullable(union(string).or(pipeParsers(boolean).then(convert(String)).parser).parser))
|
|
48761
48713
|
})),
|
|
48762
48714
|
labelText: optional(string),
|
|
48763
48715
|
size: string,
|
|
48764
|
-
coefficient: boolean,
|
|
48716
|
+
coefficient: defaulted(boolean, () => false),
|
|
48765
48717
|
rightAlign: optional(boolean),
|
|
48766
48718
|
static: defaulted(boolean, () => false),
|
|
48767
48719
|
answerForms: optional(array(object({
|
|
@@ -48797,9 +48749,9 @@ const parsePassageRefWidget = parseWidget(constant("passage-ref"), object({
|
|
|
48797
48749
|
}));
|
|
48798
48750
|
|
|
48799
48751
|
const parsePassageWidget = parseWidget(constant("passage"), object({
|
|
48800
|
-
footnotes: string,
|
|
48752
|
+
footnotes: defaulted(string, () => ""),
|
|
48801
48753
|
passageText: string,
|
|
48802
|
-
passageTitle: string,
|
|
48754
|
+
passageTitle: defaulted(string, () => ""),
|
|
48803
48755
|
showLineNumbers: boolean,
|
|
48804
48756
|
static: defaulted(boolean, () => false)
|
|
48805
48757
|
}));
|
|
@@ -48983,6 +48935,10 @@ const parseWidgetsMapEntry = ([key, widget], widgetMap, ctx) => {
|
|
|
48983
48935
|
return parseAndAssign(`sequence ${id}`, parseDeprecatedWidget);
|
|
48984
48936
|
case "lights-puzzle":
|
|
48985
48937
|
return parseAndAssign(`lights-puzzle ${id}`, parseDeprecatedWidget);
|
|
48938
|
+
case "simulator":
|
|
48939
|
+
return parseAndAssign(`simulator ${id}`, parseDeprecatedWidget);
|
|
48940
|
+
case "transformer":
|
|
48941
|
+
return parseAndAssign(`transformer ${id}`, parseDeprecatedWidget);
|
|
48986
48942
|
default:
|
|
48987
48943
|
if (getWidget(type)) {
|
|
48988
48944
|
// @ts-expect-error - 'type' is not a valid widget type
|