All files / web/src/lib/kid-songs eligibility.ts

100% Statements 52/52
87.5% Branches 21/24
100% Functions 8/8
100% Lines 52/52

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 531x 1x 1x 1x 1x 1x 1x 1x 9x 9x 217x 217x 217x 6x 6x 1x 1x 55x 55x 1x 1x 10x 10x 1x 1x 15x 12x 15x 15x 1x 1x 3x 3x 1x 1x 2x 2x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 1x 1x 2x 2x  
import { parseSongPlan } from '@/lib/song-share/songPlan'
import type { SongRow } from './queries'
 
export const ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/
export const VERSION_PATTERN = /^[a-f0-9]{64}$/
// Spelled as a code-unit scan rather than a regex character class: a class over
// C0/C1 is what lint/suspicious/noControlCharactersInRegex exists to catch, and
// suppressing that rule would hide the next one someone writes by accident.
function hasControlCharacter(value: string): boolean {
  for (let index = 0; index < value.length; index += 1) {
    const code = value.charCodeAt(index)
    if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) return true
  }
  return false
}
 
export function isValidId(value: unknown): value is string {
  return typeof value === 'string' && ID_PATTERN.test(value)
}
 
export function isValidAudioVersion(value: unknown): value is string {
  return typeof value === 'string' && VERSION_PATTERN.test(value)
}
 
export function isValidTitle(value: unknown): value is string {
  if (typeof value !== 'string') return false
  const title = value.trim()
  return title.length >= 1 && title.length <= 120 && !hasControlCharacter(title)
}
 
export function toIso(value: Date | number | string): string {
  return (value instanceof Date ? value : new Date(value)).toISOString()
}
 
export function toNullableIso(value: Date | number | string | null): string | null {
  return value == null ? null : toIso(value)
}
 
export interface EligibleSongCandidate extends SongRow {
  title: string
}
 
export function toEligibleSongCandidate(row: SongRow): EligibleSongCandidate | null {
  if (row.status !== 'completed' || row.contentReviewStatus === 'flagged') return null
  const rawTitle = parseSongPlan(row.llmOutput).title
  if (!isValidTitle(rawTitle)) return null
  return { ...row, title: rawTitle.trim() }
}
 
export function audioUrlFor(playerId: string, songId: string, version: string): string {
  return `/api/integrations/kid-songs/${playerId}/audio?songId=${songId}&v=${version}`
}