All files / web/src/components/toys/coordinate-plane/wordProblems characters.ts

100% Statements 70/70
100% Branches 13/13
100% Functions 3/3
100% Lines 70/70

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 711x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5541x 5541x 5541x 5541x 5541x 5541x 5541x 1x 1x 1x 1x 1x 1x 1x 1x 2601x 762x 762x 762x 762x 762x 1839x 2601x 628x 628x 1x 1x 1x 1x 1x 1x 940x 940x 940x 940x 940x 940x 940x  
import type { SemanticFrame, SubjectEntry } from './types'
import { capitalize } from './inflect'
 
/** A character that can star in a word problem */
export interface Character {
  name: string
  pronoun: 'she' | 'he' | 'they'
  possessive: 'her' | 'his' | 'their'
}
 
export const CHARACTERS: Character[] = [
  { name: 'Sonia', pronoun: 'she', possessive: 'her' },
  { name: 'Marcus', pronoun: 'he', possessive: 'his' },
  { name: 'Priya', pronoun: 'she', possessive: 'her' },
  { name: 'Kai', pronoun: 'he', possessive: 'his' },
  { name: 'Amara', pronoun: 'she', possessive: 'her' },
  { name: 'Leo', pronoun: 'he', possessive: 'his' },
  { name: 'Mei', pronoun: 'she', possessive: 'her' },
  { name: 'Diego', pronoun: 'he', possessive: 'his' },
  { name: 'Zara', pronoun: 'she', possessive: 'her' },
  { name: 'Noah', pronoun: 'he', possessive: 'his' },
  { name: 'Aisha', pronoun: 'she', possessive: 'her' },
  { name: 'Ravi', pronoun: 'he', possessive: 'his' },
  { name: 'Luna', pronoun: 'she', possessive: 'her' },
  { name: 'Ethan', pronoun: 'he', possessive: 'his' },
  { name: 'Yuki', pronoun: 'they', possessive: 'their' },
]
 
/**
 * Replace {name}, {pronoun}, {Pronoun}, {possessive}, {Possessive} in a string.
 */
export function resolveTemplate(text: string, character: Character): string {
  return text
    .replace(/\{name\}/g, character.name)
    .replace(/\{pronoun\}/g, character.pronoun)
    .replace(/\{Pronoun\}/g, capitalize(character.pronoun))
    .replace(/\{possessive\}/g, character.possessive)
    .replace(/\{Possessive\}/g, capitalize(character.possessive))
}
 
/**
 * Resolve a subject entry's placeholders.
 *
 * - `{Pronoun}` subjects get conjugation auto-set: 'they' → 'base', else 'thirdPerson'.
 * - All other subjects get simple template replacement with conjugation preserved.
 */
export function resolveSubject(subject: SubjectEntry, character: Character): SubjectEntry {
  if (subject.phrase === '{Pronoun}') {
    return {
      phrase: capitalize(character.pronoun),
      conjugation: character.pronoun === 'they' ? 'base' : 'thirdPerson',
    }
  }
  const resolved = resolveTemplate(subject.phrase, character)
  if (resolved === subject.phrase) return subject // no placeholders — return original
  return { phrase: resolved, conjugation: subject.conjugation }
}
 
/**
 * Resolve all character placeholders in a SemanticFrame.
 * Returns a new frame — the original is not mutated.
 */
export function resolveCharacter(frame: SemanticFrame, character: Character): SemanticFrame {
  return {
    ...frame,
    setupPhrases: frame.setupPhrases.map((p) => resolveTemplate(p, character)),
    subjects: frame.subjects.map((s) => resolveSubject(s, character)),
    solveForXQuestions: frame.solveForXQuestions?.map((q) => resolveTemplate(q, character)),
  }
}