Part of #73 — Converter Architecture
Overview
Implement a Strong CSV to openweight converter. Strong is the most popular strength training app and the most common source of workout data people want to migrate. This is the first app-specific converter and will validate the shared converter architecture.
Strong CSV Format
Known columns
| Column |
Type |
Maps to |
Notes |
Date |
datetime (format varies) |
WorkoutLog.date |
See date format notes below |
Workout Name |
string |
WorkoutLog.name |
Workout name/title |
Duration |
string (e.g. "1h 23m") |
WorkoutLog.durationSeconds |
Human-readable duration, needs parsing |
Exercise Name |
string |
ExerciseLog.exercise.name |
App-specific exercise name |
Set Order |
integer |
Set ordering within exercise |
1-based |
Weight |
number |
SetLog.weight |
In user's preferred unit |
Reps |
integer |
SetLog.reps |
Rep count |
Distance |
number |
SetLog.distance |
Distance value |
Seconds |
integer |
SetLog.durationSeconds |
For timed exercises |
Notes |
string |
SetLog.notes |
Per-set notes |
Workout Notes |
string |
WorkoutLog.notes |
Workout-level notes |
RPE |
number |
SetLog.rpe |
May be present in newer exports |
Known quirks
- Date format varies by locale: US exports use
"2024-01-15 10:30:00" but other locales may differ. Must handle multiple date formats.
- Duration is human-readable:
"1h 23m 45s" format, needs regex parsing to extract seconds.
- No unit column: Weight unit depends on the user's app setting at export time. Converter needs
--unit kg|lb flag to specify.
- No set type: Strong does not distinguish warmup/working/failure sets. All sets are treated equally. Conversion report should note this as data that cannot be inferred.
- No superset info: Strong does not export superset groupings.
- No RPE in most exports: RPE column may be absent in older exports. Handle gracefully.
- Exercise names include equipment: e.g., "Bench Press (Barbell)", "Lateral Raise (Dumbbell)". Can be parsed to extract equipment.
- Export may be paywalled: Strong Pro required for CSV export in some versions.
- Must export in English: Non-English exports may have translated column headers.
Data loss (Strong to openweight)
Strong's format is minimal, so conversion is mostly additive. However:
- No set types can be inferred (all become untyped)
- No superset groupings
- No RPE (in most exports)
- No tempo, RIR, or rest data
This should be documented in the conversion report.
Implementation
Strong-specific transformer (tools/converters/src/converters/strong.ts)
const STRONG_COLUMNS: ColumnMap = {
"Date": "date",
"Workout Name": "workoutName",
"Duration": "workoutDuration",
"Exercise Name": "exerciseName",
"Set Order": "setOrder",
"Weight": "weight",
"Reps": "reps",
"Distance": "distance",
"Seconds": "durationSeconds",
"Notes": "notes",
"Workout Notes": "workoutNotes",
"RPE": "rpe",
};
Key implementation details
- Duration parsing: Parse "1h 23m 45s" format with regex. Handle variations ("1h 23m", "45m", "1h").
- Equipment extraction: Optionally parse "Exercise (Equipment)" pattern to split into
exercise.name + exercise.equipment.
- Workout grouping: Group rows by
Date + Workout Name to form individual WorkoutLog objects.
- Exercise grouping: Within a workout, group by
Exercise Name maintaining Set Order.
- Unit handling: Accept
--unit flag. Default to preserving as-is with a warning in report if no unit specified.
Test Plan
- Fixture-based tests with sample Strong CSV data
- Verify workout grouping by date + name
- Verify exercise grouping and set ordering
- Verify duration parsing for various formats
- Verify equipment extraction from exercise names
- Verify handling of missing optional columns (RPE, Distance, Seconds)
- Verify empty/null field handling
- Roundtrip: converted output passes
validateWorkoutLog()
- Edge cases: single-exercise workouts, timed-only exercises, bodyweight exercises (weight = 0)
Depends On
Part Of
Overview
Implement a Strong CSV to openweight converter. Strong is the most popular strength training app and the most common source of workout data people want to migrate. This is the first app-specific converter and will validate the shared converter architecture.
Strong CSV Format
Known columns
DateWorkoutLog.dateWorkout NameWorkoutLog.nameDurationWorkoutLog.durationSecondsExercise NameExerciseLog.exercise.nameSet OrderWeightSetLog.weightRepsSetLog.repsDistanceSetLog.distanceSecondsSetLog.durationSecondsNotesSetLog.notesWorkout NotesWorkoutLog.notesRPESetLog.rpeKnown quirks
"2024-01-15 10:30:00"but other locales may differ. Must handle multiple date formats."1h 23m 45s"format, needs regex parsing to extract seconds.--unit kg|lbflag to specify.Data loss (Strong to openweight)
Strong's format is minimal, so conversion is mostly additive. However:
This should be documented in the conversion report.
Implementation
Strong-specific transformer (
tools/converters/src/converters/strong.ts)Key implementation details
exercise.name+exercise.equipment.Date+Workout Nameto form individual WorkoutLog objects.Exercise NamemaintainingSet Order.--unitflag. Default to preserving as-is with a warning in report if no unit specified.Test Plan
validateWorkoutLog()Depends On
Part Of