common.ts
1 import { createContext } from 'react' 2 import { z } from 'zod' 3 4 import { createRadix, type Radix } from './radixes.ts' 5 import { getErrorMessage } from 'react-error-boundary' 6 7 8 export const LS_CHARS = 'chars' 9 export const LS_RADIXES = 'radixes' 10 11 const ExportRadixes = z.array(z.object({ 12 name: z.string(), 13 radix: z.number(), 14 system: z.enum([ 'standard', 'bijective', 'balanced', 'clock', 'sum', 'balsum' ]), 15 chars: z.string(), 16 enabled: z.boolean(), 17 })) 18 19 export const AppContext = createContext<{ updateError: (error: unknown) => void }>({ updateError: () => {} }) 20 21 export function getCharsLS(): string | undefined { 22 return localStorage.getItem(LS_CHARS) ?? undefined 23 } 24 25 export function sanitizeInput(input: string, radix: Radix): string[] { 26 input = input.toUpperCase() 27 const chars = radix.system === 'balanced' ? radix.chars : `-${radix.chars}` 28 const sanitizedInput = input.replaceAll(new RegExp(`[^${chars}]`, 'g'), '') 29 const rest = input.replaceAll(new RegExp(`[${chars}]`, 'g'), '') 30 return [ sanitizedInput, rest ] 31 } 32 33 export function serializeRadixes(radixes: Radix[]) { 34 return JSON.stringify( 35 radixes.map(r => ({ name: r.name, radix: Number(r.radix), system: r.system, chars: r.chars, enabled: r.enabled })), 36 undefined, 37 '\t', 38 ) 39 } 40 41 export function unserializeRadixes(content: string): Radix[] { 42 try { 43 const radixes = ExportRadixes.parse(JSON.parse(content), { reportInput: true }) 44 return radixes.map(r => createRadix(r.radix, r.system, r.chars, r.enabled, r.name, false)) 45 } catch (error) { 46 if (error instanceof z.ZodError) throw new Error(`Error validating input file:\n\n${z.prettifyError(error)}`, { cause: error }) 47 throw new Error(`Error parsing input file:\n\n${getErrorMessage(error)}`, { cause: error }) 48 } 49 }