Skip to content

Commit 33bb9f0

Browse files
committed
[benc/assign-radio-ids-by-location] WIP
1 parent 3d8cec1 commit 33bb9f0

File tree

7 files changed

+40
-14
lines changed

7 files changed

+40
-14
lines changed

packages/perseus-core/src/data-schema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,11 @@ export type PerseusRadioChoice = {
13851385
// If this is none of the above, override the content with "None of the above"
13861386
// NOTE: perseus_data.go says this is required even though it isn't necessary.
13871387
isNoneOfTheAbove?: boolean;
1388+
/**
1389+
* An opaque string that uniquely identifies this radio choice within the
1390+
* assessment item or article.
1391+
*/
1392+
id: string;
13881393
};
13891394

13901395
export type PerseusSorterWidgetOptions = {

packages/perseus-core/src/parse-perseus-json/error-tracking-parse-context.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export class ErrorTrackingParseContext implements ParseContext {
1919
]);
2020
}
2121

22+
getPath(): PathSegment[] {
23+
return this.path;
24+
}
25+
2226
forSubtree(key: PathSegment): ParseContext {
2327
return new ErrorTrackingParseContext([...this.path, key]);
2428
}

packages/perseus-core/src/parse-perseus-json/general-purpose-parsers/defaulted.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import {success} from "../result";
22

3-
import type {Parser} from "../parser-types";
3+
import type {ParseContext, Parser} from "../parser-types";
44

55
export function defaulted<T>(
66
parser: Parser<T>,
7-
fallback: (missingValue: null | undefined) => NoInfer<T>,
7+
fallback: (missingValue: null | undefined, ctx: ParseContext) => NoInfer<T>,
88
): Parser<T> {
99
return (rawValue, ctx) => {
1010
if (rawValue == null) {
11-
return success(fallback(rawValue));
11+
return success(fallback(rawValue, ctx));
1212
}
1313
return parser(rawValue, ctx);
1414
};

packages/perseus-core/src/parse-perseus-json/parser-types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ export interface ParseContext {
4444
badValue: unknown,
4545
): Failure<Mismatch[]>;
4646

47+
/**
48+
* Returns a value indicating which part of the object tree is currently
49+
* being parsed. See also `forSubtree`.
50+
*/
51+
getPath(): PathSegment[];
52+
53+
/**
54+
* Creates a new `ParseContext` with the given `key` appended to its path.
55+
*/
4756
forSubtree(key: PathSegment): ParseContext;
4857
}
4958

packages/perseus-core/src/parse-perseus-json/perseus-parsers/radio-widget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const parseRadioWidgetV2 = parseWidgetWithVersion(
7575
isNoneOfTheAbove: optional(boolean),
7676
// deprecated
7777
widgets: parseWidgetsMapOrUndefined,
78+
id: defaulted(string, (_, ctx) => ctx.getPath().join(".")),
7879
}),
7980
),
8081
hasNoneOfTheAbove: optional(boolean),

packages/perseus/src/widgets/radio/__tests__/radio.test.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ describe("Radio Widget", () => {
287287
const q = clone(question);
288288
q.widgets["radio 1"].options.choices = answers.map(
289289
(answer, idx) => ({
290+
id: `${idx}`,
290291
content: answer,
291292
correct: idx === 1, // Correct answer is the "truthy" item
292293
}),
@@ -317,6 +318,7 @@ describe("Radio Widget", () => {
317318
const q = clone(question);
318319
q.widgets["radio 1"].options.choices = answers.map(
319320
(answer, idx) => ({
321+
id: `${idx}`,
320322
content: answer,
321323
correct: idx === 1,
322324
}),
@@ -351,6 +353,7 @@ describe("Radio Widget", () => {
351353
options: {
352354
choices: [
353355
{
356+
id: "0",
354357
correct: true,
355358
// Passage refs reference a passage widget in
356359
// the main content. The first value is the
@@ -360,8 +363,8 @@ describe("Radio Widget", () => {
360363
// 1-based!
361364
content: `{{passage-ref 1 1 "the 1st ref in the 1st passage"}}`,
362365
},
363-
{content: `Answer 2`},
364-
{content: `Answer 3`},
366+
{id: "1", content: `Answer 2`},
367+
{id: "2", content: `Answer 3`},
365368
],
366369
},
367370
},
@@ -556,10 +559,11 @@ describe("Radio Widget", () => {
556559
options: {
557560
...radioOptions,
558561
choices: [
559-
{content: "$x=-6$", correct: true},
560-
{content: "$x=4$", correct: true},
561-
{content: "$x=7$", correct: false},
562+
{id: "0", content: "$x=-6$", correct: true},
563+
{id: "1", content: "$x=4$", correct: true},
564+
{id: "2", content: "$x=7$", correct: false},
562565
{
566+
id: "3",
563567
content: "There is no such input value.",
564568
isNoneOfTheAbove: true,
565569
correct: false,
@@ -597,10 +601,11 @@ describe("Radio Widget", () => {
597601
options: {
598602
...radioOptions,
599603
choices: [
600-
{content: "$x=-6$", correct: true},
601-
{content: "$x=4$", correct: true},
602-
{content: "$x=7$", correct: false},
604+
{id: "0", content: "$x=-6$", correct: true},
605+
{id: "1", content: "$x=4$", correct: true},
606+
{id: "2", content: "$x=7$", correct: false},
603607
{
608+
id: "3",
604609
content: "There is no such input value.",
605610
isNoneOfTheAbove: true,
606611
correct: false,
@@ -669,10 +674,11 @@ describe("Radio Widget", () => {
669674
options: {
670675
...radioOptions,
671676
choices: [
672-
{content: "$x=-6$", correct: true},
673-
{content: "$x=4$", correct: true},
674-
{content: "$x=7$", correct: false},
677+
{id: "0", content: "$x=-6$", correct: true},
678+
{id: "1", content: "$x=4$", correct: true},
679+
{id: "2", content: "$x=7$", correct: false},
675680
{
681+
id: "3",
676682
content: "There is no such input value.",
677683
isNoneOfTheAbove: true,
678684
correct: false,

packages/perseus/src/widgets/radio/radio-question-builder.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class RadioQuestionBuilder {
7777
correct: options?.correct,
7878
rationale: options?.rationale,
7979
isNoneOfTheAbove: options?.isNoneOfTheAbove,
80+
id: "id-" + this.choices.length,
8081
});
8182
return this;
8283
}

0 commit comments

Comments
 (0)