@umituz/react-native-filesystem 1.0.0

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 ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@umituz/react-native-filesystem",
3
+ "version": "1.0.0",
4
+ "description": "Domain-Driven Design filesystem utilities for React Native apps with build-time module loading and runtime file operations",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
+ "scripts": {
8
+ "typecheck": "tsc --noEmit",
9
+ "lint": "tsc --noEmit",
10
+ "version:patch": "npm version patch -m 'chore: release v%s'",
11
+ "version:minor": "npm version minor -m 'chore: release v%s'",
12
+ "version:major": "npm version major -m 'chore: release v%s'"
13
+ },
14
+ "keywords": [
15
+ "react-native",
16
+ "filesystem",
17
+ "file-system",
18
+ "expo-file-system",
19
+ "module-loader",
20
+ "require-context",
21
+ "ddd",
22
+ "domain-driven-design",
23
+ "type-safe"
24
+ ],
25
+ "author": "Ümit UZ <umit@umituz.com>",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git@github.com:umituz/react-native-filesystem.git"
30
+ },
31
+ "peerDependencies": {
32
+ "expo-file-system": "~17.0.0",
33
+ "react": ">=18.2.0",
34
+ "react-native": ">=0.74.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/react": "^18.2.45",
38
+ "@types/react-native": "^0.73.0",
39
+ "expo-file-system": "~17.0.0",
40
+ "react": "^18.2.0",
41
+ "react-native": "^0.74.0",
42
+ "typescript": "^5.3.3"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "files": [
48
+ "src",
49
+ "README.md",
50
+ "LICENSE"
51
+ ]
52
+ }
53
+
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Filesystem Domain - File Entities
3
+ *
4
+ * This file defines core types and interfaces for runtime file operations.
5
+ * Uses expo-file-system for reading, writing, and managing files on device.
6
+ *
7
+ * @domain filesystem
8
+ * @layer domain/entities
9
+ */
10
+
11
+ /**
12
+ * File information interface
13
+ */
14
+ export interface FileInfo {
15
+ uri: string;
16
+ name: string;
17
+ size: number;
18
+ exists: boolean;
19
+ isDirectory: boolean;
20
+ modificationTime: number;
21
+ }
22
+
23
+ /**
24
+ * File encoding types (compatible with expo-file-system)
25
+ */
26
+ export type FileEncoding = 'utf8' | 'base64';
27
+
28
+ /**
29
+ * Directory type (compatible with expo-file-system)
30
+ */
31
+ export type DirectoryType = 'documentDirectory' | 'cacheDirectory';
32
+
33
+ /**
34
+ * File operation result
35
+ */
36
+ export interface FileOperationResult {
37
+ success: boolean;
38
+ uri?: string;
39
+ error?: string;
40
+ }
41
+
42
+ /**
43
+ * Download progress info
44
+ */
45
+ export interface DownloadProgress {
46
+ totalBytesWritten: number;
47
+ totalBytesExpectedToWrite: number;
48
+ progress: number; // 0 to 1
49
+ }
50
+
51
+ /**
52
+ * File constants
53
+ */
54
+ export const FILE_CONSTANTS = {
55
+ MAX_FILE_NAME_LENGTH: 255,
56
+ DEFAULT_ENCODING: 'utf8' as FileEncoding,
57
+ TEMP_FILE_PREFIX: 'tmp_',
58
+ } as const;
59
+
60
+ /**
61
+ * File utilities
62
+ */
63
+ export class FileUtils {
64
+ /**
65
+ * Generate unique filename with timestamp
66
+ */
67
+ static generateUniqueFilename(originalName: string): string {
68
+ const timestamp = Date.now();
69
+ const randomStr = Math.random().toString(36).substring(7);
70
+ const extension = FileUtils.getFileExtension(originalName);
71
+ const baseName = originalName.replace(extension, '').substring(0, 50);
72
+ return `${baseName}_${timestamp}_${randomStr}${extension}`;
73
+ }
74
+
75
+ /**
76
+ * Get file extension from filename
77
+ */
78
+ static getFileExtension(filename: string): string {
79
+ const match = filename.match(/\.[^.]+$/);
80
+ return match ? match[0] : '';
81
+ }
82
+
83
+ /**
84
+ * Get filename without extension
85
+ */
86
+ static getFilenameWithoutExtension(filename: string): string {
87
+ return filename.replace(/\.[^.]+$/, '');
88
+ }
89
+
90
+ /**
91
+ * Sanitize filename (remove invalid characters)
92
+ */
93
+ static sanitizeFilename(filename: string): string {
94
+ return filename
95
+ .replace(/[^a-zA-Z0-9._-]/g, '_')
96
+ .substring(0, FILE_CONSTANTS.MAX_FILE_NAME_LENGTH);
97
+ }
98
+
99
+ /**
100
+ * Format file size to human-readable string
101
+ */
102
+ static formatFileSize(bytes: number): string {
103
+ if (bytes === 0) return '0 B';
104
+ const k = 1024;
105
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
106
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
107
+ return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
108
+ }
109
+
110
+ /**
111
+ * Parse download progress percentage
112
+ */
113
+ static calculateProgress(written: number, total: number): number {
114
+ if (total === 0) return 0;
115
+ return Math.min(Math.max(written / total, 0), 1);
116
+ }
117
+
118
+ /**
119
+ * Check if path is absolute
120
+ */
121
+ static isAbsolutePath(path: string): boolean {
122
+ return path.startsWith('/') || path.startsWith('file://');
123
+ }
124
+
125
+ /**
126
+ * Join path segments
127
+ */
128
+ static joinPaths(...segments: string[]): string {
129
+ return segments
130
+ .filter(Boolean)
131
+ .join('/')
132
+ .replace(/\/+/g, '/');
133
+ }
134
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Module Context Entity
3
+ *
4
+ * Type definitions for Metro bundler's require.context feature
5
+ * Used for automatic file discovery and module loading
6
+ */
7
+
8
+ /**
9
+ * Metro bundler require.context return type
10
+ */
11
+ export interface RequireContext {
12
+ keys(): string[];
13
+ (id: string): any;
14
+ <T>(id: string): T;
15
+ resolve(id: string): string;
16
+ id: string;
17
+ }
18
+
19
+ /**
20
+ * Module collection type
21
+ * Key: module name (without extension)
22
+ * Value: module content
23
+ */
24
+ export type ModuleCollection = Record<string, any>;
25
+
26
+ /**
27
+ * File extension type for filtering
28
+ */
29
+ export type FileExtension = '.json' | '.js' | '.ts' | '.tsx';
package/src/index.ts ADDED
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Filesystem Domain - Barrel Export
3
+ *
4
+ * CENTRAL PLACE FOR ALL FILE OPERATIONS
5
+ *
6
+ * Provides two main capabilities:
7
+ * 1. Build-time module loading (require.context)
8
+ * 2. Runtime file operations (expo-file-system)
9
+ *
10
+ * @domain filesystem
11
+ * @enabled true (All apps - Infrastructure domain)
12
+ *
13
+ * ARCHITECTURE:
14
+ * - Domain Layer: Entities (ModuleContext for build-time, File for runtime)
15
+ * - Infrastructure Layer: Utils (module loading) + Services (file operations)
16
+ *
17
+ * ============================================================================
18
+ * BUILD-TIME MODULE LOADING (require.context)
19
+ * ============================================================================
20
+ *
21
+ * FEATURES:
22
+ * - Auto-discover JSON files in directory
23
+ * - Load all modules with single function call
24
+ * - Type-safe module loading
25
+ * - Metro bundler compatible (React Native)
26
+ * - Zero runtime dependencies
27
+ * - Build-time resolution (fast)
28
+ *
29
+ * USAGE - Build-time Module Loading:
30
+ *
31
+ * Basic Example:
32
+ * ```typescript
33
+ * import { loadJsonModules } from '@domains/filesystem';
34
+ *
35
+ * // Auto-load all JSON files in current directory
36
+ * const translationContext = require.context('./', false, /\.json$/);
37
+ * const translations = loadJsonModules(translationContext);
38
+ *
39
+ * export default translations;
40
+ * // Result: { common: {...}, errors: {...}, settings: {...} }
41
+ * ```
42
+ *
43
+ * Custom Transform Example:
44
+ * ```typescript
45
+ * import { loadModulesWithTransform } from '@domains/filesystem';
46
+ *
47
+ * const context = require.context('./', false, /\.json$/);
48
+ * const modules = loadModulesWithTransform(context, name => name.toUpperCase());
49
+ * // Result: { COMMON: {...}, ERRORS: {...} }
50
+ * ```
51
+ *
52
+ * Get Names Example:
53
+ * ```typescript
54
+ * import { getModuleNames } from '@domains/filesystem';
55
+ *
56
+ * const context = require.context('./', false, /\.json$/);
57
+ * const names = getModuleNames(context);
58
+ * // Result: ['common', 'errors', 'settings']
59
+ * ```
60
+ *
61
+ * ============================================================================
62
+ * RUNTIME FILE OPERATIONS (expo-file-system)
63
+ * ============================================================================
64
+ *
65
+ * FEATURES:
66
+ * - Read/write files on device
67
+ * - Download files from URLs
68
+ * - Directory management
69
+ * - Cache management
70
+ * - File copying/moving
71
+ *
72
+ * USAGE - Runtime File Operations:
73
+ *
74
+ * Read/Write Files:
75
+ * ```typescript
76
+ * import { FileSystemService } from '@domains/filesystem';
77
+ *
78
+ * // Write file
79
+ * const result = await FileSystemService.writeFile(
80
+ * FileSystemService.generateFilePath('data.json'),
81
+ * JSON.stringify({ key: 'value' })
82
+ * );
83
+ *
84
+ * // Read file
85
+ * const content = await FileSystemService.readFile(result.uri);
86
+ * ```
87
+ *
88
+ * Download Files:
89
+ * ```typescript
90
+ * import { FileSystemService } from '@domains/filesystem';
91
+ *
92
+ * const result = await FileSystemService.downloadFile(
93
+ * 'https://example.com/file.pdf'
94
+ * );
95
+ * if (result.success) {
96
+ * console.log('Downloaded to:', result.uri);
97
+ * }
98
+ * ```
99
+ *
100
+ * Directory Operations:
101
+ * ```typescript
102
+ * import { FileSystemService, FileUtils } from '@domains/filesystem';
103
+ *
104
+ * // Get document directory
105
+ * const docDir = FileSystemService.getDocumentDirectory();
106
+ *
107
+ * // List files
108
+ * const files = await FileSystemService.listDirectory(docDir);
109
+ *
110
+ * // Clear cache
111
+ * await FileSystemService.clearCache();
112
+ * ```
113
+ *
114
+ * File Utilities:
115
+ * ```typescript
116
+ * import { FileUtils } from '@domains/filesystem';
117
+ *
118
+ * // Format file size
119
+ * const size = FileUtils.formatFileSize(1024000); // "1.00 MB"
120
+ *
121
+ * // Generate unique filename
122
+ * const filename = FileUtils.generateUniqueFilename('photo.jpg');
123
+ *
124
+ * // Sanitize filename
125
+ * const safe = FileUtils.sanitizeFilename('my file!@#.txt'); // "my_file___.txt"
126
+ * ```
127
+ *
128
+ * BENEFITS:
129
+ * - Centralized file operations (no duplication)
130
+ * - Type-safe with TypeScript
131
+ * - Works across all 100+ apps
132
+ * - Used by other domains (media, etc.)
133
+ * - Clean, maintainable code
134
+ *
135
+ * @see https://docs.expo.dev/versions/latest/sdk/filesystem/
136
+ */
137
+
138
+ // ============================================================================
139
+ // BUILD-TIME MODULE LOADING
140
+ // ============================================================================
141
+
142
+ // Domain Layer - Module Context Entities
143
+ export type {
144
+ RequireContext,
145
+ ModuleCollection,
146
+ FileExtension,
147
+ } from './domain/entities/ModuleContext';
148
+
149
+ // Infrastructure Layer - Module Loading Utils
150
+ export {
151
+ loadJsonModules,
152
+ loadModulesWithTransform,
153
+ getModuleNames,
154
+ } from './infrastructure/utils/moduleLoader';
155
+
156
+ // ============================================================================
157
+ // RUNTIME FILE OPERATIONS
158
+ // ============================================================================
159
+
160
+ // Domain Layer - File Entities
161
+ export type {
162
+ FileInfo,
163
+ FileOperationResult,
164
+ DownloadProgress,
165
+ } from './domain/entities/File';
166
+
167
+ export type {
168
+ FileEncoding,
169
+ DirectoryType,
170
+ } from './domain/entities/File';
171
+
172
+ export {
173
+ FILE_CONSTANTS,
174
+ FileUtils,
175
+ } from './domain/entities/File';
176
+
177
+ // Infrastructure Layer - FileSystem Service
178
+ export { FileSystemService } from './infrastructure/services/FileSystemService';
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Filesystem Domain - FileSystem Service
3
+ *
4
+ * Service for runtime file operations using expo-file-system.
5
+ * Provides abstraction layer for file read/write/delete operations on device.
6
+ *
7
+ * @domain filesystem
8
+ * @layer infrastructure/services
9
+ */
10
+
11
+ import * as FileSystem from 'expo-file-system';
12
+ import type { FileInfo, FileOperationResult, DirectoryType, FileEncoding } from '../../domain/entities/File';
13
+ import { FileUtils } from '../../domain/entities/File';
14
+
15
+ /**
16
+ * FileSystem service for device file operations
17
+ *
18
+ * CENTRAL PLACE FOR ALL FILE OPERATIONS
19
+ * - Reading/writing files
20
+ * - Directory management
21
+ * - File downloads
22
+ * - Cache management
23
+ *
24
+ * Used by other domains (media, etc.) for file operations
25
+ */
26
+ export class FileSystemService {
27
+ /**
28
+ * Get file information
29
+ */
30
+ static async getFileInfo(uri: string): Promise<FileInfo | null> {
31
+ try {
32
+ const info = await FileSystem.getInfoAsync(uri);
33
+
34
+ if (!info.exists) {
35
+ return null;
36
+ }
37
+
38
+ return {
39
+ uri,
40
+ name: uri.split('/').pop() || '',
41
+ size: info.size || 0,
42
+ exists: info.exists,
43
+ isDirectory: info.isDirectory || false,
44
+ modificationTime: info.modificationTime || 0,
45
+ };
46
+ } catch (error) {
47
+ return null;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Read file as string
53
+ */
54
+ static async readFile(uri: string, encoding: FileEncoding = 'utf8'): Promise<string | null> {
55
+ try {
56
+ const content = await FileSystem.readAsStringAsync(uri, { encoding });
57
+ return content;
58
+ } catch (error) {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Write string to file
65
+ */
66
+ static async writeFile(uri: string, content: string, encoding: FileEncoding = 'utf8'): Promise<FileOperationResult> {
67
+ try {
68
+ await FileSystem.writeAsStringAsync(uri, content, { encoding });
69
+ return { success: true, uri };
70
+ } catch (error) {
71
+ return { success: false, error: error instanceof Error ? error.message : 'Unknown error' };
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Delete file or directory
77
+ */
78
+ static async deleteFile(uri: string): Promise<boolean> {
79
+ try {
80
+ await FileSystem.deleteAsync(uri, { idempotent: true });
81
+ return true;
82
+ } catch (error) {
83
+ return false;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Copy file
89
+ */
90
+ static async copyFile(sourceUri: string, destinationUri: string): Promise<FileOperationResult> {
91
+ try {
92
+ await FileSystem.copyAsync({
93
+ from: sourceUri,
94
+ to: destinationUri,
95
+ });
96
+ return { success: true, uri: destinationUri };
97
+ } catch (error) {
98
+ return { success: false, error: error instanceof Error ? error.message : 'Unknown error' };
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Move file
104
+ */
105
+ static async moveFile(sourceUri: string, destinationUri: string): Promise<FileOperationResult> {
106
+ try {
107
+ await FileSystem.moveAsync({
108
+ from: sourceUri,
109
+ to: destinationUri,
110
+ });
111
+ return { success: true, uri: destinationUri };
112
+ } catch (error) {
113
+ return { success: false, error: error instanceof Error ? error.message : 'Unknown error' };
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Create directory
119
+ */
120
+ static async createDirectory(uri: string): Promise<boolean> {
121
+ try {
122
+ await FileSystem.makeDirectoryAsync(uri, { intermediates: true });
123
+ return true;
124
+ } catch (error) {
125
+ return false;
126
+ }
127
+ }
128
+
129
+ /**
130
+ * List directory contents
131
+ */
132
+ static async listDirectory(uri: string): Promise<string[]> {
133
+ try {
134
+ const files = await FileSystem.readDirectoryAsync(uri);
135
+ return files;
136
+ } catch (error) {
137
+ return [];
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Check if file exists
143
+ */
144
+ static async exists(uri: string): Promise<boolean> {
145
+ try {
146
+ const info = await FileSystem.getInfoAsync(uri);
147
+ return info.exists;
148
+ } catch (error) {
149
+ return false;
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Get directory path by type
155
+ */
156
+ static getDirectoryPath(type: DirectoryType): string {
157
+ switch (type) {
158
+ case 'documentDirectory':
159
+ return FileSystem.documentDirectory || '';
160
+ case 'cacheDirectory':
161
+ return FileSystem.cacheDirectory || '';
162
+ default:
163
+ return '';
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Get document directory path
169
+ */
170
+ static getDocumentDirectory(): string {
171
+ return FileSystemService.getDirectoryPath('documentDirectory');
172
+ }
173
+
174
+ /**
175
+ * Get cache directory path
176
+ */
177
+ static getCacheDirectory(): string {
178
+ return FileSystemService.getDirectoryPath('cacheDirectory');
179
+ }
180
+
181
+ /**
182
+ * Generate unique file path in specified directory
183
+ */
184
+ static generateFilePath(filename: string, directory: DirectoryType = 'documentDirectory'): string {
185
+ const dirPath = FileSystemService.getDirectoryPath(directory);
186
+ const uniqueFilename = FileUtils.generateUniqueFilename(filename);
187
+ return FileUtils.joinPaths(dirPath, uniqueFilename);
188
+ }
189
+
190
+ /**
191
+ * Download file from URL
192
+ */
193
+ static async downloadFile(url: string, destinationUri?: string): Promise<FileOperationResult> {
194
+ try {
195
+ const destination = destinationUri || FileSystemService.generateFilePath('download');
196
+ const result = await FileSystem.downloadAsync(url, destination);
197
+ return { success: true, uri: result.uri };
198
+ } catch (error) {
199
+ return { success: false, error: error instanceof Error ? error.message : 'Download failed' };
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Get file size
205
+ */
206
+ static async getFileSize(uri: string): Promise<number> {
207
+ const info = await FileSystemService.getFileInfo(uri);
208
+ return info?.size || 0;
209
+ }
210
+
211
+ /**
212
+ * Clear cache directory
213
+ */
214
+ static async clearCache(): Promise<boolean> {
215
+ try {
216
+ const cacheDir = FileSystemService.getCacheDirectory();
217
+ if (!cacheDir) return false;
218
+
219
+ const files = await FileSystemService.listDirectory(cacheDir);
220
+ await Promise.all(
221
+ files.map(file => FileSystemService.deleteFile(FileUtils.joinPaths(cacheDir, file)))
222
+ );
223
+ return true;
224
+ } catch (error) {
225
+ return false;
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Get total size of directory
231
+ */
232
+ static async getDirectorySize(uri: string): Promise<number> {
233
+ try {
234
+ const files = await FileSystemService.listDirectory(uri);
235
+ const sizes = await Promise.all(
236
+ files.map(async file => {
237
+ const filePath = FileUtils.joinPaths(uri, file);
238
+ const info = await FileSystemService.getFileInfo(filePath);
239
+ return info?.size || 0;
240
+ })
241
+ );
242
+ return sizes.reduce((total, size) => total + size, 0);
243
+ } catch (error) {
244
+ return 0;
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Copy file to cache directory
250
+ */
251
+ static async copyToCache(sourceUri: string, filename?: string): Promise<FileOperationResult> {
252
+ const name = filename || sourceUri.split('/').pop() || 'file';
253
+ const destinationUri = FileSystemService.generateFilePath(name, 'cacheDirectory');
254
+ return FileSystemService.copyFile(sourceUri, destinationUri);
255
+ }
256
+
257
+ /**
258
+ * Copy file to document directory
259
+ */
260
+ static async copyToDocuments(sourceUri: string, filename?: string): Promise<FileOperationResult> {
261
+ const name = filename || sourceUri.split('/').pop() || 'file';
262
+ const destinationUri = FileSystemService.generateFilePath(name, 'documentDirectory');
263
+ return FileSystemService.copyFile(sourceUri, destinationUri);
264
+ }
265
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Module Loader Utilities
3
+ *
4
+ * Provides automatic module loading using Metro bundler's require.context
5
+ * Used for auto-discovering and importing files at build time
6
+ *
7
+ * USAGE:
8
+ * ```typescript
9
+ * // Auto-load all JSON files in current directory
10
+ * const context = require.context('./', false, /\.json$/);
11
+ * const modules = loadJsonModules(context);
12
+ * ```
13
+ */
14
+
15
+ import type { RequireContext, ModuleCollection } from '../../domain/entities/ModuleContext';
16
+
17
+ /**
18
+ * Load JSON modules from a require.context
19
+ *
20
+ * @param context - Metro bundler require.context result
21
+ * @returns Object with module names as keys and content as values
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const translationContext = require.context('./', false, /\.json$/);
26
+ * const translations = loadJsonModules(translationContext);
27
+ * // Result: { common: {...}, errors: {...}, settings: {...} }
28
+ * ```
29
+ */
30
+ export function loadJsonModules(context: RequireContext): ModuleCollection {
31
+ const modules: ModuleCollection = {};
32
+
33
+ context.keys().forEach((key: string) => {
34
+ // Extract module name from path
35
+ // './animation.json' -> 'animation'
36
+ // './common.json' -> 'common'
37
+ const moduleName = key
38
+ .replace('./', '')
39
+ .replace(/\.(json|js|ts|tsx)$/, '');
40
+
41
+ // Load module content
42
+ modules[moduleName] = context(key);
43
+ });
44
+
45
+ return modules;
46
+ }
47
+
48
+ /**
49
+ * Load modules with custom name transformation
50
+ *
51
+ * @param context - Metro bundler require.context result
52
+ * @param transformName - Function to transform module name
53
+ * @returns Object with transformed names as keys
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const context = require.context('./', false, /\.json$/);
58
+ * const modules = loadModulesWithTransform(context, name => name.toUpperCase());
59
+ * // Result: { COMMON: {...}, ERRORS: {...} }
60
+ * ```
61
+ */
62
+ export function loadModulesWithTransform(
63
+ context: RequireContext,
64
+ transformName: (name: string) => string
65
+ ): ModuleCollection {
66
+ const modules: ModuleCollection = {};
67
+
68
+ context.keys().forEach((key: string) => {
69
+ const baseName = key
70
+ .replace('./', '')
71
+ .replace(/\.(json|js|ts|tsx)$/, '');
72
+
73
+ const transformedName = transformName(baseName);
74
+ modules[transformedName] = context(key);
75
+ });
76
+
77
+ return modules;
78
+ }
79
+
80
+ /**
81
+ * Get list of module names from context
82
+ *
83
+ * @param context - Metro bundler require.context result
84
+ * @returns Array of module names (without extensions)
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const context = require.context('./', false, /\.json$/);
89
+ * const names = getModuleNames(context);
90
+ * // Result: ['animation', 'common', 'errors', 'settings']
91
+ * ```
92
+ */
93
+ export function getModuleNames(context: RequireContext): string[] {
94
+ return context.keys().map((key: string) =>
95
+ key
96
+ .replace('./', '')
97
+ .replace(/\.(json|js|ts|tsx)$/, '')
98
+ );
99
+ }