apa-cli
Version:
118 lines (96 loc) • 4.89 kB
JavaScript
import { execa } from 'execa';
import { Command } from 'commander';
import inquirer from 'inquirer';
import chalk from 'chalk';
import fs from 'fs';
import path from 'path';
const program = new Command();
program
.version('1.2.0')
.description('React Native project generator using custom template');
program
.command('init <project-name>')
.description('Create a new React Native project with the custom template')
.option('-v, --version <version>', 'Specify template version', 'latest')
.action(async (projectName, cmdObj) => {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'appName',
message: 'What is your app name?',
default: projectName,
},
{
type: 'input',
name: 'packageName',
message: 'Enter the Android package name (e.g., com.example.app):',
validate: (input) => {
const valid = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(input);
return valid || 'Please enter a valid package name (e.g., com.example.app)';
}
},
{
type: 'input',
name: 'version',
message: 'Enter the version of the template you want to use (e.g., v1.0.0), or press Enter for latest:',
default: cmdObj.version,
}
]);
const { appName, packageName, version } = answers;
const templateRepo = 'https://github.com/apadeveloper/react-native-template'; // Your template repo
console.log(chalk.green(`Cloning template version ${version} from ${templateRepo}`));
try {
const cloneCommand = version === 'latest'
? ['clone', templateRepo, projectName] // If 'latest', just clone the main branch
: ['clone', '--branch', version, templateRepo, projectName]; // Else, clone the specific version
await execa('git', cloneCommand);
// Change directory into the project folder
process.chdir(projectName);
updateAppNameAndPackage(appName, packageName, projectName);
console.log(chalk.green('Installing dependencies...'));
await execa('npm', ['install']); // Or yarn install if you prefer
console.log(chalk.green('Your project is ready!'));
console.log(chalk.green(`cd ${projectName} && npm start`));
} catch (error) {
console.error(chalk.red('Error while cloning or setting up the project:'), error);
}
});
function updateAppNameAndPackage(appName, packageName, projectName) {
const appJsonPath = path.join(process.cwd(), 'app.json');
const appJson = JSON.parse(fs.readFileSync(appJsonPath, 'utf8'));
appJson.name = appName;
appJson.displayName = appName;
fs.writeFileSync(appJsonPath, JSON.stringify(appJson, null, 2));
updateAndroidPackageName(packageName, projectName);
updateIOSBundleIdentifier(packageName, appName);
}
function updateAndroidPackageName(packageName, projectName) {
const androidManifestPath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'AndroidManifest.xml');
const buildGradlePath = path.join(process.cwd(), 'android', 'app', 'build.gradle');
let androidManifest = fs.readFileSync(androidManifestPath, 'utf8');
androidManifest = androidManifest.replace(/package="[^"]+"/, `package="${packageName}"`);
fs.writeFileSync(androidManifestPath, androidManifest, 'utf8');
let buildGradle = fs.readFileSync(buildGradlePath, 'utf8');
buildGradle = buildGradle.replace(/applicationId ".*"/, `applicationId "${packageName}"`);
fs.writeFileSync(buildGradlePath, buildGradle, 'utf8');
const packagePath = packageName.replace(/\./g, '/');
const oldPackagePath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'java', 'com', projectName.toLowerCase());
const newPackagePath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'java', ...packageName.split('.'));
fs.mkdirSync(newPackagePath, { recursive: true });
fs.readdirSync(oldPackagePath).forEach(file => {
fs.renameSync(path.join(oldPackagePath, file), path.join(newPackagePath, file));
});
fs.rmdirSync(oldPackagePath, { recursive: true });
}
function updateIOSBundleIdentifier(bundleIdentifier, appName) {
const plistPath = path.join(process.cwd(), 'ios', `${appName}/Info.plist`);
const projectPath = path.join(process.cwd(), 'ios', `${appName}.xcodeproj`, 'project.pbxproj');
let plistContent = fs.readFileSync(plistPath, 'utf8');
plistContent = plistContent.replace(/<key>CFBundleIdentifier<\/key>\s*<string>.*<\/string>/, `<key>CFBundleIdentifier</key>\n\t<string>${bundleIdentifier}</string>`);
fs.writeFileSync(plistPath, plistContent, 'utf8');
let projectContent = fs.readFileSync(projectPath, 'utf8');
projectContent = projectContent.replace(/PRODUCT_BUNDLE_IDENTIFIER = .*;/g, `PRODUCT_BUNDLE_IDENTIFIER = ${bundleIdentifier};`);
fs.writeFileSync(projectPath, projectContent, 'utf8');
}
program.parse(process.argv);