1import { Command } from '@expo/commander'; 2import JsonFile from '@expo/json-file'; 3import chalk from 'chalk'; 4import * as path from 'path'; 5 6import { PACKAGES_DIR, EXPO_DIR } from '../Constants'; 7import { spawnAsync } from '../Utils'; 8import generateModuleAsync from '../generate-module/generateModuleAsync'; 9 10type ActionOptions = { 11 name: string; 12 template?: string; 13 useLocalTemplate?: boolean; 14}; 15 16async function setupExpoModuleScripts(unimoduleDirectory) { 17 const packageJsonPath = path.join(unimoduleDirectory, 'package.json'); 18 const packageJson = new JsonFile(packageJsonPath); 19 const moduleScriptsVersion = (await JsonFile.getAsync( 20 path.join(PACKAGES_DIR, 'expo-module-scripts', 'package.json'), 21 'version', 22 '' 23 )) as string; 24 25 console.log(`Installing ${chalk.bold.green('expo-module-scripts')}...`); 26 27 await spawnAsync('yarn', ['add', '--dev', `expo-module-scripts@^${moduleScriptsVersion}`], { 28 cwd: unimoduleDirectory, 29 }); 30 31 console.log(`Setting up ${chalk.magenta(path.relative(EXPO_DIR, packageJsonPath))}...`); 32 33 await packageJson.setAsync('scripts', { 34 build: 'expo-module build', 35 clean: 'expo-module clean', 36 lint: 'expo-module lint', 37 test: 'expo-module test', 38 prepare: 'expo-module prepare', 39 prepublishOnly: 'expo-module prepublishOnly', 40 'expo-module': 'expo-module', 41 }); 42 43 await packageJson.setAsync('repository', { 44 type: 'git', 45 url: 'https://github.com/expo/expo.git', 46 directory: path.relative(EXPO_DIR, unimoduleDirectory), 47 }); 48 49 await packageJson.setAsync('bugs', { 50 url: 'https://github.com/expo/expo/issues', 51 }); 52 53 await packageJson.setAsync('jest', { 54 preset: 'expo-module-scripts/ios', 55 }); 56 57 // `expo generate-module` left some junk fields in package.json 58 // TODO(@tsapeta): Probably these keys should be deleted by CLI, but I'd like to do this separately since it needs some other changes as well. 59 await packageJson.deleteKeysAsync(['gitHead', '_resolved', '_integrity', '_from']); 60} 61 62async function action(options: ActionOptions) { 63 if (!options.name) { 64 throw new Error('Missing unimodule name. Run with `--name <string>`.'); 65 } 66 67 const unimoduleDirectory = path.join(PACKAGES_DIR, options.name); 68 69 await generateModuleAsync(unimoduleDirectory, options); 70 71 await setupExpoModuleScripts(unimoduleDirectory); 72} 73 74export default (program: Command) => { 75 program 76 .command('create-unimodule') 77 .alias('cu') 78 .description('Creates a new unimodule under the `packages` folder.') 79 .option('-n, --name <string>', 'Name of the package to create.', null) 80 .option( 81 '--use-local-template', 82 'Uses local `packages/expo-module-template` instead of the one published to NPM. Ignored when -t option is used.' 83 ) 84 .option( 85 '-t, --template <string>', 86 'Local directory or npm package containing template for unimodule' 87 ) 88 .asyncAction(action); 89}; 90