All files / shared settingsValidation.ts

100% Statements 29/29
95.23% Branches 20/21
100% Functions 5/5
100% Lines 29/29

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      7x                 7x 44x 5x     39x 39x     7x 110x 7x     103x 103x     7x 9x 3x     6x 6x 3x     3x     7x     110x   7x           3x 3x   3x 12x 12x 12x 6x       3x    
import { defaultSettings } from './defaults'
import type { AppSettings } from './types'
 
export const numericSettingsFields = [
  'focusMinutes',
  'shortBreakMinutes',
  'longBreakMinutes',
  'longBreakInterval'
] as const
 
export type NumericSettingField = (typeof numericSettingsFields)[number]
 
export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
    return false
  }
 
  const prototype = Object.getPrototypeOf(value)
  return prototype === Object.prototype || prototype === null
}
 
export const normalizeNumericSettingValue = (value: unknown, fallback: number): number => {
  if (typeof value !== 'number' || !Number.isFinite(value)) {
    return fallback
  }
 
  const normalized = Math.round(value)
  return normalized < 1 ? fallback : normalized
}
 
export const validateNumericSettingValue = (value: unknown, field: NumericSettingField): number => {
  if (typeof value !== 'number') {
    throw new Error(`${field} must be a number`)
  }
 
  const normalized = Math.round(value)
  if (!Number.isFinite(normalized) || normalized < 1) {
    throw new Error(`${field} must be at least 1`)
  }
 
  return normalized
}
 
export const getNormalizedNumericSetting = (
  settings: Pick<Record<NumericSettingField, unknown>, NumericSettingField>,
  field: NumericSettingField
): number => normalizeNumericSettingValue(settings[field], defaultSettings[field])
 
export const sanitizeNumericSettings = (
  settings: Pick<Record<NumericSettingField, unknown>, NumericSettingField>
): {
  normalized: Pick<AppSettings, NumericSettingField>
  patch: Partial<Pick<AppSettings, NumericSettingField>>
} => {
  const normalized = {} as Pick<AppSettings, NumericSettingField>
  const patch: Partial<Pick<AppSettings, NumericSettingField>> = {}
 
  for (const field of numericSettingsFields) {
    const nextValue = getNormalizedNumericSetting(settings, field)
    normalized[field] = nextValue
    if (settings[field] !== nextValue) {
      patch[field] = nextValue
    }
  }
 
  return { normalized, patch }
}