react-native-architecture-generator 1.1.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/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/dist/bin/rn_arch_gen.d.ts +2 -0
- package/dist/bin/rn_arch_gen.js +41 -0
- package/dist/lib/commands/feature.d.ts +3 -0
- package/dist/lib/commands/feature.js +52 -0
- package/dist/lib/commands/init.d.ts +3 -0
- package/dist/lib/commands/init.js +75 -0
- package/dist/lib/commands/model.d.ts +3 -0
- package/dist/lib/commands/model.js +94 -0
- package/dist/lib/commands/screen.d.ts +4 -0
- package/dist/lib/commands/screen.js +82 -0
- package/dist/lib/index.d.ts +12 -0
- package/dist/lib/index.js +12 -0
- package/dist/lib/models/config.d.ts +27 -0
- package/dist/lib/models/config.js +27 -0
- package/dist/lib/templates/base-templates.d.ts +18 -0
- package/dist/lib/templates/base-templates.js +453 -0
- package/dist/lib/utils/config-helper.d.ts +6 -0
- package/dist/lib/utils/config-helper.js +27 -0
- package/dist/lib/utils/feature-helper.d.ts +24 -0
- package/dist/lib/utils/feature-helper.js +400 -0
- package/dist/lib/utils/file-helper.d.ts +4 -0
- package/dist/lib/utils/file-helper.js +62 -0
- package/dist/lib/utils/packagejson-helper.d.ts +4 -0
- package/dist/lib/utils/packagejson-helper.js +76 -0
- package/dist/lib/utils/string-utils.d.ts +9 -0
- package/dist/lib/utils/string-utils.js +28 -0
- package/package.json +72 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { Routing, StateManagement } from '../models/config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Template generators for all base files in the React Native Clean Architecture project.
|
|
4
|
+
*/
|
|
5
|
+
export class BaseTemplates {
|
|
6
|
+
// ──────────── App Entry Point ────────────
|
|
7
|
+
static appEntryContent(config) {
|
|
8
|
+
const firebaseImport = config.firebase
|
|
9
|
+
? `import { initializeApp } from '@react-native-firebase/app';\n`
|
|
10
|
+
: '';
|
|
11
|
+
const firebaseInit = config.firebase
|
|
12
|
+
? ` // Initialize Firebase\n initializeApp();\n`
|
|
13
|
+
: '';
|
|
14
|
+
return `import React, { useEffect } from 'react';
|
|
15
|
+
import { StatusBar } from 'react-native';
|
|
16
|
+
${firebaseImport}import { AppNavigator } from './navigation/AppNavigator';
|
|
17
|
+
import { ThemeProvider } from './core/theme/ThemeContext';
|
|
18
|
+
${config.stateManagement === StateManagement.redux ? `import { Provider } from 'react-redux';\nimport { store } from './state/store';\n` : ''}${config.stateManagement === StateManagement.zustand ? `// Zustand stores are used directly via hooks\n` : ''}${config.stateManagement === StateManagement.context ? `import { AppProvider } from './state/AppContext';\n` : ''}
|
|
19
|
+
const App: React.FC = () => {
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
${firebaseInit} // App initialization logic
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
${config.stateManagement === StateManagement.redux ? ` <Provider store={store}>
|
|
26
|
+
<ThemeProvider>
|
|
27
|
+
<StatusBar barStyle="dark-content" />
|
|
28
|
+
<AppNavigator />
|
|
29
|
+
</ThemeProvider>
|
|
30
|
+
</Provider>` : config.stateManagement === StateManagement.context ? ` <AppProvider>
|
|
31
|
+
<ThemeProvider>
|
|
32
|
+
<StatusBar barStyle="dark-content" />
|
|
33
|
+
<AppNavigator />
|
|
34
|
+
</ThemeProvider>
|
|
35
|
+
</AppProvider>` : ` <ThemeProvider>
|
|
36
|
+
<StatusBar barStyle="dark-content" />
|
|
37
|
+
<AppNavigator />
|
|
38
|
+
</ThemeProvider>`}
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default App;
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
45
|
+
// ──────────── API Client ────────────
|
|
46
|
+
static apiClientContent() {
|
|
47
|
+
return `import axios from 'axios';
|
|
48
|
+
import Config from 'react-native-config';
|
|
49
|
+
|
|
50
|
+
const apiClient = axios.create({
|
|
51
|
+
baseURL: Config.API_BASE_URL || 'https://api.example.com',
|
|
52
|
+
timeout: 10000,
|
|
53
|
+
headers: {
|
|
54
|
+
'Content-Type': 'application/json',
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Request interceptor
|
|
59
|
+
apiClient.interceptors.request.use(
|
|
60
|
+
(config) => {
|
|
61
|
+
// Add auth token here if needed
|
|
62
|
+
// const token = await AsyncStorage.getItem('token');
|
|
63
|
+
// if (token) config.headers.Authorization = \`Bearer \${token}\`;
|
|
64
|
+
return config;
|
|
65
|
+
},
|
|
66
|
+
(error) => Promise.reject(error)
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Response interceptor
|
|
70
|
+
apiClient.interceptors.response.use(
|
|
71
|
+
(response) => response,
|
|
72
|
+
(error) => {
|
|
73
|
+
// Handle global errors (401, 403, 500, etc.)
|
|
74
|
+
if (error.response) {
|
|
75
|
+
console.error('API Error:', error.response.status, error.response.data);
|
|
76
|
+
}
|
|
77
|
+
return Promise.reject(error);
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
export default apiClient;
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
// ──────────── Error / Failures ────────────
|
|
85
|
+
static failuresContent() {
|
|
86
|
+
return `export abstract class Failure {
|
|
87
|
+
readonly message: string;
|
|
88
|
+
|
|
89
|
+
constructor(message: string) {
|
|
90
|
+
this.message = message;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class ServerFailure extends Failure {
|
|
95
|
+
constructor(message = 'Server Error') {
|
|
96
|
+
super(message);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export class CacheFailure extends Failure {
|
|
101
|
+
constructor(message = 'Cache Error') {
|
|
102
|
+
super(message);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export class NetworkFailure extends Failure {
|
|
107
|
+
constructor(message = 'Network Error') {
|
|
108
|
+
super(message);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export class GeneralFailure extends Failure {
|
|
113
|
+
constructor(message = 'Unexpected Error') {
|
|
114
|
+
super(message);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
// ──────────── Theme ────────────
|
|
120
|
+
static themeContent() {
|
|
121
|
+
return `import { StyleSheet } from 'react-native';
|
|
122
|
+
|
|
123
|
+
export const Colors = {
|
|
124
|
+
primary: '#2196F3',
|
|
125
|
+
primaryDark: '#1976D2',
|
|
126
|
+
primaryLight: '#BBDEFB',
|
|
127
|
+
accent: '#FF4081',
|
|
128
|
+
background: '#FFFFFF',
|
|
129
|
+
surface: '#F5F5F5',
|
|
130
|
+
error: '#F44336',
|
|
131
|
+
textPrimary: '#212121',
|
|
132
|
+
textSecondary: '#757575',
|
|
133
|
+
divider: '#BDBDBD',
|
|
134
|
+
// Dark mode
|
|
135
|
+
darkBackground: '#121212',
|
|
136
|
+
darkSurface: '#1E1E1E',
|
|
137
|
+
darkTextPrimary: '#FFFFFF',
|
|
138
|
+
darkTextSecondary: '#B3B3B3',
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const Spacing = {
|
|
142
|
+
xs: 4,
|
|
143
|
+
sm: 8,
|
|
144
|
+
md: 16,
|
|
145
|
+
lg: 24,
|
|
146
|
+
xl: 32,
|
|
147
|
+
xxl: 48,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const FontSizes = {
|
|
151
|
+
caption: 12,
|
|
152
|
+
body: 14,
|
|
153
|
+
subtitle: 16,
|
|
154
|
+
title: 20,
|
|
155
|
+
headline: 24,
|
|
156
|
+
display: 32,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const globalStyles = StyleSheet.create({
|
|
160
|
+
container: {
|
|
161
|
+
flex: 1,
|
|
162
|
+
backgroundColor: Colors.background,
|
|
163
|
+
},
|
|
164
|
+
centerContent: {
|
|
165
|
+
flex: 1,
|
|
166
|
+
justifyContent: 'center',
|
|
167
|
+
alignItems: 'center',
|
|
168
|
+
},
|
|
169
|
+
screenPadding: {
|
|
170
|
+
paddingHorizontal: Spacing.md,
|
|
171
|
+
paddingVertical: Spacing.sm,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
`;
|
|
175
|
+
}
|
|
176
|
+
// ──────────── Theme Context (light/dark mode) ────────────
|
|
177
|
+
static themeContextContent() {
|
|
178
|
+
return `import React, { createContext, useContext, useState, useMemo } from 'react';
|
|
179
|
+
import { useColorScheme } from 'react-native';
|
|
180
|
+
import { Colors } from './AppTheme';
|
|
181
|
+
|
|
182
|
+
type ThemeMode = 'light' | 'dark' | 'system';
|
|
183
|
+
|
|
184
|
+
interface ThemeContextType {
|
|
185
|
+
mode: ThemeMode;
|
|
186
|
+
isDark: boolean;
|
|
187
|
+
colors: typeof Colors;
|
|
188
|
+
toggleTheme: () => void;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
|
192
|
+
|
|
193
|
+
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
194
|
+
const systemColorScheme = useColorScheme();
|
|
195
|
+
const [mode, setMode] = useState<ThemeMode>('system');
|
|
196
|
+
|
|
197
|
+
const isDark = mode === 'system' ? systemColorScheme === 'dark' : mode === 'dark';
|
|
198
|
+
|
|
199
|
+
const colors = useMemo(() => ({
|
|
200
|
+
...Colors,
|
|
201
|
+
background: isDark ? Colors.darkBackground : Colors.background,
|
|
202
|
+
surface: isDark ? Colors.darkSurface : Colors.surface,
|
|
203
|
+
textPrimary: isDark ? Colors.darkTextPrimary : Colors.textPrimary,
|
|
204
|
+
textSecondary: isDark ? Colors.darkTextSecondary : Colors.textSecondary,
|
|
205
|
+
}), [isDark]);
|
|
206
|
+
|
|
207
|
+
const toggleTheme = () => {
|
|
208
|
+
setMode((prev) => (prev === 'light' ? 'dark' : 'light'));
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<ThemeContext.Provider value={{ mode, isDark, colors, toggleTheme }}>
|
|
213
|
+
{children}
|
|
214
|
+
</ThemeContext.Provider>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export const useTheme = (): ThemeContextType => {
|
|
219
|
+
const context = useContext(ThemeContext);
|
|
220
|
+
if (!context) throw new Error('useTheme must be used within ThemeProvider');
|
|
221
|
+
return context;
|
|
222
|
+
};
|
|
223
|
+
`;
|
|
224
|
+
}
|
|
225
|
+
// ──────────── Navigation / Routing ────────────
|
|
226
|
+
static navigationContent(config) {
|
|
227
|
+
if (config.routing === Routing.expoRouter) {
|
|
228
|
+
return `// Expo Router uses file-based routing.
|
|
229
|
+
// Create your routes in the app/ directory.
|
|
230
|
+
// See: https://docs.expo.dev/router/introduction/
|
|
231
|
+
|
|
232
|
+
export {};
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
// React Navigation
|
|
236
|
+
return `import React from 'react';
|
|
237
|
+
import { NavigationContainer } from '@react-navigation/native';
|
|
238
|
+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
239
|
+
|
|
240
|
+
// Import screens here
|
|
241
|
+
// import { LoginScreen } from '../features/auth/presentation/screens/LoginScreen';
|
|
242
|
+
// import { RegisterScreen } from '../features/auth/presentation/screens/RegisterScreen';
|
|
243
|
+
|
|
244
|
+
export type RootStackParamList = {
|
|
245
|
+
// Define your route params here
|
|
246
|
+
// Login: undefined;
|
|
247
|
+
// Register: undefined;
|
|
248
|
+
// Home: undefined;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const Stack = createNativeStackNavigator<RootStackParamList>();
|
|
252
|
+
|
|
253
|
+
export const AppNavigator: React.FC = () => {
|
|
254
|
+
return (
|
|
255
|
+
<NavigationContainer>
|
|
256
|
+
<Stack.Navigator
|
|
257
|
+
screenOptions={{
|
|
258
|
+
headerShown: true,
|
|
259
|
+
headerStyle: { backgroundColor: '#2196F3' },
|
|
260
|
+
headerTintColor: '#fff',
|
|
261
|
+
headerTitleStyle: { fontWeight: 'bold' },
|
|
262
|
+
}}
|
|
263
|
+
>
|
|
264
|
+
{/* Add your screens here */}
|
|
265
|
+
{/* <Stack.Screen name="Login" component={LoginScreen} /> */}
|
|
266
|
+
{/* <Stack.Screen name="Register" component={RegisterScreen} /> */}
|
|
267
|
+
</Stack.Navigator>
|
|
268
|
+
</NavigationContainer>
|
|
269
|
+
);
|
|
270
|
+
};
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
// ──────────── State Management (Store) ────────────
|
|
274
|
+
static storeContent(config) {
|
|
275
|
+
switch (config.stateManagement) {
|
|
276
|
+
case StateManagement.redux:
|
|
277
|
+
return `import { configureStore } from '@reduxjs/toolkit';
|
|
278
|
+
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
|
279
|
+
|
|
280
|
+
export const store = configureStore({
|
|
281
|
+
reducer: {
|
|
282
|
+
// Add feature reducers here
|
|
283
|
+
},
|
|
284
|
+
middleware: (getDefaultMiddleware) =>
|
|
285
|
+
getDefaultMiddleware({
|
|
286
|
+
serializableCheck: false,
|
|
287
|
+
}),
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
export type RootState = ReturnType<typeof store.getState>;
|
|
291
|
+
export type AppDispatch = typeof store.dispatch;
|
|
292
|
+
|
|
293
|
+
// Typed hooks
|
|
294
|
+
export const useAppDispatch: () => AppDispatch = useDispatch;
|
|
295
|
+
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
|
296
|
+
`;
|
|
297
|
+
case StateManagement.zustand:
|
|
298
|
+
return `// Zustand stores are defined per-feature.
|
|
299
|
+
// Each feature creates its own store using zustand's create().
|
|
300
|
+
//
|
|
301
|
+
// Example:
|
|
302
|
+
// import { create } from 'zustand';
|
|
303
|
+
//
|
|
304
|
+
// interface AuthState {
|
|
305
|
+
// isLoggedIn: boolean;
|
|
306
|
+
// login: () => void;
|
|
307
|
+
// logout: () => void;
|
|
308
|
+
// }
|
|
309
|
+
//
|
|
310
|
+
// export const useAuthStore = create<AuthState>((set) => ({
|
|
311
|
+
// isLoggedIn: false,
|
|
312
|
+
// login: () => set({ isLoggedIn: true }),
|
|
313
|
+
// logout: () => set({ isLoggedIn: false }),
|
|
314
|
+
// }));
|
|
315
|
+
|
|
316
|
+
export {};
|
|
317
|
+
`;
|
|
318
|
+
case StateManagement.context:
|
|
319
|
+
return `import React, { createContext, useContext, useReducer } from 'react';
|
|
320
|
+
|
|
321
|
+
// Define your global app state here
|
|
322
|
+
interface AppState {
|
|
323
|
+
isLoading: boolean;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
type AppAction =
|
|
327
|
+
| { type: 'SET_LOADING'; payload: boolean };
|
|
328
|
+
|
|
329
|
+
const initialState: AppState = {
|
|
330
|
+
isLoading: false,
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const appReducer = (state: AppState, action: AppAction): AppState => {
|
|
334
|
+
switch (action.type) {
|
|
335
|
+
case 'SET_LOADING':
|
|
336
|
+
return { ...state, isLoading: action.payload };
|
|
337
|
+
default:
|
|
338
|
+
return state;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
interface AppContextType {
|
|
343
|
+
state: AppState;
|
|
344
|
+
dispatch: React.Dispatch<AppAction>;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const AppContext = createContext<AppContextType | undefined>(undefined);
|
|
348
|
+
|
|
349
|
+
export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
350
|
+
const [state, dispatch] = useReducer(appReducer, initialState);
|
|
351
|
+
|
|
352
|
+
return (
|
|
353
|
+
<AppContext.Provider value={{ state, dispatch }}>
|
|
354
|
+
{children}
|
|
355
|
+
</AppContext.Provider>
|
|
356
|
+
);
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
export const useAppContext = (): AppContextType => {
|
|
360
|
+
const context = useContext(AppContext);
|
|
361
|
+
if (!context) throw new Error('useAppContext must be used within AppProvider');
|
|
362
|
+
return context;
|
|
363
|
+
};
|
|
364
|
+
`;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
// ──────────── Constants ────────────
|
|
368
|
+
static constantsContent() {
|
|
369
|
+
return `export const AppConstants = {
|
|
370
|
+
appName: 'React Native App',
|
|
371
|
+
apiVersion: 'v1',
|
|
372
|
+
cacheTimeout: 60 * 60 * 1000, // 1 hour in ms
|
|
373
|
+
} as const;
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
// ──────────── .gitignore ────────────
|
|
377
|
+
static gitignoreContent() {
|
|
378
|
+
return `# Environment files
|
|
379
|
+
.env*
|
|
380
|
+
!.env.example
|
|
381
|
+
|
|
382
|
+
# Generator config
|
|
383
|
+
.rn_arch_gen.json
|
|
384
|
+
|
|
385
|
+
# Dependencies
|
|
386
|
+
node_modules/
|
|
387
|
+
|
|
388
|
+
# React Native
|
|
389
|
+
android/app/build/
|
|
390
|
+
ios/Pods/
|
|
391
|
+
ios/build/
|
|
392
|
+
*.hprof
|
|
393
|
+
|
|
394
|
+
# Metro
|
|
395
|
+
.metro-health-check*
|
|
396
|
+
|
|
397
|
+
# IDE
|
|
398
|
+
.idea/
|
|
399
|
+
.vscode/
|
|
400
|
+
*.iml
|
|
401
|
+
*.xcworkspace
|
|
402
|
+
*.xcuserdata
|
|
403
|
+
|
|
404
|
+
# OS
|
|
405
|
+
.DS_Store
|
|
406
|
+
Thumbs.db
|
|
407
|
+
|
|
408
|
+
# Testing
|
|
409
|
+
coverage/
|
|
410
|
+
`;
|
|
411
|
+
}
|
|
412
|
+
// ──────────── Test file ────────────
|
|
413
|
+
static sampleTestContent() {
|
|
414
|
+
return `describe('Sample Test', () => {
|
|
415
|
+
it('should pass a basic assertion', () => {
|
|
416
|
+
expect(1 + 1).toBe(2);
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
`;
|
|
420
|
+
}
|
|
421
|
+
// ──────────── Localization (i18n) ────────────
|
|
422
|
+
static i18nConfigContent() {
|
|
423
|
+
return `import i18n from 'i18next';
|
|
424
|
+
import { initReactI18next } from 'react-i18next';
|
|
425
|
+
import en from './locales/en.json';
|
|
426
|
+
|
|
427
|
+
i18n.use(initReactI18next).init({
|
|
428
|
+
compatibilityJSON: 'v3',
|
|
429
|
+
resources: {
|
|
430
|
+
en: { translation: en },
|
|
431
|
+
},
|
|
432
|
+
lng: 'en',
|
|
433
|
+
fallbackLng: 'en',
|
|
434
|
+
interpolation: {
|
|
435
|
+
escapeValue: false,
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
export default i18n;
|
|
440
|
+
`;
|
|
441
|
+
}
|
|
442
|
+
static localeEnContent() {
|
|
443
|
+
return `{
|
|
444
|
+
"appTitle": "React Native App",
|
|
445
|
+
"welcome": "Welcome",
|
|
446
|
+
"login": "Login",
|
|
447
|
+
"register": "Register",
|
|
448
|
+
"email": "Email",
|
|
449
|
+
"password": "Password"
|
|
450
|
+
}
|
|
451
|
+
`;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const CONFIG_FILE = '.rn_arch_gen.json';
|
|
4
|
+
export class ConfigHelper {
|
|
5
|
+
static async saveConfig(config) {
|
|
6
|
+
await fs.writeJson(path.join(process.cwd(), CONFIG_FILE), config, { spaces: 2 });
|
|
7
|
+
}
|
|
8
|
+
static async getConfig() {
|
|
9
|
+
const configPath = path.join(process.cwd(), CONFIG_FILE);
|
|
10
|
+
if (!(await fs.pathExists(configPath))) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return await fs.readJson(configPath);
|
|
14
|
+
}
|
|
15
|
+
static getProjectName() {
|
|
16
|
+
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
17
|
+
if (!fs.existsSync(pkgPath))
|
|
18
|
+
return 'react_native_project';
|
|
19
|
+
try {
|
|
20
|
+
const pkg = fs.readJsonSync(pkgPath);
|
|
21
|
+
return pkg.name || 'react_native_project';
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return 'react_native_project';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GeneratorConfig } from '../models/config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates feature modules in 4 different architecture patterns:
|
|
4
|
+
* 1. Clean Architecture (Domain → Data → Presentation)
|
|
5
|
+
* 2. Feature-Based (Lightweight, flat structure)
|
|
6
|
+
* 3. Atomic Design + Feature (Atoms → Molecules → Organisms)
|
|
7
|
+
* 4. MVVM with Hooks (Model → ViewModel → View)
|
|
8
|
+
*/
|
|
9
|
+
export declare class FeatureHelper {
|
|
10
|
+
static generateFeature(name: string, config: GeneratorConfig): Promise<void>;
|
|
11
|
+
private static generateCleanArchFeature;
|
|
12
|
+
private static generateFeatureBasedFeature;
|
|
13
|
+
private static generateAtomicDesignFeature;
|
|
14
|
+
private static generateMvvmFeature;
|
|
15
|
+
private static generateStateManagement;
|
|
16
|
+
private static generateAuthScreens;
|
|
17
|
+
private static generateDefaultScreen;
|
|
18
|
+
private static registerInNavigation;
|
|
19
|
+
private static generateCleanArchTest;
|
|
20
|
+
private static generateFeatureBasedTest;
|
|
21
|
+
private static generateAtomicDesignTest;
|
|
22
|
+
private static generateMvvmTest;
|
|
23
|
+
private static writeFile;
|
|
24
|
+
}
|