@umituz/react-native-validation 1.2.0 → 1.3.1
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
|
@@ -39,6 +39,8 @@ npm install @umituz/react-native-validation
|
|
|
39
39
|
|
|
40
40
|
### General
|
|
41
41
|
- ✅ TypeScript type safety
|
|
42
|
+
- ✅ Image file validation (prevents zip, exe, etc.)
|
|
43
|
+
- ✅ MIME type validation
|
|
42
44
|
|
|
43
45
|
## Usage
|
|
44
46
|
|
|
@@ -141,6 +143,38 @@ const isDangerous = containsDangerousChars('<script>alert("xss")</script>');
|
|
|
141
143
|
const isValidLength = isWithinLengthLimit('text', SECURITY_LIMITS.NAME_MAX_LENGTH);
|
|
142
144
|
```
|
|
143
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
|
+
|
|
144
178
|
## API Reference
|
|
145
179
|
|
|
146
180
|
### Core Validators
|
|
@@ -168,6 +202,23 @@ const isValidLength = isWithinLengthLimit('text', SECURITY_LIMITS.NAME_MAX_LENGT
|
|
|
168
202
|
- `validateDateOfBirth(date: Date): ValidationResult`
|
|
169
203
|
- `validateAge(age: number): ValidationResult` (13-120 years)
|
|
170
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
|
+
|
|
171
222
|
### Batch Validation
|
|
172
223
|
|
|
173
224
|
- `batchValidate(validations: Array<{ field: string; validator: () => ValidationResult }>): { isValid: boolean; errors: Record<string, string> }`
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -40,3 +40,23 @@ export {
|
|
|
40
40
|
isWithinLengthLimit,
|
|
41
41
|
} from './infrastructure/utils/sanitization';
|
|
42
42
|
|
|
43
|
+
// Infrastructure Layer - MIME Type Validation
|
|
44
|
+
export {
|
|
45
|
+
IMAGE_MIME_TYPES,
|
|
46
|
+
SUPPORTED_IMAGE_MIME_TYPES,
|
|
47
|
+
EXTENSION_TO_MIME_TYPE,
|
|
48
|
+
MIME_TYPE_TO_EXTENSION,
|
|
49
|
+
} from './infrastructure/utils/mime-types.constants';
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
getFileExtension,
|
|
53
|
+
getMimeTypeFromExtension,
|
|
54
|
+
getMimeTypeFromDataUrl,
|
|
55
|
+
validateImageMimeType,
|
|
56
|
+
validateImageExtension,
|
|
57
|
+
validateImageDataUrl,
|
|
58
|
+
} from './infrastructure/utils/mime-type-validator';
|
|
59
|
+
|
|
60
|
+
// Infrastructure Layer - Image Validation
|
|
61
|
+
export { validateImageUri, getImageMimeType } from './infrastructure/utils/image-validator';
|
|
62
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Validator
|
|
3
|
+
* Single Responsibility: Validate image files and URIs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ValidationResult } from '../../domain/entities/ValidationResult';
|
|
7
|
+
import {
|
|
8
|
+
validateImageExtension,
|
|
9
|
+
validateImageDataUrl,
|
|
10
|
+
getMimeTypeFromExtension,
|
|
11
|
+
getMimeTypeFromDataUrl,
|
|
12
|
+
} from './mime-type-validator';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Check if URI is a local file path
|
|
16
|
+
*/
|
|
17
|
+
function isLocalFileUrl(uri: string): boolean {
|
|
18
|
+
return uri.startsWith('file://');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check if URI is a public URL
|
|
23
|
+
*/
|
|
24
|
+
function isPublicUrl(uri: string): boolean {
|
|
25
|
+
return uri.startsWith('http://') || uri.startsWith('https://');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if URI is a data URL
|
|
30
|
+
*/
|
|
31
|
+
function isDataUrl(uri: string): boolean {
|
|
32
|
+
return uri.startsWith('data:');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Validate image URI (supports file://, http://, https://, and data: URLs)
|
|
37
|
+
*/
|
|
38
|
+
export function validateImageUri(
|
|
39
|
+
uri: string,
|
|
40
|
+
fieldName: string = 'Image'
|
|
41
|
+
): ValidationResult {
|
|
42
|
+
if (!uri || uri.trim() === '') {
|
|
43
|
+
return { isValid: false, error: `${fieldName} is required` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Validate public URLs (assume they're images if they have image extension)
|
|
47
|
+
if (isPublicUrl(uri)) {
|
|
48
|
+
return validateImageExtension(uri, fieldName);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Validate data URLs
|
|
52
|
+
if (isDataUrl(uri)) {
|
|
53
|
+
return validateImageDataUrl(uri, fieldName);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Validate local file URLs
|
|
57
|
+
if (isLocalFileUrl(uri)) {
|
|
58
|
+
return validateImageExtension(uri, fieldName);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Unknown format
|
|
62
|
+
return {
|
|
63
|
+
isValid: false,
|
|
64
|
+
error: `${fieldName} must be a valid image URL or file path`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get MIME type from URI (supports all URI types)
|
|
70
|
+
*/
|
|
71
|
+
export function getImageMimeType(uri: string): string | null {
|
|
72
|
+
if (isDataUrl(uri)) {
|
|
73
|
+
return getMimeTypeFromDataUrl(uri);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return getMimeTypeFromExtension(uri);
|
|
77
|
+
}
|
|
78
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIME Type Validator
|
|
3
|
+
* Single Responsibility: Validate MIME types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ValidationResult } from '../../domain/entities/ValidationResult';
|
|
7
|
+
import {
|
|
8
|
+
SUPPORTED_IMAGE_MIME_TYPES,
|
|
9
|
+
EXTENSION_TO_MIME_TYPE,
|
|
10
|
+
} from './mime-types.constants';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get file extension from URI
|
|
14
|
+
*/
|
|
15
|
+
export function getFileExtension(uri: string): string | null {
|
|
16
|
+
const match = uri.match(/\.([a-z0-9]+)(?:\?|$)/i);
|
|
17
|
+
return match ? match[1].toLowerCase() : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get MIME type from file extension
|
|
22
|
+
*/
|
|
23
|
+
export function getMimeTypeFromExtension(uri: string): string | null {
|
|
24
|
+
const extension = getFileExtension(uri);
|
|
25
|
+
if (!extension) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return EXTENSION_TO_MIME_TYPE[extension] || null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get MIME type from data URL
|
|
33
|
+
*/
|
|
34
|
+
export function getMimeTypeFromDataUrl(dataUrl: string): string | null {
|
|
35
|
+
const match = dataUrl.match(/^data:([^;]+);/);
|
|
36
|
+
return match ? match[1] : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Validate MIME type is supported image type
|
|
41
|
+
*/
|
|
42
|
+
export function validateImageMimeType(
|
|
43
|
+
mimeType: string,
|
|
44
|
+
fieldName: string = 'File'
|
|
45
|
+
): ValidationResult {
|
|
46
|
+
if (!mimeType) {
|
|
47
|
+
return { isValid: false, error: `${fieldName} MIME type is required` };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!SUPPORTED_IMAGE_MIME_TYPES.includes(mimeType as any)) {
|
|
51
|
+
return {
|
|
52
|
+
isValid: false,
|
|
53
|
+
error: `${fieldName} must be an image (JPEG, PNG, WEBP, or GIF)`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { isValid: true };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Validate file extension is supported image type
|
|
62
|
+
*/
|
|
63
|
+
export function validateImageExtension(
|
|
64
|
+
uri: string,
|
|
65
|
+
fieldName: string = 'File'
|
|
66
|
+
): ValidationResult {
|
|
67
|
+
const mimeType = getMimeTypeFromExtension(uri);
|
|
68
|
+
if (!mimeType) {
|
|
69
|
+
return {
|
|
70
|
+
isValid: false,
|
|
71
|
+
error: `${fieldName} must have a valid image extension (jpg, jpeg, png, webp, gif)`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return validateImageMimeType(mimeType, fieldName);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Validate data URL is image type
|
|
80
|
+
*/
|
|
81
|
+
export function validateImageDataUrl(
|
|
82
|
+
dataUrl: string,
|
|
83
|
+
fieldName: string = 'File'
|
|
84
|
+
): ValidationResult {
|
|
85
|
+
if (!dataUrl || !dataUrl.startsWith('data:')) {
|
|
86
|
+
return {
|
|
87
|
+
isValid: false,
|
|
88
|
+
error: `${fieldName} must be a valid data URL`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const mimeType = getMimeTypeFromDataUrl(dataUrl);
|
|
93
|
+
if (!mimeType) {
|
|
94
|
+
return {
|
|
95
|
+
isValid: false,
|
|
96
|
+
error: `${fieldName} must have a valid MIME type`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return validateImageMimeType(mimeType, fieldName);
|
|
101
|
+
}
|
|
102
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIME Type Constants
|
|
3
|
+
* Single Responsibility: Define supported MIME types for validation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Supported image MIME types
|
|
8
|
+
*/
|
|
9
|
+
export const IMAGE_MIME_TYPES = {
|
|
10
|
+
JPEG: 'image/jpeg',
|
|
11
|
+
JPG: 'image/jpeg',
|
|
12
|
+
PNG: 'image/png',
|
|
13
|
+
WEBP: 'image/webp',
|
|
14
|
+
GIF: 'image/gif',
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* All supported image MIME types as array
|
|
19
|
+
*/
|
|
20
|
+
export const SUPPORTED_IMAGE_MIME_TYPES = Object.values(IMAGE_MIME_TYPES);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* File extension to MIME type mapping
|
|
24
|
+
*/
|
|
25
|
+
export const EXTENSION_TO_MIME_TYPE: Record<string, string> = {
|
|
26
|
+
jpg: IMAGE_MIME_TYPES.JPEG,
|
|
27
|
+
jpeg: IMAGE_MIME_TYPES.JPEG,
|
|
28
|
+
png: IMAGE_MIME_TYPES.PNG,
|
|
29
|
+
webp: IMAGE_MIME_TYPES.WEBP,
|
|
30
|
+
gif: IMAGE_MIME_TYPES.GIF,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* MIME type to file extension mapping
|
|
35
|
+
*/
|
|
36
|
+
export const MIME_TYPE_TO_EXTENSION: Record<string, string> = {
|
|
37
|
+
[IMAGE_MIME_TYPES.JPEG]: 'jpg',
|
|
38
|
+
[IMAGE_MIME_TYPES.PNG]: 'png',
|
|
39
|
+
[IMAGE_MIME_TYPES.WEBP]: 'webp',
|
|
40
|
+
[IMAGE_MIME_TYPES.GIF]: 'gif',
|
|
41
|
+
};
|
|
42
|
+
|