create-react-native-library
Advanced tools
Comparing version 0.33.0 to 0.34.0
228
lib/index.js
@@ -19,2 +19,4 @@ "use strict"; | ||
const COMMON_FILES = _path.default.resolve(__dirname, '../templates/common'); | ||
const COMMON_EXAMPLE_FILES = _path.default.resolve(__dirname, '../templates/common-example'); | ||
const COMMON_LOCAL_FILES = _path.default.resolve(__dirname, '../templates/common-local'); | ||
const JS_FILES = _path.default.resolve(__dirname, '../templates/js-library'); | ||
@@ -25,2 +27,3 @@ const EXPO_FILES = _path.default.resolve(__dirname, '../templates/expo-library'); | ||
const NATIVE_COMMON_FILES = _path.default.resolve(__dirname, '../templates/native-common'); | ||
const NATIVE_COMMON_EXAMPLE_FILES = _path.default.resolve(__dirname, '../templates/native-common-example'); | ||
const NATIVE_FILES = { | ||
@@ -161,6 +164,51 @@ module_legacy: _path.default.resolve(__dirname, '../templates/native-library-legacy'), | ||
type: 'string' | ||
}, | ||
'local': { | ||
description: 'Whether to create a local library', | ||
type: 'boolean' | ||
}, | ||
'example': { | ||
description: 'Whether to create an example app', | ||
type: 'boolean', | ||
default: true | ||
} | ||
}; | ||
async function create(argv) { | ||
const folder = _path.default.join(process.cwd(), argv.name); | ||
let local = false; | ||
if (typeof argv.local === 'boolean') { | ||
local = argv.local; | ||
} else { | ||
let hasPackageJson = await _fsExtra.default.pathExists(_path.default.join(process.cwd(), 'package.json')); | ||
if (hasPackageJson) { | ||
// If we're under a project with package.json, ask the user if they want to create a local library | ||
const answers = await (0, _prompts.default)({ | ||
type: 'confirm', | ||
name: 'local', | ||
message: `Looks like you're under a project folder. Do you want to create a local library?`, | ||
initial: true | ||
}); | ||
local = answers.local; | ||
} | ||
} | ||
let folder; | ||
if (argv.name && !local) { | ||
folder = _path.default.join(process.cwd(), argv.name); | ||
} else { | ||
const answers = await (0, _prompts.default)({ | ||
type: 'text', | ||
name: 'folder', | ||
message: `Where do you want to create the library?`, | ||
initial: local && argv.name && !argv.name.includes('/') ? `modules/${argv.name}` : argv.name, | ||
validate: input => { | ||
if (!input) { | ||
return 'Cannot be empty'; | ||
} | ||
if (_fsExtra.default.pathExistsSync(_path.default.join(process.cwd(), input))) { | ||
return 'Folder already exists'; | ||
} | ||
return true; | ||
} | ||
}); | ||
folder = _path.default.join(process.cwd(), answers.folder); | ||
} | ||
if (await _fsExtra.default.pathExists(folder)) { | ||
@@ -188,3 +236,3 @@ console.log(`A folder already exists at ${_kleur.default.blue(folder)}! Please specify another folder name or delete the existing one.`); | ||
} | ||
const basename = _path.default.basename(argv.name); | ||
const basename = _path.default.basename(folder); | ||
const questions = { | ||
@@ -205,3 +253,3 @@ 'slug': { | ||
'author-name': { | ||
type: 'text', | ||
type: local ? null : 'text', | ||
name: 'authorName', | ||
@@ -213,3 +261,3 @@ message: 'What is the name of package author?', | ||
'author-email': { | ||
type: 'text', | ||
type: local ? null : 'text', | ||
name: 'authorEmail', | ||
@@ -221,3 +269,3 @@ message: 'What is the email address for the package author?', | ||
'author-url': { | ||
type: 'text', | ||
type: local ? null : 'text', | ||
name: 'authorUrl', | ||
@@ -238,3 +286,3 @@ message: 'What is the URL for the package author?', | ||
'repo-url': { | ||
type: 'text', | ||
type: local ? null : 'text', | ||
name: 'repoUrl', | ||
@@ -309,2 +357,3 @@ message: 'What is the URL for the repository?', | ||
languages = type === 'library' ? 'js' : 'java-objc', | ||
example: hasExample, | ||
reactNativeVersion | ||
@@ -360,3 +409,3 @@ } = { | ||
const arch = type === 'module-new' || type === 'view-new' ? 'new' : type === 'module-mixed' || type === 'view-mixed' ? 'mixed' : 'legacy'; | ||
const example = type === 'library' ? 'expo' : 'native'; | ||
const example = hasExample && !local ? type === 'library' ? 'expo' : 'native' : 'none'; | ||
const project = slug.replace(/^(react-native-|@[^/]+\/)/, ''); | ||
@@ -377,5 +426,5 @@ let namespace; | ||
description, | ||
name: /^[A-Z]/.test(argv.name) && /^[a-z0-9]+$/i.test(argv.name) ? | ||
name: /^[A-Z]/.test(basename) && /^[a-z0-9]+$/i.test(basename) ? | ||
// If the project name is already in PascalCase, use it as-is | ||
argv.name : | ||
basename : | ||
// Otherwise, convert it to PascalCase and remove any non-alphanumeric characters | ||
@@ -432,13 +481,23 @@ `${project.charAt(0).toUpperCase()}${project.replace(/[^a-z0-9](\w)/g, (_, $1) => $1.toUpperCase()).slice(1)}`, | ||
} | ||
const spinner = (0, _ora.default)('Generating example').start(); | ||
await (0, _generateExampleApp.default)({ | ||
type: example, | ||
dest: folder, | ||
slug: options.project.slug, | ||
projectName: options.project.name, | ||
arch, | ||
reactNativeVersion | ||
}); | ||
const spinner = (0, _ora.default)().start(); | ||
if (example !== 'none') { | ||
spinner.text = 'Generating example app'; | ||
await (0, _generateExampleApp.default)({ | ||
type: example, | ||
dest: folder, | ||
slug: options.project.slug, | ||
projectName: options.project.name, | ||
arch, | ||
reactNativeVersion | ||
}); | ||
} | ||
spinner.text = 'Copying files'; | ||
await copyDir(COMMON_FILES, folder); | ||
if (local) { | ||
await copyDir(COMMON_LOCAL_FILES, folder); | ||
} else { | ||
await copyDir(COMMON_FILES, folder); | ||
if (example !== 'none') { | ||
await copyDir(COMMON_EXAMPLE_FILES, folder); | ||
} | ||
} | ||
if (languages === 'js') { | ||
@@ -448,4 +507,9 @@ await copyDir(JS_FILES, folder); | ||
} else { | ||
await copyDir(_path.default.join(EXAMPLE_FILES, 'example'), _path.default.join(folder, 'example')); | ||
if (example !== 'none') { | ||
await copyDir(_path.default.join(EXAMPLE_FILES, 'example'), _path.default.join(folder, 'example')); | ||
} | ||
await copyDir(NATIVE_COMMON_FILES, folder); | ||
if (example !== 'none') { | ||
await copyDir(NATIVE_COMMON_EXAMPLE_FILES, folder); | ||
} | ||
if (moduleType === 'module') { | ||
@@ -481,52 +545,87 @@ await copyDir(NATIVE_FILES[`${moduleType}_${arch}`], folder); | ||
} | ||
// Set `react` and `react-native` versions of root `package.json` from example `package.json` | ||
const examplePackageJson = _fsExtra.default.readJSONSync(_path.default.join(folder, 'example', 'package.json')); | ||
const rootPackageJson = _fsExtra.default.readJSONSync(_path.default.join(folder, 'package.json')); | ||
rootPackageJson.devDependencies.react = examplePackageJson.dependencies.react; | ||
rootPackageJson.devDependencies['react-native'] = examplePackageJson.dependencies['react-native']; | ||
_fsExtra.default.writeJSONSync(_path.default.join(folder, 'package.json'), rootPackageJson, { | ||
spaces: 2 | ||
}); | ||
try { | ||
await (0, _spawn.spawn)('git', ['init'], { | ||
cwd: folder | ||
if (example !== 'none') { | ||
// Set `react` and `react-native` versions of root `package.json` from example `package.json` | ||
const examplePackageJson = await _fsExtra.default.readJSON(_path.default.join(folder, 'example', 'package.json')); | ||
const rootPackageJson = await _fsExtra.default.readJSON(_path.default.join(folder, 'package.json')); | ||
rootPackageJson.devDependencies.react = examplePackageJson.dependencies.react; | ||
rootPackageJson.devDependencies['react-native'] = examplePackageJson.dependencies['react-native']; | ||
await _fsExtra.default.writeJSON(_path.default.join(folder, 'package.json'), rootPackageJson, { | ||
spaces: 2 | ||
}); | ||
await (0, _spawn.spawn)('git', ['branch', '-M', 'main'], { | ||
cwd: folder | ||
}); | ||
await (0, _spawn.spawn)('git', ['add', '.'], { | ||
cwd: folder | ||
}); | ||
await (0, _spawn.spawn)('git', ['commit', '-m', 'chore: initial commit'], { | ||
cwd: folder | ||
}); | ||
} catch (e) { | ||
// Ignore error | ||
} | ||
spinner.succeed(`Project created successfully at ${_kleur.default.yellow(argv.name)}!\n`); | ||
const platforms = { | ||
ios: { | ||
name: 'iOS', | ||
color: 'cyan' | ||
}, | ||
android: { | ||
name: 'Android', | ||
color: 'green' | ||
}, | ||
...(example === 'expo' ? { | ||
web: { | ||
name: 'Web', | ||
color: 'blue' | ||
if (!local) { | ||
let isInGitRepo = false; | ||
try { | ||
isInGitRepo = (await (0, _spawn.spawn)('git', ['rev-parse', '--is-inside-work-tree'])) === 'true'; | ||
} catch (e) { | ||
// Ignore error | ||
} | ||
if (!isInGitRepo) { | ||
try { | ||
await (0, _spawn.spawn)('git', ['init'], { | ||
cwd: folder | ||
}); | ||
await (0, _spawn.spawn)('git', ['branch', '-M', 'main'], { | ||
cwd: folder | ||
}); | ||
await (0, _spawn.spawn)('git', ['add', '.'], { | ||
cwd: folder | ||
}); | ||
await (0, _spawn.spawn)('git', ['commit', '-m', 'chore: initial commit'], { | ||
cwd: folder | ||
}); | ||
} catch (e) { | ||
// Ignore error | ||
} | ||
} : null) | ||
}; | ||
console.log((0, _dedent.default)(` | ||
} | ||
} | ||
spinner.succeed(`Project created successfully at ${_kleur.default.yellow(_path.default.relative(process.cwd(), folder))}!\n`); | ||
if (local) { | ||
let linked; | ||
const packageManager = (await _fsExtra.default.pathExists(_path.default.join(process.cwd(), 'yarn.lock'))) ? 'yarn' : 'npm'; | ||
const packageJsonPath = _path.default.join(process.cwd(), 'package.json'); | ||
if (await _fsExtra.default.pathExists(packageJsonPath)) { | ||
const packageJson = await _fsExtra.default.readJSON(packageJsonPath); | ||
const isReactNativeProject = Boolean(packageJson.dependencies?.['react-native']); | ||
if (isReactNativeProject) { | ||
packageJson.dependencies = packageJson.dependencies || {}; | ||
packageJson.dependencies[slug] = packageManager === 'yarn' ? `link:./${_path.default.relative(process.cwd(), folder)}` : `file:./${_path.default.relative(process.cwd(), folder)}`; | ||
await _fsExtra.default.writeJSON(packageJsonPath, packageJson, { | ||
spaces: 2 | ||
}); | ||
linked = true; | ||
} | ||
} | ||
console.log((0, _dedent.default)(` | ||
${_kleur.default.magenta(`${_kleur.default.bold('Get started')} with the project`)}${_kleur.default.gray(':')} | ||
${(linked ? `- Run ${_kleur.default.blue(`${packageManager} install`)} to link the library\n` : `- Link the library at ${_kleur.default.blue(_path.default.relative(process.cwd(), folder))} based on your project setup'\n`) + `- Run ${_kleur.default.blue('pod install --project-directory=ios')} to install dependencies with CocoaPods\n` + `- Run ${_kleur.default.blue('npx react-native run-android')} or ${_kleur.default.blue('npx react-native run-ios')} to build and run the app\n` + `- Import from ${_kleur.default.blue(slug)} and use it in your app.`} | ||
${_kleur.default.yellow(`Good luck!`)} | ||
`)); | ||
} else { | ||
const platforms = { | ||
ios: { | ||
name: 'iOS', | ||
color: 'cyan' | ||
}, | ||
android: { | ||
name: 'Android', | ||
color: 'green' | ||
}, | ||
...(example === 'expo' ? { | ||
web: { | ||
name: 'Web', | ||
color: 'blue' | ||
} | ||
} : null) | ||
}; | ||
console.log((0, _dedent.default)(` | ||
${_kleur.default.magenta(`${_kleur.default.bold('Get started')} with the project`)}${_kleur.default.gray(':')} | ||
${_kleur.default.gray('$')} yarn | ||
${Object.entries(platforms).map(([script, { | ||
name, | ||
color | ||
}]) => ` | ||
name, | ||
color | ||
}]) => ` | ||
${_kleur.default[color](`Run the example app on ${_kleur.default.bold(name)}`)}${_kleur.default.gray(':')} | ||
@@ -538,5 +637,6 @@ | ||
`)); | ||
} | ||
} | ||
// eslint-disable-next-line babel/no-unused-expressions | ||
_yargs.default.command('$0 <name>', 'create a react native library', args, create).demandCommand().recommendCommands().fail((message, error) => { | ||
_yargs.default.command('$0 [name]', 'create a react native library', args, create).demandCommand().recommendCommands().fail((message, error) => { | ||
console.log('\n'); | ||
@@ -543,0 +643,0 @@ if (error) { |
@@ -25,2 +25,5 @@ "use strict"; | ||
}; | ||
const PACKAGES_TO_ADD_NATIVE_DEV = { | ||
'pod-install': '^0.1.0' | ||
}; | ||
async function generateExampleApp({ | ||
@@ -105,4 +108,8 @@ type, | ||
scripts.web = 'expo start --web'; | ||
} else { | ||
Object.assign(devDependencies, PACKAGES_TO_ADD_NATIVE_DEV); | ||
} | ||
await _fsExtra.default.writeFile(_path.default.join(directory, 'package.json'), JSON.stringify(pkg, null, 2)); | ||
await _fsExtra.default.writeJSON(_path.default.join(directory, 'package.json'), pkg, { | ||
spaces: 2 | ||
}); | ||
@@ -109,0 +116,0 @@ // If the library is on new architecture, enable new arch for iOS and Android |
{ | ||
"name": "create-react-native-library", | ||
"version": "0.33.0", | ||
"version": "0.34.0", | ||
"description": "CLI to scaffold React Native libraries", | ||
@@ -40,3 +40,3 @@ "keywords": [ | ||
"scripts": { | ||
"prepack": "babel --extensions .ts,.tsx src --out-dir lib --ignore '**/__tests__/**' --source-maps --delete-dir-on-start" | ||
"prepare": "babel --extensions .ts,.tsx src --out-dir lib --ignore '**/__tests__/**' --source-maps --delete-dir-on-start" | ||
}, | ||
@@ -69,3 +69,3 @@ "dependencies": { | ||
}, | ||
"gitHead": "93f29070b303a1681431c2eeee46c27bcf703186" | ||
"gitHead": "51fc83e7e3f4e5482b81f7f9e3dff748e474cd16" | ||
} |
@@ -17,3 +17,2 @@ { | ||
"*.podspec", | ||
"!lib/typescript/example", | ||
"!ios/build", | ||
@@ -31,2 +30,5 @@ "!android/build", | ||
"scripts": { | ||
<% if (example !== 'none') { -%> | ||
"example": "yarn workspace <%- project.slug -%>-example", | ||
<% } -%> | ||
"test": "jest", | ||
@@ -40,5 +42,4 @@ "typecheck": "tsc --noEmit", | ||
<% } -%> | ||
"prepack": "bob build", | ||
"release": "release-it", | ||
"example": "yarn workspace <%- project.slug -%>-example" | ||
"prepare": "bob build", | ||
"release": "release-it" | ||
}, | ||
@@ -62,3 +63,3 @@ "keywords": [ | ||
"@commitlint/config-conventional": "^17.0.2", | ||
"@evilmartians/lefthook": "^1.2.2", | ||
"@evilmartians/lefthook": "^1.5.0", | ||
"@react-native/eslint-config": "^0.72.2", | ||
@@ -75,3 +76,5 @@ "@release-it/conventional-changelog": "^5.0.0", | ||
"jest": "^28.1.1", | ||
<% if (example === 'native') { -%> | ||
"pod-install": "^0.1.0", | ||
<% } -%> | ||
"prettier": "^2.0.5", | ||
@@ -94,5 +97,7 @@ "react": "17.0.2", | ||
}, | ||
<% if (example !== 'none') { -%> | ||
"workspaces": [ | ||
"example" | ||
], | ||
<% } -%> | ||
"packageManager": "yarn@3.6.1", | ||
@@ -99,0 +104,0 @@ "engines": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
3545023
15389
2
126