@khanacademy/perseus-core 27.3.0 → 28.0.0
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/data-schema.d.ts +32 -6
- package/dist/es/index.item-splitting.js +6 -12
- package/dist/es/index.item-splitting.js.map +1 -1
- package/dist/es/index.js +11 -9
- package/dist/es/index.js.map +1 -1
- package/dist/feature-flags.d.ts +1 -1
- package/dist/index.item-splitting.js +6 -12
- package/dist/index.item-splitting.js.map +1 -1
- package/dist/index.js +11 -9
- package/dist/index.js.map +1 -1
- package/dist/parse-perseus-json/perseus-parsers/categorizer-widget.d.ts +0 -1
- package/dist/parse-perseus-json/perseus-parsers/expression-keys.d.ts +1 -0
- package/dist/parse-perseus-json/perseus-parsers/interactive-graph-user-input.d.ts +18 -4
- package/dist/parse-perseus-json/perseus-parsers/interactive-graph-widget.d.ts +54 -12
- package/dist/parse-perseus-json/regression-tests/item-data/interactive-graph-without-show-point-labels.d.ts +63 -0
- package/package.json +1 -1
package/dist/data-schema.d.ts
CHANGED
|
@@ -434,8 +434,6 @@ export type PerseusCategorizerWidgetOptions = {
|
|
|
434
434
|
* the category. e.g. [0, 1, 0, 1, 2]
|
|
435
435
|
*/
|
|
436
436
|
values: number[];
|
|
437
|
-
/** Whether we should highlight i18n linter errors found on this widget */
|
|
438
|
-
highlightLint?: boolean;
|
|
439
437
|
};
|
|
440
438
|
/** Options for the definition widget. Reveals a definition on click. */
|
|
441
439
|
export type PerseusDefinitionWidgetOptions = {
|
|
@@ -946,6 +944,8 @@ export type PerseusGraphTypeAngle = {
|
|
|
946
944
|
startCoords?: [Coord, Coord, Coord];
|
|
947
945
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
948
946
|
pointLabels?: [string, string, string];
|
|
947
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
948
|
+
showPointLabels?: boolean;
|
|
949
949
|
};
|
|
950
950
|
export type PerseusGraphTypeCircle = {
|
|
951
951
|
type: "circle";
|
|
@@ -958,6 +958,8 @@ export type PerseusGraphTypeCircle = {
|
|
|
958
958
|
};
|
|
959
959
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
960
960
|
pointLabels?: string[];
|
|
961
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
962
|
+
showPointLabels?: boolean;
|
|
961
963
|
};
|
|
962
964
|
export type PerseusGraphTypeLinear = {
|
|
963
965
|
type: "linear";
|
|
@@ -967,6 +969,8 @@ export type PerseusGraphTypeLinear = {
|
|
|
967
969
|
startCoords?: CollinearTuple;
|
|
968
970
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
969
971
|
pointLabels?: [string, string];
|
|
972
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
973
|
+
showPointLabels?: boolean;
|
|
970
974
|
};
|
|
971
975
|
export type PerseusGraphTypeLinearSystem = {
|
|
972
976
|
type: "linear-system";
|
|
@@ -976,6 +980,8 @@ export type PerseusGraphTypeLinearSystem = {
|
|
|
976
980
|
startCoords?: CollinearTuple[];
|
|
977
981
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
978
982
|
pointLabels?: string[];
|
|
983
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
984
|
+
showPointLabels?: boolean;
|
|
979
985
|
};
|
|
980
986
|
export type PerseusGraphTypeNone = {
|
|
981
987
|
type: "none";
|
|
@@ -994,6 +1000,8 @@ export type PerseusGraphTypePoint = {
|
|
|
994
1000
|
coord?: Coord;
|
|
995
1001
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
996
1002
|
pointLabels?: string[];
|
|
1003
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1004
|
+
showPointLabels?: boolean;
|
|
997
1005
|
};
|
|
998
1006
|
export type PerseusGraphTypePolygon = {
|
|
999
1007
|
type: "polygon";
|
|
@@ -1012,6 +1020,8 @@ export type PerseusGraphTypePolygon = {
|
|
|
1012
1020
|
startCoords?: Coord[];
|
|
1013
1021
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1014
1022
|
pointLabels?: string[];
|
|
1023
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1024
|
+
showPointLabels?: boolean;
|
|
1015
1025
|
};
|
|
1016
1026
|
export type PerseusGraphTypeQuadratic = {
|
|
1017
1027
|
type: "quadratic";
|
|
@@ -1021,6 +1031,8 @@ export type PerseusGraphTypeQuadratic = {
|
|
|
1021
1031
|
startCoords?: [Coord, Coord, Coord];
|
|
1022
1032
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1023
1033
|
pointLabels?: [string, string, string];
|
|
1034
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1035
|
+
showPointLabels?: boolean;
|
|
1024
1036
|
};
|
|
1025
1037
|
export type PerseusGraphTypeSegment = {
|
|
1026
1038
|
type: "segment";
|
|
@@ -1035,22 +1047,28 @@ export type PerseusGraphTypeSegment = {
|
|
|
1035
1047
|
startCoords?: CollinearTuple[];
|
|
1036
1048
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1037
1049
|
pointLabels?: string[];
|
|
1050
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1051
|
+
showPointLabels?: boolean;
|
|
1038
1052
|
};
|
|
1039
1053
|
export type PerseusGraphTypeSinusoid = {
|
|
1040
1054
|
type: "sinusoid";
|
|
1041
1055
|
/** Expects a list of 2 Coords */
|
|
1042
|
-
coords?: Coord
|
|
1056
|
+
coords?: [Coord, Coord] | null;
|
|
1043
1057
|
/** The initial coordinates the graph renders with. */
|
|
1044
|
-
startCoords?: Coord
|
|
1058
|
+
startCoords?: [Coord, Coord];
|
|
1045
1059
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1046
1060
|
pointLabels?: string[];
|
|
1061
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1062
|
+
showPointLabels?: boolean;
|
|
1047
1063
|
};
|
|
1048
1064
|
export type PerseusGraphTypeTangent = {
|
|
1049
1065
|
type: "tangent";
|
|
1050
|
-
coords?: Coord
|
|
1051
|
-
startCoords?: Coord
|
|
1066
|
+
coords?: [Coord, Coord] | null;
|
|
1067
|
+
startCoords?: [Coord, Coord];
|
|
1052
1068
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1053
1069
|
pointLabels?: string[];
|
|
1070
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1071
|
+
showPointLabels?: boolean;
|
|
1054
1072
|
};
|
|
1055
1073
|
export type PerseusGraphTypeExponential = {
|
|
1056
1074
|
type: "exponential";
|
|
@@ -1068,6 +1086,8 @@ export type PerseusGraphTypeExponential = {
|
|
|
1068
1086
|
};
|
|
1069
1087
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1070
1088
|
pointLabels?: string[];
|
|
1089
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1090
|
+
showPointLabels?: boolean;
|
|
1071
1091
|
};
|
|
1072
1092
|
export type PerseusGraphTypeLogarithm = {
|
|
1073
1093
|
type: "logarithm";
|
|
@@ -1085,6 +1105,8 @@ export type PerseusGraphTypeLogarithm = {
|
|
|
1085
1105
|
};
|
|
1086
1106
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1087
1107
|
pointLabels?: string[];
|
|
1108
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1109
|
+
showPointLabels?: boolean;
|
|
1088
1110
|
};
|
|
1089
1111
|
export type PerseusGraphTypeAbsoluteValue = {
|
|
1090
1112
|
type: "absolute-value";
|
|
@@ -1092,6 +1114,8 @@ export type PerseusGraphTypeAbsoluteValue = {
|
|
|
1092
1114
|
startCoords?: [Coord, Coord];
|
|
1093
1115
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1094
1116
|
pointLabels?: [string, string];
|
|
1117
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1118
|
+
showPointLabels?: boolean;
|
|
1095
1119
|
};
|
|
1096
1120
|
export type PerseusGraphTypeRay = {
|
|
1097
1121
|
type: "ray";
|
|
@@ -1101,6 +1125,8 @@ export type PerseusGraphTypeRay = {
|
|
|
1101
1125
|
startCoords?: CollinearTuple;
|
|
1102
1126
|
/** Custom label for each interactive point that will help with the screen reader. */
|
|
1103
1127
|
pointLabels?: [string, string];
|
|
1128
|
+
/** Opt-in: render a visible label next to each interactive point. */
|
|
1129
|
+
showPointLabels?: boolean;
|
|
1104
1130
|
};
|
|
1105
1131
|
export type PerseusGraphTypeVector = {
|
|
1106
1132
|
type: "vector";
|
|
@@ -52,7 +52,7 @@ const parseImages=defaulted(record(string,parsePerseusImageDetail),()=>({}));
|
|
|
52
52
|
|
|
53
53
|
function parseWidget(parseType,parseOptions){return objectWithAllPropertiesRequired({type:parseType,static:optional(boolean),graded:optional(boolean),alignment:optional(string),options:parseOptions,key:optional(nullable(number)),version:optional(object({major:number,minor:number}))})}function parseWidgetWithVersion(parseVersion,parseType,parseOptions){return objectWithAllPropertiesRequired({type:parseType,static:optional(boolean),graded:optional(boolean),alignment:optional(string),options:parseOptions,key:optional(nullable(number)),version:parseVersion})}
|
|
54
54
|
|
|
55
|
-
const parseCategorizerWidget=parseWidget(constant("categorizer"),object({items:array(string),categories:array(string),randomizeItems:defaulted(boolean,()=>false),static:defaulted(boolean,()=>false),values:defaulted(array(defaulted(number,()=>0)),()=>[])
|
|
55
|
+
const parseCategorizerWidget=parseWidget(constant("categorizer"),object({items:array(string),categories:array(string),randomizeItems:defaulted(boolean,()=>false),static:defaulted(boolean,()=>false),values:defaulted(array(defaulted(number,()=>0)),()=>[])}));
|
|
56
56
|
|
|
57
57
|
const parseCSProgramWidget=parseWidget(constant("cs-program"),object({programID:string,programType:any,settings:array(object({name:string,value:string})),showEditor:boolean,showButtons:boolean,height:number}));
|
|
58
58
|
|
|
@@ -68,11 +68,13 @@ function deriveExtraKeys(widgetOptions){if(widgetOptions.extraKeys){return widge
|
|
|
68
68
|
|
|
69
69
|
function convert(f){return (rawValue,ctx)=>ctx.success(f(rawValue))}
|
|
70
70
|
|
|
71
|
+
const keypadKeys=enumeration("PLUS","MINUS","NEGATIVE","TIMES","DIVIDE","DECIMAL","PERIOD","PERCENT","CDOT","EQUAL","NEQ","GT","LT","GEQ","LEQ","FRAC_INCLUSIVE","FRAC_EXCLUSIVE","FRAC","EXP","EXP_2","EXP_3","SQRT","CUBE_ROOT","RADICAL","LEFT_PAREN","RIGHT_PAREN","LN","LOG","LOG_N","SIN","COS","TAN","PI","THETA","UP","RIGHT","DOWN","LEFT","BACKSPACE","DISMISS","JUMP_OUT_PARENTHESES","JUMP_OUT_EXPONENT","JUMP_OUT_BASE","JUMP_INTO_NUMERATOR","JUMP_OUT_NUMERATOR","JUMP_OUT_DENOMINATOR","NUM_0","NUM_1","NUM_2","NUM_3","NUM_4","NUM_5","NUM_6","NUM_7","NUM_8","NUM_9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
|
|
72
|
+
|
|
71
73
|
const parseLegacyButtonSet=enumeration("basic","basic+div","trig","prealgebra","logarithms","basic relations","advanced relations","scientific");const parseLegacyButtonSets=defaulted(array(parseLegacyButtonSet),()=>["basic","trig","prealgebra","logarithms"]);
|
|
72
74
|
|
|
73
75
|
function versionedWidgetOptions(latestMajorVersion,parseLatest){return new VersionedWidgetOptionsParserBuilder(latestMajorVersion,parseLatest,latest=>latest,(raw,ctx)=>ctx.failure("widget options with a known version number",raw))}class VersionedWidgetOptionsParserBuilder{withMigrationFrom(majorVersion,parseOldVersion,migrateToNextVersion){const parseOtherVersions=this.parser;const migrateToLatest=old=>this.migrateToLatest(migrateToNextVersion(old));return new VersionedWidgetOptionsParserBuilder(majorVersion,parseOldVersion,migrateToLatest,parseOtherVersions)}constructor(majorVersion,parseThisVersion,migrateToLatest,parseOtherVersions){this.migrateToLatest=migrateToLatest;this.parseOtherVersions=parseOtherVersions;const parseThisVersionAndMigrateToLatest=pipeParsers(parseThisVersion).then(convert(this.migrateToLatest)).parser;this.parser=(raw,ctx)=>{if(!isPlainObject(raw)){return ctx.failure("object",raw)}const versionParseResult=parseVersionedObject(raw,ctx);if(isFailure(versionParseResult)){return versionParseResult}if(versionParseResult.value.version.major!==majorVersion){return this.parseOtherVersions(raw,ctx)}return parseThisVersionAndMigrateToLatest(raw,ctx)};}}const parseVersionedObject=object({version:defaulted(object({major:number,minor:number}),()=>({major:0,minor:0}))});
|
|
74
76
|
|
|
75
|
-
const stringOrNumberOrNullOrUndefined=union(string).or(number).or(constant(null)).or(constant(undefined)).parser;function numberOrNullToString(v){return typeof v==="number"||v===null?String(v):v}const parsePossiblyInvalidAnswerForm=object({value:optional(string),form:defaulted(boolean,()=>false),simplify:defaulted(boolean,()=>false),considered:enumeration("correct","wrong","ungraded"),key:pipeParsers(stringOrNumberOrNullOrUndefined).then(convert(numberOrNullToString)).parser});function removeInvalidAnswerForms(possiblyInvalid){return possiblyInvalid.flatMap(answerForm=>{const{value}=answerForm;if(value!=null){return [{...answerForm,value}]}return []})}const parseAnswerForms=pipeParsers(defaulted(array(parsePossiblyInvalidAnswerForm),()=>[])).then(convert(removeInvalidAnswerForms)).parser;const version2$1=object({major:constant(2),minor:number});const parseExpressionWidgetV2=parseWidgetWithVersion(version2$1,constant("expression"),object({answerForms:parseAnswerForms,functions:array(string),times:boolean,visibleLabel:optional(string),ariaLabel:optional(string),buttonSets:parseLegacyButtonSets,buttonsVisible:optional(enumeration("always","never","focused")),extraKeys:optional(array(
|
|
77
|
+
const stringOrNumberOrNullOrUndefined=union(string).or(number).or(constant(null)).or(constant(undefined)).parser;function numberOrNullToString(v){return typeof v==="number"||v===null?String(v):v}const parsePossiblyInvalidAnswerForm=object({value:optional(string),form:defaulted(boolean,()=>false),simplify:defaulted(boolean,()=>false),considered:enumeration("correct","wrong","ungraded"),key:pipeParsers(stringOrNumberOrNullOrUndefined).then(convert(numberOrNullToString)).parser});function removeInvalidAnswerForms(possiblyInvalid){return possiblyInvalid.flatMap(answerForm=>{const{value}=answerForm;if(value!=null){return [{...answerForm,value}]}return []})}const parseAnswerForms=pipeParsers(defaulted(array(parsePossiblyInvalidAnswerForm),()=>[])).then(convert(removeInvalidAnswerForms)).parser;const version2$1=object({major:constant(2),minor:number});const parseExpressionWidgetV2=parseWidgetWithVersion(version2$1,constant("expression"),object({answerForms:parseAnswerForms,functions:array(string),times:boolean,visibleLabel:optional(string),ariaLabel:optional(string),buttonSets:parseLegacyButtonSets,buttonsVisible:optional(enumeration("always","never","focused")),extraKeys:optional(array(keypadKeys))}));const version1$1=object({major:constant(1),minor:number});const parseExpressionWidgetV1=parseWidgetWithVersion(version1$1,constant("expression"),object({answerForms:parseAnswerForms,functions:array(string),times:boolean,visibleLabel:optional(string),ariaLabel:optional(string),buttonSets:parseLegacyButtonSets,buttonsVisible:optional(enumeration("always","never","focused"))}));function migrateV1ToV2$1(widget){const{options}=widget;return {...widget,version:{major:2,minor:0},options:{times:options.times,buttonSets:options.buttonSets,functions:options.functions,buttonsVisible:options.buttonsVisible,visibleLabel:options.visibleLabel,ariaLabel:options.ariaLabel,answerForms:options.answerForms,extraKeys:deriveExtraKeys(options)??[]}}}const version0$1=optional(object({major:constant(0),minor:number}));const parseExpressionWidgetV0=parseWidgetWithVersion(version0$1,constant("expression"),object({functions:array(string),times:boolean,visibleLabel:optional(string),ariaLabel:optional(string),form:boolean,simplify:boolean,value:string,buttonSets:parseLegacyButtonSets,buttonsVisible:optional(enumeration("always","never","focused"))}));function migrateV0ToV1$1(widget){const{options}=widget;return {...widget,version:{major:1,minor:0},options:{times:options.times,buttonSets:options.buttonSets,functions:options.functions,buttonsVisible:options.buttonsVisible,visibleLabel:options.visibleLabel,ariaLabel:options.ariaLabel,answerForms:[{considered:"correct",form:options.form,simplify:options.simplify,value:options.value}]}}}const parseExpressionWidget=versionedWidgetOptions(2,parseExpressionWidgetV2).withMigrationFrom(1,parseExpressionWidgetV1,migrateV1ToV2$1).withMigrationFrom(0,parseExpressionWidgetV0,migrateV0ToV1$1).parser;
|
|
76
78
|
|
|
77
79
|
const parseFreeResponseWidget=parseWidget(constant("free-response"),object({allowUnlimitedCharacters:boolean,characterLimit:number,placeholder:string,question:string,scoringCriteria:array(object({text:string}))}));
|
|
78
80
|
|
|
@@ -98,7 +100,7 @@ const booleanToString=(rawValue,ctx)=>{if(typeof rawValue==="boolean"){return ct
|
|
|
98
100
|
|
|
99
101
|
const pairOfNumbers$1=pair(number,number);const stringOrEmpty=defaulted(string,()=>"");const parseKey=pipeParsers(optional(string)).then(convert(String)).parser;const parseFunctionElement=object({type:constant("function"),key:parseKey,options:object({value:string,funcName:string,rangeMin:string,rangeMax:string,color:string,strokeDasharray:string,strokeWidth:number})});const parseLabelElement=object({type:constant("label"),key:parseKey,options:object({label:string,color:string,coordX:string,coordY:string})});const parseLineElement=object({type:constant("line"),key:parseKey,options:object({color:string,startX:string,startY:string,endX:string,endY:string,strokeDasharray:string,strokeWidth:number,arrows:string})});const parseMovableLineElement=object({type:constant("movable-line"),key:parseKey,options:object({startX:string,startY:string,startSubscript:number,endX:string,endY:string,endSubscript:number,constraint:string,snap:number,constraintFn:string,constraintXMin:string,constraintXMax:string,constraintYMin:string,constraintYMax:string})});const parseMovablePointElement=object({type:constant("movable-point"),key:parseKey,options:object({startX:string,startY:string,varSubscript:number,constraint:string,snap:number,constraintFn:string,constraintXMin:stringOrEmpty,constraintXMax:stringOrEmpty,constraintYMin:stringOrEmpty,constraintYMax:stringOrEmpty})});const parseParametricElement=object({type:constant("parametric"),key:parseKey,options:object({x:string,y:string,rangeMin:string,rangeMax:string,color:string,strokeDasharray:string,strokeWidth:number})});const parsePointElement=object({type:constant("point"),key:parseKey,options:object({color:string,coordX:string,coordY:string})});const parseRectangleElement=object({type:constant("rectangle"),key:parseKey,options:object({color:string,coordX:string,coordY:string,width:string,height:string})});const parseInteractionWidget=parseWidget(constant("interaction"),object({static:defaulted(boolean,()=>false),graph:object({editableSettings:optional(array(enumeration("canvas","graph"))),box:pairOfNumbers$1,labels:array(string),range:pair(pairOfNumbers$1,pairOfNumbers$1),gridStep:pairOfNumbers$1,markings:enumeration("graph","grid","none","axes"),snapStep:optional(pairOfNumbers$1),valid:optional(union(boolean).or(string).parser),backgroundImage:optional(parsePerseusImageBackground),showProtractor:optional(boolean),showRuler:optional(boolean),rulerLabel:optional(string),rulerTicks:optional(number),tickStep:pairOfNumbers$1}),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)}));
|
|
100
102
|
|
|
101
|
-
const pairOfNumbers=pair(number,number);const parsePerseusGraphTypeAngle=object({type:constant("angle"),showAngles:optional(boolean),allowReflexAngles:optional(boolean),angleOffsetDeg:optional(nullable(number)),snapDegrees:optional(number),match:optional(constant("congruent")),coords:optional(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers)),startCoords:optional(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers)),pointLabels:optional(trio(string,string,string))});const parsePerseusGraphTypeCircle=object({type:constant("circle"),center:optional(pairOfNumbers),radius:optional(number),startCoords:optional(object({center:pairOfNumbers,radius:number})),pointLabels:optional(array(string))});const parsePerseusGraphTypeLinear=object({type:constant("linear"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),pointLabels:optional(pair(string,string))});const parsePerseusGraphTypeLinearSystem=object({type:constant("linear-system"),coords:optional(nullable(array(pair(pairOfNumbers,pairOfNumbers)))),startCoords:optional(array(pair(pairOfNumbers,pairOfNumbers))),pointLabels:optional(array(string))});const parsePerseusGraphTypeNone=object({type:constant("none")});const parsePerseusGraphTypePoint=object({type:constant("point"),numPoints:optional(union(number).or(constant("unlimited")).parser),coords:optional(nullable(array(pairOfNumbers))),startCoords:optional(array(pairOfNumbers)),coord:optional(pairOfNumbers),pointLabels:optional(array(string))});const parsePerseusGraphTypePolygon=object({type:constant("polygon"),numSides:optional(union(number).or(constant("unlimited")).parser),showAngles:optional(boolean),showSides:optional(boolean),snapTo:optional(enumeration("grid","angles","sides")),match:optional(enumeration("similar","congruent","approx","exact")),startCoords:optional(array(pairOfNumbers)),coords:optional(nullable(array(pairOfNumbers))),pointLabels:optional(array(string))});const parsePerseusGraphTypeQuadratic=object({type:constant("quadratic"),coords:optional(nullable(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers))),startCoords:optional(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers)),pointLabels:optional(trio(string,string,string))});const parsePerseusGraphTypeRay=object({type:constant("ray"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),pointLabels:optional(pair(string,string))});const parsePerseusGraphTypeSegment=object({type:constant("segment"),numSegments:optional(number),coords:optional(nullable(array(pair(pairOfNumbers,pairOfNumbers)))),startCoords:optional(array(pair(pairOfNumbers,pairOfNumbers))),pointLabels:optional(array(string))});const parsePerseusGraphTypeSinusoid=object({type:constant("sinusoid"),coords:optional(nullable(
|
|
103
|
+
const pairOfNumbers=pair(number,number);const parsePerseusGraphTypeAngle=object({type:constant("angle"),showAngles:optional(boolean),allowReflexAngles:optional(boolean),angleOffsetDeg:optional(nullable(number)),snapDegrees:optional(number),match:optional(constant("congruent")),coords:optional(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers)),startCoords:optional(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers)),pointLabels:optional(trio(string,string,string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeCircle=object({type:constant("circle"),center:optional(pairOfNumbers),radius:optional(number),startCoords:optional(object({center:pairOfNumbers,radius:number})),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeLinear=object({type:constant("linear"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),pointLabels:optional(pair(string,string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeLinearSystem=object({type:constant("linear-system"),coords:optional(nullable(array(pair(pairOfNumbers,pairOfNumbers)))),startCoords:optional(array(pair(pairOfNumbers,pairOfNumbers))),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeNone=object({type:constant("none")});const parsePerseusGraphTypePoint=object({type:constant("point"),numPoints:optional(union(number).or(constant("unlimited")).parser),coords:optional(nullable(array(pairOfNumbers))),startCoords:optional(array(pairOfNumbers)),coord:optional(pairOfNumbers),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypePolygon=object({type:constant("polygon"),numSides:optional(union(number).or(constant("unlimited")).parser),showAngles:optional(boolean),showSides:optional(boolean),snapTo:optional(enumeration("grid","angles","sides")),match:optional(enumeration("similar","congruent","approx","exact")),startCoords:optional(array(pairOfNumbers)),coords:optional(nullable(array(pairOfNumbers))),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeQuadratic=object({type:constant("quadratic"),coords:optional(nullable(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers))),startCoords:optional(trio(pairOfNumbers,pairOfNumbers,pairOfNumbers)),pointLabels:optional(trio(string,string,string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeRay=object({type:constant("ray"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),pointLabels:optional(pair(string,string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeSegment=object({type:constant("segment"),numSegments:optional(number),coords:optional(nullable(array(pair(pairOfNumbers,pairOfNumbers)))),startCoords:optional(array(pair(pairOfNumbers,pairOfNumbers))),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeSinusoid=object({type:constant("sinusoid"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeExponential=object({type:constant("exponential"),coords:optional(nullable(array(pairOfNumbers))),asymptote:optional(nullable(number)),startCoords:optional(object({coords:pair(pairOfNumbers,pairOfNumbers),asymptote:number})),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeAbsoluteValue=object({type:constant("absolute-value"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),pointLabels:optional(pair(string,string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeTangent=object({type:constant("tangent"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeLogarithm=object({type:constant("logarithm"),coords:optional(nullable(array(pairOfNumbers))),asymptote:optional(nullable(number)),startCoords:optional(object({coords:pair(pairOfNumbers,pairOfNumbers),asymptote:number})),pointLabels:optional(array(string)),showPointLabels:optional(boolean)});const parsePerseusGraphTypeVector=object({type:constant("vector"),coords:optional(nullable(pair(pairOfNumbers,pairOfNumbers))),startCoords:optional(pair(pairOfNumbers,pairOfNumbers)),match:optional(enumeration("exact","congruent"))});const parsePerseusGraphType=discriminatedUnionOn("type").withBranch("absolute-value",parsePerseusGraphTypeAbsoluteValue).withBranch("angle",parsePerseusGraphTypeAngle).withBranch("circle",parsePerseusGraphTypeCircle).withBranch("exponential",parsePerseusGraphTypeExponential).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).withBranch("tangent",parsePerseusGraphTypeTangent).withBranch("logarithm",parsePerseusGraphTypeLogarithm).withBranch("vector",parsePerseusGraphTypeVector).parser;const parseLockedFigureColor=pipeParsers(enumeration("blue","gold","green","grayH","purple","pink","red","orange")).then(convert(color=>color==="orange"?"gold":color)).parser;const parseLockedFigureFillType=enumeration("none","white","translucent","solid");const parseLockedLineStyle=enumeration("solid","dashed");const parseStrokeWeight=defaulted(enumeration("medium","thin","thick"),()=>"medium");const parseLockedLabelType=object({type:constant("label"),coord:pairOfNumbers,text:string,color:parseLockedFigureColor,size:enumeration("small","medium","large")});const parseLockedPointType=object({type:constant("point"),coord:pairOfNumbers,color:parseLockedFigureColor,filled:boolean,labels:defaulted(array(parseLockedLabelType),()=>[]),ariaLabel:optional(string)});const parseLockedLineType=object({type:constant("line"),kind:enumeration("line","ray","segment"),points:pair(parseLockedPointType,parseLockedPointType),color:parseLockedFigureColor,lineStyle:parseLockedLineStyle,showPoint1:defaulted(boolean,()=>false),showPoint2:defaulted(boolean,()=>false),weight:parseStrokeWeight,labels:defaulted(array(parseLockedLabelType),()=>[]),ariaLabel:optional(string)});const parseLockedVectorType=object({type:constant("vector"),points:pair(pairOfNumbers,pairOfNumbers),color:parseLockedFigureColor,weight:parseStrokeWeight,labels:defaulted(array(parseLockedLabelType),()=>[]),ariaLabel:optional(string)});const parseLockedEllipseType=object({type:constant("ellipse"),center:pairOfNumbers,radius:pairOfNumbers,angle:number,color:parseLockedFigureColor,fillStyle:parseLockedFigureFillType,strokeStyle:parseLockedLineStyle,weight:parseStrokeWeight,labels:defaulted(array(parseLockedLabelType),()=>[]),ariaLabel:optional(string)});const parseLockedPolygonType=object({type:constant("polygon"),points:array(pairOfNumbers),color:parseLockedFigureColor,showVertices:boolean,fillStyle:parseLockedFigureFillType,strokeStyle:parseLockedLineStyle,weight:parseStrokeWeight,labels:defaulted(array(parseLockedLabelType),()=>[]),ariaLabel:optional(string)});const numberOrNegativeInfinity=union(number).or(constant(-Infinity)).parser;const numberOrPositiveInfinity=union(number).or(constant(Infinity)).parser;const parseLockedFunctionDomain=defaulted(pair(defaulted(numberOrNegativeInfinity,()=>-Infinity),defaulted(numberOrPositiveInfinity,()=>Infinity)),()=>[-Infinity,Infinity]);const parseLockedFunctionType=object({type:constant("function"),color:parseLockedFigureColor,strokeStyle:parseLockedLineStyle,weight:parseStrokeWeight,equation:string,directionalAxis:enumeration("x","y"),domain:parseLockedFunctionDomain,labels:defaulted(array(parseLockedLabelType),()=>[]),ariaLabel:optional(string)});const parseLockedFigure=discriminatedUnionOn("type").withBranch("point",parseLockedPointType).withBranch("line",parseLockedLineType).withBranch("vector",parseLockedVectorType).withBranch("ellipse",parseLockedEllipseType).withBranch("polygon",parseLockedPolygonType).withBranch("function",parseLockedFunctionType).withBranch("label",parseLockedLabelType).parser;const parseLabelLocation=union(enumeration("onAxis","alongEdge")).or(pipeParsers(constant("")).then(convert(()=>"onAxis")).parser).parser;const parseInteractiveGraphWidget=parseWidget(constant("interactive-graph"),object({step:pairOfNumbers,gridStep:optional(pairOfNumbers),snapStep:optional(pairOfNumbers),backgroundImage:optional(parsePerseusImageBackground),markings:enumeration("graph","grid","none","axes"),labels:optional(array(string)),labelLocation:optional(parseLabelLocation),showProtractor:boolean,showRuler:optional(boolean),showTooltips:optional(boolean),rulerLabel:optional(string),rulerTicks:optional(number),range:pair(pairOfNumbers,pairOfNumbers),showAxisArrows:defaulted(object({xMin:boolean,xMax:boolean,yMin:boolean,yMax:boolean}),()=>({xMin:true,xMax:true,yMin:true,yMax:true})),showAxisTicks:defaulted(object({x:boolean,y:boolean}),()=>({x:true,y:true})),graph:defaulted(parsePerseusGraphType,()=>({type:"linear"})),correct:defaulted(parsePerseusGraphType,()=>({type:"linear"})),lockedFigures:defaulted(array(parseLockedFigure),()=>[]),fullGraphAriaLabel:optional(string),fullGraphAriaDescription:optional(string)}));
|
|
102
104
|
|
|
103
105
|
const parseLabelImageWidget=parseWidget(constant("label-image"),object({choices:array(string),imageUrl:string,imageAlt:string,imageHeight:number,imageWidth:number,markers:array(object({answers:defaulted(array(string),()=>[]),label:string,x:number,y:number})),hideChoicesFromInstructions:boolean,multipleAnswers:boolean,static:defaulted(boolean,()=>false)}));
|
|
104
106
|
|
|
@@ -118,9 +120,7 @@ function parseRenderer(rawValue,ctx){return parsePerseusRenderer(rawValue,ctx)}c
|
|
|
118
120
|
|
|
119
121
|
const parsePhetSimulationWidget=parseWidget(constant("phet-simulation"),object({url:string,description:string}));
|
|
120
122
|
|
|
121
|
-
const plotterPlotTypes=
|
|
122
|
-
|
|
123
|
-
const parsePlotterWidget=parseWidget(constant("plotter"),object({labels:array(string),categories:array(string),type:enumeration(...plotterPlotTypes),maxY:number,scaleY:defaulted(number,()=>1),labelInterval:optional(nullable(number)),snapsPerLine:defaulted(number,()=>2),starting:array(number),correct:defaulted(array(number),()=>[]),picUrl:optional(nullable(string)),picSize:optional(nullable(number)),picBoxHeight:optional(nullable(number)),plotDimensions:defaulted(array(number),()=>[380,300])}));
|
|
123
|
+
const plotterPlotTypes=enumeration("bar","line","pic","histogram","dotplot");const parsePlotterWidget=parseWidget(constant("plotter"),object({labels:array(string),categories:array(string),type:plotterPlotTypes,maxY:number,scaleY:defaulted(number,()=>1),labelInterval:optional(nullable(number)),snapsPerLine:defaulted(number,()=>2),starting:array(number),correct:defaulted(array(number),()=>[]),picUrl:optional(nullable(string)),picSize:optional(nullable(number)),picBoxHeight:optional(nullable(number)),plotDimensions:defaulted(array(number),()=>[380,300])}));
|
|
124
124
|
|
|
125
125
|
const parsePythonProgramWidget=parseWidget(constant("python-program"),object({programID:string,height:number}));
|
|
126
126
|
|
|
@@ -148,14 +148,8 @@ const booleanOrFalse=defaulted(boolean,()=>false);const parsePerseusAnswerArea=d
|
|
|
148
148
|
|
|
149
149
|
const parsePerseusItem=object({question:parsePerseusRenderer,hints:defaulted(array(parseHint),()=>[]),answerArea:parsePerseusAnswerArea});
|
|
150
150
|
|
|
151
|
-
object({status:enumeration("correct","incorrect","incomplete"),message:nullable(string)});
|
|
152
|
-
|
|
153
151
|
const coord=pair(number,number);const coordPair=pair(coord,coord);const parseAbsoluteValueBranch=object({type:constant("absolute_value"),coords:nullable(coordPair)});const parseExponentialBranch=object({type:constant("exponential"),asymptote:coordPair,coords:nullable(coordPair)});const parseLinearBranch=object({type:constant("linear"),coords:nullable(coordPair)});const parseLogarithmBranch=object({type:constant("logarithm"),asymptote:coordPair,coords:nullable(coordPair)});const parseQuadraticBranch=object({type:constant("quadratic"),coords:nullable(coordPair)});const parseSinusoidBranch=object({type:constant("sinusoid"),coords:nullable(coordPair)});const parseTangentBranch=object({type:constant("tangent"),coords:nullable(coordPair)});discriminatedUnionOn("type").withBranch("absolute_value",parseAbsoluteValueBranch).withBranch("exponential",parseExponentialBranch).withBranch("linear",parseLinearBranch).withBranch("logarithm",parseLogarithmBranch).withBranch("quadratic",parseQuadraticBranch).withBranch("sinusoid",parseSinusoidBranch).withBranch("tangent",parseTangentBranch).parser;
|
|
154
152
|
|
|
155
|
-
object({status:enumeration("correct","incorrect","incomplete"),message:optional(nullable(string))});
|
|
156
|
-
|
|
157
|
-
object({numLinePosition:number,rel:enumeration("eq","lt","gt","le","ge"),numDivisions:number});
|
|
158
|
-
|
|
159
153
|
function parseAndMigratePerseusItem(data){const object=typeof data==="string"?JSON.parse(data):data;const result=parse(object,parsePerseusItem);if(isFailure(result)){return failure({message:result.detail,invalidObject:object})}return result}
|
|
160
154
|
|
|
161
155
|
function deepClone(obj){return JSON.parse(JSON.stringify(obj))}
|