1import { Logger } from '@expo/xdl'; 2import chalk from 'chalk'; 3import * as fs from 'fs-extra'; 4import pacote from 'pacote'; 5import * as path from 'path'; 6 7const DEFAULT_TEMPLATE = 'expo-module-template@latest'; 8 9/** 10 * Fetches directory from npm or given templateDirectory into destinationPath 11 * @param destinationPath - destination for fetched template 12 * @param template - optional template provided as npm package or local directory 13 */ 14export default async function fetchTemplate(destinationPath: string, template?: string) { 15 if (template && fs.existsSync(path.resolve(template))) { 16 // local template 17 Logger.global.info(`Using local template: ${chalk.bold(path.resolve(template))}.`); 18 await fs.copy(path.resolve(template), destinationPath); 19 } else if (template && isNpmPackage(template)) { 20 // npm package 21 Logger.global.info(`Using NPM package as template: ${chalk.bold(template)}`); 22 await pacote.extract(template, destinationPath); 23 } else { 24 // default npm packge 25 Logger.global.info(`Using default NPM package as template: ${chalk.bold(DEFAULT_TEMPLATE)}`); 26 await pacote.extract(DEFAULT_TEMPLATE, destinationPath); 27 } 28 29 if (await fs.pathExists(path.join(destinationPath, 'template-unimodule.json'))) { 30 await fs.move( 31 path.join(destinationPath, 'template-unimodule.json'), 32 path.join(destinationPath, 'unimodule.json') 33 ); 34 } 35} 36 37function isNpmPackage(template: string) { 38 return ( 39 !template.match(/^\./) && // don't start with . 40 !template.match(/^_/) && // don't start with _ 41 template.toLowerCase() === template && // only lowercase 42 !/[~'!()*]/.test(template.split('/').slice(-1)[0]) && // don't contain any character from [~'!()*] 43 template.match(/^(@([^/]+?)\/)?([^/@]+)(@(((\d\.\d\.\d)(-[^/@]+)?)|latest|next))?$/) // has shape (@scope/)?actual-package-name(@0.1.1(-tag.1)?|tag-name)? 44 ); 45} 46