@khanacademy/perseus-score 4.0.2 → 5.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.
Files changed (46) hide show
  1. package/dist/es/index.js +4 -2
  2. package/dist/es/index.js.map +1 -1
  3. package/dist/has-empty-diner-widgets.d.ts +15 -0
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +4 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/score.d.ts +1 -2
  8. package/dist/util/score-noop.d.ts +1 -1
  9. package/dist/validate.d.ts +1 -1
  10. package/dist/widgets/categorizer/score-categorizer.d.ts +1 -1
  11. package/dist/widgets/categorizer/validate-categorizer.d.ts +1 -1
  12. package/dist/widgets/cs-program/score-cs-program.d.ts +1 -1
  13. package/dist/widgets/dropdown/score-dropdown.d.ts +1 -1
  14. package/dist/widgets/dropdown/validate-dropdown.d.ts +1 -1
  15. package/dist/widgets/expression/score-expression.d.ts +1 -1
  16. package/dist/widgets/expression/validate-expression.d.ts +1 -1
  17. package/dist/widgets/grapher/score-grapher.d.ts +1 -1
  18. package/dist/widgets/group/score-group.d.ts +1 -1
  19. package/dist/widgets/group/validate-group.d.ts +1 -1
  20. package/dist/widgets/iframe/score-iframe.d.ts +1 -1
  21. package/dist/widgets/input-number/score-input-number.d.ts +1 -1
  22. package/dist/widgets/interactive-graph/score-interactive-graph.d.ts +1 -1
  23. package/dist/widgets/label-image/score-label-image.d.ts +1 -1
  24. package/dist/widgets/label-image/validate-label-image.d.ts +1 -1
  25. package/dist/widgets/matcher/score-matcher.d.ts +1 -1
  26. package/dist/widgets/matrix/score-matrix.d.ts +1 -1
  27. package/dist/widgets/matrix/validate-matrix.d.ts +1 -1
  28. package/dist/widgets/mock-widget/score-mock-widget.d.ts +1 -1
  29. package/dist/widgets/mock-widget/validate-mock-widget.d.ts +1 -1
  30. package/dist/widgets/number-line/score-number-line.d.ts +1 -1
  31. package/dist/widgets/number-line/validate-number-line.d.ts +1 -1
  32. package/dist/widgets/numeric-input/score-numeric-input.d.ts +1 -1
  33. package/dist/widgets/orderer/score-orderer.d.ts +1 -1
  34. package/dist/widgets/orderer/validate-orderer.d.ts +1 -1
  35. package/dist/widgets/plotter/score-plotter.d.ts +1 -1
  36. package/dist/widgets/plotter/validate-plotter.d.ts +1 -1
  37. package/dist/widgets/radio/score-radio.d.ts +1 -1
  38. package/dist/widgets/radio/validate-radio.d.ts +1 -1
  39. package/dist/widgets/sorter/score-sorter.d.ts +1 -1
  40. package/dist/widgets/sorter/validate-sorter.d.ts +1 -1
  41. package/dist/widgets/table/score-table.d.ts +1 -1
  42. package/dist/widgets/table/validate-table.d.ts +1 -1
  43. package/dist/widgets/widget-registry.d.ts +1 -1
  44. package/package.json +3 -3
  45. package/dist/validation.types.d.ts +0 -281
  46. package/dist/validation.typetest.d.ts +0 -1
@@ -0,0 +1,15 @@
1
+ import type { PerseusItem, UserInputMap } from "@khanacademy/perseus-core";
2
+ /**
3
+ * Check the emptiness of DINER widgets (for the AX team):
4
+ * - Dropdown
5
+ * - InteractiveGraph
6
+ * - NumericInput
7
+ * - Expression
8
+ * - Radio
9
+ *
10
+ * @param {PerseusItem} itemData
11
+ * @param {UserInputMap} userInputMap
12
+ * @returns {boolean} true if there's an empty widget, otherwise false
13
+ */
14
+ declare function hasEmptyDINERWidgets(itemData: PerseusItem, userInputMap: UserInputMap): boolean;
15
+ export default hasEmptyDINERWidgets;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  export { default as KhanAnswerTypes } from "./util/answer-types";
2
2
  export type { Score } from "./util/answer-types";
3
3
  export { default as ErrorCodes } from "./error-codes";
4
- export type * from "./validation.types";
5
4
  export { default as scoreCategorizer } from "./widgets/categorizer/score-categorizer";
6
5
  export { default as validateCategorizer } from "./widgets/categorizer/validate-categorizer";
7
6
  export { default as scoreCSProgram } from "./widgets/cs-program/score-cs-program";
@@ -32,5 +31,6 @@ export { default as validateTable } from "./widgets/table/validate-table";
32
31
  export { default as scoreInputNumber, inputNumberAnswerTypes, } from "./widgets/input-number/score-input-number";
33
32
  export { scorePerseusItem, scoreWidgetsFunctional, flattenScores } from "./score";
34
33
  export { emptyWidgetsFunctional } from "./validate";
34
+ export { default as hasEmptyDINERWidgets } from "./has-empty-diner-widgets";
35
35
  export type { PerseusMockWidgetRubric, PerseusMockWidgetUserInput, } from "./widgets/mock-widget/mock-widget-validation.types";
36
36
  export * from "./widgets/widget-registry";
package/dist/index.js CHANGED
@@ -80,7 +80,7 @@ function validatePlotter(userInput,validationData){if(perseusCore.approximateDee
80
80
 
81
81
  function scoreRadio(userInput,rubric){const numSelected=userInput.choicesSelected.reduce((sum,selected)=>{return sum+(selected?1:0)},0);const numCorrect=rubric.choices.reduce((sum,currentChoice)=>{return currentChoice.correct?sum+1:sum},0);if(numCorrect>1&&numSelected!==numCorrect){return {type:"invalid",message:ErrorCodes.CHOOSE_CORRECT_NUM_ERROR}}const noneOfTheAboveSelected=rubric.choices.some((choice,index)=>choice.isNoneOfTheAbove&&userInput.choicesSelected[index]);if(noneOfTheAboveSelected&&numSelected>1){return {type:"invalid",message:ErrorCodes.NOT_NONE_ABOVE_ERROR}}const correct=userInput.choicesSelected.every((selected,i)=>{let isCorrect;if(rubric.choices[i].isNoneOfTheAbove){isCorrect=rubric.choices.every((choice,j)=>{return i===j||!choice.correct});}else {isCorrect=!!rubric.choices[i].correct;}return isCorrect===selected});return {type:"points",earned:correct?1:0,total:1,message:null}}
82
82
 
83
- function validateRadio(userInput){const numSelected=userInput.choicesSelected.reduce((sum,selected)=>{return sum+(selected?1:0)},0);if(numSelected===0){return {type:"invalid",message:null}}return null}
83
+ function validateRadio(userInput){if(!userInput.choicesSelected.includes(true)){return {type:"invalid",message:null}}return null}
84
84
 
85
85
  function scoreSorter(userInput,rubric){const correct=perseusCore.approximateDeepEqual(userInput.options,rubric.correct);return {type:"points",earned:correct?1:0,total:1,message:null}}
86
86
 
@@ -112,12 +112,15 @@ const widgets={};function registerWidget(type,scorer,validator){widgets[type]={s
112
112
 
113
113
  const noScore={type:"points",earned:0,total:0,message:null};function scoreIsEmpty(score){return score.type==="invalid"&&(!score.message||score.message.length===0)}function combineScores(scoreA,scoreB){let message;if(scoreA.type==="points"&&scoreB.type==="points"){if(scoreA.message&&scoreB.message&&scoreA.message!==scoreB.message){message=null;}else {message=scoreA.message||scoreB.message;}return {type:"points",earned:scoreA.earned+scoreB.earned,total:scoreA.total+scoreB.total,message:message}}if(scoreA.type==="points"&&scoreB.type==="invalid"){return scoreB}if(scoreA.type==="invalid"&&scoreB.type==="points"){return scoreA}if(scoreA.type==="invalid"&&scoreB.type==="invalid"){if(scoreA.message&&scoreB.message&&scoreA.message!==scoreB.message){message=null;}else {message=scoreA.message||scoreB.message;}return {type:"invalid",message:message}}throw new perseusCore.PerseusError("PerseusScore with unknown type encountered",perseusCore.Errors.InvalidInput,{metadata:{scoreA:JSON.stringify(scoreA),scoreB:JSON.stringify(scoreB)}})}function flattenScores(widgetScoreMap){return Object.values(widgetScoreMap).reduce(combineScores,noScore)}function scorePerseusItem(perseusRenderData,userInputMap,locale){const usedWidgetIds=perseusCore.getWidgetIdsFromContent(perseusRenderData.content);const scores=scoreWidgetsFunctional(perseusRenderData.widgets,usedWidgetIds,userInputMap,locale);return flattenScores(scores)}function scoreWidgetsFunctional(widgets,widgetIds,userInputMap,locale){const upgradedWidgets=perseusCore.getUpgradedWidgetOptions(widgets);const gradedWidgetIds=widgetIds.filter(id=>{const props=upgradedWidgets[id];const widgetIsGraded=props?.graded==null||props.graded;const widgetIsStatic=!!props?.static;return widgetIsGraded&&!widgetIsStatic});const widgetScores={};gradedWidgetIds.forEach(id=>{const widget=upgradedWidgets[id];if(!widget){return}const userInput=userInputMap[id];const validator=getWidgetValidator(widget.type);const scorer=getWidgetScorer(widget.type);const score=validator?.(userInput,widget.options,locale)??scorer?.(userInput,widget.options,locale);if(score!=null){widgetScores[id]=score;}});return widgetScores}
114
114
 
115
+ function hasEmptyDINERWidgets(itemData,userInputMap){const usedWidgetIds=perseusCore.getWidgetIdsFromContent(itemData.question.content);const widgets=itemData.question.widgets;for(const widgetId of usedWidgetIds){const widget=widgets[widgetId];const input=userInputMap[widgetId];switch(widget.type){case "dropdown":{if(input.value===0){return true}break}case "interactive-graph":{break}case "numeric-input":{if(!input.currentValue&&!widget.options.coefficient){return true}break}case "expression":{if(!input){return true}break}case "radio":{if(!input.choicesSelected.includes(true)){return true}break}}}return false}
116
+
115
117
  exports.ErrorCodes = ErrorCodes;
116
118
  exports.KhanAnswerTypes = KhanAnswerTypes;
117
119
  exports.emptyWidgetsFunctional = emptyWidgetsFunctional;
118
120
  exports.flattenScores = flattenScores;
119
121
  exports.getWidgetScorer = getWidgetScorer;
120
122
  exports.getWidgetValidator = getWidgetValidator;
123
+ exports.hasEmptyDINERWidgets = hasEmptyDINERWidgets;
121
124
  exports.inputNumberAnswerTypes = inputNumberAnswerTypes;
122
125
  exports.registerWidget = registerWidget;
123
126
  exports.scoreCSProgram = scoreCSProgram;