@umituz/react-native-validation 1.4.4 → 1.4.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-validation",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
4
4
  "description": "Comprehensive validation and sanitization utilities for React Native forms",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -29,7 +29,9 @@
29
29
  "react-native": ">=0.74.0"
30
30
  },
31
31
  "devDependencies": {
32
+ "@types/node": "^25.0.3",
32
33
  "@types/react": "~19.1.10",
34
+ "@types/react-native": "^0.72.8",
33
35
  "react": "19.1.0",
34
36
  "react-native": "0.81.5",
35
37
  "typescript": "~5.9.2"
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  // Domain Layer - Entities
11
- export type { ValidationResult } from './domain/entities/ValidationResult';
11
+ export type { ValidationResult } from "./domain/entities/ValidationResult";
12
12
 
13
13
  // Infrastructure Layer - Validators
14
14
  export {
@@ -24,7 +24,19 @@ export {
24
24
  validateDateOfBirth,
25
25
  validateAge,
26
26
  batchValidate,
27
- } from './infrastructure/utils/validators';
27
+ } from "./infrastructure/utils/validators";
28
+
29
+ // Dream-specific validators
30
+ export {
31
+ validateDreamTitle,
32
+ validateDreamDescription,
33
+ validateDreamMood,
34
+ validateDreamCategory,
35
+ validateDreamDate,
36
+ validateDreamTags,
37
+ validateDreamPrivacy,
38
+ validateDreamForm,
39
+ } from "./infrastructure/utils/validators";
28
40
 
29
41
  // Infrastructure Layer - Sanitization
30
42
  export {
@@ -36,7 +48,7 @@ export {
36
48
  sanitizeText,
37
49
  containsDangerousChars,
38
50
  isWithinLengthLimit,
39
- } from './infrastructure/utils/sanitization';
51
+ } from "./infrastructure/utils/sanitization";
40
52
 
41
53
  // Infrastructure Layer - MIME Type Validation
42
54
  export {
@@ -44,7 +56,7 @@ export {
44
56
  SUPPORTED_IMAGE_MIME_TYPES,
45
57
  EXTENSION_TO_MIME_TYPE,
46
58
  MIME_TYPE_TO_EXTENSION,
47
- } from './infrastructure/utils/mime-types.constants';
59
+ } from "./infrastructure/utils/mime-types.constants";
48
60
 
49
61
  export {
50
62
  getFileExtension,
@@ -53,8 +65,10 @@ export {
53
65
  validateImageMimeType,
54
66
  validateImageExtension,
55
67
  validateImageDataUrl,
56
- } from './infrastructure/utils/mime-type-validator';
68
+ } from "./infrastructure/utils/mime-type-validator";
57
69
 
58
70
  // Infrastructure Layer - Image Validation
59
- export { validateImageUri, getImageMimeType } from './infrastructure/utils/image-validator';
60
-
71
+ export {
72
+ validateImageUri,
73
+ getImageMimeType,
74
+ } from "./infrastructure/utils/image-validator";
@@ -1,92 +1,99 @@
1
1
  /**
2
2
  * Sanitization Utilities
3
- * Functions to clean and secure user input
3
+ * Secure input cleaning for user data
4
4
  */
5
5
 
6
+ /**
7
+ * Security constants for input validation
8
+ */
6
9
  export const SECURITY_LIMITS = {
7
- EMAIL_MAX_LENGTH: 254,
8
- PASSWORD_MAX_LENGTH: 128, // Reasonable limit for hash algorithms
9
- NAME_MAX_LENGTH: 50,
10
- TEXT_MAX_LENGTH: 1000,
11
- URL_MAX_LENGTH: 2048,
12
- };
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;
13
16
 
14
17
  /**
15
- * Sanitize whitespace from a string
16
- * Removes leading/trailing whitespace and replaces multiple spaces with single space
18
+ * Trim and normalize whitespace
17
19
  */
18
- export const sanitizeWhitespace = (value: string): string => {
19
- if (!value) return '';
20
- return value.trim().replace(/\s+/g, ' ');
20
+ export const sanitizeWhitespace = (input: string): string => {
21
+ return input.trim().replace(/\s+/g, ' ');
21
22
  };
22
23
 
23
24
  /**
24
- * Sanitize email
25
- * Trims, lowercases, and removes dangerous characters
25
+ * Sanitize email address
26
+ * - Trim whitespace
27
+ * - Convert to lowercase
28
+ * - Limit length
26
29
  */
27
30
  export const sanitizeEmail = (email: string): string => {
28
- if (!email) return '';
29
- // Basic sanitization: trim and lowercase
30
- let sanitized = email.trim().toLowerCase();
31
- // Remove potential dangerous characters that shouldn't be in an email
32
- // < > " ' `
33
- sanitized = sanitized.replace(/[<>"'`]/g, '');
34
- return sanitized;
31
+ const trimmed = email.trim().toLowerCase();
32
+ return trimmed.substring(0, SECURITY_LIMITS.EMAIL_MAX_LENGTH);
35
33
  };
36
34
 
37
35
  /**
38
36
  * Sanitize password
39
- * No whitespace trimming often (some allow spaces), but good to enforce consistent handling
40
- * Here we only strictly ensure it's a string, we DO NOT trim passwords usually to avoid confusion,
41
- * but for this utility we will assume standard string behavior.
42
- * actually it's safer NOT to modify password input other than ensuring it is a string.
37
+ * - Only trim (preserve case and special chars)
38
+ * - Limit length to prevent DoS
43
39
  */
44
40
  export const sanitizePassword = (password: string): string => {
45
- if (!password) return '';
46
- return password;
41
+ // Don't trim password to preserve intentional spaces
42
+ // Only limit length
43
+ return password.substring(0, SECURITY_LIMITS.PASSWORD_MAX_LENGTH);
47
44
  };
48
45
 
49
46
  /**
50
- * Sanitize name
51
- * Trims and removes special characters that are typically not in names (simple version)
47
+ * Sanitize display name
48
+ * - Trim whitespace
49
+ * - Normalize multiple spaces
50
+ * - Remove potential XSS characters
51
+ * - Limit length
52
52
  */
53
53
  export const sanitizeName = (name: string): string => {
54
- if (!name) return '';
55
- // Remove < > " ' ` / \
56
- return sanitizeWhitespace(name).replace(/[<>"'`/\\]/g, '');
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);
57
58
  };
58
59
 
59
60
  /**
60
- * Sanitize generic text
61
- * Escapes HTML characters to prevent simple injection if rendered
62
- * (Note: React handles this by default, but useful for raw data handling)
61
+ * Sanitize general text input
62
+ * - Trim whitespace
63
+ * - Remove HTML/script tags
64
+ * - Limit length
63
65
  */
64
66
  export const sanitizeText = (text: string): string => {
65
- if (!text) return '';
66
- const trimmed = text.trim();
67
- return trimmed
68
- .replace(/&/g, '&amp;')
69
- .replace(/</g, '&lt;')
70
- .replace(/>/g, '&gt;')
71
- .replace(/"/g, '&quot;')
72
- .replace(/'/g, '&#039;');
67
+ const trimmed = sanitizeWhitespace(text);
68
+ const noTags = trimmed.replace(/<[^>]*>/g, '');
69
+ return noTags.substring(0, SECURITY_LIMITS.GENERAL_TEXT_MAX_LENGTH);
73
70
  };
74
71
 
75
72
  /**
76
- * Check for dangerous characters
77
- * Returns true if string contains characters often used in attacks (<, >, etc)
73
+ * Check if string contains potentially dangerous characters
78
74
  */
79
- export const containsDangerousChars = (value: string): boolean => {
80
- if (!value) return false;
81
- // Check for script tags or SQL injection common chars
82
- const dangerousPattern = /[<>;]/;
83
- return dangerousPattern.test(value);
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));
84
86
  };
85
87
 
86
88
  /**
87
- * Check if value is within length limits
89
+ * Validate string length is within bounds
88
90
  */
89
- export const isWithinLengthLimit = (value: string, limit: number): boolean => {
90
- if (!value) return true;
91
- return value.length <= limit;
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;
92
98
  };
99
+
@@ -3,19 +3,19 @@
3
3
  * Comprehensive validation functions for React Native forms
4
4
  */
5
5
 
6
- import type { ValidationResult } from '../../domain/entities/ValidationResult';
6
+ import type { ValidationResult } from "../../domain/entities/ValidationResult";
7
7
 
8
8
  /**
9
9
  * Validate email format
10
10
  */
11
11
  export const validateEmail = (email: string): ValidationResult => {
12
- if (!email || email.trim() === '') {
13
- return { isValid: false, error: 'Email is required' };
12
+ if (!email || email.trim() === "") {
13
+ return { isValid: false, error: "Email is required" };
14
14
  }
15
15
 
16
16
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
17
17
  if (!emailRegex.test(email)) {
18
- return { isValid: false, error: 'Please enter a valid email address' };
18
+ return { isValid: false, error: "Please enter a valid email address" };
19
19
  }
20
20
 
21
21
  return { isValid: true };
@@ -26,9 +26,9 @@ export const validateEmail = (email: string): ValidationResult => {
26
26
  */
27
27
  export const validateRequired = (
28
28
  value: string,
29
- fieldName: string = 'This field'
29
+ fieldName: string = "This field",
30
30
  ): ValidationResult => {
31
- if (!value || value.trim() === '') {
31
+ if (!value || value.trim() === "") {
32
32
  return { isValid: false, error: `${fieldName} is required` };
33
33
  }
34
34
 
@@ -40,10 +40,10 @@ export const validateRequired = (
40
40
  */
41
41
  export const validateName = (
42
42
  name: string,
43
- fieldName: string = 'Name',
44
- minLength: number = 2
43
+ fieldName: string = "Name",
44
+ minLength: number = 2,
45
45
  ): ValidationResult => {
46
- if (!name || name.trim() === '') {
46
+ if (!name || name.trim() === "") {
47
47
  return { isValid: false, error: `${fieldName} is required` };
48
48
  }
49
49
 
@@ -61,13 +61,13 @@ export const validateName = (
61
61
  * Validate phone number (E.164 format)
62
62
  */
63
63
  export const validatePhone = (phone: string): ValidationResult => {
64
- if (!phone || phone.trim() === '') {
65
- return { isValid: false, error: 'Phone number is required' };
64
+ if (!phone || phone.trim() === "") {
65
+ return { isValid: false, error: "Phone number is required" };
66
66
  }
67
67
 
68
68
  const phoneRegex = /^\+[1-9]\d{1,14}$/;
69
69
  if (!phoneRegex.test(phone)) {
70
- return { isValid: false, error: 'Please enter a valid phone number' };
70
+ return { isValid: false, error: "Please enter a valid phone number" };
71
71
  }
72
72
 
73
73
  return { isValid: true };
@@ -80,7 +80,7 @@ export const validateNumberRange = (
80
80
  value: number,
81
81
  min: number,
82
82
  max: number,
83
- fieldName: string = 'Value'
83
+ fieldName: string = "Value",
84
84
  ): ValidationResult => {
85
85
  if (isNaN(value)) {
86
86
  return { isValid: false, error: `${fieldName} must be a number` };
@@ -101,7 +101,7 @@ export const validateNumberRange = (
101
101
  */
102
102
  export const validatePositiveNumber = (
103
103
  value: number,
104
- fieldName: string = 'Value'
104
+ fieldName: string = "Value",
105
105
  ): ValidationResult => {
106
106
  if (isNaN(value)) {
107
107
  return { isValid: false, error: `${fieldName} must be a number` };
@@ -120,7 +120,7 @@ export const validatePositiveNumber = (
120
120
  export const validateMinLength = (
121
121
  value: string,
122
122
  minLength: number,
123
- fieldName: string = 'Field'
123
+ fieldName: string = "Field",
124
124
  ): ValidationResult => {
125
125
  if (!value || value.trim().length < minLength) {
126
126
  return {
@@ -138,7 +138,7 @@ export const validateMinLength = (
138
138
  export const validateMaxLength = (
139
139
  value: string,
140
140
  maxLength: number,
141
- fieldName: string = 'Field'
141
+ fieldName: string = "Field",
142
142
  ): ValidationResult => {
143
143
  if (value && value.trim().length > maxLength) {
144
144
  return {
@@ -156,8 +156,8 @@ export const validateMaxLength = (
156
156
  export const validatePattern = (
157
157
  value: string,
158
158
  pattern: RegExp,
159
- fieldName: string = 'Field',
160
- errorMessage?: string
159
+ fieldName: string = "Field",
160
+ errorMessage?: string,
161
161
  ): ValidationResult => {
162
162
  if (!value) {
163
163
  return { isValid: false, error: `${fieldName} is required` };
@@ -178,18 +178,18 @@ export const validatePattern = (
178
178
  */
179
179
  export const validateDateOfBirth = (date: Date): ValidationResult => {
180
180
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
181
- return { isValid: false, error: 'Please enter a valid date' };
181
+ return { isValid: false, error: "Please enter a valid date" };
182
182
  }
183
183
 
184
184
  const today = new Date();
185
185
  const age = today.getFullYear() - date.getFullYear();
186
186
 
187
187
  if (age < 13) {
188
- return { isValid: false, error: 'You must be at least 13 years old' };
188
+ return { isValid: false, error: "You must be at least 13 years old" };
189
189
  }
190
190
 
191
191
  if (age > 120) {
192
- return { isValid: false, error: 'Please enter a valid date of birth' };
192
+ return { isValid: false, error: "Please enter a valid date of birth" };
193
193
  }
194
194
 
195
195
  return { isValid: true };
@@ -199,7 +199,7 @@ export const validateDateOfBirth = (date: Date): ValidationResult => {
199
199
  * Validate age
200
200
  */
201
201
  export const validateAge = (age: number): ValidationResult => {
202
- return validateNumberRange(age, 13, 120, 'Age');
202
+ return validateNumberRange(age, 13, 120, "Age");
203
203
  };
204
204
 
205
205
  /**
@@ -207,7 +207,7 @@ export const validateAge = (age: number): ValidationResult => {
207
207
  * Validates multiple fields and returns all errors
208
208
  */
209
209
  export const batchValidate = (
210
- validations: Array<{ field: string; validator: () => ValidationResult }>
210
+ validations: Array<{ field: string; validator: () => ValidationResult }>,
211
211
  ): { isValid: boolean; errors: Record<string, string> } => {
212
212
  const errors: Record<string, string> = {};
213
213
  let isValid = true;
@@ -223,3 +223,244 @@ export const batchValidate = (
223
223
  return { isValid, errors };
224
224
  };
225
225
 
226
+ /**
227
+ * Dream-specific validation functions
228
+ */
229
+
230
+ /**
231
+ * Validate dream title
232
+ */
233
+ export const validateDreamTitle = (
234
+ title: string,
235
+ minLength: number = 3,
236
+ maxLength: number = 100,
237
+ ): ValidationResult => {
238
+ if (!title || title.trim() === "") {
239
+ return { isValid: false, error: "Dream title is required" };
240
+ }
241
+
242
+ if (title.trim().length < minLength) {
243
+ return {
244
+ isValid: false,
245
+ error: `Dream title must be at least ${minLength} characters`,
246
+ };
247
+ }
248
+
249
+ if (title.trim().length > maxLength) {
250
+ return {
251
+ isValid: false,
252
+ error: `Dream title must be at most ${maxLength} characters`,
253
+ };
254
+ }
255
+
256
+ return { isValid: true };
257
+ };
258
+
259
+ /**
260
+ * Validate dream description
261
+ */
262
+ export const validateDreamDescription = (
263
+ description: string,
264
+ minLength: number = 10,
265
+ maxLength: number = 2000,
266
+ ): ValidationResult => {
267
+ if (!description || description.trim() === "") {
268
+ return { isValid: false, error: "Dream description is required" };
269
+ }
270
+
271
+ if (description.trim().length < minLength) {
272
+ return {
273
+ isValid: false,
274
+ error: `Dream description must be at least ${minLength} characters`,
275
+ };
276
+ }
277
+
278
+ if (description.trim().length > maxLength) {
279
+ return {
280
+ isValid: false,
281
+ error: `Dream description must be at most ${maxLength} characters`,
282
+ };
283
+ }
284
+
285
+ return { isValid: true };
286
+ };
287
+
288
+ /**
289
+ * Validate dream mood
290
+ */
291
+ export const validateDreamMood = (mood: string): ValidationResult => {
292
+ if (!mood || mood.trim() === "") {
293
+ return { isValid: false, error: "Dream mood is required" };
294
+ }
295
+
296
+ const validMoods = [
297
+ "happy",
298
+ "sad",
299
+ "scared",
300
+ "excited",
301
+ "peaceful",
302
+ "anxious",
303
+ "confused",
304
+ "angry",
305
+ "surprised",
306
+ "neutral",
307
+ ];
308
+ if (!validMoods.includes(mood.toLowerCase())) {
309
+ return {
310
+ isValid: false,
311
+ error: "Please select a valid mood",
312
+ };
313
+ }
314
+
315
+ return { isValid: true };
316
+ };
317
+
318
+ /**
319
+ * Validate dream category
320
+ */
321
+ export const validateDreamCategory = (category: string): ValidationResult => {
322
+ if (!category || category.trim() === "") {
323
+ return { isValid: false, error: "Dream category is required" };
324
+ }
325
+
326
+ const validCategories = [
327
+ "lucid",
328
+ "nightmare",
329
+ "recurring",
330
+ "prophetic",
331
+ "healing",
332
+ "creative",
333
+ "adventure",
334
+ "relationship",
335
+ "work",
336
+ "childhood",
337
+ "flying",
338
+ "falling",
339
+ "chase",
340
+ "exam",
341
+ "tooth",
342
+ "other",
343
+ ];
344
+ if (!validCategories.includes(category.toLowerCase())) {
345
+ return {
346
+ isValid: false,
347
+ error: "Please select a valid category",
348
+ };
349
+ }
350
+
351
+ return { isValid: true };
352
+ };
353
+
354
+ /**
355
+ * Validate dream date
356
+ */
357
+ export const validateDreamDate = (date: Date): ValidationResult => {
358
+ if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
359
+ return { isValid: false, error: "Please enter a valid dream date" };
360
+ }
361
+
362
+ const today = new Date();
363
+ if (date > today) {
364
+ return { isValid: false, error: "Dream date cannot be in the future" };
365
+ }
366
+
367
+ // Don't allow dreams older than 1 year
368
+ const oneYearAgo = new Date();
369
+ oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
370
+ if (date < oneYearAgo) {
371
+ return {
372
+ isValid: false,
373
+ error: "Dream date cannot be more than 1 year old",
374
+ };
375
+ }
376
+
377
+ return { isValid: true };
378
+ };
379
+
380
+ /**
381
+ * Validate dream tags
382
+ */
383
+ export const validateDreamTags = (tags: string[]): ValidationResult => {
384
+ if (!Array.isArray(tags)) {
385
+ return { isValid: false, error: "Dream tags must be an array" };
386
+ }
387
+
388
+ if (tags.length > 10) {
389
+ return { isValid: false, error: "Maximum 10 tags allowed" };
390
+ }
391
+
392
+ for (const tag of tags) {
393
+ if (typeof tag !== "string" || tag.trim().length === 0) {
394
+ return { isValid: false, error: "All tags must be non-empty strings" };
395
+ }
396
+
397
+ if (tag.trim().length > 20) {
398
+ return {
399
+ isValid: false,
400
+ error: "Each tag must be at most 20 characters",
401
+ };
402
+ }
403
+ }
404
+
405
+ return { isValid: true };
406
+ };
407
+
408
+ /**
409
+ * Validate dream privacy setting
410
+ */
411
+ export const validateDreamPrivacy = (privacy: string): ValidationResult => {
412
+ if (!privacy || privacy.trim() === "") {
413
+ return { isValid: false, error: "Privacy setting is required" };
414
+ }
415
+
416
+ const validPrivacyOptions = ["private", "friends", "public"];
417
+ if (!validPrivacyOptions.includes(privacy.toLowerCase())) {
418
+ return {
419
+ isValid: false,
420
+ error: "Please select a valid privacy setting",
421
+ };
422
+ }
423
+
424
+ return { isValid: true };
425
+ };
426
+
427
+ /**
428
+ * Complete dream form validation
429
+ * Validates all dream fields at once
430
+ */
431
+ export const validateDreamForm = (formData: {
432
+ title?: string;
433
+ description?: string;
434
+ mood?: string;
435
+ category?: string;
436
+ date?: Date;
437
+ tags?: string[];
438
+ privacy?: string;
439
+ }): { isValid: boolean; errors: Record<string, string> } => {
440
+ const validations = [
441
+ {
442
+ field: "title",
443
+ validator: () => validateDreamTitle(formData.title || ""),
444
+ },
445
+ {
446
+ field: "description",
447
+ validator: () => validateDreamDescription(formData.description || ""),
448
+ },
449
+ { field: "mood", validator: () => validateDreamMood(formData.mood || "") },
450
+ {
451
+ field: "category",
452
+ validator: () => validateDreamCategory(formData.category || ""),
453
+ },
454
+ {
455
+ field: "date",
456
+ validator: () => validateDreamDate(formData.date || new Date()),
457
+ },
458
+ { field: "tags", validator: () => validateDreamTags(formData.tags || []) },
459
+ {
460
+ field: "privacy",
461
+ validator: () => validateDreamPrivacy(formData.privacy || ""),
462
+ },
463
+ ];
464
+
465
+ return batchValidate(validations);
466
+ };
package/README.md DELETED
@@ -1,245 +0,0 @@
1
- # @umituz/react-native-validation
2
-
3
- Comprehensive validation and sanitization utilities for React Native forms. Provides reusable validation and sanitization functions for common input types.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @umituz/react-native-validation
9
- ```
10
-
11
- ## Peer Dependencies
12
-
13
- - `react` >= 18.2.0
14
- - `react-native` >= 0.74.0
15
-
16
- ## Features
17
-
18
- ### Validation
19
- - ✅ Email validation
20
- - ✅ Password validation (with strength requirements)
21
- - ✅ Phone number validation (E.164 format)
22
- - ✅ Required field validation
23
- - ✅ Name validation
24
- - ✅ Number range validation
25
- - ✅ Min/Max length validation
26
- - ✅ Pattern (regex) validation
27
- - ✅ Date of birth validation
28
- - ✅ Age validation
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
41
- - ✅ TypeScript type safety
42
- - ✅ Image file validation (prevents zip, exe, etc.)
43
- - ✅ MIME type validation
44
-
45
- ## Usage
46
-
47
- ### Basic Example
48
-
49
- ```typescript
50
- import { validateEmail, validatePassword, validateRequired } from '@umituz/react-native-validation';
51
-
52
- // Validate email
53
- const emailResult = validateEmail('user@example.com');
54
- if (!emailResult.isValid) {
55
- console.error(emailResult.error);
56
- }
57
-
58
- // Validate password
59
- const passwordResult = validatePassword('MySecure123', {
60
- minLength: 8,
61
- requireUppercase: true,
62
- requireLowercase: true,
63
- requireNumber: true,
64
- });
65
-
66
- // Validate required field
67
- const requiredResult = validateRequired('value', 'Field Name');
68
- ```
69
-
70
- ### Form Validation Example
71
-
72
- ```typescript
73
- import {
74
- validateEmail,
75
- validatePassword,
76
- validatePasswordConfirmation,
77
- validateRequired,
78
- batchValidate,
79
- } from '@umituz/react-native-validation';
80
-
81
- const validateForm = (email: string, password: string, confirmPassword: string) => {
82
- return batchValidate([
83
- { field: 'email', validator: () => validateEmail(email) },
84
- { field: 'password', validator: () => validatePassword(password) },
85
- {
86
- field: 'confirmPassword',
87
- validator: () => validatePasswordConfirmation(password, confirmPassword),
88
- },
89
- ]);
90
- };
91
-
92
- const result = validateForm('user@example.com', 'MySecure123', 'MySecure123');
93
- if (!result.isValid) {
94
- console.log('Validation errors:', result.errors);
95
- }
96
- ```
97
-
98
- ### Custom Validation
99
-
100
- ```typescript
101
- import { validatePattern, validateNumberRange } from '@umituz/react-native-validation';
102
-
103
- // Validate with custom pattern
104
- const patternResult = validatePattern(
105
- 'ABC123',
106
- /^[A-Z]{3}\d{3}$/,
107
- 'Code',
108
- 'Code must be 3 uppercase letters followed by 3 numbers'
109
- );
110
-
111
- // Validate number range
112
- const rangeResult = validateNumberRange(50, 0, 100, 'Percentage');
113
- ```
114
-
115
- ### Sanitization Example
116
-
117
- ```typescript
118
- import {
119
- sanitizeEmail,
120
- sanitizeName,
121
- sanitizeText,
122
- containsDangerousChars,
123
- SECURITY_LIMITS,
124
- } from '@umituz/react-native-validation';
125
-
126
- // Sanitize email
127
- const cleanEmail = sanitizeEmail(' User@Example.COM ');
128
- // Result: 'user@example.com'
129
-
130
- // Sanitize name
131
- const cleanName = sanitizeName(' John Doe ');
132
- // Result: 'John Doe'
133
-
134
- // Sanitize text (removes HTML tags)
135
- const cleanText = sanitizeText('<script>alert("xss")</script>Hello');
136
- // Result: 'Hello'
137
-
138
- // Check for dangerous characters
139
- const isDangerous = containsDangerousChars('<script>alert("xss")</script>');
140
- // Result: true
141
-
142
- // Check length limits
143
- const isValidLength = isWithinLengthLimit('text', SECURITY_LIMITS.NAME_MAX_LENGTH);
144
- ```
145
-
146
- ### Image Validation Example
147
-
148
- ```typescript
149
- import {
150
- validateImageUri,
151
- getImageMimeType,
152
- validateImageExtension,
153
- IMAGE_MIME_TYPES,
154
- } from '@umituz/react-native-validation';
155
-
156
- // Validate image URI (supports file://, http://, https://, and data: URLs)
157
- const result = validateImageUri('file:///path/to/image.jpg');
158
- if (!result.isValid) {
159
- console.error(result.error);
160
- }
161
-
162
- // Get MIME type from URI
163
- const mimeType = getImageMimeType('file:///path/to/image.png');
164
- // Result: 'image/png'
165
-
166
- // Validate file extension
167
- const extensionResult = validateImageExtension('image.jpg');
168
- if (!extensionResult.isValid) {
169
- console.error(extensionResult.error);
170
- }
171
-
172
- // Use MIME type constants
173
- if (mimeType === IMAGE_MIME_TYPES.PNG) {
174
- console.log('PNG image');
175
- }
176
- ```
177
-
178
- ## API Reference
179
-
180
- ### Core Validators
181
-
182
- - `validateEmail(email: string): ValidationResult`
183
- - `validatePassword(password: string, options?: PasswordOptions): ValidationResult`
184
- - `validatePasswordConfirmation(password: string, confirmPassword: string): ValidationResult`
185
- - `validateRequired(value: string, fieldName?: string): ValidationResult`
186
- - `validateName(name: string, fieldName?: string, minLength?: number): ValidationResult`
187
- - `validatePhone(phone: string): ValidationResult`
188
-
189
- ### Number Validators
190
-
191
- - `validateNumberRange(value: number, min: number, max: number, fieldName?: string): ValidationResult`
192
- - `validatePositiveNumber(value: number, fieldName?: string): ValidationResult`
193
-
194
- ### String Validators
195
-
196
- - `validateMinLength(value: string, minLength: number, fieldName?: string): ValidationResult`
197
- - `validateMaxLength(value: string, maxLength: number, fieldName?: string): ValidationResult`
198
- - `validatePattern(value: string, pattern: RegExp, fieldName?: string, errorMessage?: string): ValidationResult`
199
-
200
- ### Date Validators
201
-
202
- - `validateDateOfBirth(date: Date): ValidationResult`
203
- - `validateAge(age: number): ValidationResult` (13-120 years)
204
-
205
- ### Image Validators
206
-
207
- - `validateImageUri(uri: string, fieldName?: string): ValidationResult` - Validates image URI (supports file://, http://, https://, and data: URLs)
208
- - `validateImageMimeType(mimeType: string, fieldName?: string): ValidationResult` - Validates MIME type is supported image type
209
- - `validateImageExtension(uri: string, fieldName?: string): ValidationResult` - Validates file extension is supported image type
210
- - `validateImageDataUrl(dataUrl: string, fieldName?: string): ValidationResult` - Validates data URL is image type
211
- - `getImageMimeType(uri: string): string | null` - Get MIME type from URI (supports all URI types)
212
-
213
- ### MIME Type Utilities
214
-
215
- - `getMimeTypeFromExtension(uri: string): string | null` - Get MIME type from file extension
216
- - `getMimeTypeFromDataUrl(dataUrl: string): string | null` - Get MIME type from data URL
217
- - `IMAGE_MIME_TYPES` - Supported image MIME types constants
218
- - `SUPPORTED_IMAGE_MIME_TYPES` - Array of supported image MIME types
219
- - `EXTENSION_TO_MIME_TYPE` - File extension to MIME type mapping
220
- - `MIME_TYPE_TO_EXTENSION` - MIME type to file extension mapping
221
-
222
- ### Batch Validation
223
-
224
- - `batchValidate(validations: Array<{ field: string; validator: () => ValidationResult }>): { isValid: boolean; errors: Record<string, string> }`
225
-
226
- ## Types
227
-
228
- ```typescript
229
- interface ValidationResult {
230
- isValid: boolean;
231
- error?: string;
232
- }
233
-
234
- interface PasswordOptions {
235
- minLength?: number;
236
- requireUppercase?: boolean;
237
- requireLowercase?: boolean;
238
- requireNumber?: boolean;
239
- }
240
- ```
241
-
242
- ## License
243
-
244
- MIT
245
-