@umituz/react-native-validation 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @umituz/react-native-validation
2
2
 
3
- Comprehensive validation utilities for React Native forms. Provides reusable validation functions for common input types.
3
+ Comprehensive validation and sanitization utilities for React Native forms. Provides reusable validation and sanitization functions for common input types.
4
4
 
5
5
  ## Installation
6
6
 
@@ -15,6 +15,7 @@ npm install @umituz/react-native-validation
15
15
 
16
16
  ## Features
17
17
 
18
+ ### Validation
18
19
  - ✅ Email validation
19
20
  - ✅ Password validation (with strength requirements)
20
21
  - ✅ Phone number validation (E.164 format)
@@ -24,8 +25,19 @@ npm install @umituz/react-native-validation
24
25
  - ✅ Min/Max length validation
25
26
  - ✅ Pattern (regex) validation
26
27
  - ✅ Date of birth validation
27
- - ✅ Health & fitness validators (weight, height, age, calories, macros, etc.)
28
+ - ✅ Age validation
28
29
  - ✅ Batch validation
30
+
31
+ ### Sanitization
32
+ - ✅ Email sanitization
33
+ - ✅ Password sanitization
34
+ - ✅ Name sanitization
35
+ - ✅ Text sanitization
36
+ - ✅ XSS protection
37
+ - ✅ Length limit validation
38
+ - ✅ Whitespace normalization
39
+
40
+ ### General
29
41
  - ✅ TypeScript type safety
30
42
 
31
43
  ## Usage
@@ -81,24 +93,6 @@ if (!result.isValid) {
81
93
  }
82
94
  ```
83
95
 
84
- ### Health & Fitness Validators
85
-
86
- ```typescript
87
- import {
88
- validateWeight,
89
- validateHeight,
90
- validateAge,
91
- validateCalories,
92
- validateWorkoutDuration,
93
- } from '@umituz/react-native-validation';
94
-
95
- const weightResult = validateWeight(75); // kg
96
- const heightResult = validateHeight(175); // cm
97
- const ageResult = validateAge(25);
98
- const caloriesResult = validateCalories(2000);
99
- const durationResult = validateWorkoutDuration(45); // minutes
100
- ```
101
-
102
96
  ### Custom Validation
103
97
 
104
98
  ```typescript
@@ -116,6 +110,37 @@ const patternResult = validatePattern(
116
110
  const rangeResult = validateNumberRange(50, 0, 100, 'Percentage');
117
111
  ```
118
112
 
113
+ ### Sanitization Example
114
+
115
+ ```typescript
116
+ import {
117
+ sanitizeEmail,
118
+ sanitizeName,
119
+ sanitizeText,
120
+ containsDangerousChars,
121
+ SECURITY_LIMITS,
122
+ } from '@umituz/react-native-validation';
123
+
124
+ // Sanitize email
125
+ const cleanEmail = sanitizeEmail(' User@Example.COM ');
126
+ // Result: 'user@example.com'
127
+
128
+ // Sanitize name
129
+ const cleanName = sanitizeName(' John Doe ');
130
+ // Result: 'John Doe'
131
+
132
+ // Sanitize text (removes HTML tags)
133
+ const cleanText = sanitizeText('<script>alert("xss")</script>Hello');
134
+ // Result: 'Hello'
135
+
136
+ // Check for dangerous characters
137
+ const isDangerous = containsDangerousChars('<script>alert("xss")</script>');
138
+ // Result: true
139
+
140
+ // Check length limits
141
+ const isValidLength = isWithinLengthLimit('text', SECURITY_LIMITS.NAME_MAX_LENGTH);
142
+ ```
143
+
119
144
  ## API Reference
120
145
 
121
146
  ### Core Validators
@@ -141,19 +166,7 @@ const rangeResult = validateNumberRange(50, 0, 100, 'Percentage');
141
166
  ### Date Validators
142
167
 
143
168
  - `validateDateOfBirth(date: Date): ValidationResult`
144
- - `validateAge(age: number): ValidationResult`
145
-
146
- ### Health & Fitness Validators
147
-
148
- - `validateWeight(weight: number): ValidationResult` (20-300 kg)
149
- - `validateHeight(height: number): ValidationResult` (50-250 cm)
150
- - `validateCalories(calories: number): ValidationResult` (0-10000)
151
- - `validateMacros(grams: number, macroType: string): ValidationResult` (0-1000 g)
152
- - `validateWaterIntake(glasses: number): ValidationResult` (0-50)
153
- - `validateWorkoutDuration(minutes: number): ValidationResult` (1-600 min)
154
- - `validateReps(reps: number): ValidationResult` (1-1000)
155
- - `validateSets(sets: number): ValidationResult` (1-100)
156
- - `validateExerciseWeight(weight: number): ValidationResult` (0-1000 kg)
169
+ - `validateAge(age: number): ValidationResult` (13-120 years)
157
170
 
158
171
  ### Batch Validation
159
172
 
package/package.json CHANGED
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "@umituz/react-native-validation",
3
- "version": "1.0.0",
4
- "description": "Comprehensive validation utilities for React Native forms",
5
- "main": "./lib/index.js",
6
- "types": "./lib/index.d.ts",
3
+ "version": "1.0.2",
4
+ "description": "Comprehensive validation and sanitization utilities for React Native forms",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "typecheck": "tsc --noEmit",
10
10
  "lint": "tsc --noEmit",
11
11
  "clean": "rm -rf lib",
12
12
  "prebuild": "npm run clean",
13
- "prepublishOnly": "npm run build",
14
13
  "version:patch": "npm version patch -m 'chore: release v%s'",
15
14
  "version:minor": "npm version minor -m 'chore: release v%s'",
16
15
  "version:major": "npm version major -m 'chore: release v%s'"
@@ -22,7 +21,7 @@
22
21
  "validators",
23
22
  "form-validation"
24
23
  ],
25
- "author": "Ümit UZ <umit@umituz.com>",
24
+ "author": "\u00dcmit UZ <umit@umituz.com>",
26
25
  "license": "MIT",
27
26
  "repository": {
28
27
  "type": "git",
@@ -43,10 +42,8 @@
43
42
  "access": "public"
44
43
  },
45
44
  "files": [
46
- "lib",
47
45
  "src",
48
46
  "README.md",
49
47
  "LICENSE"
50
48
  ]
51
49
  }
52
-
package/src/index.ts CHANGED
@@ -25,15 +25,18 @@ export {
25
25
  validatePattern,
26
26
  validateDateOfBirth,
27
27
  validateAge,
28
- validateWeight,
29
- validateHeight,
30
- validateCalories,
31
- validateMacros,
32
- validateWaterIntake,
33
- validateWorkoutDuration,
34
- validateReps,
35
- validateSets,
36
- validateExerciseWeight,
37
28
  batchValidate,
38
29
  } from './infrastructure/utils/validators';
39
30
 
31
+ // Infrastructure Layer - Sanitization
32
+ export {
33
+ SECURITY_LIMITS,
34
+ sanitizeWhitespace,
35
+ sanitizeEmail,
36
+ sanitizePassword,
37
+ sanitizeName,
38
+ sanitizeText,
39
+ containsDangerousChars,
40
+ isWithinLengthLimit,
41
+ } from './infrastructure/utils/sanitization';
42
+
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Sanitization Utilities
3
+ * Secure input cleaning for user data
4
+ */
5
+
6
+ /**
7
+ * Security constants for input validation
8
+ */
9
+ export const SECURITY_LIMITS = {
10
+ EMAIL_MAX_LENGTH: 254, // RFC 5321
11
+ PASSWORD_MIN_LENGTH: 6,
12
+ PASSWORD_MAX_LENGTH: 128,
13
+ NAME_MAX_LENGTH: 100,
14
+ GENERAL_TEXT_MAX_LENGTH: 500,
15
+ } as const;
16
+
17
+ /**
18
+ * Trim and normalize whitespace
19
+ */
20
+ export const sanitizeWhitespace = (input: string): string => {
21
+ return input.trim().replace(/\s+/g, ' ');
22
+ };
23
+
24
+ /**
25
+ * Sanitize email address
26
+ * - Trim whitespace
27
+ * - Convert to lowercase
28
+ * - Limit length
29
+ */
30
+ export const sanitizeEmail = (email: string): string => {
31
+ const trimmed = email.trim().toLowerCase();
32
+ return trimmed.substring(0, SECURITY_LIMITS.EMAIL_MAX_LENGTH);
33
+ };
34
+
35
+ /**
36
+ * Sanitize password
37
+ * - Only trim (preserve case and special chars)
38
+ * - Limit length to prevent DoS
39
+ */
40
+ export const sanitizePassword = (password: string): string => {
41
+ // Don't trim password to preserve intentional spaces
42
+ // Only limit length
43
+ return password.substring(0, SECURITY_LIMITS.PASSWORD_MAX_LENGTH);
44
+ };
45
+
46
+ /**
47
+ * Sanitize display name
48
+ * - Trim whitespace
49
+ * - Normalize multiple spaces
50
+ * - Remove potential XSS characters
51
+ * - Limit length
52
+ */
53
+ export const sanitizeName = (name: string): string => {
54
+ const trimmed = sanitizeWhitespace(name);
55
+ // Remove HTML tags and script content
56
+ const noTags = trimmed.replace(/<[^>]*>/g, '');
57
+ return noTags.substring(0, SECURITY_LIMITS.NAME_MAX_LENGTH);
58
+ };
59
+
60
+ /**
61
+ * Sanitize general text input
62
+ * - Trim whitespace
63
+ * - Remove HTML/script tags
64
+ * - Limit length
65
+ */
66
+ export const sanitizeText = (text: string): string => {
67
+ const trimmed = sanitizeWhitespace(text);
68
+ const noTags = trimmed.replace(/<[^>]*>/g, '');
69
+ return noTags.substring(0, SECURITY_LIMITS.GENERAL_TEXT_MAX_LENGTH);
70
+ };
71
+
72
+ /**
73
+ * Check if string contains potentially dangerous characters
74
+ */
75
+ export const containsDangerousChars = (input: string): boolean => {
76
+ // Check for common XSS patterns
77
+ const dangerousPatterns = [
78
+ /<script/i,
79
+ /javascript:/i,
80
+ /on\w+\s*=/i, // onclick, onload, etc.
81
+ /<iframe/i,
82
+ /eval\(/i,
83
+ ];
84
+
85
+ return dangerousPatterns.some(pattern => pattern.test(input));
86
+ };
87
+
88
+ /**
89
+ * Validate string length is within bounds
90
+ */
91
+ export const isWithinLengthLimit = (
92
+ input: string,
93
+ maxLength: number,
94
+ minLength = 0
95
+ ): boolean => {
96
+ const length = input.trim().length;
97
+ return length >= minLength && length <= maxLength;
98
+ };
99
+
@@ -279,72 +279,6 @@ export const validateAge = (age: number): ValidationResult => {
279
279
  return validateNumberRange(age, 13, 120, 'Age');
280
280
  };
281
281
 
282
- /**
283
- * Validate weight (kg)
284
- */
285
- export const validateWeight = (weight: number): ValidationResult => {
286
- return validateNumberRange(weight, 20, 300, 'Weight');
287
- };
288
-
289
- /**
290
- * Validate height (cm)
291
- */
292
- export const validateHeight = (height: number): ValidationResult => {
293
- return validateNumberRange(height, 50, 250, 'Height');
294
- };
295
-
296
- /**
297
- * Validate calories
298
- */
299
- export const validateCalories = (calories: number): ValidationResult => {
300
- return validateNumberRange(calories, 0, 10000, 'Calories');
301
- };
302
-
303
- /**
304
- * Validate macros (protein, carbs, fat in grams)
305
- */
306
- export const validateMacros = (
307
- grams: number,
308
- macroType: string
309
- ): ValidationResult => {
310
- return validateNumberRange(grams, 0, 1000, macroType);
311
- };
312
-
313
- /**
314
- * Validate water intake (glasses)
315
- */
316
- export const validateWaterIntake = (glasses: number): ValidationResult => {
317
- return validateNumberRange(glasses, 0, 50, 'Water intake');
318
- };
319
-
320
- /**
321
- * Validate workout duration (minutes)
322
- */
323
- export const validateWorkoutDuration = (minutes: number): ValidationResult => {
324
- return validateNumberRange(minutes, 1, 600, 'Workout duration');
325
- };
326
-
327
- /**
328
- * Validate reps
329
- */
330
- export const validateReps = (reps: number): ValidationResult => {
331
- return validateNumberRange(reps, 1, 1000, 'Reps');
332
- };
333
-
334
- /**
335
- * Validate sets
336
- */
337
- export const validateSets = (sets: number): ValidationResult => {
338
- return validateNumberRange(sets, 1, 100, 'Sets');
339
- };
340
-
341
- /**
342
- * Validate exercise weight (kg)
343
- */
344
- export const validateExerciseWeight = (weight: number): ValidationResult => {
345
- return validateNumberRange(weight, 0, 1000, 'Weight');
346
- };
347
-
348
282
  /**
349
283
  * Batch validation
350
284
  * Validates multiple fields and returns all errors
@@ -1,8 +0,0 @@
1
- /**
2
- * Validation Result Entity
3
- * Standard return type for all validation functions
4
- */
5
- export interface ValidationResult {
6
- isValid: boolean;
7
- error?: string;
8
- }
@@ -1,6 +0,0 @@
1
- "use strict";
2
- /**
3
- * Validation Result Entity
4
- * Standard return type for all validation functions
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
package/lib/index.d.ts DELETED
@@ -1,10 +0,0 @@
1
- /**
2
- * @umituz/react-native-validation
3
- *
4
- * Comprehensive validation utilities for React Native forms.
5
- * Provides reusable validation functions for common input types.
6
- *
7
- * @package react-native-validation
8
- */
9
- export type { ValidationResult } from './domain/entities/ValidationResult';
10
- export { validateEmail, validatePassword, validatePasswordConfirmation, validateRequired, validateName, validatePhone, validateNumberRange, validatePositiveNumber, validateMinLength, validateMaxLength, validatePattern, validateDateOfBirth, validateAge, validateWeight, validateHeight, validateCalories, validateMacros, validateWaterIntake, validateWorkoutDuration, validateReps, validateSets, validateExerciseWeight, batchValidate, } from './infrastructure/utils/validators';
package/lib/index.js DELETED
@@ -1,36 +0,0 @@
1
- "use strict";
2
- /**
3
- * @umituz/react-native-validation
4
- *
5
- * Comprehensive validation utilities for React Native forms.
6
- * Provides reusable validation functions for common input types.
7
- *
8
- * @package react-native-validation
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.batchValidate = exports.validateExerciseWeight = exports.validateSets = exports.validateReps = exports.validateWorkoutDuration = exports.validateWaterIntake = exports.validateMacros = exports.validateCalories = exports.validateHeight = exports.validateWeight = exports.validateAge = exports.validateDateOfBirth = exports.validatePattern = exports.validateMaxLength = exports.validateMinLength = exports.validatePositiveNumber = exports.validateNumberRange = exports.validatePhone = exports.validateName = exports.validateRequired = exports.validatePasswordConfirmation = exports.validatePassword = exports.validateEmail = void 0;
12
- // Infrastructure Layer - Validators
13
- var validators_1 = require("./infrastructure/utils/validators");
14
- Object.defineProperty(exports, "validateEmail", { enumerable: true, get: function () { return validators_1.validateEmail; } });
15
- Object.defineProperty(exports, "validatePassword", { enumerable: true, get: function () { return validators_1.validatePassword; } });
16
- Object.defineProperty(exports, "validatePasswordConfirmation", { enumerable: true, get: function () { return validators_1.validatePasswordConfirmation; } });
17
- Object.defineProperty(exports, "validateRequired", { enumerable: true, get: function () { return validators_1.validateRequired; } });
18
- Object.defineProperty(exports, "validateName", { enumerable: true, get: function () { return validators_1.validateName; } });
19
- Object.defineProperty(exports, "validatePhone", { enumerable: true, get: function () { return validators_1.validatePhone; } });
20
- Object.defineProperty(exports, "validateNumberRange", { enumerable: true, get: function () { return validators_1.validateNumberRange; } });
21
- Object.defineProperty(exports, "validatePositiveNumber", { enumerable: true, get: function () { return validators_1.validatePositiveNumber; } });
22
- Object.defineProperty(exports, "validateMinLength", { enumerable: true, get: function () { return validators_1.validateMinLength; } });
23
- Object.defineProperty(exports, "validateMaxLength", { enumerable: true, get: function () { return validators_1.validateMaxLength; } });
24
- Object.defineProperty(exports, "validatePattern", { enumerable: true, get: function () { return validators_1.validatePattern; } });
25
- Object.defineProperty(exports, "validateDateOfBirth", { enumerable: true, get: function () { return validators_1.validateDateOfBirth; } });
26
- Object.defineProperty(exports, "validateAge", { enumerable: true, get: function () { return validators_1.validateAge; } });
27
- Object.defineProperty(exports, "validateWeight", { enumerable: true, get: function () { return validators_1.validateWeight; } });
28
- Object.defineProperty(exports, "validateHeight", { enumerable: true, get: function () { return validators_1.validateHeight; } });
29
- Object.defineProperty(exports, "validateCalories", { enumerable: true, get: function () { return validators_1.validateCalories; } });
30
- Object.defineProperty(exports, "validateMacros", { enumerable: true, get: function () { return validators_1.validateMacros; } });
31
- Object.defineProperty(exports, "validateWaterIntake", { enumerable: true, get: function () { return validators_1.validateWaterIntake; } });
32
- Object.defineProperty(exports, "validateWorkoutDuration", { enumerable: true, get: function () { return validators_1.validateWorkoutDuration; } });
33
- Object.defineProperty(exports, "validateReps", { enumerable: true, get: function () { return validators_1.validateReps; } });
34
- Object.defineProperty(exports, "validateSets", { enumerable: true, get: function () { return validators_1.validateSets; } });
35
- Object.defineProperty(exports, "validateExerciseWeight", { enumerable: true, get: function () { return validators_1.validateExerciseWeight; } });
36
- Object.defineProperty(exports, "batchValidate", { enumerable: true, get: function () { return validators_1.batchValidate; } });
@@ -1,114 +0,0 @@
1
- /**
2
- * Validation Utilities
3
- * Comprehensive validation functions for React Native forms
4
- */
5
- import type { ValidationResult } from '../../domain/entities/ValidationResult';
6
- /**
7
- * Validate email format
8
- */
9
- export declare const validateEmail: (email: string) => ValidationResult;
10
- /**
11
- * Validate password strength
12
- * @param password - Password to validate
13
- * @param minLength - Minimum password length (default: 8)
14
- * @param requireUppercase - Require uppercase letter (default: true)
15
- * @param requireLowercase - Require lowercase letter (default: true)
16
- * @param requireNumber - Require number (default: true)
17
- */
18
- export declare const validatePassword: (password: string, options?: {
19
- minLength?: number;
20
- requireUppercase?: boolean;
21
- requireLowercase?: boolean;
22
- requireNumber?: boolean;
23
- }) => ValidationResult;
24
- /**
25
- * Validate password confirmation
26
- */
27
- export declare const validatePasswordConfirmation: (password: string, confirmPassword: string) => ValidationResult;
28
- /**
29
- * Validate required field
30
- */
31
- export declare const validateRequired: (value: string, fieldName?: string) => ValidationResult;
32
- /**
33
- * Validate name
34
- */
35
- export declare const validateName: (name: string, fieldName?: string, minLength?: number) => ValidationResult;
36
- /**
37
- * Validate phone number (E.164 format)
38
- */
39
- export declare const validatePhone: (phone: string) => ValidationResult;
40
- /**
41
- * Validate number range
42
- */
43
- export declare const validateNumberRange: (value: number, min: number, max: number, fieldName?: string) => ValidationResult;
44
- /**
45
- * Validate positive number
46
- */
47
- export declare const validatePositiveNumber: (value: number, fieldName?: string) => ValidationResult;
48
- /**
49
- * Validate min length
50
- */
51
- export declare const validateMinLength: (value: string, minLength: number, fieldName?: string) => ValidationResult;
52
- /**
53
- * Validate max length
54
- */
55
- export declare const validateMaxLength: (value: string, maxLength: number, fieldName?: string) => ValidationResult;
56
- /**
57
- * Validate pattern (regex)
58
- */
59
- export declare const validatePattern: (value: string, pattern: RegExp, fieldName?: string, errorMessage?: string) => ValidationResult;
60
- /**
61
- * Validate date of birth
62
- */
63
- export declare const validateDateOfBirth: (date: Date) => ValidationResult;
64
- /**
65
- * Validate age
66
- */
67
- export declare const validateAge: (age: number) => ValidationResult;
68
- /**
69
- * Validate weight (kg)
70
- */
71
- export declare const validateWeight: (weight: number) => ValidationResult;
72
- /**
73
- * Validate height (cm)
74
- */
75
- export declare const validateHeight: (height: number) => ValidationResult;
76
- /**
77
- * Validate calories
78
- */
79
- export declare const validateCalories: (calories: number) => ValidationResult;
80
- /**
81
- * Validate macros (protein, carbs, fat in grams)
82
- */
83
- export declare const validateMacros: (grams: number, macroType: string) => ValidationResult;
84
- /**
85
- * Validate water intake (glasses)
86
- */
87
- export declare const validateWaterIntake: (glasses: number) => ValidationResult;
88
- /**
89
- * Validate workout duration (minutes)
90
- */
91
- export declare const validateWorkoutDuration: (minutes: number) => ValidationResult;
92
- /**
93
- * Validate reps
94
- */
95
- export declare const validateReps: (reps: number) => ValidationResult;
96
- /**
97
- * Validate sets
98
- */
99
- export declare const validateSets: (sets: number) => ValidationResult;
100
- /**
101
- * Validate exercise weight (kg)
102
- */
103
- export declare const validateExerciseWeight: (weight: number) => ValidationResult;
104
- /**
105
- * Batch validation
106
- * Validates multiple fields and returns all errors
107
- */
108
- export declare const batchValidate: (validations: Array<{
109
- field: string;
110
- validator: () => ValidationResult;
111
- }>) => {
112
- isValid: boolean;
113
- errors: Record<string, string>;
114
- };
@@ -1,290 +0,0 @@
1
- "use strict";
2
- /**
3
- * Validation Utilities
4
- * Comprehensive validation functions for React Native forms
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.batchValidate = exports.validateExerciseWeight = exports.validateSets = exports.validateReps = exports.validateWorkoutDuration = exports.validateWaterIntake = exports.validateMacros = exports.validateCalories = exports.validateHeight = exports.validateWeight = exports.validateAge = exports.validateDateOfBirth = exports.validatePattern = exports.validateMaxLength = exports.validateMinLength = exports.validatePositiveNumber = exports.validateNumberRange = exports.validatePhone = exports.validateName = exports.validateRequired = exports.validatePasswordConfirmation = exports.validatePassword = exports.validateEmail = void 0;
8
- /**
9
- * Validate email format
10
- */
11
- const validateEmail = (email) => {
12
- if (!email || email.trim() === '') {
13
- return { isValid: false, error: 'Email is required' };
14
- }
15
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
16
- if (!emailRegex.test(email)) {
17
- return { isValid: false, error: 'Please enter a valid email address' };
18
- }
19
- return { isValid: true };
20
- };
21
- exports.validateEmail = validateEmail;
22
- /**
23
- * Validate password strength
24
- * @param password - Password to validate
25
- * @param minLength - Minimum password length (default: 8)
26
- * @param requireUppercase - Require uppercase letter (default: true)
27
- * @param requireLowercase - Require lowercase letter (default: true)
28
- * @param requireNumber - Require number (default: true)
29
- */
30
- const validatePassword = (password, options) => {
31
- const { minLength = 8, requireUppercase = true, requireLowercase = true, requireNumber = true, } = options || {};
32
- if (!password || password.trim() === '') {
33
- return { isValid: false, error: 'Password is required' };
34
- }
35
- if (password.length < minLength) {
36
- return {
37
- isValid: false,
38
- error: `Password must be at least ${minLength} characters`,
39
- };
40
- }
41
- if (requireUppercase && !/[A-Z]/.test(password)) {
42
- return {
43
- isValid: false,
44
- error: 'Password must contain at least one uppercase letter',
45
- };
46
- }
47
- if (requireLowercase && !/[a-z]/.test(password)) {
48
- return {
49
- isValid: false,
50
- error: 'Password must contain at least one lowercase letter',
51
- };
52
- }
53
- if (requireNumber && !/[0-9]/.test(password)) {
54
- return {
55
- isValid: false,
56
- error: 'Password must contain at least one number',
57
- };
58
- }
59
- return { isValid: true };
60
- };
61
- exports.validatePassword = validatePassword;
62
- /**
63
- * Validate password confirmation
64
- */
65
- const validatePasswordConfirmation = (password, confirmPassword) => {
66
- if (!confirmPassword) {
67
- return { isValid: false, error: 'Please confirm your password' };
68
- }
69
- if (password !== confirmPassword) {
70
- return { isValid: false, error: 'Passwords do not match' };
71
- }
72
- return { isValid: true };
73
- };
74
- exports.validatePasswordConfirmation = validatePasswordConfirmation;
75
- /**
76
- * Validate required field
77
- */
78
- const validateRequired = (value, fieldName = 'This field') => {
79
- if (!value || value.trim() === '') {
80
- return { isValid: false, error: `${fieldName} is required` };
81
- }
82
- return { isValid: true };
83
- };
84
- exports.validateRequired = validateRequired;
85
- /**
86
- * Validate name
87
- */
88
- const validateName = (name, fieldName = 'Name', minLength = 2) => {
89
- if (!name || name.trim() === '') {
90
- return { isValid: false, error: `${fieldName} is required` };
91
- }
92
- if (name.trim().length < minLength) {
93
- return {
94
- isValid: false,
95
- error: `${fieldName} must be at least ${minLength} characters`,
96
- };
97
- }
98
- return { isValid: true };
99
- };
100
- exports.validateName = validateName;
101
- /**
102
- * Validate phone number (E.164 format)
103
- */
104
- const validatePhone = (phone) => {
105
- if (!phone || phone.trim() === '') {
106
- return { isValid: false, error: 'Phone number is required' };
107
- }
108
- const phoneRegex = /^\+[1-9]\d{1,14}$/;
109
- if (!phoneRegex.test(phone)) {
110
- return { isValid: false, error: 'Please enter a valid phone number' };
111
- }
112
- return { isValid: true };
113
- };
114
- exports.validatePhone = validatePhone;
115
- /**
116
- * Validate number range
117
- */
118
- const validateNumberRange = (value, min, max, fieldName = 'Value') => {
119
- if (isNaN(value)) {
120
- return { isValid: false, error: `${fieldName} must be a number` };
121
- }
122
- if (value < min || value > max) {
123
- return {
124
- isValid: false,
125
- error: `${fieldName} must be between ${min} and ${max}`,
126
- };
127
- }
128
- return { isValid: true };
129
- };
130
- exports.validateNumberRange = validateNumberRange;
131
- /**
132
- * Validate positive number
133
- */
134
- const validatePositiveNumber = (value, fieldName = 'Value') => {
135
- if (isNaN(value)) {
136
- return { isValid: false, error: `${fieldName} must be a number` };
137
- }
138
- if (value <= 0) {
139
- return { isValid: false, error: `${fieldName} must be greater than 0` };
140
- }
141
- return { isValid: true };
142
- };
143
- exports.validatePositiveNumber = validatePositiveNumber;
144
- /**
145
- * Validate min length
146
- */
147
- const validateMinLength = (value, minLength, fieldName = 'Field') => {
148
- if (!value || value.trim().length < minLength) {
149
- return {
150
- isValid: false,
151
- error: `${fieldName} must be at least ${minLength} characters`,
152
- };
153
- }
154
- return { isValid: true };
155
- };
156
- exports.validateMinLength = validateMinLength;
157
- /**
158
- * Validate max length
159
- */
160
- const validateMaxLength = (value, maxLength, fieldName = 'Field') => {
161
- if (value && value.trim().length > maxLength) {
162
- return {
163
- isValid: false,
164
- error: `${fieldName} must be at most ${maxLength} characters`,
165
- };
166
- }
167
- return { isValid: true };
168
- };
169
- exports.validateMaxLength = validateMaxLength;
170
- /**
171
- * Validate pattern (regex)
172
- */
173
- const validatePattern = (value, pattern, fieldName = 'Field', errorMessage) => {
174
- if (!value) {
175
- return { isValid: false, error: `${fieldName} is required` };
176
- }
177
- if (!pattern.test(value)) {
178
- return {
179
- isValid: false,
180
- error: errorMessage || `${fieldName} format is invalid`,
181
- };
182
- }
183
- return { isValid: true };
184
- };
185
- exports.validatePattern = validatePattern;
186
- /**
187
- * Validate date of birth
188
- */
189
- const validateDateOfBirth = (date) => {
190
- if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
191
- return { isValid: false, error: 'Please enter a valid date' };
192
- }
193
- const today = new Date();
194
- const age = today.getFullYear() - date.getFullYear();
195
- if (age < 13) {
196
- return { isValid: false, error: 'You must be at least 13 years old' };
197
- }
198
- if (age > 120) {
199
- return { isValid: false, error: 'Please enter a valid date of birth' };
200
- }
201
- return { isValid: true };
202
- };
203
- exports.validateDateOfBirth = validateDateOfBirth;
204
- /**
205
- * Validate age
206
- */
207
- const validateAge = (age) => {
208
- return (0, exports.validateNumberRange)(age, 13, 120, 'Age');
209
- };
210
- exports.validateAge = validateAge;
211
- /**
212
- * Validate weight (kg)
213
- */
214
- const validateWeight = (weight) => {
215
- return (0, exports.validateNumberRange)(weight, 20, 300, 'Weight');
216
- };
217
- exports.validateWeight = validateWeight;
218
- /**
219
- * Validate height (cm)
220
- */
221
- const validateHeight = (height) => {
222
- return (0, exports.validateNumberRange)(height, 50, 250, 'Height');
223
- };
224
- exports.validateHeight = validateHeight;
225
- /**
226
- * Validate calories
227
- */
228
- const validateCalories = (calories) => {
229
- return (0, exports.validateNumberRange)(calories, 0, 10000, 'Calories');
230
- };
231
- exports.validateCalories = validateCalories;
232
- /**
233
- * Validate macros (protein, carbs, fat in grams)
234
- */
235
- const validateMacros = (grams, macroType) => {
236
- return (0, exports.validateNumberRange)(grams, 0, 1000, macroType);
237
- };
238
- exports.validateMacros = validateMacros;
239
- /**
240
- * Validate water intake (glasses)
241
- */
242
- const validateWaterIntake = (glasses) => {
243
- return (0, exports.validateNumberRange)(glasses, 0, 50, 'Water intake');
244
- };
245
- exports.validateWaterIntake = validateWaterIntake;
246
- /**
247
- * Validate workout duration (minutes)
248
- */
249
- const validateWorkoutDuration = (minutes) => {
250
- return (0, exports.validateNumberRange)(minutes, 1, 600, 'Workout duration');
251
- };
252
- exports.validateWorkoutDuration = validateWorkoutDuration;
253
- /**
254
- * Validate reps
255
- */
256
- const validateReps = (reps) => {
257
- return (0, exports.validateNumberRange)(reps, 1, 1000, 'Reps');
258
- };
259
- exports.validateReps = validateReps;
260
- /**
261
- * Validate sets
262
- */
263
- const validateSets = (sets) => {
264
- return (0, exports.validateNumberRange)(sets, 1, 100, 'Sets');
265
- };
266
- exports.validateSets = validateSets;
267
- /**
268
- * Validate exercise weight (kg)
269
- */
270
- const validateExerciseWeight = (weight) => {
271
- return (0, exports.validateNumberRange)(weight, 0, 1000, 'Weight');
272
- };
273
- exports.validateExerciseWeight = validateExerciseWeight;
274
- /**
275
- * Batch validation
276
- * Validates multiple fields and returns all errors
277
- */
278
- const batchValidate = (validations) => {
279
- const errors = {};
280
- let isValid = true;
281
- validations.forEach(({ field, validator }) => {
282
- const result = validator();
283
- if (!result.isValid && result.error) {
284
- errors[field] = result.error;
285
- isValid = false;
286
- }
287
- });
288
- return { isValid, errors };
289
- };
290
- exports.batchValidate = batchValidate;