|
| 1 | +/** |
| 2 | + * @author Jade Yeom |
| 3 | + * @email ysw0094@gmail.com |
| 4 | + */ |
| 5 | +var process; |
| 6 | +var commander = require('commander'), fs = require('fs'), path = require('path'), chalk = require('chalk'), walk = require('walk'), inquirer = require('inquirer'), xml2js = require('xml2js'), changeCase = require('change-case'), gjs = require('gradlejs'), shell = require('shelljs'); |
| 7 | +var xmlParser = new xml2js.Parser(); |
| 8 | +var xmlBuilder = new xml2js.Builder(); |
| 9 | +commander.arguments('<name>') |
| 10 | + .version('0.0.1') |
| 11 | + .option('-g, --generate [name]', 'component (e.g activity, fragment etc..)') |
| 12 | + .option('-p, --permission <permission>', 'add uses-permission to manifest file(e.g INTERNET)') |
| 13 | + .option('-d, --dependency <dependency>', 'add dependency to build.gradle and sync gradle') |
| 14 | + .action(function (name) { |
| 15 | + var selectedPackage; |
| 16 | + var parsedJavaContent; |
| 17 | + var parsedXMLContent; |
| 18 | + presentInitialMessage(); |
| 19 | + if (commander.generate) { |
| 20 | + console.log(chalk.yellow(changeCase.pascalCase(commander.generate) + " will generated by Android CLI")); |
| 21 | + getApplicationPackage(function (pacakge) { |
| 22 | + getPackages(pacakge, function (packageList) { |
| 23 | + var questions = [{ |
| 24 | + type: 'list', |
| 25 | + name: 'package', |
| 26 | + message: "Choose your target package path", |
| 27 | + // TODO ADD JAVA PACKAGE PARSED PATH LIST |
| 28 | + choices: packageList |
| 29 | + }]; |
| 30 | + inquirer.prompt(questions).then(function (answers) { |
| 31 | + generateRenderedOutFile(commander.generate, name, answers.package); |
| 32 | + }); |
| 33 | + }); |
| 34 | + }); |
| 35 | + } |
| 36 | +}).parse(process.argv); |
| 37 | +if (commander.permission) { |
| 38 | + console.log(commander.permission); |
| 39 | + addPermissionToManifest(commander.permission, function (xml) { |
| 40 | + try { |
| 41 | + fs.writeFileSync('./app/src/main/AndroidManifest.xml', xml); |
| 42 | + console.log(chalk.green("Successful adding permission")); |
| 43 | + } |
| 44 | + catch (err) { |
| 45 | + console.log(chalk.red("Failed to adding permission")); |
| 46 | + console.log(chalk.red(err)); |
| 47 | + } |
| 48 | + }); |
| 49 | +} |
| 50 | +if (commander.dependency) { |
| 51 | + console.log(commander.dependency); |
| 52 | + var gradlePath_1 = "./app/build.gradle"; |
| 53 | + gjs.parseFile(gradlePath_1).then(function (representation) { |
| 54 | + representation.dependencies.compile.push("'" + commander.dependency + "'"); |
| 55 | + fs.writeFile(gradlePath_1, gjs.makeGradleText(representation), function (err) { |
| 56 | + if (!err) { |
| 57 | + var gradleSyncCommand = ""; |
| 58 | + if (isWindows()) |
| 59 | + gradleSyncCommand = "gradlew.bat build"; |
| 60 | + else |
| 61 | + gradleSyncCommand = "./gradlew build"; |
| 62 | + shell.exec(gradleSyncCommand, function (code, stdout, stderr) { |
| 63 | + console.log('Exit code:', code); |
| 64 | + console.log('Program output:', stdout); |
| 65 | + console.log('Program stderr:', stderr); |
| 66 | + }); |
| 67 | + } |
| 68 | + }); |
| 69 | + }); |
| 70 | +} |
| 71 | +/** |
| 72 | + * @desc Add permission to Manfest |
| 73 | + * |
| 74 | + * @param {string} permissionName - To add permission of name |
| 75 | + */ |
| 76 | +function addPermissionToManifest(permissionName, callback) { |
| 77 | + xmlParser.parseString(getManifestContent(), function (err, result) { |
| 78 | + if (!Array.isArray(result.manifest['uses-permission'])) |
| 79 | + result.manifest['uses-permission'] = []; |
| 80 | + result.manifest['uses-permission'].push({ |
| 81 | + '$': { |
| 82 | + 'android:name': "android.permission." + changeCase.upperCase(permissionName) |
| 83 | + } |
| 84 | + }); |
| 85 | + callback(xmlBuilder.buildObject(result)); |
| 86 | + }); |
| 87 | +} |
| 88 | +/** |
| 89 | + * @desc Parse package name by AndroidManifest.xml |
| 90 | + * |
| 91 | + * @param {function} callback - Call anonymous function when complete xml parse |
| 92 | + */ |
| 93 | +function getApplicationPackage(callback) { |
| 94 | + // TODO GET REAL PATH |
| 95 | + xmlParser.parseString(getManifestContent(), function (err, result) { |
| 96 | + callback(result.manifest.$.package); |
| 97 | + }); |
| 98 | +} |
| 99 | +function getManifestContent() { |
| 100 | + return fs.readFileSync('./app/src/main/AndroidManifest.xml'); |
| 101 | +} |
| 102 | +/** |
| 103 | + * @desc Parse package name list by walk module |
| 104 | + * |
| 105 | + * @param {string} packageName - Name of targeted package name |
| 106 | + * @param {function} callback - Call anonymous function when walker had end event |
| 107 | + */ |
| 108 | +function getPackages(packageName, callback) { |
| 109 | + var packageList = []; |
| 110 | + var options = { |
| 111 | + followLinks: false |
| 112 | + }; |
| 113 | + packageList.push(packageName); |
| 114 | + var walker = walk.walk("./app/src/main/java/" + packageName.replace(/\./gi, '/'), options); |
| 115 | + walker.on("directories", function (root, dirStatsArray, next) { |
| 116 | + for (var _i = 0, dirStatsArray_1 = dirStatsArray; _i < dirStatsArray_1.length; _i++) { |
| 117 | + var dir = dirStatsArray_1[_i]; |
| 118 | + packageList.push(root + "/" + dir.name.replace(/\//gi, ".")); |
| 119 | + } |
| 120 | + next(); |
| 121 | + }); |
| 122 | + walker.on("end", function () { |
| 123 | + callback(packageList.map(function (value) { |
| 124 | + return value |
| 125 | + .replace('./app/src/main/java/', '') |
| 126 | + .replace(/\//gi, '.'); |
| 127 | + })); |
| 128 | + }); |
| 129 | +} |
| 130 | +/** |
| 131 | + * @desc Render boilerplate file by our specific format |
| 132 | + * |
| 133 | + * @param {string} fileContent - Content of boilerplate file |
| 134 | + * @param {string} pkgName - Targeted package name |
| 135 | + * @param {string} componentName - Name of componentName |
| 136 | + * |
| 137 | + * @return {string} - Content of rendered file |
| 138 | + */ |
| 139 | +function renderAcFile(fileContent, pkgName, componentName) { |
| 140 | + return fileContent |
| 141 | + .replace(/{%packageName%}/gi, pkgName) |
| 142 | + .replace(/{%activityName%}/gi, changeCase.pascalCase(componentName)) |
| 143 | + .replace(/{%activityNameLowerCase%}/gi, changeCase.lowerCase(componentName)); |
| 144 | +} |
| 145 | +/** |
| 146 | + * @desc Generate rendered out file |
| 147 | + * |
| 148 | + * @param {string} componentType - Type of component |
| 149 | + * @param {string} componentName - Name of component |
| 150 | + * @param {string} targetPkg - Targeted package name |
| 151 | + */ |
| 152 | +function generateRenderedOutFile(componentType, componentName, targetPkg) { |
| 153 | + var boilerplatesPath = "./boilerplates/" + componentType; |
| 154 | + var boilerplateNameOfJAVA = componentType + ".ac.src"; |
| 155 | + var boilerplateNameOfXML = componentType + "_layout.ac.layout"; |
| 156 | + var javaFileName = "" + changeCase.pascalCase(componentName) + changeCase.pascalCase(componentType) + ".java"; |
| 157 | + var xmlFileName = changeCase.lowerCase(componentType) + "_" + changeCase.lowerCase(componentName) + ".xml"; |
| 158 | + var javaContent = fs.readFileSync(boilerplatesPath + "/" + boilerplateNameOfJAVA, 'utf-8').toString(); |
| 159 | + var xmlContent = fs.readFileSync(boilerplatesPath + "/" + boilerplateNameOfXML, 'utf-8').toString(); |
| 160 | + var parsedJavaContent = renderAcFile(javaContent, targetPkg, componentName); |
| 161 | + var parsedXMLContent = renderAcFile(xmlContent, targetPkg, componentName); |
| 162 | + try { |
| 163 | + fs.writeFileSync("./app/src/main/java/" + targetPkg.replace(/\./gi, '/') + "/" + javaFileName, parsedJavaContent); |
| 164 | + console.log(chalk.green("Successful generate " + componentType + " " + javaFileName)); |
| 165 | + } |
| 166 | + catch (err) { |
| 167 | + console.log(chalk.red("Failed to generate " + componentType + " " + javaFileName)); |
| 168 | + console.log(chalk.red(err)); |
| 169 | + } |
| 170 | + try { |
| 171 | + fs.writeFileSync("./app/src/main/res/layout/" + xmlFileName /*TODO GET REAL PATH*/, parsedXMLContent); |
| 172 | + console.log(chalk.green("Successful generate layout file " + xmlFileName)); |
| 173 | + } |
| 174 | + catch (err) { |
| 175 | + console.log(chalk.red("Failed to generate layout file " + xmlFileName)); |
| 176 | + console.log(chalk.red(err)); |
| 177 | + } |
| 178 | +} |
| 179 | +/** |
| 180 | + * @desc Just present initial message |
| 181 | + */ |
| 182 | +function presentInitialMessage() { |
| 183 | + console.log(chalk.cyan(" ___ _ _____ ___ ____ _______ _______ ____")); |
| 184 | + console.log(chalk.cyan(" / _ | / |/ / _ \/ _ \/ __ \/ _/ _ \ / ___/ / / _/")); |
| 185 | + console.log(chalk.cyan(" / __ |/ / // / , _/ /_/ // // // / / /__/ /___/ / ")); |
| 186 | + console.log(chalk.cyan("/_/ |_/_/|_/____/_/|_|\____/___/____/ \___/____/___/ ")); |
| 187 | + console.log(chalk.cyan(" ")); |
| 188 | +} |
| 189 | +function isWindows() { |
| 190 | + return /^win/.test(process.platform); |
| 191 | +} |
0 commit comments