hevy-shared 1.0.912 → 1.0.914
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/built/hevyTrainer.d.ts +12 -0
- package/built/hevyTrainer.js +44 -31
- package/built/tests/hevyTrainer.test.js +48 -27
- package/package.json +1 -1
package/built/hevyTrainer.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export declare const granularEquipmentDefaults: {
|
|
|
9
9
|
[key in TrainerGymType]: GranularEquipment[];
|
|
10
10
|
};
|
|
11
11
|
export declare const trainerEquipmentToGranularEquipments: (equipments: HevyTrainerProgramEquipment[]) => GranularEquipment[];
|
|
12
|
+
/**
|
|
13
|
+
* Converts granular equipment values back to the old HevyTrainerProgramEquipment
|
|
14
|
+
* types for backwards compatibility with old mobile clients.
|
|
15
|
+
*/
|
|
16
|
+
export declare const granularEquipmentsToTrainerEquipments: (granularEquipments: GranularEquipment[]) => HevyTrainerProgramEquipment[];
|
|
12
17
|
export declare const hevyTrainerExerciseCategories: readonly ["compound", "isolation"];
|
|
13
18
|
export declare const defaultDurationPerFrequency: Record<WeeklyTrainingFrequency, WorkoutDurationMinutes>;
|
|
14
19
|
export declare const routineNames: readonly ["full_body_1", "full_body_2_a", "full_body_2_b", "full_body_3_a", "full_body_3_b", "full_body_3_c", "upper_1_a", "lower_1_a", "upper_1_b", "lower_1_b", "push_1", "pull_1", "legs_1", "upper_2", "lower_2", "push_2_a", "pull_2_a", "legs_2_a", "push_2_b", "pull_2_b", "legs_2_b"];
|
|
@@ -142,6 +147,13 @@ export declare const normalizeExerciseCategory: (exercise: {
|
|
|
142
147
|
is_custom: boolean;
|
|
143
148
|
category?: ExerciseCategory;
|
|
144
149
|
}) => HevyTrainerExerciseCategory;
|
|
150
|
+
/**
|
|
151
|
+
* Checks if an exercise is compatible with the user's selected granular equipments
|
|
152
|
+
*
|
|
153
|
+
* - If the exercise has no granular equipments, it is compatible no matter what the user has selected
|
|
154
|
+
* - Otherwise, the exercise is only allowed if the user has all the granular equipments
|
|
155
|
+
*/
|
|
156
|
+
export declare const isEquipmentCompatible: (exercise: HevyTrainerLibraryExercise, userSelectedGranularEquipments: GranularEquipment[]) => boolean;
|
|
145
157
|
/**
|
|
146
158
|
* Sorts exercises by priority for each muscle group based on the provided priorities
|
|
147
159
|
* and adds any remaining exercises from the store that weren't in the priorities.
|
package/built/hevyTrainer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateProgram = exports.pickExerciseForPrescription = exports.getPrioritySortedExercises = exports.normalizeExerciseCategory = exports.getTrainerRestTimerSeconds = exports.getTrainerRepRange = exports.getTrainerSetCount = exports.programSplits = exports.frequencyMap = exports.routineNames = exports.defaultDurationPerFrequency = exports.hevyTrainerExerciseCategories = exports.trainerEquipmentToGranularEquipments = exports.granularEquipmentDefaults = exports.trainerGymTypes = exports.workoutDurationOptions = void 0;
|
|
3
|
+
exports.generateProgram = exports.pickExerciseForPrescription = exports.getPrioritySortedExercises = exports.isEquipmentCompatible = exports.normalizeExerciseCategory = exports.getTrainerRestTimerSeconds = exports.getTrainerRepRange = exports.getTrainerSetCount = exports.programSplits = exports.frequencyMap = exports.routineNames = exports.defaultDurationPerFrequency = exports.hevyTrainerExerciseCategories = exports.granularEquipmentsToTrainerEquipments = exports.trainerEquipmentToGranularEquipments = exports.granularEquipmentDefaults = exports.trainerGymTypes = exports.workoutDurationOptions = void 0;
|
|
4
4
|
const _1 = require(".");
|
|
5
5
|
const MAX_BARBELL_EXERCISES_PER_ROUTINE = 2;
|
|
6
6
|
exports.workoutDurationOptions = [40, 60, 80];
|
|
@@ -80,53 +80,27 @@ const trainerEquipmentToGranularEquipmentsMap = {
|
|
|
80
80
|
barbell: [
|
|
81
81
|
'adjustable_bench',
|
|
82
82
|
'barbell',
|
|
83
|
-
'dip_bar',
|
|
84
83
|
'ez_bar',
|
|
85
84
|
'flat_bench',
|
|
86
85
|
'landmine',
|
|
87
|
-
'medicine_ball',
|
|
88
86
|
'plate',
|
|
89
|
-
'pullup_bar',
|
|
90
|
-
'rings',
|
|
91
|
-
'rope',
|
|
92
87
|
'squat_rack',
|
|
93
88
|
't_bar',
|
|
94
|
-
'trap_bar',
|
|
95
|
-
],
|
|
96
|
-
dumbbell: [
|
|
97
|
-
'adjustable_bench',
|
|
98
|
-
'dip_bar',
|
|
99
|
-
'dumbbell',
|
|
100
|
-
'flat_bench',
|
|
101
|
-
'medicine_ball',
|
|
102
|
-
'pullup_bar',
|
|
103
|
-
'rings',
|
|
104
|
-
'rope',
|
|
105
89
|
],
|
|
90
|
+
dumbbell: ['adjustable_bench', 'dumbbell', 'flat_bench'],
|
|
106
91
|
machine: [
|
|
107
92
|
'adjustable_bench',
|
|
108
|
-
'air_bike',
|
|
109
|
-
'battle_rope',
|
|
110
93
|
'dip_bar',
|
|
111
94
|
'dual_cable_machine',
|
|
112
|
-
'elliptical_trainer',
|
|
113
95
|
'flat_bench',
|
|
114
96
|
'lat_pulldown_cable',
|
|
115
97
|
'leg_press_machine',
|
|
116
|
-
'medicine_ball',
|
|
117
98
|
'plate',
|
|
118
99
|
'plate_machines',
|
|
119
100
|
'pullup_bar',
|
|
120
|
-
'resistance_band',
|
|
121
|
-
'rings',
|
|
122
|
-
'rope',
|
|
123
|
-
'rowing_machine',
|
|
124
101
|
'single_cable_machine',
|
|
125
102
|
'smith_machine',
|
|
126
|
-
'spinning',
|
|
127
103
|
'stack_machines',
|
|
128
|
-
'stair_machine',
|
|
129
|
-
'treadmill',
|
|
130
104
|
],
|
|
131
105
|
};
|
|
132
106
|
const trainerEquipmentToGranularEquipments = (equipments) => {
|
|
@@ -137,6 +111,35 @@ const trainerEquipmentToGranularEquipments = (equipments) => {
|
|
|
137
111
|
return Array.from(new Set(granularEquipments));
|
|
138
112
|
};
|
|
139
113
|
exports.trainerEquipmentToGranularEquipments = trainerEquipmentToGranularEquipments;
|
|
114
|
+
const MACHINE_SPECIFIC_GRANULAR_EQUIPMENTS = [
|
|
115
|
+
'smith_machine',
|
|
116
|
+
'leg_press_machine',
|
|
117
|
+
'dual_cable_machine',
|
|
118
|
+
'single_cable_machine',
|
|
119
|
+
'lat_pulldown_cable',
|
|
120
|
+
'plate_machines',
|
|
121
|
+
'stack_machines',
|
|
122
|
+
'dip_bar',
|
|
123
|
+
'pullup_bar',
|
|
124
|
+
];
|
|
125
|
+
/**
|
|
126
|
+
* Converts granular equipment values back to the old HevyTrainerProgramEquipment
|
|
127
|
+
* types for backwards compatibility with old mobile clients.
|
|
128
|
+
*/
|
|
129
|
+
const granularEquipmentsToTrainerEquipments = (granularEquipments) => {
|
|
130
|
+
const result = [];
|
|
131
|
+
if (granularEquipments.includes('barbell')) {
|
|
132
|
+
result.push('barbell');
|
|
133
|
+
}
|
|
134
|
+
if (granularEquipments.includes('dumbbell')) {
|
|
135
|
+
result.push('dumbbell');
|
|
136
|
+
}
|
|
137
|
+
if (granularEquipments.some((eq) => MACHINE_SPECIFIC_GRANULAR_EQUIPMENTS.includes(eq))) {
|
|
138
|
+
result.push('machine');
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
};
|
|
142
|
+
exports.granularEquipmentsToTrainerEquipments = granularEquipmentsToTrainerEquipments;
|
|
140
143
|
exports.hevyTrainerExerciseCategories = ['compound', 'isolation'];
|
|
141
144
|
// These are the values that Philip decided for the default duration per frequency
|
|
142
145
|
exports.defaultDurationPerFrequency = {
|
|
@@ -263,8 +266,18 @@ const isEquipmentCompatible = (exercise, userSelectedGranularEquipments) => {
|
|
|
263
266
|
exercise.granular_equipments.length === 0) {
|
|
264
267
|
return true;
|
|
265
268
|
}
|
|
266
|
-
|
|
269
|
+
const allowedEquipments = [...userSelectedGranularEquipments];
|
|
270
|
+
// Special case: adjustable bench can substitute for flat bench
|
|
271
|
+
if (userSelectedGranularEquipments.includes('adjustable_bench')) {
|
|
272
|
+
allowedEquipments.push('flat_bench');
|
|
273
|
+
}
|
|
274
|
+
// Special case: dual cable machine can substitute for single cable machine
|
|
275
|
+
if (userSelectedGranularEquipments.includes('dual_cable_machine')) {
|
|
276
|
+
allowedEquipments.push('single_cable_machine');
|
|
277
|
+
}
|
|
278
|
+
return exercise.granular_equipments.every((granularEquipment) => allowedEquipments.includes(granularEquipment));
|
|
267
279
|
};
|
|
280
|
+
exports.isEquipmentCompatible = isEquipmentCompatible;
|
|
268
281
|
/**
|
|
269
282
|
* Checks if the routine barbell exercise limit is exceeded
|
|
270
283
|
*
|
|
@@ -364,7 +377,7 @@ const isExerciseMatch = (exercise, criteria) => {
|
|
|
364
377
|
criteria.exerciseCategory === 'compound');
|
|
365
378
|
const levelMatch = (_b = (_a = exercise.level) === null || _a === void 0 ? void 0 : _a.includes(criteria.level)) !== null && _b !== void 0 ? _b : false;
|
|
366
379
|
const goalMatch = (_d = (_c = exercise.goal) === null || _c === void 0 ? void 0 : _c.includes(criteria.goal)) !== null && _d !== void 0 ? _d : false;
|
|
367
|
-
const equipmentMatch = isEquipmentCompatible(exercise, criteria.granularEquipments);
|
|
380
|
+
const equipmentMatch = (0, exports.isEquipmentCompatible)(exercise, criteria.granularEquipments);
|
|
368
381
|
const barbellLimitOk = !isBarbellLimitExceeded(exercise, criteria.routineBarbellExerciseCount, criteria.granularEquipments);
|
|
369
382
|
return (categoryMatch && levelMatch && goalMatch && equipmentMatch && barbellLimitOk);
|
|
370
383
|
};
|
|
@@ -375,7 +388,7 @@ const isAlternativeIsolationExerciseMatch = (exercise, criteria) => {
|
|
|
375
388
|
var _a, _b;
|
|
376
389
|
const isIsolationCategory = criteria.exerciseCategory === 'isolation';
|
|
377
390
|
const isAlternativeExercise = isolationExerciseAlternatives[criteria.muscleGroup].includes(exercise.id);
|
|
378
|
-
const equipmentMatch = isEquipmentCompatible(exercise, criteria.granularEquipments);
|
|
391
|
+
const equipmentMatch = (0, exports.isEquipmentCompatible)(exercise, criteria.granularEquipments);
|
|
379
392
|
const levelMatch = (_b = (_a = exercise.level) === null || _a === void 0 ? void 0 : _a.includes(criteria.level)) !== null && _b !== void 0 ? _b : false;
|
|
380
393
|
return (isIsolationCategory && isAlternativeExercise && equipmentMatch && levelMatch);
|
|
381
394
|
};
|
|
@@ -11,59 +11,33 @@ describe('trainerEquipmentToGranularEquipments', () => {
|
|
|
11
11
|
expect(sortGranular(result)).toEqual(sortGranular([
|
|
12
12
|
'adjustable_bench',
|
|
13
13
|
'barbell',
|
|
14
|
-
'dip_bar',
|
|
15
14
|
'ez_bar',
|
|
16
15
|
'flat_bench',
|
|
17
16
|
'landmine',
|
|
18
|
-
'medicine_ball',
|
|
19
17
|
'plate',
|
|
20
|
-
'pullup_bar',
|
|
21
|
-
'rings',
|
|
22
|
-
'rope',
|
|
23
18
|
'squat_rack',
|
|
24
19
|
't_bar',
|
|
25
|
-
'trap_bar',
|
|
26
20
|
]));
|
|
27
21
|
});
|
|
28
22
|
it('returns expected granular equipments for dumbbell only', () => {
|
|
29
23
|
const result = (0, hevyTrainer_1.trainerEquipmentToGranularEquipments)(['dumbbell']);
|
|
30
|
-
expect(sortGranular(result)).toEqual(sortGranular([
|
|
31
|
-
'adjustable_bench',
|
|
32
|
-
'dip_bar',
|
|
33
|
-
'dumbbell',
|
|
34
|
-
'flat_bench',
|
|
35
|
-
'medicine_ball',
|
|
36
|
-
'pullup_bar',
|
|
37
|
-
'rings',
|
|
38
|
-
'rope',
|
|
39
|
-
]));
|
|
24
|
+
expect(sortGranular(result)).toEqual(sortGranular(['adjustable_bench', 'dumbbell', 'flat_bench']));
|
|
40
25
|
});
|
|
41
26
|
it('returns expected granular equipments for machine only', () => {
|
|
42
27
|
const result = (0, hevyTrainer_1.trainerEquipmentToGranularEquipments)(['machine']);
|
|
43
28
|
expect(sortGranular(result)).toEqual(sortGranular([
|
|
44
29
|
'adjustable_bench',
|
|
45
|
-
'air_bike',
|
|
46
|
-
'battle_rope',
|
|
47
30
|
'dip_bar',
|
|
48
31
|
'dual_cable_machine',
|
|
49
|
-
'elliptical_trainer',
|
|
50
32
|
'flat_bench',
|
|
51
33
|
'lat_pulldown_cable',
|
|
52
34
|
'leg_press_machine',
|
|
53
|
-
'medicine_ball',
|
|
54
35
|
'plate',
|
|
55
36
|
'plate_machines',
|
|
56
37
|
'pullup_bar',
|
|
57
|
-
'resistance_band',
|
|
58
|
-
'rings',
|
|
59
|
-
'rope',
|
|
60
|
-
'rowing_machine',
|
|
61
38
|
'single_cable_machine',
|
|
62
39
|
'smith_machine',
|
|
63
|
-
'spinning',
|
|
64
40
|
'stack_machines',
|
|
65
|
-
'stair_machine',
|
|
66
|
-
'treadmill',
|
|
67
41
|
]));
|
|
68
42
|
});
|
|
69
43
|
it('returns deduped union for multiple equipments', () => {
|
|
@@ -75,6 +49,53 @@ describe('trainerEquipmentToGranularEquipments', () => {
|
|
|
75
49
|
expect(sortGranular(result)).toEqual(combined);
|
|
76
50
|
});
|
|
77
51
|
});
|
|
52
|
+
const createExercise = (granularEquipments) => ({
|
|
53
|
+
id: 'test-exercise',
|
|
54
|
+
title: 'Test Exercise',
|
|
55
|
+
granular_equipments: granularEquipments,
|
|
56
|
+
});
|
|
57
|
+
describe('isEquipmentCompatible', () => {
|
|
58
|
+
it('returns true when exercise has no granular equipments', () => {
|
|
59
|
+
const exercise = createExercise(undefined);
|
|
60
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['barbell'])).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
it('returns true when exercise has empty granular equipments', () => {
|
|
63
|
+
const exercise = createExercise([]);
|
|
64
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['barbell'])).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
it('returns true when user has all required equipments', () => {
|
|
67
|
+
const exercise = createExercise(['barbell', 'squat_rack']);
|
|
68
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['barbell', 'squat_rack'])).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
it('returns false when user is missing required equipment', () => {
|
|
71
|
+
const exercise = createExercise(['barbell', 'squat_rack']);
|
|
72
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['barbell'])).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
it('returns true when user has more equipment than required', () => {
|
|
75
|
+
const exercise = createExercise(['barbell']);
|
|
76
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['barbell', 'squat_rack', 'dumbbell'])).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
describe('special case: adjustable_bench / flat_bench substitution', () => {
|
|
79
|
+
it('allows adjustable_bench to substitute for flat_bench when exercise requires flat_bench', () => {
|
|
80
|
+
const exercise = createExercise(['flat_bench']);
|
|
81
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['adjustable_bench'])).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
it('does NOT allow flat_bench to substitute for adjustable_bench when exercise requires adjustable_bench', () => {
|
|
84
|
+
const exercise = createExercise(['adjustable_bench']);
|
|
85
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['flat_bench'])).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('special case: dual_cable_machine / single_cable_machine substitution', () => {
|
|
89
|
+
it('allows dual_cable_machine to substitute for single_cable_machine when exercise requires single_cable_machine', () => {
|
|
90
|
+
const exercise = createExercise(['single_cable_machine']);
|
|
91
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['dual_cable_machine'])).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
it('does NOT allow single_cable_machine to substitute for dual_cable_machine when exercise requires dual_cable_machine', () => {
|
|
94
|
+
const exercise = createExercise(['dual_cable_machine']);
|
|
95
|
+
expect((0, hevyTrainer_1.isEquipmentCompatible)(exercise, ['single_cable_machine'])).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
78
99
|
const __1 = require("..");
|
|
79
100
|
describe('hevyTrainer gym types and defaults', () => {
|
|
80
101
|
it('defines granular equipment defaults for every trainer gym type', () => {
|