running-tools

A collection of tools for runners and their coaches
git clone https://git.ashermorgan.net/running-tools/
Log | Files | Refs | README

commit a11031a0646507e537e4b021e003bcf7b169032c
parent 68c74edb81d3493afcf0ad2b435357c682a062a6
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Sun, 29 Jun 2025 18:09:30 -0700

Miscellaneous cleanup after TypeScript migration

Update README.md, update comments, and replace formatTargetResult() with
calculateStandardResult() in calculator utils.

Diffstat:
MREADME.md | 3++-
Msrc/utils/calculators.ts | 155++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/utils/races.ts | 23+++++++++++++----------
Msrc/utils/targets.ts | 78+++++++++++++++++++-----------------------------------------------------------
Msrc/utils/units.ts | 55++++++++++++++++++++++++++++++++-----------------------
Msrc/views/BatchCalculator.vue | 74++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/views/PaceCalculator.vue | 8++++----
Msrc/views/RaceCalculator.vue | 16++++++++--------
Msrc/views/SplitCalculator.vue | 8++++----
Msrc/views/UnitCalculator.vue | 91++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/views/WorkoutCalculator.vue | 10+++++-----
11 files changed, 232 insertions(+), 289 deletions(-)

diff --git a/README.md b/README.md @@ -34,9 +34,10 @@ Run development server npm run dev ``` -Run linter and tests +Run type checker, linter, unit tests, and end-to-end tests ``` +npm run type-check npm run lint npm run test:unit npm run test:e2e diff --git a/src/utils/calculators.ts b/src/utils/calculators.ts @@ -7,18 +7,17 @@ import { DistanceUnits, DistanceUnitData, UnitSystems, convertDistance, getDefaultDistanceUnit } from '@/utils/units'; import type { DistanceTime } from '@/utils/units'; +/* + * The two possible result fields of a target result: "key" and "value" + */ export enum ResultType { Key = 'key', Value = 'value', }; -interface PreResult { - distanceValue: number, - distanceUnit: DistanceUnits, - result: TargetTypes, - time: number, -}; - +/* + * The type for target results + */ export interface TargetResult { key: string, value: string, @@ -27,58 +26,94 @@ export interface TargetResult { sort: number, }; +/* + * The type for the options specific to the race calculator + */ export interface RaceOptions { model: raceUtils.RacePredictionModel, riegelExponent: number, -} +}; +/* + * The type for the available race statistics + */ export interface RaceStats { purdyPoints: number, vo2Max: number, vo2: number, vo2MaxPercentage: number, -} +}; +/* + * The type for the options specific to the workout calculator + */ export interface WorkoutOptions extends RaceOptions { customTargetNames: boolean, -} +}; /** - * Format a distance/time result as a key/value result - * @param {PreResult} result The distance/time result + * Calculate results for a standard target + * @param {DistanceTime} input The input pace + * @param {StandardTarget} target The standard target + * @param {Function} calculateTime The function for calculating time results + * @param {Function} calculateDistance The function for calculating distance results * @param {UnitSystems} defaultUnitSystem The default unit system (imperial or metric) * @param {Boolean} preciseDurations Whether to return precise, unrounded, durations - * @returns {TargetResult} The key/value result + * @returns {TargetResult} The result */ -export function formatTargetResult(result: PreResult, defaultUnitSystem: UnitSystems, - preciseDurations: boolean = true): TargetResult { +function calculateStandardResult(input: DistanceTime, target: StandardTarget, + calculateTime: (d1: number, t1: number, d2: number) => number, + calculateDistance: (t1: number, d1: number, t2: number) => number, defaultUnitSystem: UnitSystems, + preciseDurations: boolean = true): TargetResult { + + let distanceValue, distanceUnit, time; + const d1 = convertDistance(input.distanceValue, input.distanceUnit, DistanceUnits.Meters); + if (target.type === TargetTypes.Distance) { + // Add target distance to result + distanceValue = target.distanceValue; + distanceUnit = target.distanceUnit; + + // Calculate time result + const d2 = convertDistance(target.distanceValue, target.distanceUnit, DistanceUnits.Meters); + time = calculateTime(d1, input.time, d2); + } else { + // Add target time to result + time = target.time; + + // Calculate distance result + const d2 = calculateDistance(input.time, d1, target.time); + const units = getDefaultDistanceUnit(defaultUnitSystem); + distanceValue = convertDistance(d2, DistanceUnits.Meters, units); + distanceUnit = units; + } + // Calculate numerical pace - const pace = result.time / convertDistance(result.distanceValue, result.distanceUnit, + const pace = time / convertDistance(distanceValue, distanceUnit, getDefaultDistanceUnit(defaultUnitSystem)); return { // Convert distance to key string - key: formatNumber(result.distanceValue, 0, 2, result.result === 'distance') + ' ' + - DistanceUnitData[result.distanceUnit].symbol, + key: formatNumber(distanceValue, 0, 2, target.type === TargetTypes.Time) + ' ' + + DistanceUnitData[distanceUnit].symbol, // Convert time to time string - value: formatDuration(result.time, 3, preciseDurations ? 2 : 0, result.result === 'time'), + value: formatDuration(time, 3, preciseDurations ? 2 : 0, target.type === TargetTypes.Distance), // Convert pace to pace string pace: formatDuration(pace, 3, 0, true) + ' / ' + DistanceUnitData[getDefaultDistanceUnit(defaultUnitSystem)].symbol, // Convert dist/time result to key/value - result: result.result === TargetTypes.Time ? ResultType.Value : ResultType.Key, + result: target.type === TargetTypes.Distance ? ResultType.Value : ResultType.Key, // Use time (in seconds) as sort key - sort: result.time, + sort: time, }; } /** * Calculate paces from a target - * @param {DistanceTime } input The input pace + * @param {DistanceTime} input The input pace * @param {StandardTarget} target The pace target * @param {UnitSystems} defaultUnitSystem The default unit system (imperial or metric) * @param {Boolean} preciseDurations Whether to return precise, unrounded, durations @@ -87,41 +122,9 @@ export function formatTargetResult(result: PreResult, defaultUnitSystem: UnitSys export function calculatePaceResults(input: DistanceTime, target: StandardTarget, defaultUnitSystem: UnitSystems, preciseDurations: boolean = true): TargetResult { - const result: PreResult = { - distanceValue: 0, - distanceUnit: DistanceUnits.Meters, - time: 0, - result: target.type === TargetTypes.Distance ? TargetTypes.Time : TargetTypes.Distance, - }; - const d1 = convertDistance(input.distanceValue, input.distanceUnit, DistanceUnits.Meters); - - // Add missing value to result - if (target.type === 'distance') { - // Add target distance to result - result.distanceValue = target.distanceValue; - result.distanceUnit = target.distanceUnit; - - // Convert target distance into meters - const d2 = convertDistance(target.distanceValue, target.distanceUnit, DistanceUnits.Meters); - - // Calculate time to travel distance at input pace - result.time = paceUtils.calculateTime(d1, input.time, d2); - } else { - // Add target time to result - result.time = target.time; - - // Calculate distance traveled in time at input pace - const d2 = paceUtils.calculateDistance(input.time, d1, target.time); - - // Convert output distance into default distance unit - const units = getDefaultDistanceUnit(defaultUnitSystem); - result.distanceValue = convertDistance(d2, DistanceUnits.Meters, units); - result.distanceUnit = units; - } - - // Return result - return formatTargetResult(result, defaultUnitSystem, preciseDurations); + return calculateStandardResult(input, target, (d1, t1, d2) => paceUtils.calculateTime(d1, t1, d2), + (t1, d1, t2) => paceUtils.calculateDistance(t1, d1, t2), defaultUnitSystem, preciseDurations); } /** @@ -137,42 +140,10 @@ export function calculateRaceResults(input: DistanceTime, target: StandardTarget options: RaceOptions, defaultUnitSystem: UnitSystems, preciseDurations: boolean = true): TargetResult { - const result: PreResult = { - distanceValue: 0, - distanceUnit: DistanceUnits.Meters, - time: 0, - result: target.type === TargetTypes.Distance ? TargetTypes.Time : TargetTypes.Distance, - }; - - const d1 = convertDistance(input.distanceValue, input.distanceUnit, DistanceUnits.Meters); - - // Add missing value to result - if (target.type === 'distance') { - // Add target distance to result - result.distanceValue = target.distanceValue; - result.distanceUnit = target.distanceUnit; - - // Convert target distance into meters - const d2 = convertDistance(target.distanceValue, target.distanceUnit, DistanceUnits.Meters); - - // Get prediction - result.time = raceUtils.predictTime(d1, input.time, d2, options.model, options.riegelExponent); - } else { - // Add target time to result - result.time = target.time; - - // Get prediction - const distance = raceUtils.predictDistance(input.time, d1, target.time, options.model, - options.riegelExponent); - - // Convert output distance into default distance unit - const units = getDefaultDistanceUnit(defaultUnitSystem); - result.distanceValue = convertDistance(distance, DistanceUnits.Meters, units); - result.distanceUnit = getDefaultDistanceUnit(defaultUnitSystem); - } - - // Return result - return formatTargetResult(result, defaultUnitSystem, preciseDurations); + return calculateStandardResult(input, target, + (d1, t1, d2) => raceUtils.predictTime(d1, t1, d2, options.model, options.riegelExponent), + (t1, d1, t2) => raceUtils.predictDistance(t1, d1, t2, options.model, options.riegelExponent), + defaultUnitSystem, preciseDurations); } /** diff --git a/src/utils/races.ts b/src/utils/races.ts @@ -1,10 +1,22 @@ +/* + * The available race prediction models + */ export enum RacePredictionModel { AverageModel = 'AverageModel', PurdyPointsModel = 'PurdyPointsModel', VO2MaxModel = 'VO2MaxModel', RiegelModel = 'RiegelModel', CameronModel = 'CameronModel', -} +}; + +/* + * The type for internal variables used by the Purdy Points race prediction model + */ +interface PurdyPointsVariables { + twsec: number, + a: number, + b: number, +}; /** * Estimate the point at which a function returns a target value using Newton's Method @@ -39,15 +51,6 @@ function NewtonsMethod(initialEstimate: number, target: number, method: (x: numb } /* - * The internal variables used by the Purdy Points race prediction model - */ -interface PurdyPointsVariables { - twsec: number, - a: number, - b: number, -} - -/* * Methods that implement the Purdy Points race prediction model * https://www.cs.uml.edu/~phoffman/xcinfo3.html */ diff --git a/src/utils/targets.ts b/src/utils/targets.ts @@ -2,98 +2,66 @@ import { formatDuration, formatNumber } from '@/utils/format'; import { DistanceUnits, DistanceUnitData, convertDistance } from '@/utils/units'; /* - * Enumeration for the two basic types of targets: those defined by distance vs time + * The two basic types of targets: those defined by distance and those defined by time */ export enum TargetTypes { Distance = 'distance', Time = 'time', }; -/** - * Type for basic distance-defined targets +/* + * The types for basic standard targets and target sets */ interface DistanceTarget { type: TargetTypes.Distance, distanceValue: number, distanceUnit: DistanceUnits, }; - -/** - * Type for basic time-defined targets - */ interface TimeTarget { type: TargetTypes.Time, time: number, }; - -/** - * Type for pace and race calculator targets - */ export type StandardTarget = DistanceTarget | TimeTarget; - -/* - * Type for pace and race calculator target sets - */ export interface StandardTargetSet { name: string, targets: Array<StandardTarget>, -} - -/* - * Type for a collection of pace and race calculator target sets - */ +}; export interface StandardTargetSets { [key: string]: StandardTargetSet, -} +}; /* - * Type for split calculator targets + * The types for split calculator targets and target sets */ export type SplitTarget = DistanceTarget & { splitTime?: number }; - -/* - * Type for split calculator target sets - */ export interface SplitTargetSet { name: string, targets: Array<SplitTarget>, -} - -/* - * Type for a collection of split calculator target sets - */ +}; export interface SplitTargetSets { [key: string]: SplitTargetSet, -} +}; /* - * Type for workout calculator targets + * The types for workout calculator targets and target sets */ export type WorkoutTarget = StandardTarget & { splitValue: number, splitUnit: DistanceUnits, customName?: string, }; - -/* - * Type for workout calculator target sets - */ export interface WorkoutTargetSet { name: string, targets: Array<WorkoutTarget>, -} - -/* - * Type for a collection of workout calculator target sets - */ +}; export interface WorkoutTargetSets { [key: string]: WorkoutTargetSet, -} +}; /* - * Enumeration for the three types of targets sets: standard (pace & race), split, and workout + * The three types of targets sets: standard (pace & race), split, and workout */ export enum TargetSetTypes { Standard = 'standard', @@ -102,18 +70,10 @@ export enum TargetSetTypes { }; /* - * Type for generic targets + * The types for generic targets and target sets */ export type Target = StandardTarget | SplitTarget | WorkoutTarget; - -/* - * Type for generic target sets - */ export type TargetSet = StandardTargetSet | SplitTargetSet | WorkoutTargetSet; - -/* - * Type for generic collection of target sets - */ export type TargetSets = StandardTargetSets | SplitTargetSets | WorkoutTargetSets; /** @@ -135,7 +95,7 @@ export function sort(targets: Array<Target>): Array<Target> { /** * Generate a string description of a workout target * @param {WorkoutTarget} target The workout target - * @return {String} The string description + * @return {string} The string description */ export function workoutTargetToString(target: WorkoutTarget): string { let result = formatNumber(target.splitValue, 0, 2, false) + ' ' + @@ -149,7 +109,7 @@ export function workoutTargetToString(target: WorkoutTarget): string { return result; } -/** +/* * A set of common pace calculator targets */ const common_pace_targets: StandardTargetSet = { @@ -192,7 +152,7 @@ const common_pace_targets: StandardTargetSet = { ]), }; -/** +/* * A set of common race calculator targets */ const common_race_targets: StandardTargetSet = { @@ -220,7 +180,7 @@ const common_race_targets: StandardTargetSet = { }; -/** +/* * A set of targets for 5K mile splits */ const five_k_mile_splits: SplitTargetSet = { @@ -232,7 +192,7 @@ const five_k_mile_splits: SplitTargetSet = { ], }; -/** +/* * A set of common workout calculator targets */ const common_workout_targets: WorkoutTargetSet = { @@ -257,7 +217,7 @@ const common_workout_targets: WorkoutTargetSet = { ], }; -export const defaultTargetSets: TargetSets = { +export const defaultTargetSets: { [key: string]: TargetSet } = { '_pace_targets': common_pace_targets, '_race_targets': common_race_targets, '_split_targets': five_k_mile_splits, diff --git a/src/utils/units.ts b/src/utils/units.ts @@ -1,5 +1,5 @@ -/** - * The data included for each unit +/* + * The type for the data available for each unit */ export interface UnitData { name: string, @@ -7,14 +7,14 @@ export interface UnitData { value: number, }; -/** - * The supported time units +/* + * The available time units */ export enum TimeUnits { Seconds = 'seconds', Minutes = 'minutes', Hours = 'hours', -} +}; export const TimeUnitData: { [key in TimeUnits]: UnitData } = { [TimeUnits.Seconds]: { name: 'Seconds', @@ -33,8 +33,8 @@ export const TimeUnitData: { [key in TimeUnits]: UnitData } = { }, }; -/** - * The supported distance units +/* + * The available distance units */ export enum DistanceUnits { Meters = 'meters', @@ -42,7 +42,7 @@ export enum DistanceUnits { Kilometers = 'kilometers', Miles = 'miles', Marathons = 'marathons', -} +}; export const DistanceUnitData: { [key in DistanceUnits]: UnitData } = { [DistanceUnits.Meters]: { name: 'Meters', @@ -71,14 +71,14 @@ export const DistanceUnitData: { [key in DistanceUnits]: UnitData } = { }, }; -/** - * The supported speed units +/* + * The available speed units */ export enum SpeedUnits { MetersPerSecond = 'meters_per_second', KilometersPerHour = 'kilometers_per_hour', MilesPerHour = 'miles_per_hour', -} +}; export const SpeedUnitData: { [key in SpeedUnits]: UnitData } = { [SpeedUnits.MetersPerSecond]: { name: 'Meters per Second', @@ -97,14 +97,14 @@ export const SpeedUnitData: { [key in SpeedUnits]: UnitData } = { }, }; -/** - * The supported pace units +/* + * The available pace units */ export enum PaceUnits { SecondsPerMeter = 'seconds_per_meter', TimePerKilometer = 'seconds_per_kilometer', TimePerMile = 'seconds_per_mile', -} +}; export const PaceUnitData: { [key in PaceUnits]: UnitData } = { [PaceUnits.SecondsPerMeter]: { name: 'Seconds per Meter', @@ -123,24 +123,33 @@ export const PaceUnitData: { [key in PaceUnits]: UnitData } = { }, }; -/** - * The supported speed and pace units +/* + * The available speed and pace units */ export type SpeedPaceUnits = SpeedUnits | PaceUnits; -export enum UnitSystems { - Metric = 'metric', - Imperial = 'imperial', -}; - +/* + * The type for a distance input + */ export interface Distance { distanceValue: number, distanceUnit: DistanceUnits, -} +}; +/* + * The type for a distance/time input pair + */ export interface DistanceTime extends Distance { time: number, -} +}; + +/* + * The available unit systems + */ +export enum UnitSystems { + Metric = 'metric', + Imperial = 'imperial', +}; /** * Convert between time units diff --git a/src/views/BatchCalculator.vue b/src/views/BatchCalculator.vue @@ -38,10 +38,10 @@ Target Set: <target-set-selector v-model:selectedTargetSet="selectedTargetSet" :set-type="options.calculator === BatchCompatableCalculators.Workout ? - TargetSetTypes.Workout : TargetSetTypes.Standard" v-model:targetSets="targetSets" + targetUtils.TargetSetTypes.Workout : targetUtils.TargetSetTypes.Standard" + v-model:targetSets="targetSets" :default-unit-system="defaultUnitSystem" :customWorkoutNames="options.calculator === BatchCompatableCalculators.Workout ? - (advancedOptions as WorkoutOptions).customTargetNames : false" - :default-unit-system="defaultUnitSystem"/> + (advancedOptions as WorkoutOptions).customTargetNames : false"/> </div> <div v-if="options.calculator === 'workout'"> Target Name Customization: @@ -66,11 +66,9 @@ import { computed } from 'vue'; import * as calcUtils from '@/utils/calculators'; -import type { TargetResult, RaceOptions, WorkoutOptions } from '@/utils/calculators'; +import type { RaceOptions, TargetResult, WorkoutOptions } from '@/utils/calculators'; import { RacePredictionModel } from '@/utils/races'; -import { TargetSetTypes, defaultTargetSets } from '@/utils/targets'; -import type { Target, TargetSets, StandardTargetSet, StandardTargetSets, WorkoutTarget, - WorkoutTargetSet, WorkoutTargetSets } from '@/utils/targets'; +import * as targetUtils from '@/utils/targets'; import { DistanceUnits, UnitSystems, detectDefaultUnitSystem } from '@/utils/units'; import type { Distance, DistanceTime } from '@/utils/units'; @@ -83,25 +81,25 @@ import TimeInput from '@/components/TimeInput.vue'; import useStorage from '@/composables/useStorage'; -/** +/* * The calculators that may be used from within the batch calculator */ enum BatchCompatableCalculators { Pace = 'pace', Race = 'race', Workout = 'workout', -} +}; -/** - * The batch calculator settings type +/* + * The type for options specific to the batch calculator */ interface BatchCalculatorOptions { calculator: BatchCompatableCalculators, increment: number, rows: number, -} +}; -/** +/* * The input pace */ const input = useStorage<DistanceTime>('batch-calculator-input', { @@ -110,7 +108,7 @@ const input = useStorage<DistanceTime>('batch-calculator-input', { time: 1200, }); -/** +/* * The batch input options */ const options = useStorage<BatchCalculatorOptions>('batch-calculator-options', { @@ -119,12 +117,12 @@ const options = useStorage<BatchCalculatorOptions>('batch-calculator-options', { rows: 20, }); -/** +/* * The default unit system */ const defaultUnitSystem = useStorage<UnitSystems>('default-unit-system', detectDefaultUnitSystem()); -/** +/* * The current selected target sets for each calculator */ const selectedPaceTargetSet = useStorage<string>('pace-calculator-target-set', '_pace_targets'); @@ -132,20 +130,20 @@ const selectedRaceTargetSet = useStorage<string>('race-calculator-target-set', ' const selectedWorkoutTargetSet = useStorage<string>('workout-calculator-target-set', '_workout_targets'); -/** +/* * The target sets for each calculator */ -const paceTargetSets = useStorage<StandardTargetSets>('pace-calculator-target-sets', { - _pace_targets: defaultTargetSets._pace_targets as StandardTargetSet +const paceTargetSets = useStorage<targetUtils.StandardTargetSets>('pace-calculator-target-sets', { + _pace_targets: targetUtils.defaultTargetSets._pace_targets as targetUtils.StandardTargetSet }); -const raceTargetSets = useStorage<StandardTargetSets>('race-calculator-target-sets', { - _race_targets: defaultTargetSets._race_targets as StandardTargetSet +const raceTargetSets = useStorage<targetUtils.StandardTargetSets>('race-calculator-target-sets', { + _race_targets: targetUtils.defaultTargetSets._race_targets as targetUtils.StandardTargetSet }); -const workoutTargetSets = useStorage<WorkoutTargetSets>('workout-calculator-target-sets', { - _workout_targets: defaultTargetSets._workout_targets as WorkoutTargetSet +const workoutTargetSets = useStorage<targetUtils.WorkoutTargetSets>('workout-calculator-target-sets', { + _workout_targets: targetUtils.defaultTargetSets._workout_targets as targetUtils.WorkoutTargetSet }); -/** +/* * The advanced options for each calculator */ const raceOptions = useStorage<RaceOptions>('race-calculator-options', { @@ -158,7 +156,7 @@ const workoutOptions = useStorage<WorkoutOptions>('workout-calculator-options', riegelExponent: 1.06, }); -/** +/* * The input distance */ const inputDistance = computed<Distance>(() => ({ @@ -166,7 +164,7 @@ const inputDistance = computed<Distance>(() => ({ distanceUnit: input.value.distanceUnit, })); -/** +/* * The set of input times */ const inputTimes = computed<Array<number>>(() => { @@ -177,7 +175,7 @@ const inputTimes = computed<Array<number>>(() => { return results; }); -/** +/* * The selected target set for the current calculator */ const selectedTargetSet = computed<string>({ @@ -214,10 +212,10 @@ const selectedTargetSet = computed<string>({ }, }); -/** +/* * The target sets for the current calculator */ -const targetSets = computed<TargetSets>({ +const targetSets = computed<targetUtils.TargetSets>({ get: () => { switch (options.value.calculator) { case (BatchCompatableCalculators.Pace): { @@ -232,26 +230,26 @@ const targetSets = computed<TargetSets>({ } } }, - set: (newValue: TargetSets) => { + set: (newValue: targetUtils.TargetSets) => { switch (options.value.calculator) { case (BatchCompatableCalculators.Pace): { - paceTargetSets.value = newValue as StandardTargetSets; + paceTargetSets.value = newValue as targetUtils.StandardTargetSets; break; } case (BatchCompatableCalculators.Race): { - raceTargetSets.value = newValue as StandardTargetSets; + raceTargetSets.value = newValue as targetUtils.StandardTargetSets; break; } default: case (BatchCompatableCalculators.Workout): { - workoutTargetSets.value = newValue as WorkoutTargetSets; + workoutTargetSets.value = newValue as targetUtils.WorkoutTargetSets; break; } } }, }); -/** +/* * The advanced options for the current calculator */ const advancedOptions = computed<null | RaceOptions | WorkoutOptions>({ @@ -288,10 +286,10 @@ const advancedOptions = computed<null | RaceOptions | WorkoutOptions>({ }, }); -/** +/* * The appropriate calculate_results function for the current calculator */ -const calculateResult = computed<(x: DistanceTime, y: Target) => TargetResult>(() => { +const calculateResult = computed<(x: DistanceTime, y: targetUtils.Target) => TargetResult>(() => { switch(options.value.calculator) { case (BatchCompatableCalculators.Pace): { return (x,y) => calcUtils.calculatePaceResults(x, y, defaultUnitSystem.value, false); @@ -302,8 +300,8 @@ const calculateResult = computed<(x: DistanceTime, y: Target) => TargetResult>(( } default: case (BatchCompatableCalculators.Workout): { - return (x,y) => calcUtils.calculateWorkoutResults(x, y as WorkoutTarget, workoutOptions.value, - false); + return (x,y) => calcUtils.calculateWorkoutResults(x, y as targetUtils.WorkoutTarget, + workoutOptions.value, false); } } }); diff --git a/src/views/PaceCalculator.vue b/src/views/PaceCalculator.vue @@ -43,7 +43,7 @@ import TargetSetSelector from '@/components/TargetSetSelector.vue'; import useStorage from '@/composables/useStorage'; -/** +/* * The input pace */ const input = useStorage<DistanceTime>('pace-calculator-input', { @@ -52,17 +52,17 @@ const input = useStorage<DistanceTime>('pace-calculator-input', { time: 1200, }); -/** +/* * The default unit system */ const defaultUnitSystem = useStorage<UnitSystems>('default-unit-system', detectDefaultUnitSystem()); -/** +/* * The current selected target set */ const selectedTargetSet = useStorage<string>('pace-calculator-target-set', '_pace_targets'); -/** +/* * The target sets */ const targetSets = useStorage<StandardTargetSets>('pace-calculator-target-sets', { diff --git a/src/views/RaceCalculator.vue b/src/views/RaceCalculator.vue @@ -52,7 +52,7 @@ import { computed } from 'vue'; import { calculateRaceResults, calculateRaceStats } from '@/utils/calculators'; -import type { RaceOptions } from '@/utils/calculators'; +import type { RaceOptions, RaceStats } from '@/utils/calculators'; import { formatNumber } from '@/utils/format'; import { RacePredictionModel } from '@/utils/races'; import { defaultTargetSets } from '@/utils/targets'; @@ -67,7 +67,7 @@ import TargetSetSelector from '@/components/TargetSetSelector.vue'; import useStorage from '@/composables/useStorage'; -/** +/* * The input race */ const input = useStorage<DistanceTime>('race-calculator-input', { @@ -76,12 +76,12 @@ const input = useStorage<DistanceTime>('race-calculator-input', { time: 1200, }); -/** +/* * The default unit system */ const defaultUnitSystem = useStorage<UnitSystems>('default-unit-system', detectDefaultUnitSystem()); -/** +/* * The race prediction options */ const options = useStorage<RaceOptions>('race-calculator-options', { @@ -89,22 +89,22 @@ const options = useStorage<RaceOptions>('race-calculator-options', { riegelExponent: 1.06, }); -/** +/* * The current selected target set */ const selectedTargetSet = useStorage<string>('race-calculator-target-set', '_race_targets'); -/** +/* * The target sets */ const targetSets = useStorage<StandardTargetSets>('race-calculator-target-sets', { _race_targets: defaultTargetSets._race_targets }); -/** +/* * The statistics for the current input race */ -const raceStats = computed(() => calculateRaceStats(input.value)); +const raceStats = computed<RaceStats>(() => calculateRaceStats(input.value)); </script> <style scoped> diff --git a/src/views/SplitCalculator.vue b/src/views/SplitCalculator.vue @@ -36,24 +36,24 @@ import TargetSetSelector from '@/components/TargetSetSelector.vue'; import useStorage from '@/composables/useStorage'; -/** +/* * The default unit system */ const defaultUnitSystem = useStorage<UnitSystems>('default-unit-system', detectDefaultUnitSystem()); -/** +/* * The current selected target set */ const selectedTargetSet = useStorage<string>('split-calculator-target-set', '_split_targets'); -/** +/* * The default output targets */ const targetSets = useStorage<SplitTargetSets>('split-calculator-target-sets', { _split_targets: defaultTargetSets._split_targets as SplitTargetSet }); -/** +/* * The active target set */ const targetSet = computed({ diff --git a/src/views/UnitCalculator.vue b/src/views/UnitCalculator.vue @@ -38,26 +38,14 @@ import { computed, ref } from 'vue'; import { formatDuration, formatNumber } from '@/utils/format'; -import { DistanceUnits, DistanceUnitData, TimeUnits, TimeUnitData, PaceUnits, SpeedUnits, SpeedUnitData, - PaceUnitData, convertDistance, convertTime, convertSpeedPace } from '@/utils/units'; -import type { SpeedPaceUnits, UnitData } from '@/utils/units'; +import * as unitUtils from '@/utils/units'; import DecimalInput from '@/components/DecimalInput.vue'; import TimeInput from '@/components/TimeInput.vue'; import useStorage from '@/composables/useStorage'; -/** - * The supported time units: Hours, Minutes, Seconds, and 'hh:mm:ss' - */ -type ExtendedTimeUnits = TimeUnits | 'hh:mm:ss'; - -/** - * All supported distance, time, speed, and pace units - */ -type AllUnits = DistanceUnits | ExtendedTimeUnits | SpeedPaceUnits; - -/** +/* * The three categories of units */ enum UnitTypes { @@ -66,14 +54,24 @@ enum UnitTypes { SpeedPace = 'speed_and_pace', } -/** +/* + * The supported time units: Hours, Minutes, Seconds, and 'hh:mm:ss' + */ +type ExtendedTimeUnits = unitUtils.TimeUnits | 'hh:mm:ss'; + +/* + * The support units from all categories + */ +type AllUnits = unitUtils.DistanceUnits | ExtendedTimeUnits | unitUtils.SpeedPaceUnits; + +/* * The type of the calculator inputs */ interface UnitCalculatorInputs { [UnitTypes.Distance]: { inputValue: number, - inputUnit: DistanceUnits, - outputUnit: DistanceUnits, + inputUnit: unitUtils.DistanceUnits, + outputUnit: unitUtils.DistanceUnits, }, [UnitTypes.Time]: { inputValue: number, @@ -82,38 +80,38 @@ interface UnitCalculatorInputs { }, [UnitTypes.SpeedPace]: { inputValue: number, - inputUnit: SpeedPaceUnits, - outputUnit: SpeedPaceUnits, + inputUnit: unitUtils.SpeedPaceUnits, + outputUnit: unitUtils.SpeedPaceUnits, }, }; -/** +/* * The calculator inputs */ const inputs = useStorage<UnitCalculatorInputs>('unit-calculator-inputs', { [UnitTypes.Distance]: { inputValue: 1, - inputUnit: DistanceUnits.Miles, - outputUnit: DistanceUnits.Kilometers, + inputUnit: unitUtils.DistanceUnits.Miles, + outputUnit: unitUtils.DistanceUnits.Kilometers, }, [UnitTypes.Time]: { inputValue: 1, - inputUnit: TimeUnits.Seconds, + inputUnit: unitUtils.TimeUnits.Seconds, outputUnit: 'hh:mm:ss', }, [UnitTypes.SpeedPace]: { inputValue: 600, - inputUnit: PaceUnits.TimePerMile, - outputUnit: SpeedUnits.MilesPerHour, + inputUnit: unitUtils.PaceUnits.TimePerMile, + outputUnit: unitUtils.SpeedUnits.MilesPerHour, }, }); -/** +/* * The unit category */ const category = ref<UnitTypes>(UnitTypes.Distance); -/** +/* * The inputs for the current category */ const input = computed<{ inputValue: number, inputUnit: AllUnits, outputUnit: AllUnits }>({ @@ -126,8 +124,8 @@ const input = computed<{ inputValue: number, inputUnit: AllUnits, outputUnit: Al case UnitTypes.Distance: { inputs.value[category.value] = { inputValue: newValue.inputValue, - inputUnit: newValue.inputUnit as DistanceUnits, - outputUnit: newValue.outputUnit as DistanceUnits, + inputUnit: newValue.inputUnit as unitUtils.DistanceUnits, + outputUnit: newValue.outputUnit as unitUtils.DistanceUnits, }; break; } @@ -142,27 +140,27 @@ const input = computed<{ inputValue: number, inputUnit: AllUnits, outputUnit: Al case UnitTypes.SpeedPace: { inputs.value[category.value] = { inputValue: newValue.inputValue, - inputUnit: newValue.inputUnit as SpeedPaceUnits, - outputUnit: newValue.outputUnit as SpeedPaceUnits, + inputUnit: newValue.inputUnit as unitUtils.SpeedPaceUnits, + outputUnit: newValue.outputUnit as unitUtils.SpeedPaceUnits, }; break; } } - } + }, }); -/** - * The names of the units in the current category +/* + * The data for the units in the current category */ -const units = computed<{ [key in AllUnits]?: UnitData }>(() => { +const units = computed<{ [key in AllUnits]?: unitUtils.UnitData }>(() => { switch (category.value) { default: case UnitTypes.Distance: { - return DistanceUnitData; + return unitUtils.DistanceUnitData; } case UnitTypes.Time: { return { - ...TimeUnitData, + ...unitUtils.TimeUnitData, 'hh:mm:ss': { name: 'hh:mm:ss', symbol: '', @@ -171,20 +169,21 @@ const units = computed<{ [key in AllUnits]?: UnitData }>(() => { }; } case UnitTypes.SpeedPace: { - return { ...PaceUnitData, ...SpeedUnitData }; + return { ...unitUtils.PaceUnitData, ...unitUtils.SpeedUnitData }; } } }); -/** +/* * The output value */ const outputValue = computed<number>(() => { switch (category.value) { default: case UnitTypes.Distance: { - return convertDistance(input.value.inputValue, input.value.inputUnit as DistanceUnits, - input.value.outputUnit as DistanceUnits); + return unitUtils.convertDistance(input.value.inputValue, + input.value.inputUnit as unitUtils.DistanceUnits, + input.value.outputUnit as unitUtils.DistanceUnits); } case UnitTypes.Time: { // Correct input and output units for 'hh:mm:ss' unit @@ -192,11 +191,13 @@ const outputValue = computed<number>(() => { const realOutput = input.value.outputUnit === 'hh:mm:ss' ? 'seconds' : input.value.outputUnit; // Calculate conversion - return convertTime(input.value.inputValue, realInput as TimeUnits, realOutput as TimeUnits); + return unitUtils.convertTime(input.value.inputValue, realInput as unitUtils.TimeUnits, + realOutput as unitUtils.TimeUnits); } case UnitTypes.SpeedPace: { - return convertSpeedPace(input.value.inputValue, input.value.inputUnit as SpeedPaceUnits, - input.value.outputUnit as SpeedPaceUnits); + return unitUtils.convertSpeedPace(input.value.inputValue, + input.value.inputUnit as unitUtils.SpeedPaceUnits, + input.value.outputUnit as unitUtils.SpeedPaceUnits); } } }); @@ -207,7 +208,7 @@ const outputValue = computed<number>(() => { * @returns {boolean} Whether the unit should be represented as a time */ function isTimeUnit(unit: AllUnits): boolean { - return unit in PaceUnitData || unit === 'hh:mm:ss'; + return unit in unitUtils.PaceUnitData || unit === 'hh:mm:ss'; } </script> diff --git a/src/views/WorkoutCalculator.vue b/src/views/WorkoutCalculator.vue @@ -55,7 +55,7 @@ import TargetSetSelector from '@/components/TargetSetSelector.vue'; import useStorage from '@/composables/useStorage'; -/** +/* * The input race */ const input = useStorage<DistanceTime>('workout-calculator-input', { @@ -64,12 +64,12 @@ const input = useStorage<DistanceTime>('workout-calculator-input', { time: 1200, }); -/** +/* * The default unit system */ const defaultUnitSystem = useStorage<UnitSystems>('default-unit-system', detectDefaultUnitSystem()); -/** +/* * The race prediction options */ const options = useStorage<WorkoutOptions>('workout-calculator-options', { @@ -78,12 +78,12 @@ const options = useStorage<WorkoutOptions>('workout-calculator-options', { riegelExponent: 1.06, }); -/** +/* * The current selected target set */ const selectedTargetSet = useStorage<string>('workout-calculator-target-set', '_workout_targets'); -/** +/* * The target sets */ const targetSets = useStorage<WorkoutTargetSets>('workout-calculator-target-sets', {