/** * Unit Validation Utilities * Ensures all stored units comply with metric-only storage rule * * Custom Knowledge Requirement: * "Unit Conversion Rules: Storage: Always metric in DB (km/h, m, cm, kg)" */ import { convertValueToMetric, getMetricUnit } from './units'; export const METRIC_UNITS = [ 'km/h', // Speed 'm', // Distance (large) 'cm', // Distance (small) 'kg', // Weight 'g', // Weight (small) 'G', // G-force 'celsius', // Temperature 'seconds', // Time 'minutes', // Time 'hours', // Time 'count', // Dimensionless '%', // Percentage ] as const; export const IMPERIAL_UNITS = [ 'mph', // Speed 'ft', // Distance 'in', // Distance 'lbs', // Weight 'fahrenheit', // Temperature ] as const; export type MetricUnit = typeof METRIC_UNITS[number]; export type ImperialUnit = typeof IMPERIAL_UNITS[number]; /** * Check if a unit is metric */ export function isMetricUnit(unit: string): unit is MetricUnit { return METRIC_UNITS.includes(unit as MetricUnit); } /** * Validate that a unit is metric (throws if not) */ export function validateMetricUnit(unit: string, fieldName: string = 'unit'): void { if (!isMetricUnit(unit)) { throw new Error( `${fieldName} must be metric. Received "${unit}", expected one of: ${METRIC_UNITS.join(', ')}` ); } } /** * Ensure value is in metric units, converting if necessary * * @example * ```typescript * const { value, unit } = ensureMetricUnit(60, 'mph'); * // Returns: { value: 96.56, unit: 'km/h' } * ``` */ export function ensureMetricUnit( value: number, unit: string ): { value: number; unit: MetricUnit } { if (isMetricUnit(unit)) { return { value, unit }; } // Convert imperial to metric const metricValue = convertValueToMetric(value, unit); const metricUnit = getMetricUnit(unit) as MetricUnit; return { value: metricValue, unit: metricUnit }; } /** * Batch validate an array of measurements */ export function validateMetricUnits( measurements: Array<{ value: number; unit: string; name: string }> ): { valid: boolean; errors: string[] } { const errors: string[] = []; measurements.forEach(({ unit, name }) => { if (!isMetricUnit(unit)) { errors.push(`${name}: "${unit}" is not a valid metric unit`); } }); return { valid: errors.length === 0, errors }; }