@khanacademy/perseus-core 18.3.0 → 18.5.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/index.js CHANGED
@@ -70,7 +70,7 @@ function parse(value,parser){const result=parser(value,new ErrorTrackingParseCon
70
70
 
71
71
  const any=(rawValue,ctx)=>ctx.success(rawValue);
72
72
 
73
- function array(elementParser){return (rawValue,ctx)=>{if(!Array.isArray(rawValue)){return ctx.failure("array",rawValue)}const elementResults=rawValue.map((elem,i)=>elementParser(elem,ctx.forSubtree(i)));return all(elementResults,concat)}}function concat(a,b){return [...a,...b]}
73
+ function array(elementParser){return (rawValue,ctx)=>{if(!Array.isArray(rawValue)){return ctx.failure("array",rawValue)}const elementResults=rawValue.map((elem,i)=>elementParser(elem,ctx.forSubtree(i)));return all(elementResults,concat)}}function arrayWithIndex(elementParserFactory){return (rawValue,ctx)=>{if(!Array.isArray(rawValue)){return ctx.failure("array",rawValue)}const elementResults=rawValue.map((elem,index)=>{const elementParser=elementParserFactory(index);return elementParser(elem,ctx.forSubtree(index))});return all(elementResults,concat)}}function concat(a,b){return [...a,...b]}
74
74
 
75
75
  function boolean(rawValue,ctx){if(typeof rawValue==="boolean"){return ctx.success(rawValue)}return ctx.failure("boolean",rawValue)}
76
76
 
@@ -186,7 +186,7 @@ const parsePythonProgramWidget=parseWidget(constant("python-program"),object({pr
186
186
 
187
187
  function deriveNumCorrect(choices){return choices.filter(c=>c.correct).length}
188
188
 
189
- const parseWidgetsMapOrUndefined=defaulted(optional((rawVal,ctx)=>parseWidgetsMap(rawVal,ctx)),()=>undefined);function getDefaultOptions(){return {choices:[{content:""},{content:""},{content:""},{content:""}]}}const parseOnePerLine=defaulted(optional(boolean),()=>undefined);const parseNoneOfTheAbove=defaulted(optional(constant(false)),()=>undefined);const version3=optional(object({major:constant(3),minor:number}));const parseRadioWidgetV3=parseWidgetWithVersion(version3,constant("radio"),object({numCorrect:optional(number),choices:array(object({content:defaulted(string,()=>""),rationale:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean)})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean)}));const version2=optional(object({major:constant(2),minor:number}));const parseRadioWidgetV2=parseWidgetWithVersion(version2,constant("radio"),defaulted(object({numCorrect:optional(number),choices:array(object({content:defaulted(string,()=>""),clue:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean),widgets:parseWidgetsMapOrUndefined})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean),onePerLine:parseOnePerLine,displayCount:optional(any),noneOfTheAbove:parseNoneOfTheAbove}),getDefaultOptions));const version1=optional(object({major:constant(1),minor:number}));const parseRadioWidgetV1=parseWidgetWithVersion(version1,constant("radio"),defaulted(object({choices:array(object({content:defaulted(string,()=>""),clue:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean),widgets:parseWidgetsMapOrUndefined})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean),onePerLine:parseOnePerLine,displayCount:optional(any),noneOfTheAbove:parseNoneOfTheAbove}),getDefaultOptions));const version0=optional(object({major:constant(0),minor:number}));const parseRadioWidgetV0=parseWidgetWithVersion(version0,constant("radio"),defaulted(object({choices:array(object({content:defaulted(string,()=>""),clue:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean),widgets:parseWidgetsMapOrUndefined})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean),onePerLine:parseOnePerLine,displayCount:optional(any),noneOfTheAbove:parseNoneOfTheAbove}),getDefaultOptions));function migrateV2toV3(widget){const{options}=widget;return {...widget,version:{major:3,minor:0},options:{numCorrect:options.numCorrect,hasNoneOfTheAbove:options.hasNoneOfTheAbove,countChoices:options.countChoices,randomize:options.randomize,multipleSelect:options.multipleSelect,deselectEnabled:options.deselectEnabled,choices:options.choices.map(choice=>({content:choice.content,rationale:choice.clue,correct:choice.correct,isNoneOfTheAbove:choice.isNoneOfTheAbove}))}}}function migrateV1ToV2(widget){const{options}=widget;return {...widget,version:{major:2,minor:0},options:{...options,numCorrect:deriveNumCorrect(options.choices)}}}function migrateV0ToV1(widget){const{options}=widget;const{noneOfTheAbove:_,...rest}=options;return {...widget,version:{major:1,minor:0},options:{...rest,hasNoneOfTheAbove:false,noneOfTheAbove:undefined}}}const parseRadioWidget=versionedWidgetOptions(3,parseRadioWidgetV3).withMigrationFrom(2,parseRadioWidgetV2,migrateV2toV3).withMigrationFrom(1,parseRadioWidgetV1,migrateV1ToV2).withMigrationFrom(0,parseRadioWidgetV0,migrateV0ToV1).parser;
189
+ const parseWidgetsMapOrUndefined=defaulted(optional((rawVal,ctx)=>parseWidgetsMap(rawVal,ctx)),()=>undefined);function getDefaultOptions(){return {choices:[{content:"",id:generateChoiceId(0)},{content:"",id:generateChoiceId(1)},{content:"",id:generateChoiceId(2)},{content:"",id:generateChoiceId(3)}]}}const parseOnePerLine=defaulted(optional(boolean),()=>undefined);const parseNoneOfTheAbove=defaulted(optional(constant(false)),()=>undefined);function generateChoiceId(index){return `radio-choice-${index}`}const version3=optional(object({major:constant(3),minor:number}));const parseRadioWidgetV3=parseWidgetWithVersion(version3,constant("radio"),object({numCorrect:optional(number),choices:arrayWithIndex(index=>object({content:defaulted(string,()=>""),rationale:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean),id:defaulted(string,()=>generateChoiceId(index))})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean)}));const version2=optional(object({major:constant(2),minor:number}));const parseRadioWidgetV2=parseWidgetWithVersion(version2,constant("radio"),defaulted(object({numCorrect:optional(number),choices:array(object({content:defaulted(string,()=>""),clue:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean),widgets:parseWidgetsMapOrUndefined})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean),onePerLine:parseOnePerLine,displayCount:optional(any),noneOfTheAbove:parseNoneOfTheAbove}),getDefaultOptions));const version1=optional(object({major:constant(1),minor:number}));const parseRadioWidgetV1=parseWidgetWithVersion(version1,constant("radio"),defaulted(object({choices:array(object({content:defaulted(string,()=>""),clue:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean),widgets:parseWidgetsMapOrUndefined})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean),onePerLine:parseOnePerLine,displayCount:optional(any),noneOfTheAbove:parseNoneOfTheAbove}),getDefaultOptions));const version0=optional(object({major:constant(0),minor:number}));const parseRadioWidgetV0=parseWidgetWithVersion(version0,constant("radio"),defaulted(object({choices:array(object({content:defaulted(string,()=>""),clue:optional(string),correct:optional(boolean),isNoneOfTheAbove:optional(boolean),widgets:parseWidgetsMapOrUndefined})),hasNoneOfTheAbove:optional(boolean),countChoices:optional(boolean),randomize:optional(boolean),multipleSelect:optional(boolean),deselectEnabled:optional(boolean),onePerLine:parseOnePerLine,displayCount:optional(any),noneOfTheAbove:parseNoneOfTheAbove}),getDefaultOptions));function migrateV2toV3(widget){const{options}=widget;return {...widget,version:{major:3,minor:0},options:{numCorrect:options.numCorrect,hasNoneOfTheAbove:options.hasNoneOfTheAbove,countChoices:options.countChoices,randomize:options.randomize,multipleSelect:options.multipleSelect,deselectEnabled:options.deselectEnabled,choices:options.choices.map((choice,index)=>({content:choice.content,rationale:choice.clue,correct:choice.correct,isNoneOfTheAbove:choice.isNoneOfTheAbove,id:generateChoiceId(index)}))}}}function migrateV1ToV2(widget){const{options}=widget;return {...widget,version:{major:2,minor:0},options:{...options,numCorrect:deriveNumCorrect(options.choices)}}}function migrateV0ToV1(widget){const{options}=widget;const{noneOfTheAbove:_,...rest}=options;return {...widget,version:{major:1,minor:0},options:{...rest,hasNoneOfTheAbove:false,noneOfTheAbove:undefined}}}const parseRadioWidget=versionedWidgetOptions(3,parseRadioWidgetV3).withMigrationFrom(2,parseRadioWidgetV2,migrateV2toV3).withMigrationFrom(1,parseRadioWidgetV1,migrateV1ToV2).withMigrationFrom(0,parseRadioWidgetV0,migrateV0ToV1).parser;
190
190
 
191
191
  const parseSorterWidget=parseWidget(constant("sorter"),object({correct:array(string),padding:boolean,layout:enumeration("horizontal","vertical")}));
192
192
 
@@ -208,7 +208,7 @@ const parsePerseusAnswerArea=pipeParsers(defaulted(object({}),()=>({}))).then(co
208
208
 
209
209
  const parsePerseusItem$1=object({question:parsePerseusRenderer,hints:defaulted(array(parseHint),()=>[]),answerArea:parsePerseusAnswerArea});
210
210
 
211
- const parseCategorizerUserInput=object({values:array(number)});
211
+ const parseCategorizerUserInput=object({values:array(optional(nullable(number)))});
212
212
 
213
213
  const parseCSProgramUserInput=object({status:enumeration("correct","incorrect","incomplete"),message:nullable(string)});
214
214
 
@@ -252,7 +252,7 @@ const parseUserInputMap=(rawValue,ctx)=>{if(!isPlainObject(rawValue)){return ctx
252
252
 
253
253
  function parsePerseusItem(json){if(isRealJSONParse(JSON.parse)){return JSON.parse(json)}throw new Error("Something went wrong.")}function parseAndMigratePerseusItem(data){throwErrorIfCheatingDetected();const object=typeof data==="string"?JSON.parse(data):data;const result=parse(object,parsePerseusItem$1);if(isFailure(result)){return failure({message:result.detail,invalidObject:object})}return result}function parseAndMigratePerseusArticle(data){throwErrorIfCheatingDetected();const object=typeof data==="string"?JSON.parse(data):data;const result=parse(object,parsePerseusArticle);if(isFailure(result)){return failure({message:result.detail,invalidObject:object})}return result}function parseAndMigrateUserInputMap(data){const object=typeof data==="string"?JSON.parse(data):data;const result=parse(object,parseUserInputMap);if(isFailure(result)){return failure({message:result.detail,invalidObject:object})}return result}function throwErrorIfCheatingDetected(){if(!isRealJSONParse(JSON.parse)){throw new Error("Something went wrong.")}}
254
254
 
255
- const libName="@khanacademy/perseus-core";const libVersion="18.3.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
255
+ const libName="@khanacademy/perseus-core";const libVersion="18.5.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
256
256
 
257
257
  const Errors=Object.freeze({Unknown:"Unknown",Internal:"Internal",InvalidInput:"InvalidInput",NotAllowed:"NotAllowed",TransientService:"TransientService",Service:"Service"});
258
258
 
@@ -318,7 +318,7 @@ function getLabelImagePublicWidgetOptions(options){return {...options,markers:op
318
318
 
319
319
  const defaultWidgetOptions$h={choices:[],imageAlt:"",imageUrl:"",imageWidth:0,imageHeight:0,markers:[],multipleAnswers:false,hideChoicesFromInstructions:false};const labelImageWidgetLogic={name:"label-image",defaultWidgetOptions: defaultWidgetOptions$h,getPublicWidgetOptions:getLabelImagePublicWidgetOptions,accessible:widgetOptions=>{const labelImageOptions=widgetOptions;if(labelImageOptions.imageUrl!==""&&labelImageOptions.imageAlt===""){return false}return true}};
320
320
 
321
- const seededRNG=function(seed){let randomSeed=seed;return function(){let seed=randomSeed;seed=seed+0x7ed55d16+(seed<<12)&0xffffffff;seed=(seed^0xc761c23c^seed>>>19)&0xffffffff;seed=seed+0x165667b1+(seed<<5)&0xffffffff;seed=(seed+0xd3a2646c^seed<<9)&0xffffffff;seed=seed+0xfd7046c5+(seed<<3)&0xffffffff;seed=(seed^0xb55a4f09^seed>>>16)&0xffffffff;return (randomSeed=seed&0xfffffff)/0x10000000}};function shuffle(array,randomSeed,ensurePermuted=false){let random;if(typeof randomSeed==="function"){random=randomSeed;}else {random=seededRNG(randomSeed);}function isValidShuffle(shuffled){return ensurePermuted?!___default.default.isEqual(array,shuffled):true}return constrainedShuffle(array,random,isValidShuffle)}function constrainedShuffle(array,random,isValidShuffle){const maxIterations=100;const shuffled=[...array];if(shuffled.every(value=>___default.default.isEqual(value,shuffled[0]))){return shuffled}for(let i=0;i<maxIterations;i++){shuffleInPlace(shuffled,random);if(isValidShuffle(shuffled)){return shuffled}}throw new Error(`constrainedShuffle: constraint not met after ${maxIterations} attempts`)}function shuffleInPlace(a,random){for(let i=a.length-1;i>0;i--){const k=randomIntInRange(0,i,random);[a[k],a[i]]=[a[i],a[k]];}}function randomIntInRange(min,max,random){return Math.floor(random()*(max-min+1))+min}const random=seededRNG(new Date().getTime()&0xffffffff);
321
+ const seededRNG=function(seed){let randomSeed=seed;return function(){let seed=randomSeed;seed=seed+0x7ed55d16+(seed<<12)&0xffffffff;seed=(seed^0xc761c23c^seed>>>19)&0xffffffff;seed=seed+0x165667b1+(seed<<5)&0xffffffff;seed=(seed+0xd3a2646c^seed<<9)&0xffffffff;seed=seed+0xfd7046c5+(seed<<3)&0xffffffff;seed=(seed^0xb55a4f09^seed>>>16)&0xffffffff;return (randomSeed=seed&0xfffffff)/0x10000000}};function shuffle(array,randomSeed,ensurePermuted=false){let random;if(typeof randomSeed==="function"){random=randomSeed;}else {random=seededRNG(randomSeed);}function isValidShuffle(shuffled){return ensurePermuted?!___default.default.isEqual(array,shuffled):true}return constrainedShuffle(array,random,isValidShuffle)}function constrainedShuffle(array,random,isValidShuffle){const maxIterations=100;const shuffled=[...array];if(shuffled.every(value=>___default.default.isEqual(value,shuffled[0]))){return shuffled}for(let i=0;i<maxIterations;i++){shuffleInPlace(shuffled,random);if(isValidShuffle(shuffled)){return shuffled}}throw new Error(`constrainedShuffle: constraint not met after ${maxIterations} attempts`)}function shuffleInPlace(a,random){for(let i=a.length-1;i>0;i--){const k=randomIntInRange(0,i,random);[a[k],a[i]]=[a[i],a[k]];}}function randomIntInRange(min,max,random){return Math.floor(random()*(max-min+1))+min}const random=seededRNG(new Date().getTime()&0xffffffff);function randomizeArrayElements(inputArray){return inputArray.map(element=>{const randomSortNumber=Math.random();return {element,randomSortNumber}}).sort((a,b)=>a.randomSortNumber-b.randomSortNumber).map(item=>item.element)}
322
322
 
323
323
  const shuffleMatcher=(options,problemNum)=>{const rng=seededRNG(problemNum);return {left:!options.orderMatters?options.left:shuffleDisplacingFirst$1(options.left,rng),right:shuffleDisplacingFirst$1(options.right,rng)}};function getMatcherPublicWidgetOptions(options){return {...options,left:options.orderMatters?sortAllButFirst$1(options.left):options.left,right:sortAllButFirst$1(options.right)}}function sortAllButFirst$1([first,...rest]){return [first,...rest.sort()]}function shuffleDisplacingFirst$1(array,rng){function isFirstElementDisplaced(shuffled){return shuffled[0]!==array[0]}return constrainedShuffle(array,rng,isFirstElementDisplaced)}
324
324
 
@@ -358,7 +358,7 @@ const defaultWidgetOptions$6={scaleY:1,maxY:10,snapsPerLine:2,correct:[1],starti
358
358
 
359
359
  const defaultWidgetOptions$5={programID:"",height:400};const pythonProgramWidgetLogic={name:"python-program",defaultWidgetOptions: defaultWidgetOptions$5,accessible:true};
360
360
 
361
- function getRadioChoicePublicData(choice){const{content,isNoneOfTheAbove}=choice;return {content,isNoneOfTheAbove}}function usesNumCorrect(multipleSelect,countChoices,numCorrect){return multipleSelect&&countChoices&&numCorrect}function getRadioPublicWidgetOptions(options){const{numCorrect,choices,multipleSelect,countChoices}=options;return {...options,numCorrect:usesNumCorrect(multipleSelect,countChoices,numCorrect)?numCorrect:undefined,choices:choices.map(getRadioChoicePublicData)}}
361
+ function getRadioChoicePublicData(choice){const{id,content,isNoneOfTheAbove}=choice;return {id,content,isNoneOfTheAbove}}function usesNumCorrect(multipleSelect,countChoices,numCorrect){return multipleSelect&&countChoices&&numCorrect}function getRadioPublicWidgetOptions(options){const{numCorrect,choices,multipleSelect,countChoices}=options;return {...options,numCorrect:usesNumCorrect(multipleSelect,countChoices,numCorrect)?numCorrect:undefined,choices:choices.map(getRadioChoicePublicData)}}
362
362
 
363
363
  const currentVersion={major:2,minor:0};const defaultWidgetOptions$4={choices:[{},{},{},{}],randomize:false,hasNoneOfTheAbove:false,multipleSelect:false,countChoices:false,deselectEnabled:false};const radioWidgetLogic={name:"radio",version:currentVersion,defaultWidgetOptions:defaultWidgetOptions$4,getPublicWidgetOptions:getRadioPublicWidgetOptions,accessible:true};
364
364
 
@@ -503,6 +503,7 @@ exports.pluck = pluck;
503
503
  exports.pythonProgramLogic = pythonProgramWidgetLogic;
504
504
  exports.radioLogic = radioWidgetLogic;
505
505
  exports.random = random;
506
+ exports.randomizeArrayElements = randomizeArrayElements;
506
507
  exports.seededRNG = seededRNG;
507
508
  exports.shuffle = shuffle;
508
509
  exports.shuffleMatcher = shuffleMatcher;