hevy-shared 1.0.941 → 1.0.943
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/API/APIClient.d.ts +5 -5
- package/built/API/APIClient.js +8 -8
- package/built/API/types.d.ts +1 -1
- package/built/hevyTrainer.d.ts +3 -13
- package/built/hevyTrainer.js +5 -48
- package/built/index.d.ts +0 -5
- package/built/index.js +2 -3
- package/built/tests/utils.test.js +52 -0
- package/built/utils.d.ts +10 -0
- package/built/utils.js +39 -2
- package/package.json +1 -1
package/built/API/APIClient.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClientAuthToken, DeepReadonly } from '..';
|
|
2
|
-
import { RequestConfig, HTTPResponse, HTTPClient,
|
|
2
|
+
import { RequestConfig, HTTPResponse, HTTPClient, HTTPRequestCompletionCallback, HTTPErrorHandler } from './types';
|
|
3
3
|
interface HevyAPIClientConfig<UserContext> {
|
|
4
4
|
/**
|
|
5
5
|
* How long before predicted token expiry to request a new token. We request
|
|
@@ -90,7 +90,7 @@ export declare class HevyAPIClient<UserContext = never> {
|
|
|
90
90
|
private static readonly DEFAULT_TOKEN_REFRESH_THROTTLE_MS;
|
|
91
91
|
private static readonly DEFAULT_REFRESH_AUTH_TOKEN_API_ENDPOINT;
|
|
92
92
|
private readonly _config;
|
|
93
|
-
private
|
|
93
|
+
private _requestCompletionCallbacks;
|
|
94
94
|
private _errorHandlers;
|
|
95
95
|
private _authTokenFactory;
|
|
96
96
|
private _legacyAuthToken;
|
|
@@ -133,12 +133,12 @@ export declare class HevyAPIClient<UserContext = never> {
|
|
|
133
133
|
* This is a lower level API than {@link attachErrorHandler} - prefer using
|
|
134
134
|
* that one instead of this one if it's enough to suit your needs.
|
|
135
135
|
*/
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
attachRequestCompletionCallback(onResult: HTTPRequestCompletionCallback): void;
|
|
137
|
+
removeRequestCompletionCallbacks(): void;
|
|
138
138
|
/**
|
|
139
139
|
* Adds a callback to be executed on receiving an HTTP error from the server.
|
|
140
140
|
* This callback will not be executed for any other type of error, such as a
|
|
141
|
-
* network error. For that and more, use {@link
|
|
141
|
+
* network error. For that and more, use {@link attachRequestCompletionCallback}.
|
|
142
142
|
*/
|
|
143
143
|
attachErrorHandler(onError: HTTPErrorHandler<{
|
|
144
144
|
willRetry: boolean;
|
package/built/API/APIClient.js
CHANGED
|
@@ -20,7 +20,7 @@ const __1 = require("..");
|
|
|
20
20
|
const types_1 = require("./types");
|
|
21
21
|
class HevyAPIClient {
|
|
22
22
|
constructor(httpClient, config) {
|
|
23
|
-
this.
|
|
23
|
+
this._requestCompletionCallbacks = [];
|
|
24
24
|
this._errorHandlers = [];
|
|
25
25
|
this._authTokenFactory = {
|
|
26
26
|
type: 'value',
|
|
@@ -146,11 +146,11 @@ class HevyAPIClient {
|
|
|
146
146
|
response,
|
|
147
147
|
});
|
|
148
148
|
}
|
|
149
|
-
this.
|
|
149
|
+
this._requestCompletionCallbacks.forEach((cb) => cb({ isSuccess: true, value: response }, request));
|
|
150
150
|
return response;
|
|
151
151
|
}
|
|
152
152
|
catch (e) {
|
|
153
|
-
this.
|
|
153
|
+
this._requestCompletionCallbacks.forEach((cb) => cb({ isSuccess: false, error: e }, request));
|
|
154
154
|
if (!(0, types_1.isHTTPError)(e))
|
|
155
155
|
throw e;
|
|
156
156
|
const { response } = e;
|
|
@@ -250,16 +250,16 @@ class HevyAPIClient {
|
|
|
250
250
|
* This is a lower level API than {@link attachErrorHandler} - prefer using
|
|
251
251
|
* that one instead of this one if it's enough to suit your needs.
|
|
252
252
|
*/
|
|
253
|
-
|
|
254
|
-
this.
|
|
253
|
+
attachRequestCompletionCallback(onResult) {
|
|
254
|
+
this._requestCompletionCallbacks.push(onResult);
|
|
255
255
|
}
|
|
256
|
-
|
|
257
|
-
this.
|
|
256
|
+
removeRequestCompletionCallbacks() {
|
|
257
|
+
this._requestCompletionCallbacks.length = 0;
|
|
258
258
|
}
|
|
259
259
|
/**
|
|
260
260
|
* Adds a callback to be executed on receiving an HTTP error from the server.
|
|
261
261
|
* This callback will not be executed for any other type of error, such as a
|
|
262
|
-
* network error. For that and more, use {@link
|
|
262
|
+
* network error. For that and more, use {@link attachRequestCompletionCallback}.
|
|
263
263
|
*/
|
|
264
264
|
attachErrorHandler(onError) {
|
|
265
265
|
this._errorHandlers.push(onError);
|
package/built/API/types.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface HTTPRequestFactory<T = unknown> {
|
|
|
23
23
|
headers: Record<string, string>;
|
|
24
24
|
try(): Promise<HTTPResponse<T>>;
|
|
25
25
|
}
|
|
26
|
-
export type
|
|
26
|
+
export type HTTPRequestCompletionCallback<T = unknown, R = unknown> = (result: Result<HTTPResponse<T>>, request: HTTPRequestFactory<R>) => void;
|
|
27
27
|
export type HTTPErrorHandler<E, T = unknown, R = unknown> = (response: HTTPResponse<T>, request: HTTPRequestFactory<R>, extraData: E) => void;
|
|
28
28
|
export interface HTTPResponse<T = unknown> {
|
|
29
29
|
status: number;
|
package/built/hevyTrainer.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { WeeklyTrainingFrequency, TrainingGoal, TrainingLevel, SimplifiedMuscleGroup, MuscleGroup, LibraryExercise, ExerciseCategory, GranularEquipment, HevyTrainerProgramEquipment
|
|
1
|
+
import { WeeklyTrainingFrequency, TrainingGoal, TrainingLevel, SimplifiedMuscleGroup, MuscleGroup, LibraryExercise, ExerciseCategory, GranularEquipment, HevyTrainerProgramEquipment } from '.';
|
|
2
2
|
export type HevyTrainerExerciseCategory = typeof hevyTrainerExerciseCategories[number];
|
|
3
3
|
export type HevyTrainerRoutineName = typeof routineNames[number];
|
|
4
4
|
export declare const workoutDurationOptions: readonly [40, 60, 80];
|
|
5
5
|
export type WorkoutDurationMinutes = typeof workoutDurationOptions[number];
|
|
6
|
-
export declare const trainingGoalRestPresets: readonly ["strength_short", "strength_medium", "strength_long", "build_muscle_short", "build_muscle_medium", "build_muscle_long", "fat_loss_short", "fat_loss_medium", "fat_loss_long"];
|
|
7
|
-
export type TrainingGoalRestPreset = typeof trainingGoalRestPresets[number];
|
|
8
6
|
export declare const trainerGymTypes: readonly ["home_gym", "garage_gym", "commercial_gym", "full_gym"];
|
|
9
7
|
export type TrainerGymType = typeof trainerGymTypes[number];
|
|
10
8
|
export declare const granularEquipmentDefaults: {
|
|
@@ -47,7 +45,6 @@ export interface ProgramGenerationParams<T extends HevyTrainerLibraryExercise> {
|
|
|
47
45
|
selectedLevel: TrainingLevel;
|
|
48
46
|
selectedEquipments: GranularEquipment[];
|
|
49
47
|
selectedWorkoutDurationMinutes?: WorkoutDurationMinutes;
|
|
50
|
-
selectedRestTimerLength: RestTimerLength;
|
|
51
48
|
exerciseStore: T[];
|
|
52
49
|
focusMuscle?: SimplifiedMuscleGroup;
|
|
53
50
|
excludedExerciseIds?: Set<string>;
|
|
@@ -75,7 +72,7 @@ export type RestTimersPerCategory = {
|
|
|
75
72
|
[key in HevyTrainerExerciseCategory]: number;
|
|
76
73
|
};
|
|
77
74
|
export type RestTimers = {
|
|
78
|
-
[key in
|
|
75
|
+
[key in TrainingGoal]: RestTimersPerCategory;
|
|
79
76
|
};
|
|
80
77
|
export type ExercisePriorities = {
|
|
81
78
|
[key in MuscleGroup]: exerciseId[];
|
|
@@ -138,14 +135,7 @@ export interface TrainerProgram {
|
|
|
138
135
|
}
|
|
139
136
|
export declare const getTrainerSetCount: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, frequency: WeeklyTrainingFrequency) => number;
|
|
140
137
|
export declare const getTrainerRepRange: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, exerciseCategory: HevyTrainerExerciseCategory) => RepRange;
|
|
141
|
-
export declare const getTrainerRestTimerSeconds: (trainerAlgorithmSettings: TrainerAlgorithmSettings,
|
|
142
|
-
/**
|
|
143
|
-
* Converts a RestTimerLength to a TrainingGoalRestPreset
|
|
144
|
-
* @param goal - The training goal
|
|
145
|
-
* @param length - The rest timer length
|
|
146
|
-
* @returns The training goal rest preset
|
|
147
|
-
*/
|
|
148
|
-
export declare const getGoalRestPreset: (goal: TrainingGoal, length: RestTimerLength) => TrainingGoalRestPreset;
|
|
138
|
+
export declare const getTrainerRestTimerSeconds: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, exerciseCategory: HevyTrainerExerciseCategory) => number;
|
|
149
139
|
/**
|
|
150
140
|
* Normalizes the exercise category to a HevyTrainerExerciseCategory
|
|
151
141
|
* - Treat custom exercises and exercises with no category as `compound`
|
package/built/hevyTrainer.js
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateProgram = exports.pickExerciseForPrescription = exports.getPrioritySortedExercises = exports.isEquipmentCompatible = exports.normalizeExerciseCategory = exports.
|
|
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
|
exports.workoutDurationOptions = [40, 60, 80];
|
|
6
|
-
exports.trainingGoalRestPresets = [
|
|
7
|
-
'strength_short',
|
|
8
|
-
'strength_medium',
|
|
9
|
-
'strength_long',
|
|
10
|
-
'build_muscle_short',
|
|
11
|
-
'build_muscle_medium',
|
|
12
|
-
'build_muscle_long',
|
|
13
|
-
'fat_loss_short',
|
|
14
|
-
'fat_loss_medium',
|
|
15
|
-
'fat_loss_long',
|
|
16
|
-
];
|
|
17
6
|
exports.trainerGymTypes = [
|
|
18
7
|
'home_gym',
|
|
19
8
|
'garage_gym',
|
|
@@ -214,42 +203,10 @@ const getTrainerRepRange = (trainerAlgorithmSettings, goal, exerciseCategory) =>
|
|
|
214
203
|
return trainerAlgorithmSettings.rep_ranges[goal][exerciseCategory];
|
|
215
204
|
};
|
|
216
205
|
exports.getTrainerRepRange = getTrainerRepRange;
|
|
217
|
-
const getTrainerRestTimerSeconds = (trainerAlgorithmSettings,
|
|
218
|
-
return trainerAlgorithmSettings.rest_timers[
|
|
206
|
+
const getTrainerRestTimerSeconds = (trainerAlgorithmSettings, goal, exerciseCategory) => {
|
|
207
|
+
return trainerAlgorithmSettings.rest_timers[goal][exerciseCategory];
|
|
219
208
|
};
|
|
220
209
|
exports.getTrainerRestTimerSeconds = getTrainerRestTimerSeconds;
|
|
221
|
-
/**
|
|
222
|
-
* Converts a RestTimerLength to a TrainingGoalRestPreset
|
|
223
|
-
* @param goal - The training goal
|
|
224
|
-
* @param length - The rest timer length
|
|
225
|
-
* @returns The training goal rest preset
|
|
226
|
-
*/
|
|
227
|
-
const getGoalRestPreset = (goal, length) => {
|
|
228
|
-
switch (goal) {
|
|
229
|
-
case 'strength':
|
|
230
|
-
if (length === 'short')
|
|
231
|
-
return 'strength_short';
|
|
232
|
-
if (length === 'long')
|
|
233
|
-
return 'strength_long';
|
|
234
|
-
return 'strength_medium';
|
|
235
|
-
case 'build_muscle':
|
|
236
|
-
if (length === 'short')
|
|
237
|
-
return 'build_muscle_short';
|
|
238
|
-
if (length === 'long')
|
|
239
|
-
return 'build_muscle_long';
|
|
240
|
-
return 'build_muscle_medium';
|
|
241
|
-
case 'fat_loss':
|
|
242
|
-
if (length === 'short')
|
|
243
|
-
return 'fat_loss_short';
|
|
244
|
-
if (length === 'long')
|
|
245
|
-
return 'fat_loss_long';
|
|
246
|
-
return 'fat_loss_medium';
|
|
247
|
-
default:
|
|
248
|
-
(0, _1.exhaustiveTypeCheck)(goal);
|
|
249
|
-
return 'strength_medium';
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
exports.getGoalRestPreset = getGoalRestPreset;
|
|
253
210
|
/**
|
|
254
211
|
* Normalizes the exercise category to a HevyTrainerExerciseCategory
|
|
255
212
|
* - Treat custom exercises and exercises with no category as `compound`
|
|
@@ -541,7 +498,7 @@ exports.pickExerciseForPrescription = pickExerciseForPrescription;
|
|
|
541
498
|
*/
|
|
542
499
|
const generateProgram = (params) => {
|
|
543
500
|
var _a;
|
|
544
|
-
const { trainerAlgorithmSettings, selectedDays, selectedGoal, selectedLevel, selectedEquipments, selectedWorkoutDurationMinutes,
|
|
501
|
+
const { trainerAlgorithmSettings, selectedDays, selectedGoal, selectedLevel, selectedEquipments, selectedWorkoutDurationMinutes, exerciseStore, focusMuscle, excludedExerciseIds, } = params;
|
|
545
502
|
const routines = exports.programSplits[selectedDays];
|
|
546
503
|
const program = {
|
|
547
504
|
name: selectedDays,
|
|
@@ -608,7 +565,7 @@ const generateProgram = (params) => {
|
|
|
608
565
|
sets: (0, exports.getTrainerSetCount)(trainerAlgorithmSettings, selectedGoal, selectedDays),
|
|
609
566
|
repRangeStart: repRange.rep_range_start,
|
|
610
567
|
repRangeEnd: repRange.rep_range_end,
|
|
611
|
-
restTimerSeconds: (0, exports.getTrainerRestTimerSeconds)(trainerAlgorithmSettings,
|
|
568
|
+
restTimerSeconds: (0, exports.getTrainerRestTimerSeconds)(trainerAlgorithmSettings, selectedGoal, exercisePrescription.category),
|
|
612
569
|
warmupSetCount: exercisePrescription.warmup_set_count,
|
|
613
570
|
notes: (_a = trainerAlgorithmSettings.exercise_notes[exercise.id]) !== null && _a !== void 0 ? _a : '',
|
|
614
571
|
});
|
package/built/index.d.ts
CHANGED
|
@@ -640,11 +640,9 @@ export declare const isCustomExerciseType: (x: any) => x is CustomExerciseType;
|
|
|
640
640
|
export declare const trainingGoals: readonly ["strength", "build_muscle", "fat_loss"];
|
|
641
641
|
export declare const trainingLevels: readonly ["beginner", "intermediate", "advanced"];
|
|
642
642
|
export declare const exerciseCategories: readonly ["isolation", "compound", "assistance-compound"];
|
|
643
|
-
export declare const restTimerLengths: readonly ["short", "medium", "long"];
|
|
644
643
|
export type TrainingGoal = Lookup<typeof trainingGoals>;
|
|
645
644
|
export type TrainingLevel = Lookup<typeof trainingLevels>;
|
|
646
645
|
export type ExerciseCategory = Lookup<typeof exerciseCategories>;
|
|
647
|
-
export type RestTimerLength = typeof restTimerLengths[number];
|
|
648
646
|
export type HevyTrainerProgramEquipment = Extract<Equipment, 'barbell' | 'dumbbell' | 'machine'>;
|
|
649
647
|
export declare const hevyTrainerProgramEquipments: readonly ["barbell", "dumbbell", "machine"];
|
|
650
648
|
export declare const granularEquipments: readonly ["barbell", "dumbbell", "kettlebell", "plate", "medicine_ball", "ez_bar", "landmine", "trap_bar", "pullup_bar", "dip_bar", "squat_rack", "flat_bench", "adjustable_bench", "dual_cable_machine", "single_cable_machine", "lat_pulldown_cable", "leg_press_machine", "smith_machine", "t_bar", "plate_machines", "stack_machines", "treadmill", "elliptical_trainer", "rowing_machine", "spinning", "stair_machine", "air_bike", "suspension_band", "resistance_band", "battle_rope", "rings", "jump_rope"];
|
|
@@ -1261,7 +1259,6 @@ export interface HevyTrainerProgram {
|
|
|
1261
1259
|
focus_muscle?: SimplifiedMuscleGroup;
|
|
1262
1260
|
next_workout_index: number;
|
|
1263
1261
|
workout_duration_minutes?: WorkoutDurationMinutes;
|
|
1264
|
-
rest_timer_length: RestTimerLength;
|
|
1265
1262
|
}
|
|
1266
1263
|
export interface PostHevyTrainerProgramRequestBody {
|
|
1267
1264
|
program: {
|
|
@@ -1274,7 +1271,6 @@ export interface PostHevyTrainerProgramRequestBody {
|
|
|
1274
1271
|
routines: RoutineUpdate[];
|
|
1275
1272
|
next_workout_index?: number;
|
|
1276
1273
|
workout_duration_minutes?: WorkoutDurationMinutes;
|
|
1277
|
-
rest_timer_length: RestTimerLength;
|
|
1278
1274
|
};
|
|
1279
1275
|
}
|
|
1280
1276
|
export interface UpdateHevyTrainerProgramRequestBody {
|
|
@@ -1288,7 +1284,6 @@ export interface UpdateHevyTrainerProgramRequestBody {
|
|
|
1288
1284
|
focus_muscle?: SimplifiedMuscleGroup;
|
|
1289
1285
|
next_workout_index?: number;
|
|
1290
1286
|
workout_duration_minutes?: WorkoutDurationMinutes;
|
|
1291
|
-
rest_timer_length?: RestTimerLength;
|
|
1292
1287
|
routines: {
|
|
1293
1288
|
id: string;
|
|
1294
1289
|
title: string;
|
package/built/index.js
CHANGED
|
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.isPublicWorkout = exports.isSetType = exports.isRPE = exports.validRpeValues = exports.isSetPersonalRecordType = exports.supportedInstructionsLanguages = exports.weeklyTrainingFrequencies = exports.isGranularEquipment = exports.granularEquipments = exports.hevyTrainerProgramEquipments = exports.
|
|
18
|
-
exports.isOAuthScope = exports.supportedScopes = exports.isSuggestedUserSource = exports.isValidUserWorkoutMetricsType = exports.isBodyMeasurementKey = exports.measurementsList = exports.isHevyTrainerRoutine = exports.isWorkoutBiometrics =
|
|
17
|
+
exports.isHeartRateSamples = exports.isPublicWorkout = exports.isSetType = exports.isRPE = exports.validRpeValues = exports.isSetPersonalRecordType = exports.supportedInstructionsLanguages = exports.weeklyTrainingFrequencies = exports.isGranularEquipment = exports.granularEquipments = exports.hevyTrainerProgramEquipments = exports.exerciseCategories = exports.trainingLevels = exports.trainingGoals = exports.isCustomExerciseType = exports.customExericseTypes = exports.isExerciseType = exports.exerciseTypes = exports.isExerciseRepType = exports.exerciseRepTypes = exports.isEquipmentFilter = exports.equipmentFilters = exports.isEquipment = exports.equipments = exports.simplifiedMuscleGroupToMuscleGroups = exports.isMuscleGroupFilter = exports.muscleGroupFilters = exports.isMuscleGroup = exports.muscleGroups = exports.isSimplifiedMuscleGroup = exports.simplifiedMuscleGroups = exports.miscellaneousMuscles = exports.chestMuscles = exports.backMuscles = exports.legMuscles = exports.armMuscles = exports.shoulderMuscles = exports.coreMuscles = exports.DefaultClientConfiguration = exports.parseClientAuthTokenResponse = exports.isCoachRole = exports.isErrorResponse = exports.isLivePRVolumeOption = exports.isTimerVolumeOption = exports.isWeekday = exports.orderedWeekdays = exports.isBodyMeasurementUnit = exports.isDistanceUnitShort = exports.isDistanceUnit = exports.isWeightUnit = void 0;
|
|
18
|
+
exports.isOAuthScope = exports.supportedScopes = exports.isSuggestedUserSource = exports.isValidUserWorkoutMetricsType = exports.isBodyMeasurementKey = exports.measurementsList = exports.isHevyTrainerRoutine = exports.isWorkoutBiometrics = void 0;
|
|
19
19
|
const typeUtils_1 = require("./typeUtils");
|
|
20
20
|
__exportStar(require("./constants"), exports);
|
|
21
21
|
__exportStar(require("./utils"), exports);
|
|
@@ -227,7 +227,6 @@ exports.exerciseCategories = [
|
|
|
227
227
|
'compound',
|
|
228
228
|
'assistance-compound',
|
|
229
229
|
];
|
|
230
|
-
exports.restTimerLengths = ['short', 'medium', 'long'];
|
|
231
230
|
exports.hevyTrainerProgramEquipments = [
|
|
232
231
|
'barbell',
|
|
233
232
|
'dumbbell',
|
|
@@ -210,6 +210,58 @@ describe('utils', () => {
|
|
|
210
210
|
expect((0, utils_1.findMapped)([], () => undefined)).toBeUndefined();
|
|
211
211
|
});
|
|
212
212
|
});
|
|
213
|
+
describe('toFragmentedJSON', () => {
|
|
214
|
+
it('converts any array into an array of JSON chunks with a maximum given length', () => {
|
|
215
|
+
expect((0, utils_1.toFragmentedJSON)([
|
|
216
|
+
{ value: 'AAAAAAAAAAAAAAAA' },
|
|
217
|
+
{ value: 'BBBBBBBBBBBBBBBBBBBBB' },
|
|
218
|
+
{ value: 'CCCCCCCCCCCCCCCC' },
|
|
219
|
+
], 64)).toEqual([
|
|
220
|
+
JSON.stringify([
|
|
221
|
+
{ value: 'AAAAAAAAAAAAAAAA' },
|
|
222
|
+
{ value: 'BBBBBBBBBBBBBBBBBBBBB' },
|
|
223
|
+
]),
|
|
224
|
+
JSON.stringify([{ value: 'CCCCCCCCCCCCCCCC' }]),
|
|
225
|
+
]);
|
|
226
|
+
expect((0, utils_1.toFragmentedJSON)([
|
|
227
|
+
{ value: 'AAAAAAAAAAAAAAAA' },
|
|
228
|
+
{ value: 'BBBBBBBBBBBBBBBBBBBBB' },
|
|
229
|
+
{ value: 'CCCCCCCCCCCCCCCC' },
|
|
230
|
+
], 35)).toEqual([
|
|
231
|
+
JSON.stringify([{ value: 'AAAAAAAAAAAAAAAA' }]),
|
|
232
|
+
JSON.stringify([{ value: 'BBBBBBBBBBBBBBBBBBBBB' }]),
|
|
233
|
+
JSON.stringify([{ value: 'CCCCCCCCCCCCCCCC' }]),
|
|
234
|
+
]);
|
|
235
|
+
expect(() => (0, utils_1.toFragmentedJSON)([
|
|
236
|
+
{ value: 'AAAAAAAAAAAAAAAA' },
|
|
237
|
+
{ value: 'BBBBBBBBBBBBBBBBBBBBB' },
|
|
238
|
+
{ value: 'CCCCCCCCCCCCCCCC' },
|
|
239
|
+
], 34)).toThrow();
|
|
240
|
+
expect((0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 15)).toEqual([
|
|
241
|
+
JSON.stringify(['A', 'B', 'C']),
|
|
242
|
+
]);
|
|
243
|
+
expect((0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 10)).toEqual([
|
|
244
|
+
JSON.stringify(['A', 'B']),
|
|
245
|
+
JSON.stringify(['C']),
|
|
246
|
+
]);
|
|
247
|
+
expect((0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 5)).toEqual([
|
|
248
|
+
JSON.stringify(['A']),
|
|
249
|
+
JSON.stringify(['B']),
|
|
250
|
+
JSON.stringify(['C']),
|
|
251
|
+
]);
|
|
252
|
+
expect(() => (0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 1)).toThrow();
|
|
253
|
+
expect(() => (0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 0)).toThrow();
|
|
254
|
+
expect((0, utils_1.toFragmentedJSON)([], 1)).toEqual([]);
|
|
255
|
+
expect((0, utils_1.toFragmentedJSON)([], 0)).toEqual([]);
|
|
256
|
+
});
|
|
257
|
+
it('returns an empty array for an empty input array', () => {
|
|
258
|
+
expect((0, utils_1.toFragmentedJSON)(['blah'], 100)).toEqual([
|
|
259
|
+
JSON.stringify(['blah']),
|
|
260
|
+
]);
|
|
261
|
+
expect((0, utils_1.toFragmentedJSON)([], 100)).toEqual([]);
|
|
262
|
+
expect((0, utils_1.toFragmentedJSON)([], 100)).not.toEqual([JSON.stringify([])]);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
213
265
|
describe('getClosestDataPointBeforeTargetDate', () => {
|
|
214
266
|
it('gets the closest data point before a target date, if such a data point exists, using a function to extract the date from the data points', () => {
|
|
215
267
|
var _a, _b, _c, _d;
|
package/built/utils.d.ts
CHANGED
|
@@ -90,6 +90,16 @@ export declare const stringToNumber: (value?: string) => number | undefined;
|
|
|
90
90
|
* such value was produced. Equivalent to `firstNotNullOfOrNull` in Kotlin.
|
|
91
91
|
*/
|
|
92
92
|
export declare const findMapped: <T, R>(array: T[], transform: (element: T) => R) => R | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* converts any array into an array of JSON chunks with a maximum given length
|
|
95
|
+
* @param data an array of objects or primitives to be split into chunks
|
|
96
|
+
* @param maxLength maximum length of any single returned JSON string
|
|
97
|
+
* @returns an array of JSON strings, each one no longer than `maxLength`
|
|
98
|
+
* @throws an error if fragmentation is impossible due to input data structure
|
|
99
|
+
*/
|
|
100
|
+
export declare const toFragmentedJSON: <T>(data: T[], maxLength: number, options?: {
|
|
101
|
+
lengthIn: "utf8bytes" | "characters";
|
|
102
|
+
}) => string[];
|
|
93
103
|
/**
|
|
94
104
|
* Finds the closest data point that occurs before or at the target date using binary search.
|
|
95
105
|
* Assumes input array is sorted by date in ascending order.
|
package/built/utils.js
CHANGED
|
@@ -3,8 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
exports.rawInstructionsToIndexedSteps = exports.formatSetValue = exports.exerciseWeight = exports.distance = exports.weekdayNumberMap = void 0;
|
|
6
|
+
exports.calculateCurrentWeekStreak = exports.getYoutubeVideoId = exports.validateYoutubeUrl = exports.splitAtUsernamesAndLinks = exports.isVersionAGreaterOrEqualToVersionB = exports.generateUserGroupValue = exports.generateUserGroup = exports.isBaseExerciseTemplate = exports.getStrengthLevelFromPercentile = exports.numberToLocaleString = exports.numberWithCommas = exports.setVolume = exports.oneRepMax = exports.oneRepMaxPercentageMap = exports.getEstimatedExercisesDurationSeconds = exports.ESTIMATED_REST_TIMER_DURATION = exports.ESTIMATED_SET_DURATION = exports.UserFacingIndicatorToSetIndicator = exports.workoutSetCount = exports.userExerciseSetWeight = exports.workoutDistanceMeters = exports.workoutReps = exports.workoutDurationSeconds = exports.removeAccents = exports.getClosestDataPointAroundTargetDate = exports.getClosestDataPointBeforeTargetDate = exports.toFragmentedJSON = exports.findMapped = exports.stringToNumber = exports.forceStringToNumber = exports.formatDurationInput = exports.isValidFormattedTime = exports.isWholeNumber = exports.isNumber = exports.isValidUuid = exports.isValidPhoneNumber = exports.isValidWebUrl = exports.URL_REGEX = exports.isValidEmail = exports.secondsToWordFormatMinutes = exports.secondsToWordFormat = exports.secondsToClockFormat = exports.secondsToClockParts = exports.isValidUsername = exports.roundToWholeNumber = exports.roundToOneDecimal = exports.roundToTwoDecimal = exports.divide = exports.clampNumber = exports.num = void 0;
|
|
7
|
+
exports.rawInstructionsToIndexedSteps = exports.formatSetValue = exports.exerciseWeight = exports.distance = exports.weekdayNumberMap = exports.startOfWeek = void 0;
|
|
8
8
|
const dayjs_1 = __importDefault(require("dayjs"));
|
|
9
9
|
const _1 = require(".");
|
|
10
10
|
/**
|
|
@@ -298,6 +298,43 @@ const findMapped = (array, transform) => {
|
|
|
298
298
|
}
|
|
299
299
|
};
|
|
300
300
|
exports.findMapped = findMapped;
|
|
301
|
+
/**
|
|
302
|
+
* converts any array into an array of JSON chunks with a maximum given length
|
|
303
|
+
* @param data an array of objects or primitives to be split into chunks
|
|
304
|
+
* @param maxLength maximum length of any single returned JSON string
|
|
305
|
+
* @returns an array of JSON strings, each one no longer than `maxLength`
|
|
306
|
+
* @throws an error if fragmentation is impossible due to input data structure
|
|
307
|
+
*/
|
|
308
|
+
const toFragmentedJSON = (data, maxLength, options = { lengthIn: 'utf8bytes' }) => {
|
|
309
|
+
const outputArray = [];
|
|
310
|
+
const recurse = (left, right) => {
|
|
311
|
+
if (left === right)
|
|
312
|
+
return;
|
|
313
|
+
// slice the array and convert it to JSON
|
|
314
|
+
const sliceJson = JSON.stringify(data.slice(left, right));
|
|
315
|
+
const length = options.lengthIn === 'characters'
|
|
316
|
+
? sliceJson.length
|
|
317
|
+
: Buffer.byteLength(sliceJson, 'utf8');
|
|
318
|
+
if (length <= maxLength) {
|
|
319
|
+
// the size is good, push the chunk to the output array
|
|
320
|
+
outputArray.push(sliceJson);
|
|
321
|
+
}
|
|
322
|
+
else if (right > left + 1) {
|
|
323
|
+
// there are at least 2 elements in the current slice
|
|
324
|
+
const middle = Math.ceil((left + right) / 2);
|
|
325
|
+
recurse(left, middle);
|
|
326
|
+
recurse(middle, right);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// we can't subdivide any further but the string is still too long
|
|
330
|
+
throw new Error(`couldn't subdivide element`);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
outputArray.length = 0;
|
|
334
|
+
recurse(0, data.length);
|
|
335
|
+
return outputArray;
|
|
336
|
+
};
|
|
337
|
+
exports.toFragmentedJSON = toFragmentedJSON;
|
|
301
338
|
/**
|
|
302
339
|
* Finds the closest data point that occurs before or at the target date using binary search.
|
|
303
340
|
* Assumes input array is sorted by date in ascending order.
|