UNPKG

zura-stack-native

Version:

A comprehensive React Native CLI project generator with production-ready setup

249 lines (218 loc) 6.82 kB
const fs = require('fs-extra'); const path = require('path'); const chalk = require('chalk'); class ConfigGenerator { constructor(config) { this.config = config; } async generateAll() { try { await this.generateBabelConfig(); await this.generateTypeScriptConfig(); await this.generateTailwindConfig(); await this.generateMetroConfig(); await this.generateESLintConfig(); if (this.config.testing) { await this.generateJestConfig(); await this.generateJestSetup(); } } catch (error) { throw new Error(`Configuration generation failed: ${error.message}`); } } async generateBabelConfig() { const content = `module.exports = { presets: ['@react-native/babel-preset'], plugins: [ 'react-native-reanimated/plugin', [ 'module-resolver', { root: ['./src'], extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'], alias: { '@': './src', '@components': './src/components', '@screens': './src/screens', '@utils': './src/utils', '@store': './src/store', '@hooks': './src/hooks', }, }, ], ], };`; await fs.writeFile(path.join(this.config.projectPath, 'babel.config.js'), content); } async generateTypeScriptConfig() { const content = `{ "extends": "@react-native/typescript-config/tsconfig.json", "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"], "@screens/*": ["src/screens/*"], "@utils/*": ["src/utils/*"], "@store/*": ["src/store/*"], "@hooks/*": ["src/hooks/*"] }, "types": ["jest", "node"] }, "include": ["src/**/*", "__tests__/**/*", "e2e/**/*"], "exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"] }`; await fs.writeFile(path.join(this.config.projectPath, 'tsconfig.json'), content); } async generateTailwindConfig() { const content = `/** @type {import('tailwindcss').Config} */ module.exports = { content: ["./App.{js,jsx,ts,tsx}", "./src/**/*.{js,jsx,ts,tsx}"], theme: { extend: {}, }, plugins: [], }`; await fs.writeFile(path.join(this.config.projectPath, 'tailwind.config.js'), content); } async generateMetroConfig() { const content = `const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); /** * Metro configuration * https://facebook.github.io/metro/docs/configuration * * @type {import('metro-config').MetroConfig} */ const config = {}; module.exports = mergeConfig(getDefaultConfig(__dirname), config);`; await fs.writeFile(path.join(this.config.projectPath, 'metro.config.js'), content); } async generateESLintConfig() { const content = `module.exports = { root: true, extends: '@react-native', rules: { 'prettier/prettier': 'off', }, };`; await fs.writeFile(path.join(this.config.projectPath, '.eslintrc.js'), content); } async generateJestConfig() { const content = `module.exports = { preset: 'react-native', setupFilesAfterEnv: ['<rootDir>/jest.setup.js'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], transformIgnorePatterns: [ 'node_modules/(?!(react-native|@react-native|@react-navigation|react-native-reanimated|react-native-safe-area-context|react-native-screens|@react-native-community|react-native-vector-icons|react-native-svg|react-native-linear-gradient|@react-native-masked-view|react-native-responsive-screen|react-native-responsive-fontsize|lucide-react-native)/)', ], testEnvironment: 'jsdom', testMatch: [ '<rootDir>/src/**/__tests__/**/*.(ts|tsx|js)', '<rootDir>/src/**/?(*.)(spec|test).(ts|tsx|js)', '<rootDir>/__tests__/**/*.(ts|tsx|js)', ], collectCoverageFrom: [ 'src/**/*.{ts,tsx}', '!src/**/*.d.ts', '!src/**/index.ts', '!src/**/*.stories.{ts,tsx}', ], coverageThreshold: { global: { branches: 70, functions: 70, lines: 70, statements: 70, }, }, moduleNameMapper: { '^@/(.*)$': '<rootDir>/src/$1', '^@/components/(.*)$': '<rootDir>/src/components/$1', '^@/screens/(.*)$': '<rootDir>/src/screens/$1', '^@/utils/(.*)$': '<rootDir>/src/utils/$1', '^@/store/(.*)$': '<rootDir>/src/store/$1', '^@/hooks/(.*)$': '<rootDir>/src/hooks/$1', }, };`; await fs.writeFile(path.join(this.config.projectPath, 'jest.config.js'), content); } async generateJestSetup() { const content = `import '@testing-library/jest-native/extend-expect'; // Mock react-native-reanimated jest.mock('react-native-reanimated', () => { const Reanimated = require('react-native-reanimated/mock'); Reanimated.default.call = () => {}; return Reanimated; }); // Mock react-native-safe-area-context jest.mock('react-native-safe-area-context', () => ({ SafeAreaProvider: ({ children }) => children, SafeAreaView: ({ children }) => children, useSafeAreaInsets: () => ({ top: 0, right: 0, bottom: 0, left: 0, }), })); // Mock react-native-responsive-screen jest.mock('react-native-responsive-screen', () => ({ widthPercentageToDP: jest.fn((width) => width), heightPercentageToDP: jest.fn((height) => height), })); // Mock react-native-responsive-fontsize jest.mock('react-native-responsive-fontsize', () => jest.fn((size) => size)); // Mock lucide-react-native jest.mock('lucide-react-native', () => ({ Home: 'Home', User: 'User', Settings: 'Settings', Bell: 'Bell', Plus: 'Plus', Minus: 'Minus', RotateCcw: 'RotateCcw', LogOut: 'LogOut', Mail: 'Mail', Hash: 'Hash', Moon: 'Moon', Sun: 'Sun', Globe: 'Globe', Smartphone: 'Smartphone', MessageCircle: 'MessageCircle', })); // Mock Dimensions jest.mock('react-native/Libraries/Utilities/Dimensions', () => ({ get: jest.fn().mockReturnValue({ width: 375, height: 812, }), addEventListener: jest.fn(), removeEventListener: jest.fn(), })); // Mock AsyncStorage jest.mock('@react-native-async-storage/async-storage', () => require('@react-native-async-storage/async-storage/jest/async-storage-mock') ); // Mock NativeWind jest.mock('nativewind', () => ({ styled: jest.fn((component) => component), useColorScheme: jest.fn(() => 'light'), })); // Mock react-native-css-interop jest.mock('react-native-css-interop', () => ({ vars: jest.fn(() => ({})), })); // Global test utilities global.console = { ...console, // Uncomment to ignore a specific log level // log: jest.fn(), // debug: jest.fn(), // info: jest.fn(), // warn: jest.fn(), // error: jest.fn(), };`; await fs.writeFile(path.join(this.config.projectPath, 'jest.setup.js'), content); } } module.exports = { ConfigGenerator };