UNPKG

@react-native-community/bob

Version:
343 lines (291 loc) 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = create; exports.args = void 0; var _path = _interopRequireDefault(require("path")); var _fsExtra = _interopRequireDefault(require("fs-extra")); var _ejs = _interopRequireDefault(require("ejs")); var _dedent = _interopRequireDefault(require("dedent")); var _chalk = _interopRequireDefault(require("chalk")); var _crossSpawn = _interopRequireDefault(require("cross-spawn")); var _validateNpmPackageName = _interopRequireDefault(require("validate-npm-package-name")); var _githubUsername = _interopRequireDefault(require("github-username")); var _prompts = _interopRequireDefault(require("./utils/prompts")); var _package = _interopRequireDefault(require("../package.json")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const BINARIES = /(gradlew|\.(jar|keystore|png|jpg|gif))$/; const COMMON_FILES = _path.default.resolve(__dirname, '../templates/common'); const JS_FILES = _path.default.resolve(__dirname, '../templates/js-library'); const EXPO_FILES = _path.default.resolve(__dirname, '../templates/expo-library'); const CPP_FILES = _path.default.resolve(__dirname, '../templates/cpp-library'); const EXAMPLE_FILES = _path.default.resolve(__dirname, '../templates/example'); // Android const NATIVE_FILES = moduleType => { switch (moduleType) { case 'module': return _path.default.resolve(__dirname, '../templates/native-library'); case 'view': return _path.default.resolve(__dirname, '../templates/native-view-library'); } }; // Objc const OBJC_FILES = moduleType => { switch (moduleType) { case 'module': return _path.default.resolve(__dirname, '../templates/objc-library'); case 'view': return _path.default.resolve(__dirname, '../templates/objc-view-library'); } }; // Swift const SWIFT_FILES = moduleType => { switch (moduleType) { case 'module': return _path.default.resolve(__dirname, '../templates/swift-library'); case 'view': return _path.default.resolve(__dirname, '../templates/swift-view-library'); } }; const args = { 'slug': { description: 'Name of the npm package', type: 'string' }, 'description': { description: 'Description of the npm package', type: 'string' }, 'author-name': { description: 'Name of the package author', type: 'string' }, 'author-email': { description: 'Email address of the package author', type: 'string' }, 'author-url': { description: 'URL for the package author', type: 'string' }, 'repo-url': { description: 'URL for the repository', type: 'string' }, 'type': { description: 'Type package do you want to develop', choices: ['native', 'native-swift', 'js', 'cpp', 'expo'] } }; exports.args = args; async function create(argv) { const folder = _path.default.join(process.cwd(), argv.name); if (await _fsExtra.default.pathExists(folder)) { console.log(`A folder already exists at ${_chalk.default.blue(folder)}! Please specify another folder name or delete the existing one.`); process.exit(1); } let name, email; try { name = _crossSpawn.default.sync('git', ['config', '--get', 'user.name']).stdout.toString().trim(); email = _crossSpawn.default.sync('git', ['config', '--get', 'user.email']).stdout.toString().trim(); } catch (e) {// Ignore error } const basename = _path.default.basename(argv.name); const questions = { 'slug': { type: 'text', name: 'slug', message: 'What is the name of the npm package?', initial: (0, _validateNpmPackageName.default)(basename).validForNewPackages ? /^(@|react-native)/.test(basename) ? basename : `react-native-${basename}` : undefined, validate: input => (0, _validateNpmPackageName.default)(input).validForNewPackages || 'Must be a valid npm package name' }, 'description': { type: 'text', name: 'description', message: 'What is the description for the package?', validate: input => Boolean(input) || 'Cannot be empty' }, 'author-name': { type: 'text', name: 'authorName', message: 'What is the name of package author?', initial: name, validate: input => Boolean(input) || 'Cannot be empty' }, 'author-email': { type: 'text', name: 'authorEmail', message: 'What is the email address for the package author?', initial: email, validate: input => /^\S+@\S+$/.test(input) || 'Must be a valid email address' }, 'author-url': { type: 'text', name: 'authorUrl', message: 'What is the URL for the package author?', // @ts-ignore: this is supported, but types are wrong initial: async previous => { try { const username = await (0, _githubUsername.default)(previous); return `https://github.com/${username}`; } catch (e) {// Ignore error } return undefined; }, validate: input => /^https?:\/\//.test(input) || 'Must be a valid URL' }, 'repo-url': { type: 'text', name: 'repoUrl', message: 'What is the URL for the repository?', // @ts-ignore: this is supported, but types are wrong initial: (_, answers) => { if (/^https?:\/\/github.com\/[^/]+/.test(answers.authorUrl)) { return `${answers.authorUrl}/${answers.slug.replace(/^@/, '').replace(/\//g, '-')}`; } return ''; }, validate: input => /^https?:\/\//.test(input) || 'Must be a valid URL' }, 'type': { type: 'select', name: 'type', message: 'What type of package do you want to develop?', choices: [{ title: 'Native module in Kotlin and Objective-C', value: 'native' }, { title: 'Native module in Kotlin and Swift', value: 'native-swift' }, { title: 'Native module with C++ code', value: 'cpp' }, { title: 'Native view in Kotlin and Objective-C', value: 'native-view' }, { title: 'Native view in Kotlin and Swift', value: 'native-view-swift' }, { title: 'JavaScript library with native example', value: 'js' }, { title: 'JavaScript library with Expo example and Web support', value: 'expo' }] } }; const { slug, description, authorName, authorEmail, authorUrl, repoUrl, type } = { ...argv, ...(await (0, _prompts.default)(Object.entries(questions).filter(([k, v]) => !(argv[k] && v.validate ? v.validate(argv[k]) === true : Boolean(argv[k]))).map(([, v]) => v))) }; const project = slug.replace(/^(react-native-|@[^/]+\/)/, ''); const moduleType = type === 'native-view' || type === 'native-view-swift' ? 'view' : 'module'; const options = { bob: { version: _package.default.version }, project: { slug, description, name: `${project.charAt(0).toUpperCase()}${project.replace(/[^a-z0-9](\w)/g, (_, $1) => $1.toUpperCase()).slice(1)}`, package: slug.replace(/[^a-z0-9]/g, '').toLowerCase(), podspec: slug.replace(/[^a-z0-9]+/g, '-').replace(/^-/, ''), native: type === 'native' || type === 'cpp' || 'native-swift' || 'native-view' || 'native-view-swift', cpp: type === 'cpp', swift: type === 'native-swift' || 'native-view-swift', module: type !== 'js', moduleType }, author: { name: authorName, email: authorEmail, url: authorUrl }, repo: repoUrl }; const copyDir = async (source, dest) => { await _fsExtra.default.mkdirp(dest); const files = await _fsExtra.default.readdir(source); for (const f of files) { const target = _path.default.join(dest, _ejs.default.render(f.replace(/^\$/, ''), options, { openDelimiter: '{', closeDelimiter: '}' })); const file = _path.default.join(source, f); const stats = await _fsExtra.default.stat(file); if (stats.isDirectory()) { await copyDir(file, target); } else if (!file.match(BINARIES)) { const content = await _fsExtra.default.readFile(file, 'utf8'); await _fsExtra.default.writeFile(target, _ejs.default.render(content, options)); } else { await _fsExtra.default.copyFile(file, target); } } }; await copyDir(COMMON_FILES, folder); if (type === 'expo') { await copyDir(JS_FILES, folder); await copyDir(EXPO_FILES, folder); } else if (type === 'js') { await copyDir(JS_FILES, folder); await copyDir(_path.default.join(EXAMPLE_FILES, 'example'), _path.default.join(folder, 'example')); } else { await copyDir(_path.default.join(EXAMPLE_FILES, 'example'), _path.default.join(folder, 'example')); await copyDir(NATIVE_FILES(moduleType), folder); if (type === 'cpp') { await copyDir(CPP_FILES, folder); } else if (type === 'native-swift') { await copyDir(SWIFT_FILES(moduleType), folder); } else { await copyDir(OBJC_FILES(moduleType), folder); } } try { _crossSpawn.default.sync('git', ['init'], { cwd: folder }); _crossSpawn.default.sync('git', ['add', '.'], { cwd: folder }); _crossSpawn.default.sync('git', ['commit', '-m', 'chore: initial commit'], { cwd: folder }); } catch (e) {// Ignore error } const platforms = { ios: { name: 'iOS', color: 'cyan' }, android: { name: 'Android', color: 'green' }, ...(type === 'expo' ? { web: { name: 'Web', color: 'blue' } } : null) }; console.log((0, _dedent.default)((0, _chalk.default)` Project created successfully at {yellow ${argv.name}}! {magenta {bold Get started} with the project}{gray :} {gray $} yarn ${Object.entries(platforms).map(([script, { name, color }]) => (0, _chalk.default)` {${color} Run the example app on {bold ${name}}}{gray :} {gray $} yarn example ${script}`).join('\n')} {yellow Good luck!} `)); } //# sourceMappingURL=create.js.map