ignite-boilerplate-andross-typescript
Version:
Customized version of ignite Andross With TypeScript Support.
398 lines (348 loc) • 13.9 kB
JavaScript
const options = require('./options')
const { merge, pipe, assoc, omit, __ } = require('ramda')
const { getReactNativeVersion } = require('./lib/react-native-version')
const patterns = require('./lib/patterns')
/**
* Is Android installed?
*
* $ANDROID_HOME/tools folder has to exist.
*
* @param {*} context - The gluegun context.
* @returns {boolean}
*/
const isAndroidInstalled = function (context) {
const androidHome = process.env['ANDROID_HOME']
const hasAndroidEnv = !context.strings.isBlank(androidHome)
const hasAndroid = hasAndroidEnv && context.filesystem.exists(`${androidHome}/tools`) === 'dir'
return Boolean(hasAndroid)
}
/**
* Let's install.
*
* @param {any} context - The gluegun context.
*/
async function install (context) {
const {
filesystem,
parameters,
ignite,
reactNative,
print,
system,
prompt,
template
} = context
const { colors } = print
const { red, yellow, bold, gray, blue } = colors
const perfStart = (new Date()).getTime()
const name = parameters.third
const spinner = print
.spin(`using the ${blue('Andross Typescript')} ignite boilerplate`)
.succeed()
// attempt to install React Native or die trying
const rnInstall = await reactNative.install({
name,
version: getReactNativeVersion(context)
})
if (rnInstall.exitCode > 0) process.exit(rnInstall.exitCode)
// remove the __tests__ directory and App.js that come with React Native
filesystem.remove('__tests__')
filesystem.remove('App.js')
// copy our App, Tests & storybook directories
spinner.text = '▸ copying files'
spinner.start()
filesystem.copy(`${__dirname}/boilerplate/App`, `${process.cwd()}/App`, {
overwrite: true,
matching: '!*.ejs'
})
spinner.stop()
// --max, --min, interactive
let answers
if (parameters.options.max) {
answers = options.answers.max
} else if (parameters.options.min) {
answers = options.answers.min
} else {
answers = await prompt.ask(options.questions)
}
// generate some templates
spinner.text = '▸ generating files'
const templates = [
{ template: 'index.js.ejs', target: 'index.js' },
{ template: 'README.md', target: 'README.md' },
{ template: 'ignite.json.ejs', target: 'ignite/ignite.json' },
{ template: '.editorconfig', target: '.editorconfig' },
{ template: '.babelrc', target: '.babelrc' },
{ template: '.env.example', target: '.env.example' },
{ template: 'rn-cli.config.js', target: 'rn-cli.config.js' },
{ template: 'TestConfig/Setup/test-preprocessor.js', target: 'TestConfig/Setup/test-preprocessor.js' },
{ template: 'TestConfig/Setup/test-setup.js', target: 'TestConfig/Setup/test-setup.js' },
{ template: 'TestConfig/Setup/test-shim.js', target: 'TestConfig/Setup/test-shim.js' },
{ template: 'TestConfig/__mocks__/fileMock.js', target: 'TestConfig/__mocks__/fileMock.js' },
{ template: 'TestConfig/__mocks__/react-native-i18n.mock.js', target: 'TestConfig/__mocks__/react-native-i18n.mock.js' },
{ template: 'TestConfig/__mocks__/react-native-mapbox-gl.mock.js', target: 'TestConfig/__mocks__/react-native-mapbox-gl.mock.js' },
{ template: 'TestConfig/__mocks__/styleMock.js', target: 'TestConfig/__mocks__/styleMock.js' },
{ template: 'tsconfig.json', target: 'tsconfig.json' },
{ template: 'jsconfig.json', target: 'jsconfig.json' },
{ template: 'tslint.json', target: 'tslint.json' },
{ template: 'typings.d.ts', target: 'typings.d.ts' },
{ template: 'app.json', target: 'app.json' }
]
const templateProps = {
name,
igniteVersion: ignite.version,
reactNativeVersion: rnInstall.version,
}
await ignite.copyBatch(context, templates, templateProps, {
quiet: true,
directory: `${ignite.ignitePluginPath()}/boilerplate`
})
/**
* Append to files
*/
// https://github.com/facebook/react-native/issues/12724
filesystem.appendAsync('.gitattributes', '*.bat text eol=crlf')
filesystem.append('.gitignore', '\n# Misc\n#')
filesystem.append('.gitignore', '\n.env\n')
/**
* Merge the package.json from our template into the one provided from react-native init.
*/
async function mergePackageJsons () {
// transform our package.json in case we need to replace variables
const rawJson = await template.generate({
directory: `${ignite.ignitePluginPath()}/boilerplate`,
template: 'package.json.ejs',
props: templateProps
})
const newPackageJson = JSON.parse(rawJson)
// read in the react-native created package.json
const currentPackage = filesystem.read('package.json', 'json')
// deep merge, lol
const newPackage = pipe(
assoc(
'dependencies',
merge(currentPackage.dependencies, newPackageJson.dependencies)
),
assoc(
'devDependencies',
merge(currentPackage.devDependencies, newPackageJson.devDependencies)
),
assoc('scripts', merge(currentPackage.scripts, newPackageJson.scripts)),
merge(
__,
omit(['dependencies', 'devDependencies', 'scripts'], newPackageJson)
)
)(currentPackage)
// write this out
filesystem.write('package.json', newPackage, { jsonIndent: 2 })
}
await mergePackageJsons()
spinner.stop()
// react native link -- must use spawn & stdio: ignore or it hangs!! :(
spinner.text = `▸ linking native libraries`
spinner.start()
await system.spawn('react-native link', { stdio: 'ignore' })
spinner.stop()
// pass long the debug flag if we're running in that mode
const debugFlag = parameters.options.debug ? '--debug' : ''
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// NOTE(steve): I'm re-adding this here because boilerplates now hold permanent files
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
try {
// boilerplate adds itself to get plugin.js/generators etc
// Could be directory, npm@version, or just npm name. Default to passed in values
const boilerplate = parameters.options.b || parameters.options.boilerplate || 'ignite-ir-boilerplate-andross'
await system.spawn(`ignite add ${boilerplate} ${debugFlag}`, { stdio: 'inherit' })
// now run install of Ignite Plugins
switch ((answers['login-screen'])) {
case 'No Login Screen':{
break;
}
case 'Simple Login Screen':{
spinner.text = '▸ copying files'
spinner.start()
filesystem.copy(`${__dirname}/templates/login`, `${process.cwd()}/App`, {
overwrite: true
})
spinner.stop()
break;
}
case 'Sms Login Screen':{
spinner.text = '▸ copying files'
spinner.start()
filesystem.copy(`${__dirname}/templates/smslogin`, `${process.cwd()}/App`, {
overwrite: true
})
spinner.stop()
break;
}
}
switch ((answers['main-screen'])) {
case 'Simple Screen':{
break;
}
case 'Bottom Tabbed Screen':{
spinner.text = '▸ copying files'
spinner.start()
filesystem.copy(`${__dirname}/templates/tabbed/Components`, `${process.cwd()}/App/Components`, {
overwrite: true
})
spinner.stop()
const props = { name:'LaunchScreen' }
const jobs = [
{
template: 'tabbed/Containers/LaunchScreen.ejs',
target: `App/Containers/LaunchScreen.tsx`
},
{
template: 'tabbed/Containers/MainTabs/FifthTab.tsx',
target: `App/Containers/LaunchScreenTabs/FifthTab.tsx`
},
{
template: 'tabbed/Containers/MainTabs/FirstTab.tsx',
target: `App/Containers/LaunchScreenTabs/FirstTab.tsx`
},
{
template: 'tabbed/Containers/MainTabs/FourthTab.tsx',
target: `App/Containers/LaunchScreenTabs/FourthTab.tsx`
},
{
template: 'tabbed/Containers/MainTabs/SecondTab.tsx',
target: `App/Containers/LaunchScreenTabs/SecondTab.tsx`
},
{
template: 'tabbed/Containers/MainTabs/ThirdTab.tsx',
target: `App/Containers/LaunchScreenTabs/ThirdTab.tsx`
}
]
await ignite.copyBatch(context, jobs, props)
break;
}
case 'Top Tabbed Screen':{
spinner.text = '▸ copying files'
spinner.start()
filesystem.copy(`${__dirname}/templates/toptabbed/Components`, `${process.cwd()}/App/Components`, {
overwrite: true
})
spinner.stop()
const props = { name:'LaunchScreen' }
const jobs = [
{
template: 'toptabbed/Containers/ttlaunchscreen.ejs',
target: `App/Containers/LaunchScreen.tsx`
},
{
template: 'toptabbed/Containers/MainTabs/CallsScreen.tsx',
target: `App/Containers/LaunchScreenTabs/CallsScreen.tsx`
},
{
template: 'toptabbed/Containers/MainTabs/ChatsScreen.tsx',
target: `App/Containers/LaunchScreenTabs/ChatsScreen.tsx`
},
{
template: 'toptabbed/Containers/MainTabs/GroupsScreen.tsx',
target: `App/Containers/LaunchScreenTabs/GroupsScreen.tsx`
}
]
await ignite.copyBatch(context, jobs, props)
break;
}
case 'Navigation Drawer Screen':{
spinner.text = '▸ copying files'
spinner.start()
filesystem.copy(`${__dirname}/templates/drawer/Components`, `${process.cwd()}/App/Components`, {
overwrite: true
})
spinner.stop()
const props = { name:'LaunchScreen' }
const jobs = [
{
template: 'drawer/Containers/LaunchScreen.ejs',
target: `App/Containers/LaunchScreen.tsx`
},
{
template: 'drawer/Containers/MainTabs/FifthTab.tsx',
target: `App/Containers/LaunchScreenTabs/FifthTab.tsx`
},
{
template: 'drawer/Containers/MainTabs/FirstTab.tsx',
target: `App/Containers/LaunchScreenTabs/FirstTab.tsx`
},
{
template: 'drawer/Containers/MainTabs/FourthTab.tsx',
target: `App/Containers/LaunchScreenTabs/FourthTab.tsx`
},
{
template: 'drawer/Containers/MainTabs/SecondTab.tsx',
target: `App/Containers/LaunchScreenTabs/SecondTab.tsx`
},
{
template: 'drawer/Containers/MainTabs/ThirdTab.tsx',
target: `App/Containers/LaunchScreenTabs/ThirdTab.tsx`
}
]
await ignite.copyBatch(context, jobs, props)
break;
}
case 'Social Media Screen':{
spinner.text = '▸ copying files'
spinner.start()
filesystem.copy(`${__dirname}/templates/socialmedia`, `${process.cwd()}/App`, {
overwrite: true
})
spinner.stop()
const appNavFilePath = `${process.cwd()}/App/Navigation/AppNavigation.tsx`
const importToAdd = `import ChatScreen from '../Containers/ChatScreen'`
const routeToAdd = ` ChatScreen: { screen: ChatScreen },`
if (!filesystem.exists(appNavFilePath)) {
const msg = `No '${appNavFilePath}' file found. Can't insert container.`
print.error(msg)
process.exit(1)
}
// insert container import
ignite.patchInFile(appNavFilePath, {
after: patterns[patterns.constants.PATTERN_IMPORTS],
insert: importToAdd
})
// insert container route
ignite.patchInFile(appNavFilePath, {
after: patterns[patterns.constants.PATTERN_ROUTES],
insert: routeToAdd
})
break;
}
}
} catch (e) {
ignite.log(e)
throw e
}
// git configuration
const gitExists = await filesystem.exists('./.git')
if (!gitExists && !parameters.options['skip-git'] && system.which('git')) {
// initial git
const spinner = print.spin('configuring git')
// TODO: Make husky hooks optional
const huskyCmd = '' // `&& node node_modules/husky/bin/install .`
system.run(`git init . && git add . && git commit -m "Initial commit." ${huskyCmd}`)
spinner.succeed(`configured git`)
}
const perfDuration = parseInt(((new Date()).getTime() - perfStart) / 10) / 100
spinner.succeed(`ignited ${yellow(name)} in ${perfDuration}s`)
const androidInfo = isAndroidInstalled(context) ? ''
: `\n\nTo run in Android, make sure you've followed the latest react-native setup instructions at https://facebook.github.io/react-native/docs/getting-started.html before using ignite.\nYou won't be able to run ${bold('react-native run-android')} successfully until you have.`
const successMessage = `
${red('Ignite CLI')} ignited ${yellow(name)} in ${gray(`${perfDuration}s`)}
To get started:
cd ${name}
react-native run-ios
react-native run-android${androidInfo}
ignite --help
${gray('Read the walkthrough at https://github.com/infinitered/ignite-ir-boilerplate-andross/blob/master/readme.md#boilerplate-walkthrough')}
${blue('Need additional help? Join our Slack community at http://community.infinite.red.')}
${bold('Now get cooking! 🍽')}
`
print.info(successMessage)
}
module.exports = {
install
}