@khanacademy/perseus-score 1.1.0 → 2.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.
@@ -5,29 +5,30 @@
5
5
  *
6
6
  * These types are:
7
7
  *
8
- * `Perseus<Widget>UserInput`: the data returned by the widget that the user
9
- * entered. This is referred to as the 'guess' in some older parts of Perseus.
8
+ * * `Perseus<Widget>UserInput`: the data from the widget that represents the
9
+ * data the user entered. This is referred to as the 'guess' in some older
10
+ * parts of Perseus.
10
11
  *
11
- * `Perseus<Widget>ValidationData`: the data needed to do validation of the
12
- * user input. Validation refers to the different checks that we can do both on
13
- * the client-side (before submitting user input for scoring) and on the
14
- * server-side (when we score it). As such, it cannot contain any of the
15
- * sensitive scoring data that would reveal the answer.
12
+ * * `Perseus<Widget>ValidationData`: the data needed to do validation of the
13
+ * user input. Validation refers to the different checks that we can do
14
+ * both on the client-side (before submitting user input for scoring) and
15
+ * on the server-side (when we score it). As such, it cannot contain any of
16
+ * the sensitive scoring data that would reveal the answer.
16
17
  *
17
- * `Perseus<Widget>ScoringData` (nee `Perseus<Widget>Rubric`): the data needed
18
- * to score the user input. By convention, this type is defined as the set of
19
- * sensitive answer data and then intersected with
20
- * `Perseus<Widget>ValidationData`.
18
+ * * `Perseus<Widget>Rubric` (nee `Perseus<Widget>Rubric`): the data
19
+ * needed to score the user input. By convention, this type is defined as
20
+ * the set of sensitive answer data and then intersected with
21
+ * `Perseus<Widget>ValidationData`.
21
22
  *
22
23
  * For example:
23
24
  * ```
24
- * type Perseus<Widget>ScoringData = {
25
+ * type Perseus<Widget>Rubric = {
25
26
  * correct: string; // Used _only_ for scoring
26
27
  * size: number; // Used _only_ for scoring
27
28
  * } & Perseus<Widget>ValidationData;
28
29
  * ```
29
30
  */
30
- import type { GrapherAnswerTypes, PerseusDropdownChoice, PerseusExpressionAnswerForm, PerseusGradedGroupSetWidgetOptions, PerseusGradedGroupWidgetOptions, PerseusGraphType, PerseusGroupWidgetOptions, PerseusMatcherWidgetOptions, PerseusMatrixWidgetAnswers, PerseusNumericInputAnswer, PerseusOrdererWidgetOptions, PerseusRadioChoice, PerseusGraphCorrectType, InteractiveMarkerType, Relationship } from "@khanacademy/perseus-core";
31
+ import type { GrapherAnswerTypes, PerseusDropdownChoice, PerseusExpressionAnswerForm, PerseusGradedGroupSetWidgetOptions, PerseusGradedGroupWidgetOptions, PerseusGraphType, PerseusGroupWidgetOptions, PerseusMatrixWidgetAnswers, PerseusNumericInputAnswer, PerseusOrdererWidgetOptions, PerseusRadioChoice, PerseusGraphCorrectType, MakeWidgetMap, Relationship } from "@khanacademy/perseus-core";
31
32
  export type PerseusScore = {
32
33
  type: "invalid";
33
34
  message?: string | null | undefined;
@@ -42,16 +43,15 @@ export type ValidationResult = Extract<PerseusScore, {
42
43
  type: "invalid";
43
44
  }> | null;
44
45
  export type UserInputStatus = "correct" | "incorrect" | "incomplete";
45
- export type PerseusCategorizerScoringData = {
46
+ export type PerseusCategorizerRubric = {
46
47
  values: ReadonlyArray<number>;
47
48
  } & PerseusCategorizerValidationData;
48
49
  export type PerseusCategorizerUserInput = {
49
- values: PerseusCategorizerScoringData["values"];
50
+ values: PerseusCategorizerRubric["values"];
50
51
  };
51
52
  export type PerseusCategorizerValidationData = {
52
53
  items: ReadonlyArray<string>;
53
54
  };
54
- export type PerseusCSProgramRubric = Empty;
55
55
  export type PerseusCSProgramUserInput = {
56
56
  status: UserInputStatus;
57
57
  message: string | null;
@@ -68,6 +68,9 @@ export type PerseusExpressionRubric = {
68
68
  };
69
69
  export type PerseusExpressionUserInput = string;
70
70
  export type PerseusGroupRubric = PerseusGroupWidgetOptions;
71
+ export type PerseusGroupValidationData = {
72
+ widgets: ValidationDataMap;
73
+ };
71
74
  export type PerseusGroupUserInput = UserInputMap;
72
75
  export type PerseusGradedGroupRubric = PerseusGradedGroupWidgetOptions;
73
76
  export type PerseusGradedGroupSetRubric = PerseusGradedGroupSetWidgetOptions;
@@ -75,7 +78,6 @@ export type PerseusGrapherRubric = {
75
78
  correct: GrapherAnswerTypes;
76
79
  };
77
80
  export type PerseusGrapherUserInput = PerseusGrapherRubric["correct"];
78
- export type PerseusIFrameRubric = Empty;
79
81
  export type PerseusIFrameUserInput = {
80
82
  status: UserInputStatus;
81
83
  message: string | null;
@@ -95,11 +97,22 @@ export type PerseusInteractiveGraphRubric = {
95
97
  graph: PerseusGraphType;
96
98
  };
97
99
  export type PerseusInteractiveGraphUserInput = PerseusGraphType;
98
- export type PerseusLabelImageRubric = Empty;
100
+ export type PerseusLabelImageRubric = {
101
+ markers: ReadonlyArray<{
102
+ answers: ReadonlyArray<string>;
103
+ label: string;
104
+ }>;
105
+ };
99
106
  export type PerseusLabelImageUserInput = {
100
- markers: ReadonlyArray<InteractiveMarkerType>;
107
+ markers: ReadonlyArray<{
108
+ selected?: ReadonlyArray<string>;
109
+ label: string;
110
+ }>;
111
+ };
112
+ export type PerseusMatcherRubric = {
113
+ left: ReadonlyArray<string>;
114
+ right: ReadonlyArray<string>;
101
115
  };
102
- export type PerseusMatcherRubric = PerseusMatcherWidgetOptions;
103
116
  export type PerseusMatcherUserInput = {
104
117
  left: ReadonlyArray<string>;
105
118
  right: ReadonlyArray<string>;
@@ -111,13 +124,7 @@ export type PerseusMatrixValidationData = Empty;
111
124
  export type PerseusMatrixUserInput = {
112
125
  answers: PerseusMatrixRubric["answers"];
113
126
  };
114
- export type PerseusMockWidgetRubric = {
115
- value: string;
116
- };
117
- export type PerseusMockWidgetUserInput = {
118
- currentValue: string;
119
- };
120
- export type PerseusNumberLineScoringData = {
127
+ export type PerseusNumberLineRubric = {
121
128
  correctRel: string | null | undefined;
122
129
  correctX: number;
123
130
  range: ReadonlyArray<number>;
@@ -142,7 +149,7 @@ export type PerseusOrdererRubric = PerseusOrdererWidgetOptions;
142
149
  export type PerseusOrdererUserInput = {
143
150
  current: ReadonlyArray<string>;
144
151
  };
145
- export type PerseusPlotterScoringData = {
152
+ export type PerseusPlotterRubric = {
146
153
  correct: ReadonlyArray<number>;
147
154
  } & PerseusPlotterValidationData;
148
155
  export type PerseusPlotterValidationData = {
@@ -166,12 +173,107 @@ export type PerseusTableRubric = {
166
173
  answers: ReadonlyArray<ReadonlyArray<string>>;
167
174
  };
168
175
  export type PerseusTableUserInput = ReadonlyArray<ReadonlyArray<string>>;
169
- export type Rubric = PerseusCategorizerScoringData | PerseusCSProgramRubric | PerseusDropdownRubric | PerseusExpressionRubric | PerseusGroupRubric | PerseusGradedGroupRubric | PerseusGradedGroupSetRubric | PerseusGrapherRubric | PerseusIFrameRubric | PerseusInputNumberRubric | PerseusInteractiveGraphRubric | PerseusLabelImageRubric | PerseusMatcherRubric | PerseusMatrixRubric | PerseusMockWidgetRubric | PerseusNumberLineScoringData | PerseusNumericInputRubric | PerseusOrdererRubric | PerseusPlotterScoringData | PerseusRadioRubric | PerseusSorterRubric | PerseusTableRubric;
170
- export type UserInput = PerseusCategorizerUserInput | PerseusCSProgramUserInput | PerseusDropdownUserInput | PerseusExpressionUserInput | PerseusGrapherUserInput | PerseusIFrameUserInput | PerseusInputNumberUserInput | PerseusInteractiveGraphUserInput | PerseusLabelImageUserInput | PerseusMatcherUserInput | PerseusMatrixUserInput | PerseusMockWidgetUserInput | PerseusNumberLineUserInput | PerseusNumericInputUserInput | PerseusOrdererUserInput | PerseusPlotterUserInput | PerseusRadioUserInput | PerseusSorterUserInput | PerseusTableUserInput;
171
- export type UserInputMap = {
172
- [widgetId: string]: UserInput | UserInputMap;
176
+ export interface RubricRegistry {
177
+ categorizer: PerseusCategorizerRubric;
178
+ dropdown: PerseusDropdownRubric;
179
+ expression: PerseusExpressionRubric;
180
+ "graded-group-set": PerseusGradedGroupSetRubric;
181
+ "graded-group": PerseusGradedGroupRubric;
182
+ grapher: PerseusGrapherRubric;
183
+ group: PerseusGroupRubric;
184
+ image: PerseusLabelImageRubric;
185
+ "input-number": PerseusInputNumberRubric;
186
+ "interactive-graph": PerseusInteractiveGraphRubric;
187
+ "label-image": PerseusLabelImageRubric;
188
+ matcher: PerseusMatcherRubric;
189
+ matrix: PerseusMatrixRubric;
190
+ "number-line": PerseusNumberLineRubric;
191
+ "numeric-input": PerseusNumericInputRubric;
192
+ orderer: PerseusOrdererRubric;
193
+ plotter: PerseusPlotterRubric;
194
+ radio: PerseusRadioRubric;
195
+ sorter: PerseusSorterRubric;
196
+ table: PerseusTableRubric;
197
+ }
198
+ /**
199
+ * A map of scoring data (previously referred to as "rubric"), keyed by
200
+ * `widgetId`. This data is used to score a learner's guess for a PerseusItem.
201
+ *
202
+ * NOTE: The value in this map is intentionally a subset of WidgetOptions<T>.
203
+ * By using the same shape (minus any unneeded render data), we are able to
204
+ * share functionality that understands how to traverse maps of `widget id` to
205
+ * `options`.
206
+ */
207
+ export type RubricMap = {
208
+ [Property in keyof RubricRegistry as `${Property} ${number}`]: {
209
+ type: Property;
210
+ static?: boolean;
211
+ options: RubricRegistry[Property];
212
+ };
173
213
  };
214
+ export type Rubric = RubricRegistry[keyof RubricRegistry];
215
+ /**
216
+ * This is an interface so that it can be extended if a widget is created
217
+ * outside of this Perseus package. See `PerseusWidgetTypes` for a full
218
+ * explanation.
219
+ */
220
+ interface UserInputRegistry {
221
+ categorizer: PerseusCategorizerUserInput;
222
+ "cs-program": PerseusCSProgramUserInput;
223
+ dropdown: PerseusDropdownUserInput;
224
+ expression: PerseusExpressionUserInput;
225
+ grapher: PerseusGrapherUserInput;
226
+ group: PerseusGroupUserInput;
227
+ iframe: PerseusIFrameUserInput;
228
+ "input-number": PerseusInputNumberUserInput;
229
+ "interactive-graph": PerseusInteractiveGraphUserInput;
230
+ "label-image": PerseusLabelImageUserInput;
231
+ matcher: PerseusMatcherUserInput;
232
+ matrix: PerseusMatrixUserInput;
233
+ "number-line": PerseusNumberLineUserInput;
234
+ "numeric-input": PerseusNumericInputUserInput;
235
+ orderer: PerseusOrdererUserInput;
236
+ plotter: PerseusPlotterUserInput;
237
+ radio: PerseusRadioUserInput;
238
+ sorter: PerseusSorterUserInput;
239
+ table: PerseusTableUserInput;
240
+ }
241
+ /** A union type of all the widget user input types */
242
+ export type UserInput = UserInputRegistry[keyof UserInputRegistry];
243
+ /**
244
+ * A map of widget IDs to user input types (strongly typed based on the format
245
+ * of the widget ID).
246
+ */
247
+ export type UserInputMap = MakeWidgetMap<UserInputRegistry>;
174
248
  /**
175
249
  * deprecated prefer using UserInputMap
176
250
  */
177
251
  export type UserInputArray = ReadonlyArray<UserInputArray | UserInput | null | undefined>;
252
+ export interface ValidationDataTypes {
253
+ categorizer: PerseusCategorizerValidationData;
254
+ group: PerseusGroupValidationData;
255
+ plotter: PerseusPlotterValidationData;
256
+ }
257
+ /**
258
+ * A map of validation data, keyed by `widgetId`. This data is used to check if
259
+ * a question is answerable. This data represents the minimal intersection of
260
+ * data that's available in the client (widget options) and server (scoring
261
+ * data) and is represented by a group of types known as "validation data".
262
+ *
263
+ * NOTE: The value in this map is intentionally a subset of WidgetOptions<T>.
264
+ * By using the same shape (minus any unneeded data), we are able to pass a
265
+ * `PerseusWidgetsMap` or ` into any function that accepts a
266
+ * `ValidationDataMap` without any mutation of data.
267
+ */
268
+ export type ValidationDataMap = {
269
+ [Property in keyof ValidationDataTypes as `${Property} ${number}`]: {
270
+ type: Property;
271
+ static?: boolean;
272
+ options: ValidationDataTypes[Property];
273
+ };
274
+ };
275
+ /**
276
+ * A union type of all the different widget validation data types that exist.
277
+ */
278
+ export type ValidationData = ValidationDataTypes[keyof ValidationDataTypes];
279
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,3 @@
1
- import type { PerseusCategorizerScoringData, PerseusCategorizerUserInput, PerseusScore } from "../../validation.types";
2
- declare function scoreCategorizer(userInput: PerseusCategorizerUserInput, scoringData: PerseusCategorizerScoringData): PerseusScore;
1
+ import type { PerseusCategorizerRubric, PerseusCategorizerUserInput, PerseusScore } from "../../validation.types";
2
+ declare function scoreCategorizer(userInput: PerseusCategorizerUserInput, rubric: PerseusCategorizerRubric): PerseusScore;
3
3
  export default scoreCategorizer;
@@ -1,3 +1,3 @@
1
1
  import type { PerseusCSProgramUserInput, PerseusScore } from "../../validation.types";
2
- declare function scoreCSProgram(state: PerseusCSProgramUserInput): PerseusScore;
2
+ declare function scoreCSProgram(userInput: PerseusCSProgramUserInput): PerseusScore;
3
3
  export default scoreCSProgram;
@@ -1,3 +1,3 @@
1
1
  import type { PerseusExpressionRubric, PerseusExpressionUserInput, PerseusScore } from "../../validation.types";
2
- declare function scoreExpression(userInput: PerseusExpressionUserInput, rubric: PerseusExpressionRubric, strings: any, locale: string): PerseusScore;
2
+ declare function scoreExpression(userInput: PerseusExpressionUserInput, rubric: PerseusExpressionRubric, locale: string): PerseusScore;
3
3
  export default scoreExpression;
@@ -1,3 +1,3 @@
1
- import type { PerseusGrapherUserInput, PerseusGrapherRubric, PerseusScore } from "../../validation.types";
1
+ import type { PerseusGrapherRubric, PerseusGrapherUserInput, PerseusScore } from "../../validation.types";
2
2
  declare function scoreGrapher(userInput: PerseusGrapherUserInput, rubric: PerseusGrapherRubric): PerseusScore;
3
3
  export default scoreGrapher;
@@ -1,3 +1,3 @@
1
- import type { PerseusScore, PerseusInteractiveGraphRubric, PerseusInteractiveGraphUserInput } from "@khanacademy/perseus-score";
1
+ import type { PerseusInteractiveGraphRubric, PerseusScore, PerseusInteractiveGraphUserInput } from "@khanacademy/perseus-score";
2
2
  declare function scoreInteractiveGraph(userInput: PerseusInteractiveGraphUserInput, rubric: PerseusInteractiveGraphRubric): PerseusScore;
3
3
  export default scoreInteractiveGraph;
@@ -1,9 +1,8 @@
1
1
  import type { PerseusLabelImageUserInput, PerseusLabelImageRubric, PerseusScore } from "../../validation.types";
2
- import type { InteractiveMarkerType } from "@khanacademy/perseus-core";
3
2
  type InteractiveMarkerScore = {
4
3
  hasAnswers: boolean;
5
4
  isCorrect: boolean;
6
5
  };
7
- export declare function scoreLabelImageMarker(marker: InteractiveMarkerType): InteractiveMarkerScore;
8
- declare function scoreLabelImage(userInput: PerseusLabelImageUserInput, rubric?: PerseusLabelImageRubric): PerseusScore;
6
+ export declare function scoreLabelImageMarker(userInput: PerseusLabelImageUserInput["markers"][number]["selected"], rubric: PerseusLabelImageRubric["markers"][number]["answers"]): InteractiveMarkerScore;
7
+ declare function scoreLabelImage(userInput: PerseusLabelImageUserInput, rubric: PerseusLabelImageRubric): PerseusScore;
9
8
  export default scoreLabelImage;
@@ -0,0 +1,3 @@
1
+ import type { PerseusLabelImageUserInput, ValidationResult } from "../../validation.types";
2
+ declare function validateLabelImage(userInput: PerseusLabelImageUserInput): ValidationResult;
3
+ export default validateLabelImage;
@@ -1,3 +1,3 @@
1
1
  import type { PerseusMatcherRubric, PerseusMatcherUserInput, PerseusScore } from "../../validation.types";
2
- declare function scoreMatcher(state: PerseusMatcherUserInput, rubric: PerseusMatcherRubric): PerseusScore;
2
+ declare function scoreMatcher(userInput: PerseusMatcherUserInput, rubric: PerseusMatcherRubric): PerseusScore;
3
3
  export default scoreMatcher;
@@ -1,3 +1,3 @@
1
- import type { PerseusMatrixUserInput, PerseusMatrixRubric, PerseusScore } from "../../validation.types";
1
+ import type { PerseusMatrixRubric, PerseusMatrixUserInput, PerseusScore } from "../../validation.types";
2
2
  declare function scoreMatrix(userInput: PerseusMatrixUserInput, rubric: PerseusMatrixRubric): PerseusScore;
3
3
  export default scoreMatrix;
@@ -1,4 +1,4 @@
1
- import type { PerseusMatrixUserInput, PerseusMatrixValidationData, ValidationResult } from "../../validation.types";
1
+ import type { PerseusMatrixUserInput, ValidationResult } from "../../validation.types";
2
2
  /**
3
3
  * Checks user input from the matrix widget to see if it is scorable.
4
4
  *
@@ -7,5 +7,5 @@ import type { PerseusMatrixUserInput, PerseusMatrixValidationData, ValidationRes
7
7
  *
8
8
  * @see `scoreMatrix()` for more details.
9
9
  */
10
- declare function validateMatrix(userInput: PerseusMatrixUserInput, validationData: PerseusMatrixValidationData): ValidationResult;
10
+ declare function validateMatrix(userInput: PerseusMatrixUserInput): ValidationResult;
11
11
  export default validateMatrix;
@@ -1,3 +1,3 @@
1
- import type { PerseusNumberLineScoringData, PerseusNumberLineUserInput, PerseusScore } from "../../validation.types";
2
- declare function scoreNumberLine(userInput: PerseusNumberLineUserInput, scoringData: PerseusNumberLineScoringData): PerseusScore;
1
+ import type { PerseusNumberLineRubric, PerseusNumberLineUserInput, PerseusScore } from "../../validation.types";
2
+ declare function scoreNumberLine(userInput: PerseusNumberLineUserInput, rubric: PerseusNumberLineRubric): PerseusScore;
3
3
  export default scoreNumberLine;
@@ -1,3 +1,3 @@
1
- import type { PerseusPlotterUserInput, PerseusPlotterScoringData, PerseusScore } from "../../validation.types";
2
- declare function scorePlotter(userInput: PerseusPlotterUserInput, scoringData: PerseusPlotterScoringData): PerseusScore;
1
+ import type { PerseusPlotterUserInput, PerseusPlotterRubric, PerseusScore } from "../../validation.types";
2
+ declare function scorePlotter(userInput: PerseusPlotterUserInput, rubric: PerseusPlotterRubric): PerseusScore;
3
3
  export default scorePlotter;
@@ -1,3 +1,3 @@
1
- import type { PerseusSorterUserInput, PerseusSorterRubric, PerseusScore } from "../../validation.types";
1
+ import type { PerseusSorterRubric, PerseusSorterUserInput, PerseusScore } from "../../validation.types";
2
2
  declare function scoreSorter(userInput: PerseusSorterUserInput, rubric: PerseusSorterRubric): PerseusScore;
3
3
  export default scoreSorter;
@@ -1,3 +1,3 @@
1
- import type { PerseusScore, PerseusTableRubric, PerseusTableUserInput } from "../../validation.types";
1
+ import type { PerseusTableRubric, PerseusScore, PerseusTableUserInput } from "../../validation.types";
2
2
  declare function scoreTable(userInput: PerseusTableUserInput, rubric: PerseusTableRubric): PerseusScore;
3
3
  export default scoreTable;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Perseus score",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "1.1.0",
6
+ "version": "2.0.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -26,9 +26,9 @@
26
26
  "test": "bash -c 'yarn --silent --cwd \"../..\" test ${@:0} $($([[ ${@: -1} = -* ]] || [[ ${@: -1} = bash ]]) && echo $PWD)'"
27
27
  },
28
28
  "dependencies": {
29
- "@khanacademy/kas": "^0.4.11",
30
- "@khanacademy/kmath": "^0.3.0",
31
- "@khanacademy/perseus-core": "3.2.0"
29
+ "@khanacademy/kas": "^0.4.12",
30
+ "@khanacademy/kmath": "^0.3.1",
31
+ "@khanacademy/perseus-core": "3.3.0"
32
32
  },
33
33
  "devDependencies": {},
34
34
  "peerDependencies": {},