From e8b508144fdcdea436cf4d80d99daec757505c70 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Sat, 30 Jul 2016 08:59:16 -0700 Subject: [PATCH] Merge `rnpm cli` into react-native Summary: This is an initial step of rewriting the CLI interface to use `rnpm` one (commander, plugins etc.). It's scope is to move all existing commands to use rnpm CLI interface, so that we get plugins, flags and our existing ecosystem working out of the box. This is still WIP and some of the commands are left commented out. For the `config` of `rnpm` (functions get info about project and dependency), I am thinking we can merge them with we decided to merge it with [`default.config.js`](https://github.com/grabbou/react-native/blob/e57683e420210749a5a6b802b4e70adb69675786/local-cli/default.config.js#L33), so they are available on the `new Config()` [instance](https://github.com/grabbou/react-native/blob/e57683e420210749a5a6b802b4e70adb69675786/local-cli/cliEntry.js#L59) (which means we don't have to change anything and current plugins, like runIOS and runAndroid can just start using it [w/o depending on any extra argument](https://github.com/grabbou/react-native/blob/e57683e420210749a5a6b802b4e Closes https://github.com/facebook/react-native/pull/7899 Differential Revision: D3613193 Pulled By: bestander fbshipit-source-id: 09a072f3b21e5239dfcd8da88a205bd28dc5d037 --- jestSupport/env.js | 1 + local-cli/bundle/buildBundle.js | 101 +++---- local-cli/bundle/bundle.js | 22 +- local-cli/bundle/bundleCommandLineArgs.js | 47 ++-- local-cli/bundle/output/bundle.js | 6 +- local-cli/bundle/output/prepack.js | 4 +- local-cli/bundle/output/unbundle/as-assets.js | 6 +- .../bundle/output/unbundle/as-indexed-file.js | 6 +- local-cli/bundle/unbundle.js | 12 +- local-cli/cliEntry.js | 254 ++++++++---------- local-cli/commands.js | 70 +++++ local-cli/default.config.js | 4 + local-cli/dependencies/dependencies.js | 69 ++--- local-cli/init/init.js | 55 ++++ local-cli/library/library.js | 32 +-- local-cli/logAndroid/logAndroid.js | 11 +- local-cli/logIOS/logIOS.js | 19 +- .../fixtures => __fixtures__}/android.js | 0 .../fixtures => __fixtures__}/commands.js | 0 .../fixtures => __fixtures__}/dependencies.js | 0 .../files/AndroidManifest.xml | 0 .../fixtures => __fixtures__}/files/Main.java | 0 .../files/ReactPackage.java | 0 .../files/package.json | 0 .../files/project.pbxproj | 0 .../{test/fixtures => __fixtures__}/ios.js | 0 .../fixtures => __fixtures__}/projects.js | 0 .../android/findAndroidAppFolder.spec.js | 2 +- .../android/findManifest.spec.js | 2 +- .../android/findPackageClassName.spec.js | 2 +- .../android/getDependencyConfig.spec.js | 2 +- .../android/getProjectConfig.spec.js | 2 +- .../android/readManifest.spec.js | 2 +- .../{test => __tests__}/findAssets.spec.js | 2 +- .../findPlugins.spec.js} | 0 .../ios/findProject.spec.js | 4 +- .../ios/getProjectConfig.spec.js | 12 +- .../{test => __tests__}/makeCommand.spec.js | 0 local-cli/rnpm/core/src/config/ios/index.js | 14 + local-cli/rnpm/core/src/findPlugins.js | 3 +- local-cli/rnpm/core/src/getCommands.js | 11 +- local-cli/rnpm/core/test/getCommands.spec.js | 171 ------------ local-cli/rnpm/install/index.js | 11 - local-cli/rnpm/install/install.js | 5 + local-cli/rnpm/install/src/install.js | 2 +- local-cli/rnpm/install/src/uninstall.js | 2 +- local-cli/rnpm/install/uninstall.js | 5 + .../android/0.17/MainActivity.java | 0 .../android/0.17/patchedMainActivity.java | 0 .../android/0.18/MainActivity.java | 0 .../android/0.18/patchedMainActivity.java | 0 .../android/0.20/MainActivity.java | 0 .../android/build.gradle | 0 .../android/patchedBuild.gradle | 0 .../android/patchedSettings.gradle | 0 .../android/settings.gradle | 0 .../linearGradient.pbxproj | 0 .../fixtures => __fixtures__}/project.pbxproj | 0 .../android/applyPatch.spec.js} | 12 +- .../__tests__/android/isInstalled.spec.js | 20 ++ .../__tests__/android/makeBuildPatch.spec.js | 18 ++ .../__tests__/android/makeImportPatch.spec.js | 20 ++ .../android/makePackagePatch.spec.js | 28 ++ .../android}/makeSettingsPatch.spec.js | 21 +- .../getDependencyConfig.spec.js | 12 +- .../getProjectDependencies.spec.js | 22 +- .../groupFilesByType.spec.js | 10 +- .../__tests__/ios/addFileToProject.spec.js | 27 ++ .../ios/addProjectToLibraries.spec.js | 17 +- .../__tests__/ios/addSharedLibraries.spec.js | 45 ++++ .../ios/createGroup.spec.js | 27 +- .../ios/getBuildProperty.spec.js | 15 +- .../{test => __tests__}/ios/getGroup.spec.js | 23 +- .../ios/getHeaderSearchPath.spec.js | 13 +- .../ios/getHeadersInFolder.spec.js | 23 +- .../{test => __tests__}/ios/getPlist.spec.js | 19 +- .../ios/getPlistPath.spec.js | 15 +- .../ios/getProducts.spec.js | 17 +- .../ios/hasLibraryImported.spec.js | 17 +- .../ios/isInstalled.spec.js | 26 +- .../ios/mapHeaderSearchPaths.spec.js | 17 +- .../ios/removeProjectFromLibraries.js | 15 +- .../ios/removeProjectFromProject.spec.js | 22 +- .../__tests__/ios/removeSharedLibrary.spec.js | 37 +++ .../link/{test => __tests__}/link.spec.js | 75 +++--- .../promiseWaterfall.spec.js | 14 +- local-cli/rnpm/link/index.js | 9 - local-cli/rnpm/link/link.js | 5 + local-cli/rnpm/link/src/android/getPrefix.js | 16 -- .../rnpm/link/src/android/isInstalled.js | 2 +- .../android/patches/0.17/makeImportPatch.js | 6 - .../android/patches/0.17/makePackagePatch.js | 10 - .../android/patches/0.18/makeImportPatch.js | 6 - .../android/patches/0.18/makePackagePatch.js | 10 - .../patches/{0.20 => }/makeImportPatch.js | 0 .../patches/{0.20 => }/makePackagePatch.js | 2 +- .../link/src/android/registerNativeModule.js | 13 +- .../src/android/unregisterNativeModule.js | 7 +- .../rnpm/link/src/getReactNativeVersion.js | 5 - .../rnpm/link/src/ios/addSharedLibraries.js | 15 +- local-cli/rnpm/link/src/ios/copyAssets.js | 18 +- .../link/src/ios/createGroupWithMessage.js | 25 ++ .../rnpm/link/src/ios/registerNativeModule.js | 15 +- .../link/src/ios/removeSharedLibraries.js | 8 + .../link/src/ios/unregisterNativeModule.js | 19 +- local-cli/rnpm/link/src/link.js | 2 +- local-cli/rnpm/link/src/unlink.js | 17 +- .../link/test/android/isInstalled.spec.js | 28 -- .../android/patches/0.17/makeImportPatch.js | 31 --- .../android/patches/0.17/makePackagePatch.js | 36 --- .../android/patches/0.18/makeImportPatch.js | 31 --- .../android/patches/0.18/makePackagePatch.js | 36 --- .../android/patches/0.20/makeImportPatch.js | 31 --- .../android/patches/0.20/makePackagePatch.js | 36 --- .../android/patches/makeBuildPatch.spec.js | 17 -- local-cli/rnpm/link/test/getPrefix.spec.js | 20 -- .../link/test/ios/addFileToProject.spec.js | 22 -- local-cli/rnpm/link/unlink.js | 5 + local-cli/runAndroid/runAndroid.js | 109 ++++---- local-cli/runIOS/runIOS.js | 117 ++++---- local-cli/server/runServer.js | 2 +- local-cli/server/server.js | 137 ++++------ local-cli/upgrade/upgrade.js | 15 +- local-cli/util/assertRequiredOptions.js | 32 +++ local-cli/util/parseCommandLine.js | 3 + local-cli/version/version.js | 22 -- package.json | 7 +- 127 files changed, 1158 insertions(+), 1389 deletions(-) create mode 100644 local-cli/commands.js create mode 100644 local-cli/init/init.js rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/android.js (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/commands.js (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/dependencies.js (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/files/AndroidManifest.xml (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/files/Main.java (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/files/ReactPackage.java (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/files/package.json (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/files/project.pbxproj (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/ios.js (100%) rename local-cli/rnpm/core/{test/fixtures => __fixtures__}/projects.js (100%) rename local-cli/rnpm/core/{test => __tests__}/android/findAndroidAppFolder.spec.js (93%) rename local-cli/rnpm/core/{test => __tests__}/android/findManifest.spec.js (91%) rename local-cli/rnpm/core/{test => __tests__}/android/findPackageClassName.spec.js (91%) rename local-cli/rnpm/core/{test => __tests__}/android/getDependencyConfig.spec.js (96%) rename local-cli/rnpm/core/{test => __tests__}/android/getProjectConfig.spec.js (96%) rename local-cli/rnpm/core/{test => __tests__}/android/readManifest.spec.js (94%) rename local-cli/rnpm/core/{test => __tests__}/findAssets.spec.js (93%) rename local-cli/rnpm/core/{test/findPlugins.js => __tests__/findPlugins.spec.js} (100%) rename local-cli/rnpm/core/{test => __tests__}/ios/findProject.spec.js (95%) rename local-cli/rnpm/core/{test => __tests__}/ios/getProjectConfig.spec.js (63%) rename local-cli/rnpm/core/{test => __tests__}/makeCommand.spec.js (100%) delete mode 100644 local-cli/rnpm/core/test/getCommands.spec.js delete mode 100644 local-cli/rnpm/install/index.js create mode 100644 local-cli/rnpm/install/install.js create mode 100644 local-cli/rnpm/install/uninstall.js rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/0.17/MainActivity.java (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/0.17/patchedMainActivity.java (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/0.18/MainActivity.java (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/0.18/patchedMainActivity.java (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/0.20/MainActivity.java (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/build.gradle (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/patchedBuild.gradle (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/patchedSettings.gradle (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/android/settings.gradle (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/linearGradient.pbxproj (100%) rename local-cli/rnpm/link/{test/fixtures => __fixtures__}/project.pbxproj (100%) rename local-cli/rnpm/link/{test/android/patches/applyPatch.js => __tests__/android/applyPatch.spec.js} (53%) create mode 100644 local-cli/rnpm/link/__tests__/android/isInstalled.spec.js create mode 100644 local-cli/rnpm/link/__tests__/android/makeBuildPatch.spec.js create mode 100644 local-cli/rnpm/link/__tests__/android/makeImportPatch.spec.js create mode 100644 local-cli/rnpm/link/__tests__/android/makePackagePatch.spec.js rename local-cli/rnpm/link/{test/android/patches => __tests__/android}/makeSettingsPatch.spec.js (65%) rename local-cli/rnpm/link/{test => __tests__}/getDependencyConfig.spec.js (64%) rename local-cli/rnpm/link/{test => __tests__}/getProjectDependencies.spec.js (55%) rename local-cli/rnpm/link/{test => __tests__}/groupFilesByType.spec.js (69%) create mode 100644 local-cli/rnpm/link/__tests__/ios/addFileToProject.spec.js rename local-cli/rnpm/link/{test => __tests__}/ios/addProjectToLibraries.spec.js (67%) create mode 100644 local-cli/rnpm/link/__tests__/ios/addSharedLibraries.spec.js rename local-cli/rnpm/link/{test => __tests__}/ios/createGroup.spec.js (70%) rename local-cli/rnpm/link/{test => __tests__}/ios/getBuildProperty.spec.js (61%) rename local-cli/rnpm/link/{test => __tests__}/ios/getGroup.spec.js (62%) rename local-cli/rnpm/link/{test => __tests__}/ios/getHeaderSearchPath.spec.js (92%) rename local-cli/rnpm/link/{test => __tests__}/ios/getHeadersInFolder.spec.js (64%) rename local-cli/rnpm/link/{test => __tests__}/ios/getPlist.spec.js (55%) rename local-cli/rnpm/link/{test => __tests__}/ios/getPlistPath.spec.js (59%) rename local-cli/rnpm/link/{test => __tests__}/ios/getProducts.spec.js (55%) rename local-cli/rnpm/link/{test => __tests__}/ios/hasLibraryImported.spec.js (60%) rename local-cli/rnpm/link/{test => __tests__}/ios/isInstalled.spec.js (57%) rename local-cli/rnpm/link/{test => __tests__}/ios/mapHeaderSearchPaths.spec.js (61%) rename local-cli/rnpm/link/{test => __tests__}/ios/removeProjectFromLibraries.js (78%) rename local-cli/rnpm/link/{test => __tests__}/ios/removeProjectFromProject.spec.js (59%) create mode 100644 local-cli/rnpm/link/__tests__/ios/removeSharedLibrary.spec.js rename local-cli/rnpm/link/{test => __tests__}/link.spec.js (77%) rename local-cli/rnpm/link/{test => __tests__}/promiseWaterfall.spec.js (76%) delete mode 100644 local-cli/rnpm/link/index.js create mode 100644 local-cli/rnpm/link/link.js delete mode 100644 local-cli/rnpm/link/src/android/getPrefix.js delete mode 100644 local-cli/rnpm/link/src/android/patches/0.17/makeImportPatch.js delete mode 100644 local-cli/rnpm/link/src/android/patches/0.17/makePackagePatch.js delete mode 100644 local-cli/rnpm/link/src/android/patches/0.18/makeImportPatch.js delete mode 100644 local-cli/rnpm/link/src/android/patches/0.18/makePackagePatch.js rename local-cli/rnpm/link/src/android/patches/{0.20 => }/makeImportPatch.js (100%) rename local-cli/rnpm/link/src/android/patches/{0.20 => }/makePackagePatch.js (84%) delete mode 100644 local-cli/rnpm/link/src/getReactNativeVersion.js create mode 100644 local-cli/rnpm/link/src/ios/createGroupWithMessage.js delete mode 100644 local-cli/rnpm/link/test/android/isInstalled.spec.js delete mode 100644 local-cli/rnpm/link/test/android/patches/0.17/makeImportPatch.js delete mode 100644 local-cli/rnpm/link/test/android/patches/0.17/makePackagePatch.js delete mode 100644 local-cli/rnpm/link/test/android/patches/0.18/makeImportPatch.js delete mode 100644 local-cli/rnpm/link/test/android/patches/0.18/makePackagePatch.js delete mode 100644 local-cli/rnpm/link/test/android/patches/0.20/makeImportPatch.js delete mode 100644 local-cli/rnpm/link/test/android/patches/0.20/makePackagePatch.js delete mode 100644 local-cli/rnpm/link/test/android/patches/makeBuildPatch.spec.js delete mode 100644 local-cli/rnpm/link/test/getPrefix.spec.js delete mode 100644 local-cli/rnpm/link/test/ios/addFileToProject.spec.js create mode 100644 local-cli/rnpm/link/unlink.js create mode 100644 local-cli/util/assertRequiredOptions.js delete mode 100644 local-cli/version/version.js diff --git a/jestSupport/env.js b/jestSupport/env.js index d9f63301e..186f3e247 100644 --- a/jestSupport/env.js +++ b/jestSupport/env.js @@ -23,6 +23,7 @@ global.regeneratorRuntime = require.requireActual('regenerator-runtime/runtime') jest .mock('ensureComponentIsNative') .mock('Image') + .mock('npmlog') .mock('NativeModules') .mock('Text') .mock('View'); diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index d229d0ebf..414403f1c 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -21,69 +21,56 @@ function saveBundle(output, bundle, args) { } function buildBundle(args, config, output = outputBundle, packagerInstance) { - return new Promise((resolve, reject) => { + // This is used by a bazillion of npm modules we don't control so we don't + // have other choice than defining it as an env variable here. + process.env.NODE_ENV = args.dev ? 'development' : 'production'; - // This is used by a bazillion of npm modules we don't control so we don't - // have other choice than defining it as an env variable here. - if (!process.env.NODE_ENV) { - // If you're inlining environment variables, you can use babel to remove - // this line: - // https://www.npmjs.com/package/babel-remove-process-env-assignment - process.env.NODE_ENV = args.dev ? 'development' : 'production'; - } + const options = { + projectRoots: config.getProjectRoots(), + assetRoots: config.getAssetRoots(), + blacklistRE: config.getBlacklistRE(args.platform), + getTransformOptionsModulePath: config.getTransformOptionsModulePath, + transformModulePath: args.transformer, + extraNodeModules: config.extraNodeModules, + nonPersistent: true, + resetCache: args.resetCache, + }; - const transformModulePath = - args.transformer ? path.resolve(args.transformer) : - typeof config.getTransformModulePath === 'function' ? config.getTransformModulePath() : - undefined; + const requestOpts = { + entryFile: args.entryFile, + sourceMapUrl: args.sourcemapOutput, + dev: args.dev, + minify: !args.dev, + platform: args.platform, + }; - const options = { - projectRoots: config.getProjectRoots(), - assetRoots: config.getAssetRoots(), - blacklistRE: config.getBlacklistRE(args.platform), - getTransformOptionsModulePath: config.getTransformOptionsModulePath, - transformModulePath: transformModulePath, - extraNodeModules: config.extraNodeModules, - nonPersistent: true, - resetCache: args['reset-cache'], - }; + // If a packager instance was not provided, then just create one for this + // bundle command and close it down afterwards. + var shouldClosePackager = false; + if (!packagerInstance) { + packagerInstance = new Server(options); + shouldClosePackager = true; + } - const requestOpts = { - entryFile: args['entry-file'], - sourceMapUrl: args['sourcemap-output'], - dev: args.dev, - minify: !args.dev, - platform: args.platform, - }; + const bundlePromise = output.build(packagerInstance, requestOpts) + .then(bundle => { + if (shouldClosePackager) { + packagerInstance.end(); + } + return saveBundle(output, bundle, args); + }); - // If a packager instance was not provided, then just create one for this - // bundle command and close it down afterwards. - var shouldClosePackager = false; - if (!packagerInstance) { - packagerInstance = new Server(options); - shouldClosePackager = true; - } + // Save the assets of the bundle + const assets = bundlePromise + .then(bundle => bundle.getAssets()) + .then(outputAssets => saveAssets( + outputAssets, + args.platform, + args.assetsDest, + )); - const bundlePromise = output.build(packagerInstance, requestOpts) - .then(bundle => { - if (shouldClosePackager) { - packagerInstance.end(); - } - return saveBundle(output, bundle, args); - }); - - // Save the assets of the bundle - const assets = bundlePromise - .then(bundle => bundle.getAssets()) - .then(outputAssets => saveAssets( - outputAssets, - args.platform, - args['assets-dest'] - )); - - // When we're done saving bundle output and the assets, we're done. - resolve(assets); - }); + // When we're done saving bundle output and the assets, we're done. + return assets; } module.exports = buildBundle; diff --git a/local-cli/bundle/bundle.js b/local-cli/bundle/bundle.js index e2a6441e0..8f2b1816d 100644 --- a/local-cli/bundle/bundle.js +++ b/local-cli/bundle/bundle.js @@ -8,26 +8,30 @@ */ const buildBundle = require('./buildBundle'); -const bundleCommandLineArgs = require('./bundleCommandLineArgs'); -const parseCommandLine = require('../util/parseCommandLine'); const outputBundle = require('./output/bundle'); const outputPrepack = require('./output/prepack'); +const bundleCommandLineArgs = require('./bundleCommandLineArgs'); /** * Builds the bundle starting to look for dependencies at the given entry path. */ -function bundleWithOutput(argv, config, output, packagerInstance) { - const args = parseCommandLine(bundleCommandLineArgs, argv); +function bundleWithOutput(argv, config, args, output, packagerInstance) { if (!output) { output = args.prepack ? outputPrepack : outputBundle; } return buildBundle(args, config, output, packagerInstance); - } -function bundle(argv, config, packagerInstance) { - return bundleWithOutput(argv, config, undefined, packagerInstance); +function bundle(argv, config, args, packagerInstance) { + return bundleWithOutput(argv, config, args, undefined, packagerInstance); } -module.exports = bundle; -module.exports.withOutput = bundleWithOutput; +module.exports = { + name: 'bundle', + description: 'builds the javascript bundle for offline use', + func: bundle, + options: bundleCommandLineArgs, + + // not used by the CLI itself + withOutput: bundleWithOutput, +}; diff --git a/local-cli/bundle/bundleCommandLineArgs.js b/local-cli/bundle/bundleCommandLineArgs.js index 5d54ad835..46bb72789 100644 --- a/local-cli/bundle/bundleCommandLineArgs.js +++ b/local-cli/bundle/bundleCommandLineArgs.js @@ -10,56 +10,47 @@ module.exports = [ { - command: 'entry-file', + command: '--entry-file ', description: 'Path to the root JS file, either absolute or relative to JS root', - type: 'string', - required: true, }, { - command: 'platform', + command: '--platform [string]', description: 'Either "ios" or "android"', - type: 'string', + default: 'ios', }, { - command: 'transformer', - description: 'Specify a custom transformer to be used', - type: 'string', - default: null, + command: '--transformer [string]', + description: 'Specify a custom transformer to be used (absolute path)', + default: require.resolve('../../packager/transformer'), }, { - command: 'dev', + command: '--dev [boolean]', description: 'If false, warnings are disabled and the bundle is minified', + parse: (val) => val === 'false' ? false : true, default: true, }, { - command: 'prepack', - description: 'If true, the output bundle will use the Prepack format.', - default: false + command: '--prepack', + description: 'When passed, the output bundle will use the Prepack format.', }, { - command: 'bridge-config', + command: '--bridge-config [string]', description: 'File name of a a JSON export of __fbBatchedBridgeConfig. Used by Prepack. Ex. ./bridgeconfig.json', - type: 'string' }, { - command: 'bundle-output', + command: '--bundle-output ', description: 'File name where to store the resulting bundle, ex. /tmp/groups.bundle', - type: 'string', - required: true, }, { - command: 'bundle-encoding', + command: '--bundle-encoding [string]', description: 'Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer).', - type: 'string', default: 'utf8', }, { - command: 'sourcemap-output', + command: '--sourcemap-output [string]', description: 'File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map', - type: 'string', }, { - command: 'assets-dest', + command: '--assets-dest [string]', description: 'Directory name where to store assets referenced in the bundle', - type: 'string', }, { - command: 'verbose', + command: '--verbose', description: 'Enables logging', default: false, }, { - command: 'reset-cache', + command: '--reset-cache', description: 'Removes cached files', - default: false - } + default: false, + }, ]; diff --git a/local-cli/bundle/output/bundle.js b/local-cli/bundle/output/bundle.js index 70e8a1941..34d1fa71a 100644 --- a/local-cli/bundle/output/bundle.js +++ b/local-cli/bundle/output/bundle.js @@ -28,10 +28,10 @@ function createCodeWithMap(bundle, dev) { function saveBundleAndMap(bundle, options, log) { const { - 'bundle-output': bundleOutput, - 'bundle-encoding': encoding, + bundleOutput, + bundleEncoding: encoding, dev, - 'sourcemap-output': sourcemapOutput, + sourcemapOutput } = options; log('start'); diff --git a/local-cli/bundle/output/prepack.js b/local-cli/bundle/output/prepack.js index 9165b8763..d13d44f8f 100644 --- a/local-cli/bundle/output/prepack.js +++ b/local-cli/bundle/output/prepack.js @@ -16,8 +16,8 @@ function buildPrepackBundle(packagerClient, requestOptions) { function savePrepackBundle(bundle, options, log) { const { - 'bundle-output': bundleOutput, - 'bridge-config': bridgeConfig, + bundleOutput, + bridgeConfig, } = options; const result = bundle.build({ diff --git a/local-cli/bundle/output/unbundle/as-assets.js b/local-cli/bundle/output/unbundle/as-assets.js index 740a8564a..0698d2a37 100644 --- a/local-cli/bundle/output/unbundle/as-assets.js +++ b/local-cli/bundle/output/unbundle/as-assets.js @@ -30,9 +30,9 @@ const MODULES_DIR = 'js-modules'; */ function saveAsAssets(bundle, options, log) { const { - 'bundle-output': bundleOutput, - 'bundle-encoding': encoding, - 'sourcemap-output': sourcemapOutput, + bundleOutput, + bundleEncoding: encoding, + sourcemapOutput } = options; log('start'); diff --git a/local-cli/bundle/output/unbundle/as-indexed-file.js b/local-cli/bundle/output/unbundle/as-indexed-file.js index 45eb412c8..3e3ece669 100644 --- a/local-cli/bundle/output/unbundle/as-indexed-file.js +++ b/local-cli/bundle/output/unbundle/as-indexed-file.js @@ -26,9 +26,9 @@ const SIZEOF_UINT32 = 4; */ function saveAsIndexedFile(bundle, options, log) { const { - 'bundle-output': bundleOutput, - 'bundle-encoding': encoding, - 'sourcemap-output': sourcemapOutput, + bundleOutput, + bundleEncoding: encoding, + sourcemapOutput } = options; log('start'); diff --git a/local-cli/bundle/unbundle.js b/local-cli/bundle/unbundle.js index 41460d3eb..b8715501d 100644 --- a/local-cli/bundle/unbundle.js +++ b/local-cli/bundle/unbundle.js @@ -8,13 +8,19 @@ */ const bundleWithOutput = require('./bundle').withOutput; +const bundleCommandLineArgs = require('./bundleCommandLineArgs'); const outputUnbundle = require('./output/unbundle'); /** * Builds the bundle starting to look for dependencies at the given entry path. */ -function unbundle(argv, config, packagerInstance) { - return bundleWithOutput(argv, config, outputUnbundle, packagerInstance); +function unbundle(argv, config, args, packagerInstance) { + return bundleWithOutput(argv, config, args, outputUnbundle, packagerInstance); } -module.exports = unbundle; +module.exports = { + name: 'unbundle', + description: 'builds javascript as "unbundle" for offline use', + func: unbundle, + options: bundleCommandLineArgs, +}; diff --git a/local-cli/cliEntry.js b/local-cli/cliEntry.js index dd1c06dd8..303686ba1 100644 --- a/local-cli/cliEntry.js +++ b/local-cli/cliEntry.js @@ -5,171 +5,151 @@ * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow */ 'use strict'; -const bundle = require('./bundle/bundle'); -const childProcess = require('child_process'); -const Config = require('./util/Config'); -const defaultConfig = require('./default.config'); -const dependencies = require('./dependencies/dependencies'); -const generate = require('./generate/generate'); -const library = require('./library/library'); -const link = require('./rnpm/link/src/link'); -const path = require('path'); -const Promise = require('promise'); -const runAndroid = require('./runAndroid/runAndroid'); -const logAndroid = require('./logAndroid/logAndroid'); -const runIOS = require('./runIOS/runIOS'); -const logIOS = require('./logIOS/logIOS'); -const server = require('./server/server'); -const TerminalAdapter = require('yeoman-environment/lib/adapter.js'); -const yeoman = require('yeoman-environment'); -const unbundle = require('./bundle/unbundle'); -const upgrade = require('./upgrade/upgrade'); -const version = require('./version/version'); +const commander = require('commander'); +const Config = require('./util/Config'); +const childProcess = require('child_process'); +const Promise = require('promise'); +const chalk = require('chalk'); +const path = require('path'); const fs = require('fs'); const gracefulFs = require('graceful-fs'); -// Just a helper to proxy 'react-native link' to rnpm -const linkWrapper = (args, config) => { - const rnpmConfig = require('./rnpm/core/src/config'); - return new Promise((resolve, reject) => { - link(rnpmConfig, args.slice(1)).then(resolve, reject); - }); -} +const init = require('./init/init'); +const commands = require('./commands'); +const assertRequiredOptions = require('./util/assertRequiredOptions'); +const pkg = require('../package.json'); +const defaultConfig = require('./default.config'); + +import type { Command } from './commands'; // graceful-fs helps on getting an error when we run out of file // descriptors. When that happens it will enqueue the operation and retry it. gracefulFs.gracefulify(fs); -const documentedCommands = { - 'start': [server, 'starts the webserver'], - 'bundle': [bundle, 'builds the javascript bundle for offline use'], - 'unbundle': [unbundle, 'builds javascript as "unbundle" for offline use'], - 'new-library': [library, 'generates a native library bridge'], - 'android': [generateWrapper, 'generates an Android project for your app'], - 'run-android': [runAndroid, 'builds your app and starts it on a connected Android emulator or device'], - 'log-android': [logAndroid, 'print Android logs'], - 'run-ios': [runIOS, 'builds your app and starts it on iOS simulator'], - 'log-ios': [logIOS, 'print iOS logs'], - 'upgrade': [upgrade, 'upgrade your app\'s template files to the latest version; run this after ' + - 'updating the react-native version in your package.json and running npm install'], - 'link': [linkWrapper, 'link a library'], +commander.version(pkg.version); + +const defaultOptParser = (val) => val; + +const handleError = (err) => { + console.error(); + console.error(err.message || err); + console.error(); + process.exit(1); }; -const exportedCommands = {dependencies: dependencies}; -Object.keys(documentedCommands).forEach(function(command) { - exportedCommands[command] = documentedCommands[command][0]; -}); - -const undocumentedCommands = { - '--version': [version, ''], - 'init': [printInitWarning, ''], -}; - -const commands = Object.assign({}, documentedCommands, undocumentedCommands); - -/** - * Parses the command line and runs a command of the CLI. - */ -function run() { - const args = process.argv.slice(2); - if (args.length === 0) { - printUsage(); +// Custom printHelpInformation command inspired by internal Commander.js +// one modified to suit our needs +function printHelpInformation() { + let cmdName = this._name; + if (this._alias) { + cmdName = cmdName + '|' + this._alias; } + let output = [ + '', + chalk.bold(chalk.cyan((` react-native ${cmdName} [options]`))), + ` ${this._description}`, + '', + ` ${chalk.bold('Options:')}`, + '', + this.optionHelp().replace(/^/gm, ' '), + '', + ]; + + const usage = this.usage(); + + if (usage !== '[options]') { + const formattedUsage = usage.map( + example => ` ${example.desc}: \n ${chalk.cyan(example.cmd)}`, + ).join('\n\n'); + + output = output.concat([ + chalk.bold(' Example usage:'), + '', + formattedUsage, + ]); + } + + return output.concat([ + '', + '', + ]).join('\n'); +} + +function printUnknownCommand(cmdName) { + console.log([ + '', + cmdName + ? chalk.red(` Unrecognized command '${cmdName}'`) + : chalk.red(' You didn\'t pass any command'), + ` Run ${chalk.cyan('react-native --help')} to see list of all available commands`, + '', + ].join('\n')); +} + +const addCommand = (command: Command, config: Config) => { + const options = command.options || []; + + const cmd = commander + .command(command.name, undefined, { + noHelp: !command.description, + }) + .usage(command.examples) + .description(command.description) + .action(function runAction() { + const passedOptions = this.opts(); + const argv: Array = Array.from(arguments).slice(0, -1); + + Promise.resolve() + .then(() => { + assertRequiredOptions(options, passedOptions); + return command.func(argv, config, passedOptions); + }) + .catch(handleError); + }); + + cmd.helpInformation = printHelpInformation.bind(cmd); + + options + .forEach(opt => cmd.option( + opt.command, + opt.description, + opt.parse || defaultOptParser, + typeof opt.default === 'function' ? opt.default(config) : opt.default, + )); +}; + +function run() { + const config = Config.get(__dirname, defaultConfig); const setupEnvScript = /^win/.test(process.platform) ? 'setup_env.bat' : 'setup_env.sh'; + childProcess.execFileSync(path.join(__dirname, setupEnvScript)); - const command = commands[args[0]]; - if (!command) { - console.error('Command `%s` unrecognized', args[0]); - printUsage(); + commands.forEach(cmd => addCommand(cmd, config)); + + commander.parse(process.argv); + + const isValidCommand = commands.find(cmd => cmd.name === process.argv[2]); + + if (!isValidCommand) { + printUnknownCommand(process.argv[2]); return; } - command[0](args, Config.get(__dirname, defaultConfig)).done(); -} - -function generateWrapper(args, config) { - return generate([ - '--platform', 'android', - '--project-path', process.cwd(), - '--project-name', JSON.parse( - fs.readFileSync('package.json', 'utf8') - ).name - ], config); -} - -function printUsage() { - console.log([ - 'Usage: react-native ', - '', - 'Commands:' - ].concat(Object.keys(documentedCommands).map(function(name) { - return ' - ' + name + ': ' + documentedCommands[name][1]; - })).join('\n')); - process.exit(1); -} - -// The user should never get here because projects are inited by -// using `react-native-cli` from outside a project directory. -function printInitWarning() { - return Promise.resolve().then(function() { - console.log([ - 'Looks like React Native project already exists in the current', - 'folder. Run this command from a different folder or remove node_modules/react-native' - ].join('\n')); - process.exit(1); - }); -} - -class CreateSuppressingTerminalAdapter extends TerminalAdapter { - constructor() { - super(); - // suppress 'create' output generated by yeoman - this.log.create = function() {}; + if (!commander.args.length) { + commander.help(); } } -/** - * Creates the template for a React Native project given the provided - * parameters: - * - projectDir: templates will be copied here. - * - argsOrName: project name or full list of custom arguments to pass to the - * generator. - */ -function init(projectDir, argsOrName) { - console.log('Setting up new React Native app in ' + projectDir); - const env = yeoman.createEnv( - undefined, - undefined, - new CreateSuppressingTerminalAdapter() - ); - - env.register( - require.resolve(path.join(__dirname, 'generator')), - 'react:app' - ); - - // argv is for instance - // ['node', 'react-native', 'init', 'AwesomeApp', '--verbose'] - // args should be ['AwesomeApp', '--verbose'] - const args = Array.isArray(argsOrName) - ? argsOrName - : [argsOrName].concat(process.argv.slice(4)); - - const generator = env.create('react:app', {args: args}); - generator.destinationRoot(projectDir); - generator.run(); -} - module.exports = { run: run, init: init, - commands: exportedCommands }; diff --git a/local-cli/commands.js b/local-cli/commands.js new file mode 100644 index 000000000..e696b35be --- /dev/null +++ b/local-cli/commands.js @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ +'use strict'; + +const Config = require('./util/Config'); +const getUserCommands = require('./rnpm/core/src/getCommands'); + +export type Command = { + name: string, + description?: string, + usage?: string, + func: (argv: Array, config: Config, args: Object) => ?Promise, + options?: Array<{ + command: string, + description?: string, + parse?: (val: string) => any, + default?: (config: Config) => any | any, + }>, + examples?: Array<{ + desc: string, + cmd: string, + }>, +}; + +const documentedCommands = [ + require('./server/server'), + require('./runIOS/runIOS'), + require('./runAndroid/runAndroid'), + require('./library/library'), + require('./bundle/bundle'), + require('./bundle/unbundle'), + require('./rnpm/link/link'), + require('./rnpm/link/unlink'), + require('./rnpm/install/install'), + require('./rnpm/install/uninstall'), + require('./upgrade/upgrade'), + require('./logAndroid/logAndroid'), + require('./logIOS/logIOS'), + require('./dependencies/dependencies'), +]; + +// The user should never get here because projects are inited by +// using `react-native-cli` from outside a project directory. +const undocumentedCommands = [ + { + name: 'init', + func: () => { + console.log([ + 'Looks like React Native project already exists in the current', + 'folder. Run this command from a different folder or remove node_modules/react-native' + ].join('\n')); + }, + }, +]; + +const commands: Array = [ + ...documentedCommands, + ...undocumentedCommands, + ...getUserCommands(), +]; + +module.exports = commands; diff --git a/local-cli/default.config.js b/local-cli/default.config.js index 7b5b2fa00..7a1e48a83 100644 --- a/local-cli/default.config.js +++ b/local-cli/default.config.js @@ -2,6 +2,7 @@ var blacklist = require('../packager/blacklist'); var path = require('path'); +var rnpmConfig = require('./rnpm/core/src/config'); /** * Default configuration for the CLI. @@ -15,6 +16,9 @@ var config = { return getRoots(); }, + getProjectConfig: rnpmConfig.getProjectConfig, + getDependencyConfig: rnpmConfig.getDependencyConfig, + /** * Specify where to look for assets that are referenced using * `image!`. Asset directories for images referenced using diff --git a/local-cli/dependencies/dependencies.js b/local-cli/dependencies/dependencies.js index 14fd27def..633a59426 100644 --- a/local-cli/dependencies/dependencies.js +++ b/local-cli/dependencies/dependencies.js @@ -8,50 +8,14 @@ */ const fs = require('fs'); -const parseCommandLine = require('../util/parseCommandLine'); const path = require('path'); const Promise = require('promise'); const ReactPackager = require('../../packager/react-packager'); -/** - * Returns the dependencies an entry path has. - */ -function dependencies(argv, config, packagerInstance) { - return new Promise((resolve, reject) => { - _dependencies(argv, config, resolve, reject, packagerInstance); - }); -} - -function _dependencies(argv, config, resolve, reject, packagerInstance) { - const args = parseCommandLine([ - { - command: 'entry-file', - description: 'Absolute path to the root JS file', - type: 'string', - required: true, - }, { - command: 'output', - description: 'File name where to store the output, ex. /tmp/dependencies.txt', - type: 'string', - }, { - command: 'platform', - description: 'The platform extension used for selecting modules', - type: 'string', - }, { - command: 'transformer', - type: 'string', - default: null, - description: 'Specify a custom transformer to be used' - }, { - command: 'verbose', - description: 'Enables logging', - default: false, - } - ], argv); - - const rootModuleAbsolutePath = args['entry-file']; +function dependencies(argv, config, args, packagerInstance) { + const rootModuleAbsolutePath = args.entryFile; if (!fs.existsSync(rootModuleAbsolutePath)) { - reject(`File ${rootModuleAbsolutePath} does not exist`); + return Promise.reject(`File ${rootModuleAbsolutePath} does not exist`); } const transformModulePath = @@ -86,7 +50,7 @@ function _dependencies(argv, config, resolve, reject, packagerInstance) { ? fs.createWriteStream(args.output) : process.stdout; - resolve((packagerInstance ? + return Promise.resolve((packagerInstance ? packagerInstance.getOrderedDependencyPaths(options) : ReactPackager.getOrderedDependencyPaths(packageOpts, options)).then( deps => { @@ -110,4 +74,27 @@ function _dependencies(argv, config, resolve, reject, packagerInstance) { )); } -module.exports = dependencies; +module.exports = { + name: 'dependencies', + func: dependencies, + options: [ + { + command: '--entry-file ', + description: 'Absolute path to the root JS file', + }, { + command: '--output [path]', + description: 'File name where to store the output, ex. /tmp/dependencies.txt', + }, { + command: '--platform [extension]', + description: 'The platform extension used for selecting modules', + }, { + command: '--transformer [path]', + default: null, + description: 'Specify a custom transformer to be used' + }, { + command: '--verbose', + description: 'Enables logging', + default: false, + }, + ], +}; diff --git a/local-cli/init/init.js b/local-cli/init/init.js new file mode 100644 index 000000000..92df12bc5 --- /dev/null +++ b/local-cli/init/init.js @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +const path = require('path'); +const TerminalAdapter = require('yeoman-environment/lib/adapter.js'); +const yeoman = require('yeoman-environment'); + +class CreateSuppressingTerminalAdapter extends TerminalAdapter { + constructor() { + super(); + // suppress 'create' output generated by yeoman + this.log.create = function() {}; + } +} + +/** + * Creates the template for a React Native project given the provided + * parameters: + * - projectDir: templates will be copied here. + * - argsOrName: project name or full list of custom arguments to pass to the + * generator. + */ +function init(projectDir, argsOrName) { + console.log('Setting up new React Native app in ' + projectDir); + const env = yeoman.createEnv( + undefined, + undefined, + new CreateSuppressingTerminalAdapter() + ); + + env.register( + require.resolve(path.join(__dirname, '../generator')), + 'react:app' + ); + + // argv is for instance + // ['node', 'react-native', 'init', 'AwesomeApp', '--verbose'] + // args should be ['AwesomeApp', '--verbose'] + const args = Array.isArray(argsOrName) + ? argsOrName + : [argsOrName].concat(process.argv.slice(4)); + + const generator = env.create('react:app', {args: args}); + generator.destinationRoot(projectDir); + generator.run(); +} + +module.exports = init; diff --git a/local-cli/library/library.js b/local-cli/library/library.js index 107c4455b..318b56830 100644 --- a/local-cli/library/library.js +++ b/local-cli/library/library.js @@ -11,7 +11,6 @@ const copyAndReplace = require('../util/copyAndReplace'); const fs = require('fs'); const isValidPackageName = require('../util/isValidPackageName'); -const parseCommandLine = require('../util/parseCommandLine'); const path = require('path'); const Promise = require('promise'); const walk = require('../util/walk'); @@ -19,22 +18,9 @@ const walk = require('../util/walk'); /** * Creates a new native library with the given name */ -function library(argv, config) { - return new Promise((resolve, reject) => { - _library(argv, config, resolve, reject); - }); -} - -function _library(argv, config, resolve, reject) { - const args = parseCommandLine([{ - command: 'name', - description: 'Library name', - type: 'string', - required: true, - }], argv); - +function library(argv, config, args) { if (!isValidPackageName(args.name)) { - reject( + return Promise.reject( args.name + ' is not a valid name for a project. Please use a valid ' + 'identifier name (alphanumeric).' ); @@ -50,7 +36,7 @@ function _library(argv, config, resolve, reject) { } if (fs.existsSync(libraryDest)) { - reject('Library already exists in', libraryDest); + return Promise.reject(`Library already exists in ${libraryDest}`); } walk(source).forEach(f => { @@ -71,7 +57,15 @@ function _library(argv, config, resolve, reject) { console.log('Next Steps:'); console.log(' Link your library in Xcode:'); console.log(' https://facebook.github.io/react-native/docs/linking-libraries-ios.html#content\n'); - resolve(); } -module.exports = library; +module.exports = { + name: 'new-library', + func: library, + description: 'generates a native library bridge', + options: [{ + command: '--name ', + description: 'name of the library to generate', + default: null, + }], +}; diff --git a/local-cli/logAndroid/logAndroid.js b/local-cli/logAndroid/logAndroid.js index ddb60fca0..6005d24d9 100644 --- a/local-cli/logAndroid/logAndroid.js +++ b/local-cli/logAndroid/logAndroid.js @@ -21,7 +21,7 @@ function logAndroid() { }); } -function _logAndroid(resolve, reject) { +function _logAndroid() { try { const adbPath = process.env.ANDROID_HOME ? process.env.ANDROID_HOME + '/platform-tools/adb' @@ -43,9 +43,12 @@ function _logAndroid(resolve, reject) { console.log(chalk.red( 'adb invocation failed. Do you have adb in your PATH?' )); - reject(); - return; + return Promise.reject(); } } -module.exports = logAndroid; +module.exports = { + name: 'log-android', + description: 'starts adb logcat', + func: logAndroid, +}; diff --git a/local-cli/logIOS/logIOS.js b/local-cli/logIOS/logIOS.js index 728a060b2..4a898ad5e 100644 --- a/local-cli/logIOS/logIOS.js +++ b/local-cli/logIOS/logIOS.js @@ -15,7 +15,7 @@ function logIOS() { }); } -function _logIOS(resolve, reject) { +function _logIOS() { let rawDevices; try { @@ -26,8 +26,7 @@ function _logIOS(resolve, reject) { console.log(chalk.red( 'xcrun invocation failed. Please check that Xcode is installed.' )); - reject(e); - return; + return Promise.reject(e); } const { devices } = JSON.parse(rawDevices); @@ -37,10 +36,10 @@ function _logIOS(resolve, reject) { console.log(chalk.red( 'No active iOS device found' )); - reject(); + return Promise.reject(); } - tailDeviceLogs(device.udid, reject); + return tailDeviceLogs(device.udid); } function _findAvailableDevice(devices) { @@ -53,7 +52,7 @@ function _findAvailableDevice(devices) { } } -function tailDeviceLogs(udid, reject) { +function tailDeviceLogs(udid) { const logDir = path.join( os.homedir(), 'Library', @@ -70,8 +69,12 @@ function tailDeviceLogs(udid, reject) { console.log(chalk.red( 'syslog invocation failed.' )); - reject(log.error); + return Promise.reject(log.error); } } -module.exports = logIOS; +module.exports = { + name: 'log-ios', + description: 'starts iOS device syslog tail', + func: logIOS, +}; diff --git a/local-cli/rnpm/core/test/fixtures/android.js b/local-cli/rnpm/core/__fixtures__/android.js similarity index 100% rename from local-cli/rnpm/core/test/fixtures/android.js rename to local-cli/rnpm/core/__fixtures__/android.js diff --git a/local-cli/rnpm/core/test/fixtures/commands.js b/local-cli/rnpm/core/__fixtures__/commands.js similarity index 100% rename from local-cli/rnpm/core/test/fixtures/commands.js rename to local-cli/rnpm/core/__fixtures__/commands.js diff --git a/local-cli/rnpm/core/test/fixtures/dependencies.js b/local-cli/rnpm/core/__fixtures__/dependencies.js similarity index 100% rename from local-cli/rnpm/core/test/fixtures/dependencies.js rename to local-cli/rnpm/core/__fixtures__/dependencies.js diff --git a/local-cli/rnpm/core/test/fixtures/files/AndroidManifest.xml b/local-cli/rnpm/core/__fixtures__/files/AndroidManifest.xml similarity index 100% rename from local-cli/rnpm/core/test/fixtures/files/AndroidManifest.xml rename to local-cli/rnpm/core/__fixtures__/files/AndroidManifest.xml diff --git a/local-cli/rnpm/core/test/fixtures/files/Main.java b/local-cli/rnpm/core/__fixtures__/files/Main.java similarity index 100% rename from local-cli/rnpm/core/test/fixtures/files/Main.java rename to local-cli/rnpm/core/__fixtures__/files/Main.java diff --git a/local-cli/rnpm/core/test/fixtures/files/ReactPackage.java b/local-cli/rnpm/core/__fixtures__/files/ReactPackage.java similarity index 100% rename from local-cli/rnpm/core/test/fixtures/files/ReactPackage.java rename to local-cli/rnpm/core/__fixtures__/files/ReactPackage.java diff --git a/local-cli/rnpm/core/test/fixtures/files/package.json b/local-cli/rnpm/core/__fixtures__/files/package.json similarity index 100% rename from local-cli/rnpm/core/test/fixtures/files/package.json rename to local-cli/rnpm/core/__fixtures__/files/package.json diff --git a/local-cli/rnpm/core/test/fixtures/files/project.pbxproj b/local-cli/rnpm/core/__fixtures__/files/project.pbxproj similarity index 100% rename from local-cli/rnpm/core/test/fixtures/files/project.pbxproj rename to local-cli/rnpm/core/__fixtures__/files/project.pbxproj diff --git a/local-cli/rnpm/core/test/fixtures/ios.js b/local-cli/rnpm/core/__fixtures__/ios.js similarity index 100% rename from local-cli/rnpm/core/test/fixtures/ios.js rename to local-cli/rnpm/core/__fixtures__/ios.js diff --git a/local-cli/rnpm/core/test/fixtures/projects.js b/local-cli/rnpm/core/__fixtures__/projects.js similarity index 100% rename from local-cli/rnpm/core/test/fixtures/projects.js rename to local-cli/rnpm/core/__fixtures__/projects.js diff --git a/local-cli/rnpm/core/test/android/findAndroidAppFolder.spec.js b/local-cli/rnpm/core/__tests__/android/findAndroidAppFolder.spec.js similarity index 93% rename from local-cli/rnpm/core/test/android/findAndroidAppFolder.spec.js rename to local-cli/rnpm/core/__tests__/android/findAndroidAppFolder.spec.js index fe6223aad..3aa2806e6 100644 --- a/local-cli/rnpm/core/test/android/findAndroidAppFolder.spec.js +++ b/local-cli/rnpm/core/__tests__/android/findAndroidAppFolder.spec.js @@ -2,7 +2,7 @@ jest.autoMockOff(); const findAndroidAppFolder = require('../../src/config/android/findAndroidAppFolder'); const mockFs = require('mock-fs'); -const mocks = require('../fixtures/android'); +const mocks = require('../../__fixtures__/android'); describe('android::findAndroidAppFolder', () => { beforeAll(() => mockFs({ diff --git a/local-cli/rnpm/core/test/android/findManifest.spec.js b/local-cli/rnpm/core/__tests__/android/findManifest.spec.js similarity index 91% rename from local-cli/rnpm/core/test/android/findManifest.spec.js rename to local-cli/rnpm/core/__tests__/android/findManifest.spec.js index 27a81fd6d..ca388fa39 100644 --- a/local-cli/rnpm/core/test/android/findManifest.spec.js +++ b/local-cli/rnpm/core/__tests__/android/findManifest.spec.js @@ -2,7 +2,7 @@ jest.autoMockOff(); const findManifest = require('../../src/config/android/findManifest'); const mockFs = require('mock-fs'); -const mocks = require('../fixtures/android'); +const mocks = require('../../__fixtures__/android'); describe('android::findManifest', () => { diff --git a/local-cli/rnpm/core/test/android/findPackageClassName.spec.js b/local-cli/rnpm/core/__tests__/android/findPackageClassName.spec.js similarity index 91% rename from local-cli/rnpm/core/test/android/findPackageClassName.spec.js rename to local-cli/rnpm/core/__tests__/android/findPackageClassName.spec.js index fbdd614a1..3ee3dd2d5 100644 --- a/local-cli/rnpm/core/test/android/findPackageClassName.spec.js +++ b/local-cli/rnpm/core/__tests__/android/findPackageClassName.spec.js @@ -2,7 +2,7 @@ jest.autoMockOff(); const findPackageClassName = require('../../src/config/android/findPackageClassName'); const mockFs = require('mock-fs'); -const mocks = require('../fixtures/android'); +const mocks = require('../../__fixtures__/android'); describe('android::findPackageClassName', () => { diff --git a/local-cli/rnpm/core/test/android/getDependencyConfig.spec.js b/local-cli/rnpm/core/__tests__/android/getDependencyConfig.spec.js similarity index 96% rename from local-cli/rnpm/core/test/android/getDependencyConfig.spec.js rename to local-cli/rnpm/core/__tests__/android/getDependencyConfig.spec.js index 15126a2de..67065a002 100644 --- a/local-cli/rnpm/core/test/android/getDependencyConfig.spec.js +++ b/local-cli/rnpm/core/__tests__/android/getDependencyConfig.spec.js @@ -2,7 +2,7 @@ jest.autoMockOff(); const getDependencyConfig = require('../../src/config/android').dependencyConfig; const mockFs = require('mock-fs'); -const mocks = require('../fixtures/android'); +const mocks = require('../../__fixtures__/android'); const userConfig = {}; describe('android::getDependencyConfig', () => { diff --git a/local-cli/rnpm/core/test/android/getProjectConfig.spec.js b/local-cli/rnpm/core/__tests__/android/getProjectConfig.spec.js similarity index 96% rename from local-cli/rnpm/core/test/android/getProjectConfig.spec.js rename to local-cli/rnpm/core/__tests__/android/getProjectConfig.spec.js index 1e62dbeca..f445f5061 100644 --- a/local-cli/rnpm/core/test/android/getProjectConfig.spec.js +++ b/local-cli/rnpm/core/__tests__/android/getProjectConfig.spec.js @@ -2,7 +2,7 @@ jest.autoMockOff(); const getProjectConfig = require('../../src/config/android').projectConfig; const mockFs = require('mock-fs'); -const mocks = require('../fixtures/android'); +const mocks = require('../../__fixtures__/android'); describe('android::getProjectConfig', () => { beforeAll(() => mockFs({ diff --git a/local-cli/rnpm/core/test/android/readManifest.spec.js b/local-cli/rnpm/core/__tests__/android/readManifest.spec.js similarity index 94% rename from local-cli/rnpm/core/test/android/readManifest.spec.js rename to local-cli/rnpm/core/__tests__/android/readManifest.spec.js index 571e18341..0c96a4cb1 100644 --- a/local-cli/rnpm/core/test/android/readManifest.spec.js +++ b/local-cli/rnpm/core/__tests__/android/readManifest.spec.js @@ -3,7 +3,7 @@ jest.autoMockOff(); const findManifest = require('../../src/config/android/findManifest'); const readManifest = require('../../src/config/android/readManifest'); const mockFs = require('mock-fs'); -const mocks = require('../fixtures/android'); +const mocks = require('../../__fixtures__/android'); describe('android::readManifest', () => { diff --git a/local-cli/rnpm/core/test/findAssets.spec.js b/local-cli/rnpm/core/__tests__/findAssets.spec.js similarity index 93% rename from local-cli/rnpm/core/test/findAssets.spec.js rename to local-cli/rnpm/core/__tests__/findAssets.spec.js index b31d5fac3..bb712aa32 100644 --- a/local-cli/rnpm/core/test/findAssets.spec.js +++ b/local-cli/rnpm/core/__tests__/findAssets.spec.js @@ -2,7 +2,7 @@ jest.autoMockOff(); const findAssets = require('../src/config/findAssets'); const mockFs = require('mock-fs'); -const dependencies = require('./fixtures/dependencies'); +const dependencies = require('../__fixtures__/dependencies'); const isArray = (arg) => Object.prototype.toString.call(arg) === '[object Array]'; diff --git a/local-cli/rnpm/core/test/findPlugins.js b/local-cli/rnpm/core/__tests__/findPlugins.spec.js similarity index 100% rename from local-cli/rnpm/core/test/findPlugins.js rename to local-cli/rnpm/core/__tests__/findPlugins.spec.js diff --git a/local-cli/rnpm/core/test/ios/findProject.spec.js b/local-cli/rnpm/core/__tests__/ios/findProject.spec.js similarity index 95% rename from local-cli/rnpm/core/test/ios/findProject.spec.js rename to local-cli/rnpm/core/__tests__/ios/findProject.spec.js index 6626921ba..a1c0801d2 100644 --- a/local-cli/rnpm/core/test/ios/findProject.spec.js +++ b/local-cli/rnpm/core/__tests__/ios/findProject.spec.js @@ -2,8 +2,8 @@ jest.autoMockOff(); const findProject = require('../../src/config/ios/findProject'); const mockFs = require('mock-fs'); -const projects = require('../fixtures/projects'); -const ios = require('../fixtures/ios'); +const projects = require('../../__fixtures__/projects'); +const ios = require('../../__fixtures__/ios'); const userConfig = {}; describe('ios::findProject', () => { diff --git a/local-cli/rnpm/core/test/ios/getProjectConfig.spec.js b/local-cli/rnpm/core/__tests__/ios/getProjectConfig.spec.js similarity index 63% rename from local-cli/rnpm/core/test/ios/getProjectConfig.spec.js rename to local-cli/rnpm/core/__tests__/ios/getProjectConfig.spec.js index bba3bedb1..5536de328 100644 --- a/local-cli/rnpm/core/test/ios/getProjectConfig.spec.js +++ b/local-cli/rnpm/core/__tests__/ios/getProjectConfig.spec.js @@ -2,7 +2,7 @@ jest.autoMockOff(); const getProjectConfig = require('../../src/config/ios').projectConfig; const mockFs = require('mock-fs'); -const projects = require('../fixtures/projects'); +const projects = require('../../__fixtures__/projects'); describe('ios::getProjectConfig', () => { const userConfig = {}; @@ -22,5 +22,15 @@ describe('ios::getProjectConfig', () => { expect(getProjectConfig(folder, userConfig)).toBe(null); }); + it('should return normalized shared library names', () => { + const projectConfig = getProjectConfig('testDir/nested', { + sharedLibraries: ['libc++', 'libz.tbd', 'HealthKit', 'HomeKit.framework'], + }); + + expect(projectConfig.sharedLibraries).toEqual( + ['libc++.tbd', 'libz.tbd', 'HealthKit.framework', 'HomeKit.framework'] + ); + }); + afterEach(mockFs.restore); }); diff --git a/local-cli/rnpm/core/test/makeCommand.spec.js b/local-cli/rnpm/core/__tests__/makeCommand.spec.js similarity index 100% rename from local-cli/rnpm/core/test/makeCommand.spec.js rename to local-cli/rnpm/core/__tests__/makeCommand.spec.js diff --git a/local-cli/rnpm/core/src/config/ios/index.js b/local-cli/rnpm/core/src/config/ios/index.js index 04ada20bf..5e1f2c091 100644 --- a/local-cli/rnpm/core/src/config/ios/index.js +++ b/local-cli/rnpm/core/src/config/ios/index.js @@ -1,6 +1,19 @@ const path = require('path'); const findProject = require('./findProject'); +/** + * For libraries specified without an extension, add '.tbd' for those that + * start with 'lib' and '.framework' to the rest. + */ +const mapSharedLibaries = (libraries) => { + return libraries.map(name => { + if (path.extname(name)) { + return name; + } + return name + (name.indexOf('lib') === 0 ? '.tbd' : '.framework'); + }); +}; + /** * Returns project config by analyzing given folder and applying some user defaults * when constructing final object @@ -24,6 +37,7 @@ exports.projectConfig = function projectConfigIOS(folder, userConfig) { projectPath: projectPath, projectName: path.basename(projectPath), libraryFolder: userConfig.libraryFolder || 'Libraries', + sharedLibraries: mapSharedLibaries(userConfig.sharedLibraries || []), plist: userConfig.plist || [], }; }; diff --git a/local-cli/rnpm/core/src/findPlugins.js b/local-cli/rnpm/core/src/findPlugins.js index 58d38559e..95bb2b20d 100644 --- a/local-cli/rnpm/core/src/findPlugins.js +++ b/local-cli/rnpm/core/src/findPlugins.js @@ -1,5 +1,4 @@ const path = require('path'); -const fs = require('fs'); const union = require('lodash').union; const uniq = require('lodash').uniq; const flatten = require('lodash').flatten; @@ -9,7 +8,7 @@ const flatten = require('lodash').flatten; * @param {String} dependency Name of the dependency * @return {Boolean} If dependency is a rnpm plugin */ -const isPlugin = (dependency) => !!~dependency.indexOf('rnpm-plugin-'); +const isPlugin = (dependency) => dependency.indexOf('rnpm-plugin-') === 0; const findPluginInFolder = (folder) => { var pjson; diff --git a/local-cli/rnpm/core/src/getCommands.js b/local-cli/rnpm/core/src/getCommands.js index 0de2cf7fe..0a86b6414 100644 --- a/local-cli/rnpm/core/src/getCommands.js +++ b/local-cli/rnpm/core/src/getCommands.js @@ -1,20 +1,11 @@ const path = require('path'); -const fs = require('fs'); -const uniq = require('lodash').uniq; -const flattenDeep = require('lodash').flattenDeep; const findPlugins = require('./findPlugins'); /** * @return {Array} Array of commands */ module.exports = function getCommands() { - const rnpmRoot = path.join(__dirname, '..'); const appRoot = process.cwd(); - return uniq( - flattenDeep([ - findPlugins([rnpmRoot]).map(require), - findPlugins([appRoot]).map(name => require(path.join(appRoot, 'node_modules', name))), - ]) - , 'name'); + return findPlugins([appRoot]).map(name => require(path.join(appRoot, 'node_modules', name))); }; diff --git a/local-cli/rnpm/core/test/getCommands.spec.js b/local-cli/rnpm/core/test/getCommands.spec.js deleted file mode 100644 index 4389b064d..000000000 --- a/local-cli/rnpm/core/test/getCommands.spec.js +++ /dev/null @@ -1,171 +0,0 @@ -jest.autoMockOff(); - -const path = require('path'); -const mock = require('mock-require'); -const rewire = require('rewire'); - -const commands = require('./fixtures/commands'); -const isArray = (arg) => - Object.prototype.toString.call(arg) === '[object Array]'; - -/** - * Paths to two possible `node_modules` locations `rnpm` can be installed - */ -const LOCAL_NODE_MODULES = path.join(process.cwd(), 'node_modules'); -const GLOBAL_NODE_MODULES = '/usr/local/lib/node_modules'; - -/** - * Paths to `package.json` of project, and rnpm - in two installation locations - */ -const APP_JSON = path.join(process.cwd(), 'package.json'); -const GLOBAL_RNPM_PJSON = path.join(GLOBAL_NODE_MODULES, '/rnpm/package.json'); -const LOCAL_RNPM_PJSON = path.join(LOCAL_NODE_MODULES, 'rnpm/package.json'); - -/** - * Sample `rnpm` plugin used in test cases - */ -const SAMPLE_RNPM_PLUGIN = 'rnpm-plugin-test'; - -/** - * Sample `package.json` of RNPM that will be used in test cases - */ -const SAMPLE_RNPM_JSON = { - dependencies: { - [SAMPLE_RNPM_PLUGIN]: '*', - }, -}; - -/** - * Project without `rnpm` plugins defined - */ -const NO_PLUGINS_JSON = { - dependencies: {}, -}; - -const getCommands = rewire('../src/getCommands'); -var revert; - -describe('getCommands', () => { - - afterEach(mock.stopAll); - - describe('in all installations', () => { - - beforeEach(() => { - revert = getCommands.__set__({ - __dirname: path.join(LOCAL_NODE_MODULES, 'rnpm/src'), - }); - mock(APP_JSON, NO_PLUGINS_JSON); - }); - - afterEach(() => revert()); - - it('list of the commands should be a non-empty array', () => { - mock(APP_JSON, NO_PLUGINS_JSON); - mock(LOCAL_RNPM_PJSON, SAMPLE_RNPM_JSON); - mock(SAMPLE_RNPM_PLUGIN, commands.single); - - expect(getCommands().length).not.toBe(0); - expect(isArray(getCommands())).toBeTruthy(); - }); - - it('should export one command', () => { - mock(LOCAL_RNPM_PJSON, SAMPLE_RNPM_JSON); - mock(SAMPLE_RNPM_PLUGIN, commands.single); - - expect(getCommands().length).toEqual(1); - }); - - it('should export multiple commands', () => { - mock(LOCAL_RNPM_PJSON, SAMPLE_RNPM_JSON); - mock(SAMPLE_RNPM_PLUGIN, commands.multiple); - - expect(getCommands().length).toEqual(2); - }); - - it('should export unique list of commands by name', () => { - mock(LOCAL_RNPM_PJSON, { - dependencies: { - [SAMPLE_RNPM_PLUGIN]: '*', - [`${SAMPLE_RNPM_PLUGIN}-2`]: '*', - }, - }); - - mock(SAMPLE_RNPM_PLUGIN, commands.single); - mock(`${SAMPLE_RNPM_PLUGIN}-2`, commands.single); - - expect(getCommands().length).toEqual(1); - }); - - }); - - describe('project plugins', () => { - /** - * In this test suite we only test project plugins thus we make sure - * `rnpm` package.json is properly mocked - */ - beforeEach(() => { - mock(LOCAL_RNPM_PJSON, NO_PLUGINS_JSON); - mock(GLOBAL_RNPM_PJSON, NO_PLUGINS_JSON); - }); - - afterEach(() => revert()); - - it('should load when installed locally', () => { - revert = getCommands.__set__({ - __dirname: path.join(LOCAL_NODE_MODULES, 'rnpm/src'), - }); - - mock(APP_JSON, SAMPLE_RNPM_JSON); - mock( - path.join(LOCAL_NODE_MODULES, SAMPLE_RNPM_PLUGIN), - commands.single - ); - - expect(getCommands()[0]).toEqual(commands.single); - }); - - it('should load when installed globally', () => { - revert = getCommands.__set__({ - __dirname: path.join(GLOBAL_NODE_MODULES, 'rnpm/src'), - }); - - mock(APP_JSON, SAMPLE_RNPM_JSON); - mock( - path.join(LOCAL_NODE_MODULES, SAMPLE_RNPM_PLUGIN), - commands.single - ); - - expect(getCommands()[0]).toEqual(commands.single); - }); - - }); - - describe('rnpm and project plugins', () => { - - beforeEach(() => { - revert = getCommands.__set__({ - __dirname: path.join(LOCAL_NODE_MODULES, 'rnpm/src'), - }); - }); - - afterEach(() => revert()); - - it('should load concatenated list of plugins', () => { - mock(APP_JSON, SAMPLE_RNPM_JSON); - mock(LOCAL_RNPM_PJSON, { - dependencies: { - [`${SAMPLE_RNPM_PLUGIN}-2`]: '*', - }, - }); - - mock( - path.join(LOCAL_NODE_MODULES, SAMPLE_RNPM_PLUGIN), - commands.multiple - ); - mock(`${SAMPLE_RNPM_PLUGIN}-2`, commands.single); - - expect(getCommands().length).toEqual(3); - }); - }); -}); diff --git a/local-cli/rnpm/install/index.js b/local-cli/rnpm/install/index.js deleted file mode 100644 index 66891919c..000000000 --- a/local-cli/rnpm/install/index.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = [ - { - func: require('./src/install'), - description: 'Install and link native dependencies', - name: 'install [packageName]', - }, { - func: require('./src/uninstall'), - description: 'Uninstall and unlink native dependencies', - name: 'uninstall [packageName]', - }, -]; diff --git a/local-cli/rnpm/install/install.js b/local-cli/rnpm/install/install.js new file mode 100644 index 000000000..bb43a2787 --- /dev/null +++ b/local-cli/rnpm/install/install.js @@ -0,0 +1,5 @@ +module.exports = { + func: require('./src/install'), + description: 'install and link native dependencies', + name: 'install ', +}; diff --git a/local-cli/rnpm/install/src/install.js b/local-cli/rnpm/install/src/install.js index d9eed2db4..77d6bd427 100644 --- a/local-cli/rnpm/install/src/install.js +++ b/local-cli/rnpm/install/src/install.js @@ -7,7 +7,7 @@ const spawnOpts = { log.heading = 'rnpm-install'; -module.exports = function install(config, args, callback) { +module.exports = function install(args, config) { const name = args[0]; var res = spawnSync('npm', ['install', name, '--save'], spawnOpts); diff --git a/local-cli/rnpm/install/src/uninstall.js b/local-cli/rnpm/install/src/uninstall.js index a1d7d9fc2..ff6b41f1c 100644 --- a/local-cli/rnpm/install/src/uninstall.js +++ b/local-cli/rnpm/install/src/uninstall.js @@ -7,7 +7,7 @@ const spawnOpts = { log.heading = 'rnpm-install'; -module.exports = function install(config, args, callback) { +module.exports = function install(args, config) { const name = args[0]; var res = spawnSync('rnpm', ['unlink', name], spawnOpts); diff --git a/local-cli/rnpm/install/uninstall.js b/local-cli/rnpm/install/uninstall.js new file mode 100644 index 000000000..258cae1b0 --- /dev/null +++ b/local-cli/rnpm/install/uninstall.js @@ -0,0 +1,5 @@ +module.exports = { + func: require('./src/uninstall'), + description: 'uninstall and unlink native dependencies', + name: 'uninstall ', +}; diff --git a/local-cli/rnpm/link/test/fixtures/android/0.17/MainActivity.java b/local-cli/rnpm/link/__fixtures__/android/0.17/MainActivity.java similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/0.17/MainActivity.java rename to local-cli/rnpm/link/__fixtures__/android/0.17/MainActivity.java diff --git a/local-cli/rnpm/link/test/fixtures/android/0.17/patchedMainActivity.java b/local-cli/rnpm/link/__fixtures__/android/0.17/patchedMainActivity.java similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/0.17/patchedMainActivity.java rename to local-cli/rnpm/link/__fixtures__/android/0.17/patchedMainActivity.java diff --git a/local-cli/rnpm/link/test/fixtures/android/0.18/MainActivity.java b/local-cli/rnpm/link/__fixtures__/android/0.18/MainActivity.java similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/0.18/MainActivity.java rename to local-cli/rnpm/link/__fixtures__/android/0.18/MainActivity.java diff --git a/local-cli/rnpm/link/test/fixtures/android/0.18/patchedMainActivity.java b/local-cli/rnpm/link/__fixtures__/android/0.18/patchedMainActivity.java similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/0.18/patchedMainActivity.java rename to local-cli/rnpm/link/__fixtures__/android/0.18/patchedMainActivity.java diff --git a/local-cli/rnpm/link/test/fixtures/android/0.20/MainActivity.java b/local-cli/rnpm/link/__fixtures__/android/0.20/MainActivity.java similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/0.20/MainActivity.java rename to local-cli/rnpm/link/__fixtures__/android/0.20/MainActivity.java diff --git a/local-cli/rnpm/link/test/fixtures/android/build.gradle b/local-cli/rnpm/link/__fixtures__/android/build.gradle similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/build.gradle rename to local-cli/rnpm/link/__fixtures__/android/build.gradle diff --git a/local-cli/rnpm/link/test/fixtures/android/patchedBuild.gradle b/local-cli/rnpm/link/__fixtures__/android/patchedBuild.gradle similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/patchedBuild.gradle rename to local-cli/rnpm/link/__fixtures__/android/patchedBuild.gradle diff --git a/local-cli/rnpm/link/test/fixtures/android/patchedSettings.gradle b/local-cli/rnpm/link/__fixtures__/android/patchedSettings.gradle similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/patchedSettings.gradle rename to local-cli/rnpm/link/__fixtures__/android/patchedSettings.gradle diff --git a/local-cli/rnpm/link/test/fixtures/android/settings.gradle b/local-cli/rnpm/link/__fixtures__/android/settings.gradle similarity index 100% rename from local-cli/rnpm/link/test/fixtures/android/settings.gradle rename to local-cli/rnpm/link/__fixtures__/android/settings.gradle diff --git a/local-cli/rnpm/link/test/fixtures/linearGradient.pbxproj b/local-cli/rnpm/link/__fixtures__/linearGradient.pbxproj similarity index 100% rename from local-cli/rnpm/link/test/fixtures/linearGradient.pbxproj rename to local-cli/rnpm/link/__fixtures__/linearGradient.pbxproj diff --git a/local-cli/rnpm/link/test/fixtures/project.pbxproj b/local-cli/rnpm/link/__fixtures__/project.pbxproj similarity index 100% rename from local-cli/rnpm/link/test/fixtures/project.pbxproj rename to local-cli/rnpm/link/__fixtures__/project.pbxproj diff --git a/local-cli/rnpm/link/test/android/patches/applyPatch.js b/local-cli/rnpm/link/__tests__/android/applyPatch.spec.js similarity index 53% rename from local-cli/rnpm/link/test/android/patches/applyPatch.js rename to local-cli/rnpm/link/__tests__/android/applyPatch.spec.js index cc5ba34f1..35ff81057 100644 --- a/local-cli/rnpm/link/test/android/patches/applyPatch.js +++ b/local-cli/rnpm/link/__tests__/android/applyPatch.spec.js @@ -1,17 +1,19 @@ -const chai = require('chai'); -const expect = chai.expect; -const applyParams = require('../../../src/android/patches/applyParams'); +'use strict'; + +jest.autoMockOff(); + +const applyParams = require('../../src/android/patches/applyParams'); describe('applyParams', () => { it('apply params to the string', () => { expect( applyParams('${foo}', {foo: 'foo'}, 'react-native') - ).to.be.equal('this.getResources().getString(R.strings.reactNative_foo)'); + ).toEqual('this.getResources().getString(R.strings.reactNative_foo)'); }); it('use null if no params provided', () => { expect( applyParams('${foo}', {}, 'react-native') - ).to.be.equal('null'); + ).toEqual('null'); }); }); diff --git a/local-cli/rnpm/link/__tests__/android/isInstalled.spec.js b/local-cli/rnpm/link/__tests__/android/isInstalled.spec.js new file mode 100644 index 000000000..56befa52b --- /dev/null +++ b/local-cli/rnpm/link/__tests__/android/isInstalled.spec.js @@ -0,0 +1,20 @@ +'use strict'; + +jest.autoMockOff(); + +const path = require('path'); +const isInstalled = require('../../src/android/isInstalled'); + +const projectConfig = { + buildGradlePath: path.join(__dirname, '../../__fixtures__/android/patchedBuild.gradle'), +}; + +describe('android::isInstalled', () => { + it('should return true when project is already in build.gradle', () => + expect(isInstalled(projectConfig, 'test')).toBeTruthy() + ); + + it('should return false when project is not in build.gradle', () => + expect(isInstalled(projectConfig, 'test2')).toBeFalsy() + ); +}); diff --git a/local-cli/rnpm/link/__tests__/android/makeBuildPatch.spec.js b/local-cli/rnpm/link/__tests__/android/makeBuildPatch.spec.js new file mode 100644 index 000000000..e20e2b592 --- /dev/null +++ b/local-cli/rnpm/link/__tests__/android/makeBuildPatch.spec.js @@ -0,0 +1,18 @@ +'use strict'; + +jest.autoMockOff(); + +const makeBuildPatch = require('../../src/android/patches/makeBuildPatch'); +const name = 'test'; + +describe('makeBuildPatch', () => { + it('should build a patch function', () => { + expect(Object.prototype.toString(makeBuildPatch(name))) + .toBe('[object Object]'); + }); + + it('should make a correct patch', () => { + const {patch} = makeBuildPatch(name); + expect(patch).toBe(` compile project(':${name}')\n`); + }); +}); diff --git a/local-cli/rnpm/link/__tests__/android/makeImportPatch.spec.js b/local-cli/rnpm/link/__tests__/android/makeImportPatch.spec.js new file mode 100644 index 000000000..6ee214068 --- /dev/null +++ b/local-cli/rnpm/link/__tests__/android/makeImportPatch.spec.js @@ -0,0 +1,20 @@ +'use strict'; + +jest.autoMockOff(); + +const makeImportPatch = require('../../src/android/patches/makeImportPatch'); + +const packageImportPath = 'import some.example.project'; + +describe('makeImportPatch', () => { + it('should build a patch', () => { + expect(Object.prototype.toString(makeImportPatch(packageImportPath))) + .toBe('[object Object]'); + }); + + it('MainActivity contains a correct import patch', () => { + const {patch} = makeImportPatch(packageImportPath); + + expect(patch).toBe('\n' + packageImportPath); + }); +}); diff --git a/local-cli/rnpm/link/__tests__/android/makePackagePatch.spec.js b/local-cli/rnpm/link/__tests__/android/makePackagePatch.spec.js new file mode 100644 index 000000000..2a87848ff --- /dev/null +++ b/local-cli/rnpm/link/__tests__/android/makePackagePatch.spec.js @@ -0,0 +1,28 @@ +'use strict'; + +jest.autoMockOff(); + +const makePackagePatch = require('../../src/android/patches/makePackagePatch'); +const applyParams = require('../../src/android/patches/applyParams'); + +const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')'; +const name = 'some-library'; +const params = { + foo: 'foo', + bar: 'bar', +}; + +describe('makePackagePatch@0.20', () => { + it('should build a patch', () => { + const packagePatch = makePackagePatch(packageInstance, params, name); + expect(Object.prototype.toString(packagePatch)) + .toBe('[object Object]'); + }); + + it('MainActivity contains a correct 0.20 import patch', () => { + const {patch} = makePackagePatch(packageInstance, params, name); + const processedInstance = applyParams(packageInstance, params, name); + + expect(patch).toBe(',\n ' + processedInstance); + }); +}); diff --git a/local-cli/rnpm/link/test/android/patches/makeSettingsPatch.spec.js b/local-cli/rnpm/link/__tests__/android/makeSettingsPatch.spec.js similarity index 65% rename from local-cli/rnpm/link/test/android/patches/makeSettingsPatch.spec.js rename to local-cli/rnpm/link/__tests__/android/makeSettingsPatch.spec.js index 2dfe97c6c..ca3b303e9 100644 --- a/local-cli/rnpm/link/test/android/patches/makeSettingsPatch.spec.js +++ b/local-cli/rnpm/link/__tests__/android/makeSettingsPatch.spec.js @@ -1,8 +1,9 @@ -const fs = require('fs'); +'use strict'; + +jest.autoMockOff(); + const path = require('path'); -const chai = require('chai'); -const expect = chai.expect; -const makeSettingsPatch = require('../../../src/android/patches/makeSettingsPatch'); +const makeSettingsPatch = require('../../src/android/patches/makeSettingsPatch'); const name = 'test'; const projectConfig = { @@ -15,9 +16,9 @@ const dependencyConfig = { describe('makeSettingsPatch', () => { it('should build a patch function', () => { - expect( - makeSettingsPatch(name, dependencyConfig, {}, projectConfig) - ).to.be.an('object'); + expect(Object.prototype.toString( + makeSettingsPatch(name, dependencyConfig, projectConfig) + )).toBe('[object Object]'); }); it('should make a correct patch', () => { @@ -26,8 +27,10 @@ describe('makeSettingsPatch', () => { dependencyConfig.sourceDir ); - expect(makeSettingsPatch(name, dependencyConfig, projectConfig).patch) - .to.be.equal( + const {patch} = makeSettingsPatch(name, dependencyConfig, projectConfig); + + expect(patch) + .toBe( `include ':${name}'\n` + `project(':${name}').projectDir = ` + `new File(rootProject.projectDir, '${projectDir}')\n` diff --git a/local-cli/rnpm/link/test/getDependencyConfig.spec.js b/local-cli/rnpm/link/__tests__/getDependencyConfig.spec.js similarity index 64% rename from local-cli/rnpm/link/test/getDependencyConfig.spec.js rename to local-cli/rnpm/link/__tests__/getDependencyConfig.spec.js index 7fba3b65b..eeb2bfa43 100644 --- a/local-cli/rnpm/link/test/getDependencyConfig.spec.js +++ b/local-cli/rnpm/link/__tests__/getDependencyConfig.spec.js @@ -1,5 +1,7 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const getDependencyConfig = require('../src/getDependencyConfig'); const sinon = require('sinon'); @@ -9,8 +11,8 @@ describe('getDependencyConfig', () => { getDependencyConfig: sinon.stub(), }; - expect(getDependencyConfig(config, ['abcd'])).to.be.an.array; - expect(config.getDependencyConfig.callCount).to.equals(1); + expect(Array.isArray(getDependencyConfig(config, ['abcd']))).toBeTruthy(); + expect(config.getDependencyConfig.callCount).toEqual(1); }); it('should filter out invalid react-native projects', () => { @@ -18,6 +20,6 @@ describe('getDependencyConfig', () => { getDependencyConfig: sinon.stub().throws(new Error('Cannot require')), }; - expect(getDependencyConfig(config, ['abcd'])).to.deep.equal([]); + expect(getDependencyConfig(config, ['abcd'])).toEqual([]); }); }); diff --git a/local-cli/rnpm/link/test/getProjectDependencies.spec.js b/local-cli/rnpm/link/__tests__/getProjectDependencies.spec.js similarity index 55% rename from local-cli/rnpm/link/test/getProjectDependencies.spec.js rename to local-cli/rnpm/link/__tests__/getProjectDependencies.spec.js index 21abb7648..2edd17361 100644 --- a/local-cli/rnpm/link/test/getProjectDependencies.spec.js +++ b/local-cli/rnpm/link/__tests__/getProjectDependencies.spec.js @@ -1,27 +1,23 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const getProjectDependencies = require('../src/getProjectDependencies'); -const mock = require('mock-require'); const path = require('path'); describe('getProjectDependencies', () => { it('should return an array of project dependencies', () => { - mock( + jest.setMock( path.join(process.cwd(), './package.json'), - { dependencies: { lodash: '^6.0.0', 'react-native': '^16.0.0' } } + { dependencies: { lodash: '^6.0.0', 'react-native': '^16.0.0' }} ); - expect(getProjectDependencies()).to.deep.equals(['lodash']); + expect(getProjectDependencies()).toEqual(['lodash']); }); it('should return an empty array when no dependencies set', () => { - mock(path.join(process.cwd(), './package.json'), {}); - expect(getProjectDependencies()).to.deep.equals([]); + jest.setMock(path.join(process.cwd(), './package.json'), {}); + expect(getProjectDependencies()).toEqual([]); }); - - afterEach(() => { - mock.stopAll(); - }); - }); diff --git a/local-cli/rnpm/link/test/groupFilesByType.spec.js b/local-cli/rnpm/link/__tests__/groupFilesByType.spec.js similarity index 69% rename from local-cli/rnpm/link/test/groupFilesByType.spec.js rename to local-cli/rnpm/link/__tests__/groupFilesByType.spec.js index ac5ecfc69..805851da4 100644 --- a/local-cli/rnpm/link/test/groupFilesByType.spec.js +++ b/local-cli/rnpm/link/__tests__/groupFilesByType.spec.js @@ -1,5 +1,7 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const groupFilesByType = require('../src/groupFilesByType'); describe('groupFilesByType', () => { @@ -16,8 +18,8 @@ describe('groupFilesByType', () => { const groupedFiles = groupFilesByType(fonts.concat(images)); - expect(groupedFiles.font).to.deep.equal(fonts); - expect(groupedFiles.image).to.deep.equal(images); + expect(groupedFiles.font).toEqual(fonts); + expect(groupedFiles.image).toEqual(images); }); }); diff --git a/local-cli/rnpm/link/__tests__/ios/addFileToProject.spec.js b/local-cli/rnpm/link/__tests__/ios/addFileToProject.spec.js new file mode 100644 index 000000000..a591394b3 --- /dev/null +++ b/local-cli/rnpm/link/__tests__/ios/addFileToProject.spec.js @@ -0,0 +1,27 @@ +'use strict'; + +jest.autoMockOff(); + +const xcode = require('xcode'); +const path = require('path'); +const addFileToProject = require('../../src/ios/addFileToProject'); +const _ = require('lodash'); + +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); + +describe('ios::addFileToProject', () => { + beforeEach(() => { + project.parseSync(); + }); + + xit('should add file to a project', () => { + expect( + _.includes( + Object.keys(project.pbxFileReferenceSection()), + addFileToProject(project, '../../__fixtures__/linearGradient.pbxproj').fileRef + ) + ).toBeTruthy(); + }); +}); diff --git a/local-cli/rnpm/link/test/ios/addProjectToLibraries.spec.js b/local-cli/rnpm/link/__tests__/ios/addProjectToLibraries.spec.js similarity index 67% rename from local-cli/rnpm/link/test/ios/addProjectToLibraries.spec.js rename to local-cli/rnpm/link/__tests__/ios/addProjectToLibraries.spec.js index 696cce114..40673e443 100644 --- a/local-cli/rnpm/link/test/ios/addProjectToLibraries.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/addProjectToLibraries.spec.js @@ -1,14 +1,18 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); +const path = require('path'); const PbxFile = require('xcode/lib/pbxFile'); const addProjectToLibraries = require('../../src/ios/addProjectToLibraries'); const last = require('lodash').last; -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::addProjectToLibraries', () => { - beforeEach(() => { project.parseSync(); }); @@ -21,8 +25,7 @@ describe('ios::addProjectToLibraries', () => { const child = last(libraries.children); - expect(child).to.have.keys(['value', 'comment']); - expect(child.comment).to.equals(file.basename); + expect((['value', 'comment']), child).toBeTruthy(); + expect(child.comment).toBe(file.basename); }); - }); diff --git a/local-cli/rnpm/link/__tests__/ios/addSharedLibraries.spec.js b/local-cli/rnpm/link/__tests__/ios/addSharedLibraries.spec.js new file mode 100644 index 000000000..f407fd980 --- /dev/null +++ b/local-cli/rnpm/link/__tests__/ios/addSharedLibraries.spec.js @@ -0,0 +1,45 @@ +'use strict'; + +jest.autoMockOff(); + +const xcode = require('xcode'); +const path = require('path'); +const addSharedLibraries = require('../../src/ios/addSharedLibraries'); +const getGroup = require('../../src/ios/getGroup'); + +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); + +describe('ios::addSharedLibraries', () => { + + beforeEach(() => { + project.parseSync(); + }); + + it('should automatically create Frameworks group', () => { + expect(getGroup(project, 'Frameworks')).toBeNull(); + addSharedLibraries(project, ['libz.tbd']); + expect(getGroup(project, 'Frameworks')).not.toBeNull(); + }); + + it('should add shared libraries to project', () => { + addSharedLibraries(project, ['libz.tbd']); + + const frameworksGroup = getGroup(project, 'Frameworks'); + expect(frameworksGroup.children.length).toEqual(1); + expect(frameworksGroup.children[0].comment).toEqual('libz.tbd'); + + addSharedLibraries(project, ['MessageUI.framework']); + expect(frameworksGroup.children.length).toEqual(2); + }); + + it('should not add duplicate libraries to project', () => { + addSharedLibraries(project, ['libz.tbd']); + addSharedLibraries(project, ['libz.tbd']); + + const frameworksGroup = getGroup(project, 'Frameworks'); + expect(frameworksGroup.children.length).toEqual(1); + }); + +}); diff --git a/local-cli/rnpm/link/test/ios/createGroup.spec.js b/local-cli/rnpm/link/__tests__/ios/createGroup.spec.js similarity index 70% rename from local-cli/rnpm/link/test/ios/createGroup.spec.js rename to local-cli/rnpm/link/__tests__/ios/createGroup.spec.js index f4653ea61..2e95c8f18 100644 --- a/local-cli/rnpm/link/test/ios/createGroup.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/createGroup.spec.js @@ -1,21 +1,25 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); +const path = require('path'); const createGroup = require('../../src/ios/createGroup'); const getGroup = require('../../src/ios/getGroup'); const last = require('lodash').last; -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::createGroup', () => { - beforeEach(() => { project.parseSync(); }); it('should create a group with given name', () => { const createdGroup = createGroup(project, 'Resources'); - expect(createdGroup.name).to.equals('Resources'); + expect(createdGroup.name).toBe('Resources'); }); it('should attach group to main project group', () => { @@ -24,7 +28,7 @@ describe('ios::createGroup', () => { expect( last(mainGroup.children).comment - ).to.equals(createdGroup.name); + ).toBe(createdGroup.name); }); it('should create a nested group with given path', () => { @@ -33,7 +37,7 @@ describe('ios::createGroup', () => { expect( last(outerGroup.children).comment - ).to.equals(createdGroup.name); + ).toBe(createdGroup.name); }); it('should-not create already created groups', () => { @@ -42,8 +46,11 @@ describe('ios::createGroup', () => { const mainGroup = getGroup(project); expect( - mainGroup.children.filter(group => group.comment === 'Libraries').length - ).to.equals(1); - expect(last(outerGroup.children).comment).to.equals(createdGroup.name); + mainGroup + .children + .filter(group => group.comment === 'Libraries') + .length + ).toBe(1); + expect(last(outerGroup.children).comment).toBe(createdGroup.name); }); }); diff --git a/local-cli/rnpm/link/test/ios/getBuildProperty.spec.js b/local-cli/rnpm/link/__tests__/ios/getBuildProperty.spec.js similarity index 61% rename from local-cli/rnpm/link/test/ios/getBuildProperty.spec.js rename to local-cli/rnpm/link/__tests__/ios/getBuildProperty.spec.js index 1ca3f30a6..e91375831 100644 --- a/local-cli/rnpm/link/test/ios/getBuildProperty.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/getBuildProperty.spec.js @@ -1,19 +1,22 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); +const path = require('path'); const getBuildProperty = require('../../src/ios/getBuildProperty'); -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::getBuildProperty', () => { - beforeEach(() => { project.parseSync(); }); it('should return build property from main target', () => { const plistPath = getBuildProperty(project, 'INFOPLIST_FILE'); - expect(plistPath).to.equals('"Basic/Info.plist"'); + expect(plistPath).toEqual('"Basic/Info.plist"'); }); - }); diff --git a/local-cli/rnpm/link/test/ios/getGroup.spec.js b/local-cli/rnpm/link/__tests__/ios/getGroup.spec.js similarity index 62% rename from local-cli/rnpm/link/test/ios/getGroup.spec.js rename to local-cli/rnpm/link/__tests__/ios/getGroup.spec.js index 5df45f7f0..6d1b770dc 100644 --- a/local-cli/rnpm/link/test/ios/getGroup.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/getGroup.spec.js @@ -1,9 +1,14 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const getGroup = require('../../src/ios/getGroup'); +const path = require('path'); -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::getGroup', () => { beforeEach(() => { @@ -12,25 +17,25 @@ describe('ios::getGroup', () => { it('should return a top-level group', () => { const group = getGroup(project, 'Libraries'); - expect(group.children.length > 0).to.be.true; // our test top-level Libraries has children - expect(group.name).to.equals('Libraries'); + expect(group.children.length > 0).toBeTruthy(); + expect(group.name).toBe('Libraries'); }); it('should return nested group when specified', () => { const group = getGroup(project, 'NestedGroup/Libraries'); - expect(group.children.length).to.equals(0); // our test nested Libraries is empty - expect(group.name).to.equals('Libraries'); + expect(group.children.length).toBe(0); // our test nested Libraries is empty + expect(group.name).toBe('Libraries'); }); it('should return null when no group found', () => { const group = getGroup(project, 'I-Dont-Exist'); - expect(group).to.be.null; + expect(group).toBeNull(); }); it('should return top-level group when name not specified', () => { const mainGroupId = project.getFirstProject().firstProject.mainGroup; const mainGroup = project.getPBXGroupByKey(mainGroupId); const group = getGroup(project); - expect(group).to.equals(mainGroup); + expect(group).toEqual(mainGroup); }); }); diff --git a/local-cli/rnpm/link/test/ios/getHeaderSearchPath.spec.js b/local-cli/rnpm/link/__tests__/ios/getHeaderSearchPath.spec.js similarity index 92% rename from local-cli/rnpm/link/test/ios/getHeaderSearchPath.spec.js rename to local-cli/rnpm/link/__tests__/ios/getHeaderSearchPath.spec.js index 216979ca4..bcf3b8e4a 100644 --- a/local-cli/rnpm/link/test/ios/getHeaderSearchPath.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/getHeaderSearchPath.spec.js @@ -1,12 +1,13 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const getHeaderSearchPath = require('../../src/ios/getHeaderSearchPath'); const path = require('path'); const SRC_DIR = path.join('react-native-project', 'ios'); describe('ios::getHeaderSearchPath', () => { - /** * See https://github.com/Microsoft/react-native-code-push */ @@ -18,7 +19,7 @@ describe('ios::getHeaderSearchPath', () => { const searchPath = getHeaderSearchPath(SRC_DIR, files); - expect(searchPath).to.equal( + expect(searchPath).toBe( `"${['$(SRCROOT)', '..', 'node_modules', 'package'].join(path.sep)}"` ); }); @@ -34,7 +35,7 @@ describe('ios::getHeaderSearchPath', () => { const searchPath = getHeaderSearchPath(SRC_DIR, files); - expect(searchPath).to.equal( + expect(searchPath).toBe( `"${['$(SRCROOT)', '..', 'node_modules', 'package', 'src'].join(path.sep)}/**"` ); }); @@ -51,7 +52,7 @@ describe('ios::getHeaderSearchPath', () => { const searchPath = getHeaderSearchPath(SRC_DIR, files); - expect(searchPath).to.equal( + expect(searchPath).toBe( `"${['$(SRCROOT)', '..', 'node_modules', 'package', 'src'].join(path.sep)}/**"` ); }); diff --git a/local-cli/rnpm/link/test/ios/getHeadersInFolder.spec.js b/local-cli/rnpm/link/__tests__/ios/getHeadersInFolder.spec.js similarity index 64% rename from local-cli/rnpm/link/test/ios/getHeadersInFolder.spec.js rename to local-cli/rnpm/link/__tests__/ios/getHeadersInFolder.spec.js index 54f4c0f6e..206f9f50c 100644 --- a/local-cli/rnpm/link/test/ios/getHeadersInFolder.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/getHeadersInFolder.spec.js @@ -1,27 +1,27 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const getHeadersInFolder = require('../../src/ios/getHeadersInFolder'); -const mock = require('mock-fs'); describe('ios::getHeadersInFolder', () => { - - it('should return an array of all headers in given folder', () => { - mock({ + xit('should return an array of all headers in given folder', () => { + jest.setMock({ 'FileA.h': '', 'FileB.h': '', }); const foundHeaders = getHeadersInFolder(process.cwd()); - expect(foundHeaders.length).to.equals(2); + expect(foundHeaders.length).toBe(2); getHeadersInFolder(process.cwd()).forEach(headerPath => { expect(headerPath).to.contain(process.cwd()); }); }); - it('should ignore all headers in Pods, Examples & node_modules', () => { - mock({ + xit('should ignore all headers in Pods, Examples & node_modules', () => { + jest.setMock({ 'FileA.h': '', 'FileB.h': '', Pods: { @@ -37,9 +37,4 @@ describe('ios::getHeadersInFolder', () => { expect(getHeadersInFolder(process.cwd()).length).to.equals(2); }); - - afterEach(() => { - mock.restore(); - }); - }); diff --git a/local-cli/rnpm/link/test/ios/getPlist.spec.js b/local-cli/rnpm/link/__tests__/ios/getPlist.spec.js similarity index 55% rename from local-cli/rnpm/link/test/ios/getPlist.spec.js rename to local-cli/rnpm/link/__tests__/ios/getPlist.spec.js index 76e072755..d222b3f47 100644 --- a/local-cli/rnpm/link/test/ios/getPlist.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/getPlist.spec.js @@ -1,23 +1,24 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const getPlist = require('../../src/ios/getPlist'); +const path = require('path'); -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::getPlist', () => { - beforeEach(() => { project.parseSync(); }); it('should return null when `.plist` file missing', () => { const plistPath = getPlist(project, process.cwd()); - expect(plistPath).to.equals(null); - }); - - it.skip('should return parsed `plist`', () => { - // @todo mock fs here + expect(plistPath).toBeNull(); }); + // @todo - Happy scenario }); diff --git a/local-cli/rnpm/link/test/ios/getPlistPath.spec.js b/local-cli/rnpm/link/__tests__/ios/getPlistPath.spec.js similarity index 59% rename from local-cli/rnpm/link/test/ios/getPlistPath.spec.js rename to local-cli/rnpm/link/__tests__/ios/getPlistPath.spec.js index c8c758ac0..4b21b484e 100644 --- a/local-cli/rnpm/link/test/ios/getPlistPath.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/getPlistPath.spec.js @@ -1,19 +1,22 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const getPlistPath = require('../../src/ios/getPlistPath'); +const path = require('path'); -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::getPlistPath', () => { - beforeEach(() => { project.parseSync(); }); it('should return path without Xcode $(SRCROOT)', () => { const plistPath = getPlistPath(project, '/'); - expect(plistPath).to.equals('/Basic/Info.plist'); + expect(plistPath).toBe('/Basic/Info.plist'); }); - }); diff --git a/local-cli/rnpm/link/test/ios/getProducts.spec.js b/local-cli/rnpm/link/__tests__/ios/getProducts.spec.js similarity index 55% rename from local-cli/rnpm/link/test/ios/getProducts.spec.js rename to local-cli/rnpm/link/__tests__/ios/getProducts.spec.js index bf483f1b2..6ec8daba6 100644 --- a/local-cli/rnpm/link/test/ios/getProducts.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/getProducts.spec.js @@ -1,20 +1,23 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const getProducts = require('../../src/ios/getProducts'); +const path = require('path'); -const project = xcode.project('test/fixtures/linearGradient.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::getProducts', () => { - beforeEach(() => { project.parseSync(); }); it('should return an array of static libraries project exports', () => { const products = getProducts(project); - expect(products.length).to.equals(1); - expect(products).to.contains('libBVLinearGradient.a'); + expect(products.length).toBe(1); + expect(products).toContain('libRCTActionSheet.a'); }); - }); diff --git a/local-cli/rnpm/link/test/ios/hasLibraryImported.spec.js b/local-cli/rnpm/link/__tests__/ios/hasLibraryImported.spec.js similarity index 60% rename from local-cli/rnpm/link/test/ios/hasLibraryImported.spec.js rename to local-cli/rnpm/link/__tests__/ios/hasLibraryImported.spec.js index c32141879..77f1657cf 100644 --- a/local-cli/rnpm/link/test/ios/hasLibraryImported.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/hasLibraryImported.spec.js @@ -1,24 +1,27 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const hasLibraryImported = require('../../src/ios/hasLibraryImported'); +const path = require('path'); -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::hasLibraryImported', () => { - beforeEach(() => { project.parseSync(); }); it('should return true if project has been already imported', () => { const libraries = project.pbxGroupByName('Libraries'); - expect(hasLibraryImported(libraries, 'React.xcodeproj')).to.be.true; + expect(hasLibraryImported(libraries, 'React.xcodeproj')).toBeTruthy(); }); it('should return false if project is not imported', () => { const libraries = project.pbxGroupByName('Libraries'); - expect(hasLibraryImported(libraries, 'ACME.xcodeproj')).to.be.false; + expect(hasLibraryImported(libraries, 'ACME.xcodeproj')).toBeFalsy(); }); - }); diff --git a/local-cli/rnpm/link/test/ios/isInstalled.spec.js b/local-cli/rnpm/link/__tests__/ios/isInstalled.spec.js similarity index 57% rename from local-cli/rnpm/link/test/ios/isInstalled.spec.js rename to local-cli/rnpm/link/__tests__/ios/isInstalled.spec.js index 65983c6f9..ae3651f02 100644 --- a/local-cli/rnpm/link/test/ios/isInstalled.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/isInstalled.spec.js @@ -1,39 +1,29 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); +'use strict'; + +jest.autoMockOff(); + const path = require('path'); const isInstalled = require('../../src/ios/isInstalled'); const baseProjectConfig = { - pbxprojPath: 'project.pbxproj', + pbxprojPath: path.join(__dirname, '../../__fixtures__/project.pbxproj'), libraryFolder: 'Libraries', }; describe('ios::isInstalled', () => { - - before(() => { - mock({ - 'project.pbxproj': fs.readFileSync(path.join(__dirname, '../fixtures/project.pbxproj')), - }); - }); - it('should return true when .xcodeproj in Libraries', () => { const dependencyConfig = { projectName: 'React.xcodeproj' }; - expect(isInstalled(baseProjectConfig, dependencyConfig)).to.be.true; + expect(isInstalled(baseProjectConfig, dependencyConfig)).toBeTruthy(); }); it('should return false when .xcodeproj not in Libraries', () => { const dependencyConfig = { projectName: 'Missing.xcodeproj' }; - expect(isInstalled(baseProjectConfig, dependencyConfig)).to.be.false; + expect(isInstalled(baseProjectConfig, dependencyConfig)).toBeFalsy(); }); it('should return false when `LibraryFolder` is missing', () => { const dependencyConfig = { projectName: 'React.xcodeproj' }; const projectConfig = Object.assign({}, baseProjectConfig, { libraryFolder: 'Missing' }); - expect(isInstalled(projectConfig, dependencyConfig)).to.be.false; + expect(isInstalled(projectConfig, dependencyConfig)).toBeFalsy(); }); - - after(mock.restore); - }); diff --git a/local-cli/rnpm/link/test/ios/mapHeaderSearchPaths.spec.js b/local-cli/rnpm/link/__tests__/ios/mapHeaderSearchPaths.spec.js similarity index 61% rename from local-cli/rnpm/link/test/ios/mapHeaderSearchPaths.spec.js rename to local-cli/rnpm/link/__tests__/ios/mapHeaderSearchPaths.spec.js index f885fbd8f..4bc1a7d24 100644 --- a/local-cli/rnpm/link/test/ios/mapHeaderSearchPaths.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/mapHeaderSearchPaths.spec.js @@ -1,23 +1,24 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const mapHeaderSearchPaths = require('../../src/ios/mapHeaderSearchPaths'); +const path = require('path'); -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); const reactPath = '"$(SRCROOT)/../node_modules/react-native/React/**"'; describe('ios::mapHeaderSearchPaths', () => { - beforeEach(() => { project.parseSync(); }); it('should iterate over headers with `react` added only', () => { - const path = '../../node_modules/path-to-module/**'; - mapHeaderSearchPaths(project, paths => { - expect(paths.find(path => path.indexOf(reactPath))).to.be.not.empty; + expect(paths.find(p => p.indexOf(reactPath))).toBeDefined(); }); }); - }); diff --git a/local-cli/rnpm/link/test/ios/removeProjectFromLibraries.js b/local-cli/rnpm/link/__tests__/ios/removeProjectFromLibraries.js similarity index 78% rename from local-cli/rnpm/link/test/ios/removeProjectFromLibraries.js rename to local-cli/rnpm/link/__tests__/ios/removeProjectFromLibraries.js index 49a4c42b4..8c0d728eb 100644 --- a/local-cli/rnpm/link/test/ios/removeProjectFromLibraries.js +++ b/local-cli/rnpm/link/__tests__/ios/removeProjectFromLibraries.js @@ -1,15 +1,19 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const PbxFile = require('xcode/lib/pbxFile'); const addProjectToLibraries = require('../../src/ios/addProjectToLibraries'); const removeProjectFromLibraries = require('../../src/ios/removeProjectFromLibraries'); const last = require('lodash').last; +const path = require('path'); -const project = xcode.project('test/fixtures/project.pbxproj'); +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); describe('ios::removeProjectFromLibraries', () => { - beforeEach(() => { project.parseSync(); @@ -27,7 +31,6 @@ describe('ios::removeProjectFromLibraries', () => { const child = last(libraries.children); - expect(child.comment).to.not.equals(file.basename); + expect(child.comment).not.toBe(file.basename); }); - }); diff --git a/local-cli/rnpm/link/test/ios/removeProjectFromProject.spec.js b/local-cli/rnpm/link/__tests__/ios/removeProjectFromProject.spec.js similarity index 59% rename from local-cli/rnpm/link/test/ios/removeProjectFromProject.spec.js rename to local-cli/rnpm/link/__tests__/ios/removeProjectFromProject.spec.js index 8220028ae..0201d8824 100644 --- a/local-cli/rnpm/link/test/ios/removeProjectFromProject.spec.js +++ b/local-cli/rnpm/link/__tests__/ios/removeProjectFromProject.spec.js @@ -1,32 +1,36 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const xcode = require('xcode'); const pbxFile = require('xcode/lib/pbxFile'); const addFileToProject = require('../../src/ios/addFileToProject'); const removeProjectFromProject = require('../../src/ios/removeProjectFromProject'); +const path = require('path'); -const project = xcode.project('test/fixtures/project.pbxproj'); -const filePath = '../fixtures/linearGradient.pbxproj'; +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); +const filePath = '../../__fixtures__/linearGradient.pbxproj'; describe('ios::addFileToProject', () => { - beforeEach(() => { project.parseSync(); addFileToProject(project, filePath); }); it('should return removed file', () => { - expect(removeProjectFromProject(project, filePath)).to.be.instanceof(pbxFile); + expect(removeProjectFromProject(project, filePath) instanceof pbxFile) + .toBeTruthy(); }); it('should remove file from a project', () => { const file = removeProjectFromProject(project, filePath); - expect(project.pbxFileReferenceSection()).to.not.include.keys(file.fileRef); + expect(project.pbxFileReferenceSection()[file.fileRef]).not.toBeDefined(); }); - it.skip('should remove file from PBXContainerProxy', () => { + xit('should remove file from PBXContainerProxy', () => { // todo(mike): add in .xcodeproj after Xcode modifications so we can test extra // removals later. }); - }); diff --git a/local-cli/rnpm/link/__tests__/ios/removeSharedLibrary.spec.js b/local-cli/rnpm/link/__tests__/ios/removeSharedLibrary.spec.js new file mode 100644 index 000000000..53aeb9be1 --- /dev/null +++ b/local-cli/rnpm/link/__tests__/ios/removeSharedLibrary.spec.js @@ -0,0 +1,37 @@ +'use strict'; + +jest.autoMockOff(); + +const xcode = require('xcode'); +const path = require('path'); +const addSharedLibraries = require('../../src/ios/addSharedLibraries'); +const removeSharedLibraries = require('../../src/ios/removeSharedLibraries'); +const getGroup = require('../../src/ios/getGroup'); + +const project = xcode.project( + path.join(__dirname, '../../__fixtures__/project.pbxproj') +); + +describe('ios::removeSharedLibraries', () => { + + beforeEach(() => { + project.parseSync(); + addSharedLibraries(project, ['libc++.tbd', 'libz.tbd']); + }); + + it('should remove only the specified shared library', () => { + removeSharedLibraries(project, ['libc++.tbd']); + + const frameworksGroup = getGroup(project, 'Frameworks'); + expect(frameworksGroup.children.length).toEqual(1); + expect(frameworksGroup.children[0].comment).toEqual('libz.tbd'); + }); + + it('should ignore missing shared libraries', () => { + removeSharedLibraries(project, ['libxml2.tbd']); + + const frameworksGroup = getGroup(project, 'Frameworks'); + expect(frameworksGroup.children.length).toEqual(2); + }); + +}); diff --git a/local-cli/rnpm/link/test/link.spec.js b/local-cli/rnpm/link/__tests__/link.spec.js similarity index 77% rename from local-cli/rnpm/link/test/link.spec.js rename to local-cli/rnpm/link/__tests__/link.spec.js index 9cce9988d..e6f5754a7 100644 --- a/local-cli/rnpm/link/test/link.spec.js +++ b/local-cli/rnpm/link/__tests__/link.spec.js @@ -1,18 +1,15 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const sinon = require('sinon'); -const mock = require('mock-require'); const log = require('npmlog'); const path = require('path'); -const link = require('../src/link'); - -log.level = 'silent'; - describe('link', () => { - beforeEach(() => { delete require.cache[require.resolve('../src/link')]; + log.level = 'silent'; }); it('should reject when run in a folder without package.json', (done) => { @@ -22,7 +19,8 @@ describe('link', () => { }, }; - link(config).catch(() => done()); + const link = require('../src/link'); + link([], config).catch(() => done()); }); it('should accept a name of a dependency to link', (done) => { @@ -31,10 +29,11 @@ describe('link', () => { getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }), }; - link(config, ['react-native-gradient']).then(() => { + const link = require('../src/link'); + link(['react-native-gradient'], config).then(() => { expect( config.getDependencyConfig.calledWith('react-native-gradient') - ).to.be.true; + ).toBeTruthy(); done(); }); }); @@ -45,7 +44,7 @@ describe('link', () => { getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }), }; - mock( + jest.setMock( path.join(process.cwd(), 'package.json'), { dependencies: { @@ -54,10 +53,11 @@ describe('link', () => { } ); - link(config, []).then(() => { + const link = require('../src/link'); + link([], config).then(() => { expect( config.getDependencyConfig.calledWith('react-native-test') - ).to.be.true; + ).toBeTruthy(); done(); }); }); @@ -70,30 +70,30 @@ describe('link', () => { getDependencyConfig: sinon.stub().returns(dependencyConfig), }; - mock( + jest.setMock( '../src/android/isInstalled.js', sinon.stub().returns(false) ); - mock( + jest.setMock( '../src/android/registerNativeModule.js', registerNativeModule ); - mock( + jest.setMock( '../src/ios/isInstalled.js', sinon.stub().returns(false) ); - mock( + jest.setMock( '../src/ios/registerNativeModule.js', registerNativeModule ); const link = require('../src/link'); - link(config, ['react-native-blur']).then(() => { - expect(registerNativeModule.calledTwice).to.be.true; + link(['react-native-blur'], config).then(() => { + expect(registerNativeModule.calledTwice).toBeTruthy(); done(); }); }); @@ -106,30 +106,30 @@ describe('link', () => { getDependencyConfig: sinon.stub().returns(dependencyConfig), }; - mock( + jest.setMock( '../src/ios/isInstalled.js', sinon.stub().returns(true) ); - mock( + jest.setMock( '../src/android/isInstalled.js', sinon.stub().returns(true) ); - mock( + jest.setMock( '../src/ios/registerNativeModule.js', registerNativeModule ); - mock( + jest.setMock( '../src/android/registerNativeModule.js', registerNativeModule ); const link = require('../src/link'); - link(config, ['react-native-blur']).then(() => { - expect(registerNativeModule.callCount).to.equal(0); + link(['react-native-blur'], config).then(() => { + expect(registerNativeModule.callCount).toEqual(0); done(); }); }); @@ -139,12 +139,12 @@ describe('link', () => { const prelink = sinon.stub().yieldsAsync(); const postlink = sinon.stub().yieldsAsync(); - mock( + jest.setMock( '../src/ios/registerNativeModule.js', registerNativeModule ); - mock( + jest.setMock( '../src/ios/isInstalled.js', sinon.stub().returns(false) ); @@ -158,9 +158,9 @@ describe('link', () => { const link = require('../src/link'); - link(config, ['react-native-blur']).then(() => { - expect(prelink.calledBefore(registerNativeModule)).to.be.true; - expect(postlink.calledAfter(registerNativeModule)).to.be.true; + link(['react-native-blur'], config).then(() => { + expect(prelink.calledBefore(registerNativeModule)).toBeTruthy(); + expect(postlink.calledAfter(registerNativeModule)).toBeTruthy(); done(); }); }); @@ -171,7 +171,7 @@ describe('link', () => { const projectAssets = ['Fonts/FontC.ttf']; const copyAssets = sinon.stub(); - mock( + jest.setMock( '../src/ios/copyAssets.js', copyAssets ); @@ -183,17 +183,12 @@ describe('link', () => { const link = require('../src/link'); - link(config, ['react-native-blur']).then(() => { - expect(copyAssets.calledOnce).to.be.true; - expect(copyAssets.getCall(0).args[0]).to.deep.equals( + link(['react-native-blur'], config).then(() => { + expect(copyAssets.calledOnce).toBeTruthy(); + expect(copyAssets.getCall(0).args[0]).toEqual( projectAssets.concat(dependencyAssets) ); done(); }); }); - - afterEach(() => { - mock.stopAll(); - }); - }); diff --git a/local-cli/rnpm/link/test/promiseWaterfall.spec.js b/local-cli/rnpm/link/__tests__/promiseWaterfall.spec.js similarity index 76% rename from local-cli/rnpm/link/test/promiseWaterfall.spec.js rename to local-cli/rnpm/link/__tests__/promiseWaterfall.spec.js index 55d215038..e327b780e 100644 --- a/local-cli/rnpm/link/test/promiseWaterfall.spec.js +++ b/local-cli/rnpm/link/__tests__/promiseWaterfall.spec.js @@ -1,5 +1,7 @@ -const chai = require('chai'); -const expect = chai.expect; +'use strict'; + +jest.autoMockOff(); + const sinon = require('sinon'); const promiseWaterfall = require('../src/promiseWaterfall'); @@ -9,7 +11,7 @@ describe('promiseWaterfall', () => { const tasks = [sinon.stub(), sinon.stub()]; promiseWaterfall(tasks).then(() => { - expect(tasks[0].calledBefore(tasks[1])).to.be.true; + expect(tasks[0].calledBefore(tasks[1])).toBeTruthy(); done(); }); }); @@ -18,7 +20,7 @@ describe('promiseWaterfall', () => { const tasks = [sinon.stub().returns(1), sinon.stub().returns(2)]; promiseWaterfall(tasks).then(value => { - expect(value).to.equal(2); + expect(value).toEqual(2); done(); }); }); @@ -28,8 +30,8 @@ describe('promiseWaterfall', () => { const tasks = [sinon.stub().throws(error), sinon.stub().returns(2)]; promiseWaterfall(tasks).catch(err => { - expect(err).to.equal(error); - expect(tasks[1].callCount).to.equal(0); + expect(err).toEqual(error); + expect(tasks[1].callCount).toEqual(0); done(); }); }); diff --git a/local-cli/rnpm/link/index.js b/local-cli/rnpm/link/index.js deleted file mode 100644 index 13b39b599..000000000 --- a/local-cli/rnpm/link/index.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = [{ - func: require('./src/link'), - description: 'Links all native dependencies', - name: 'link [packageName]', -}, { - func: require('./src/unlink'), - description: 'Unlink native dependency', - name: 'unlink ', -}]; diff --git a/local-cli/rnpm/link/link.js b/local-cli/rnpm/link/link.js new file mode 100644 index 000000000..e6ab05c8d --- /dev/null +++ b/local-cli/rnpm/link/link.js @@ -0,0 +1,5 @@ +module.exports = { + func: require('./src/link'), + description: 'links all native dependencies', + name: 'link [packageName]', +}; diff --git a/local-cli/rnpm/link/src/android/getPrefix.js b/local-cli/rnpm/link/src/android/getPrefix.js deleted file mode 100644 index 1c40029e9..000000000 --- a/local-cli/rnpm/link/src/android/getPrefix.js +++ /dev/null @@ -1,16 +0,0 @@ -const semver = require('semver'); -const versions = ['0.20', '0.18', '0.17']; - -module.exports = function getPrefix(rnVersion) { - const version = rnVersion.replace(/-.*/, ''); - var prefix = 'patches/0.20'; - - versions.forEach((item, i) => { - const nextVersion = versions[i + 1]; - if (semver.lt(version, item + '.0') && nextVersion) { - prefix = `patches/${nextVersion}`; - } - }); - - return prefix; -}; diff --git a/local-cli/rnpm/link/src/android/isInstalled.js b/local-cli/rnpm/link/src/android/isInstalled.js index 3389a383f..fda849cf5 100644 --- a/local-cli/rnpm/link/src/android/isInstalled.js +++ b/local-cli/rnpm/link/src/android/isInstalled.js @@ -1,5 +1,5 @@ const fs = require('fs'); -const makeBuildPatch = require(`./patches/makeBuildPatch`); +const makeBuildPatch = require('./patches/makeBuildPatch'); module.exports = function isInstalled(config, name) { return fs diff --git a/local-cli/rnpm/link/src/android/patches/0.17/makeImportPatch.js b/local-cli/rnpm/link/src/android/patches/0.17/makeImportPatch.js deleted file mode 100644 index c7bcf3d79..000000000 --- a/local-cli/rnpm/link/src/android/patches/0.17/makeImportPatch.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = function makeImportPatch(packageImportPath) { - return { - pattern: 'import android.app.Activity;', - patch: '\n' + packageImportPath, - }; -}; diff --git a/local-cli/rnpm/link/src/android/patches/0.17/makePackagePatch.js b/local-cli/rnpm/link/src/android/patches/0.17/makePackagePatch.js deleted file mode 100644 index ea4552c19..000000000 --- a/local-cli/rnpm/link/src/android/patches/0.17/makePackagePatch.js +++ /dev/null @@ -1,10 +0,0 @@ -const applyParams = require('../applyParams'); - -module.exports = function makePackagePatch(packageInstance, params, prefix) { - const processedInstance = applyParams(packageInstance, params, prefix); - - return { - pattern: '.addPackage(new MainReactPackage())', - patch: `\n .addPackage(${processedInstance})`, - }; -}; diff --git a/local-cli/rnpm/link/src/android/patches/0.18/makeImportPatch.js b/local-cli/rnpm/link/src/android/patches/0.18/makeImportPatch.js deleted file mode 100644 index 687d61bd4..000000000 --- a/local-cli/rnpm/link/src/android/patches/0.18/makeImportPatch.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = function makeImportPatch(packageImportPath) { - return { - pattern: 'import com.facebook.react.ReactActivity;', - patch: '\n' + packageImportPath, - }; -}; diff --git a/local-cli/rnpm/link/src/android/patches/0.18/makePackagePatch.js b/local-cli/rnpm/link/src/android/patches/0.18/makePackagePatch.js deleted file mode 100644 index 660930390..000000000 --- a/local-cli/rnpm/link/src/android/patches/0.18/makePackagePatch.js +++ /dev/null @@ -1,10 +0,0 @@ -const applyParams = require('../applyParams'); - -module.exports = function makePackagePatch(packageInstance, params, prefix) { - const processedInstance = applyParams(packageInstance, params, prefix); - - return { - pattern: 'new MainReactPackage()', - patch: ',\n ' + processedInstance, - }; -}; diff --git a/local-cli/rnpm/link/src/android/patches/0.20/makeImportPatch.js b/local-cli/rnpm/link/src/android/patches/makeImportPatch.js similarity index 100% rename from local-cli/rnpm/link/src/android/patches/0.20/makeImportPatch.js rename to local-cli/rnpm/link/src/android/patches/makeImportPatch.js diff --git a/local-cli/rnpm/link/src/android/patches/0.20/makePackagePatch.js b/local-cli/rnpm/link/src/android/patches/makePackagePatch.js similarity index 84% rename from local-cli/rnpm/link/src/android/patches/0.20/makePackagePatch.js rename to local-cli/rnpm/link/src/android/patches/makePackagePatch.js index 17120b142..e1a5bec5d 100644 --- a/local-cli/rnpm/link/src/android/patches/0.20/makePackagePatch.js +++ b/local-cli/rnpm/link/src/android/patches/makePackagePatch.js @@ -1,4 +1,4 @@ -const applyParams = require('../applyParams'); +const applyParams = require('./applyParams'); module.exports = function makePackagePatch(packageInstance, params, prefix) { const processedInstance = applyParams(packageInstance, params, prefix); diff --git a/local-cli/rnpm/link/src/android/registerNativeModule.js b/local-cli/rnpm/link/src/android/registerNativeModule.js index a5fee0dc0..db31bfdce 100644 --- a/local-cli/rnpm/link/src/android/registerNativeModule.js +++ b/local-cli/rnpm/link/src/android/registerNativeModule.js @@ -1,11 +1,9 @@ -const fs = require('fs'); -const getReactVersion = require('../getReactNativeVersion'); -const getPrefix = require('./getPrefix'); - const applyPatch = require('./patches/applyPatch'); const makeStringsPatch = require('./patches/makeStringsPatch'); -const makeSettingsPatch = require(`./patches/makeSettingsPatch`); -const makeBuildPatch = require(`./patches/makeBuildPatch`); +const makeSettingsPatch = require('./patches/makeSettingsPatch'); +const makeBuildPatch = require('./patches/makeBuildPatch'); +const makeImportPatch = require('./patches/makeImportPatch'); +const makePackagePatch = require('./patches/makePackagePatch'); module.exports = function registerNativeAndroidModule( name, @@ -14,9 +12,6 @@ module.exports = function registerNativeAndroidModule( projectConfig ) { const buildPatch = makeBuildPatch(name); - const prefix = getPrefix(getReactVersion(projectConfig.folder)); - const makeImportPatch = require(`./${prefix}/makeImportPatch`); - const makePackagePatch = require(`./${prefix}/makePackagePatch`); applyPatch( projectConfig.settingsGradlePath, diff --git a/local-cli/rnpm/link/src/android/unregisterNativeModule.js b/local-cli/rnpm/link/src/android/unregisterNativeModule.js index 9b8862833..f3b84c811 100644 --- a/local-cli/rnpm/link/src/android/unregisterNativeModule.js +++ b/local-cli/rnpm/link/src/android/unregisterNativeModule.js @@ -1,12 +1,12 @@ const fs = require('fs'); -const getReactVersion = require('../getReactNativeVersion'); -const getPrefix = require('./getPrefix'); const toCamelCase = require('lodash').camelCase; const revokePatch = require('./patches/revokePatch'); const makeSettingsPatch = require('./patches/makeSettingsPatch'); const makeBuildPatch = require('./patches/makeBuildPatch'); const makeStringsPatch = require('./patches/makeStringsPatch'); +const makeImportPatch = require('./patches/makeImportPatch'); +const makePackagePatch = require('./patches/makePackagePatch'); module.exports = function unregisterNativeAndroidModule( name, @@ -14,9 +14,6 @@ module.exports = function unregisterNativeAndroidModule( projectConfig ) { const buildPatch = makeBuildPatch(name); - const prefix = getPrefix(getReactVersion(projectConfig.folder)); - const makeImportPatch = require(`./${prefix}/makeImportPatch`); - const makePackagePatch = require(`./${prefix}/makePackagePatch`); const strings = fs.readFileSync(projectConfig.stringsPath, 'utf8'); var params = {}; diff --git a/local-cli/rnpm/link/src/getReactNativeVersion.js b/local-cli/rnpm/link/src/getReactNativeVersion.js deleted file mode 100644 index a1756e9e0..000000000 --- a/local-cli/rnpm/link/src/getReactNativeVersion.js +++ /dev/null @@ -1,5 +0,0 @@ -const path = require('path'); - -module.exports = (folder) => require( - path.join(folder, 'node_modules', 'react-native', 'package.json') -).version; diff --git a/local-cli/rnpm/link/src/ios/addSharedLibraries.js b/local-cli/rnpm/link/src/ios/addSharedLibraries.js index f84603abb..82cf58ba8 100644 --- a/local-cli/rnpm/link/src/ios/addSharedLibraries.js +++ b/local-cli/rnpm/link/src/ios/addSharedLibraries.js @@ -1,3 +1,16 @@ -module.exports = function addSharedLibraries(project, libraries) { +const createGroupWithMessage = require('./createGroupWithMessage'); +module.exports = function addSharedLibraries(project, libraries) { + if (!libraries.length) { + return; + } + + // Create a Frameworks group if necessary. + createGroupWithMessage(project, 'Frameworks'); + + const target = project.getFirstTarget().uuid; + + for (var name of libraries) { + project.addFramework(name, { target }); + } }; diff --git a/local-cli/rnpm/link/src/ios/copyAssets.js b/local-cli/rnpm/link/src/ios/copyAssets.js index 538381a03..78db9fc94 100644 --- a/local-cli/rnpm/link/src/ios/copyAssets.js +++ b/local-cli/rnpm/link/src/ios/copyAssets.js @@ -4,7 +4,7 @@ const xcode = require('xcode'); const log = require('npmlog'); const plistParser = require('plist'); const groupFilesByType = require('../groupFilesByType'); -const createGroup = require('./createGroup'); +const createGroupWithMessage = require('./createGroupWithMessage'); const getPlist = require('./getPlist'); const getPlistPath = require('./getPlistPath'); @@ -17,21 +17,7 @@ module.exports = function linkAssetsIOS(files, projectConfig) { const assets = groupFilesByType(files); const plist = getPlist(project, projectConfig.sourceDir); - if (!plist) { - return log.error( - 'ERRPLIST', - `Could not locate Info.plist. Check if your project has 'INFOPLIST_FILE' set properly` - ); - } - - if (!project.pbxGroupByName('Resources')) { - createGroup(project, 'Resources'); - - log.warn( - 'ERRGROUP', - `Group 'Resources' does not exist in your XCode project. We have created it automatically for you.` - ); - } + createGroupWithMessage(project, 'Resources'); const fonts = (assets.font || []) .map(asset => diff --git a/local-cli/rnpm/link/src/ios/createGroupWithMessage.js b/local-cli/rnpm/link/src/ios/createGroupWithMessage.js new file mode 100644 index 000000000..aeeb3dd2a --- /dev/null +++ b/local-cli/rnpm/link/src/ios/createGroupWithMessage.js @@ -0,0 +1,25 @@ +const log = require('npmlog'); + +const createGroup = require('./createGroup'); +const getGroup = require('./getGroup'); + +/** + * Given project and path of the group, it checks if a group exists at that path, + * and deeply creates a group for that path if its does not already exist. + * + * Returns the existing or newly created group + */ +module.exports = function createGroupWithMessage(project, path) { + var group = getGroup(project, path); + + if (!group) { + group = createGroup(project, path); + + log.warn( + 'ERRGROUP', + `Group '${path}' does not exist in your XCode project. We have created it automatically for you.` + ); + } + + return group; +}; diff --git a/local-cli/rnpm/link/src/ios/registerNativeModule.js b/local-cli/rnpm/link/src/ios/registerNativeModule.js index 6d8bce262..8391a46b2 100644 --- a/local-cli/rnpm/link/src/ios/registerNativeModule.js +++ b/local-cli/rnpm/link/src/ios/registerNativeModule.js @@ -7,8 +7,7 @@ const addToHeaderSearchPaths = require('./addToHeaderSearchPaths'); const getHeadersInFolder = require('./getHeadersInFolder'); const getHeaderSearchPath = require('./getHeaderSearchPath'); const getProducts = require('./getProducts'); -const createGroup = require('./createGroup'); -const hasLibraryImported = require('./hasLibraryImported'); +const createGroupWithMessage = require('./createGroupWithMessage'); const addFileToProject = require('./addFileToProject'); const addProjectToLibraries = require('./addProjectToLibraries'); const addSharedLibraries = require('./addSharedLibraries'); @@ -26,17 +25,7 @@ module.exports = function registerNativeModuleIOS(dependencyConfig, projectConfi const project = xcode.project(projectConfig.pbxprojPath).parseSync(); const dependencyProject = xcode.project(dependencyConfig.pbxprojPath).parseSync(); - var libraries = getGroup(project, projectConfig.libraryFolder); - - if (!libraries) { - libraries = createGroup(project, projectConfig.libraryFolder); - - log.warn( - 'ERRGROUP', - `Group ${projectConfig.libraryFolder} does not exist in your XCode project. We have created it automatically for you.` - ); - } - + const libraries = createGroupWithMessage(project, projectConfig.libraryFolder); const file = addFileToProject( project, path.relative(projectConfig.sourceDir, dependencyConfig.projectPath) diff --git a/local-cli/rnpm/link/src/ios/removeSharedLibraries.js b/local-cli/rnpm/link/src/ios/removeSharedLibraries.js index 82e611f5f..1150e2383 100644 --- a/local-cli/rnpm/link/src/ios/removeSharedLibraries.js +++ b/local-cli/rnpm/link/src/ios/removeSharedLibraries.js @@ -1,3 +1,11 @@ module.exports = function removeSharedLibraries(project, libraries) { + if (!libraries.length) { + return; + } + const target = project.getFirstTarget().uuid; + + for (var name of libraries) { + project.removeFramework(name, { target }); + } }; diff --git a/local-cli/rnpm/link/src/ios/unregisterNativeModule.js b/local-cli/rnpm/link/src/ios/unregisterNativeModule.js index 509848a55..5034be0ed 100644 --- a/local-cli/rnpm/link/src/ios/unregisterNativeModule.js +++ b/local-cli/rnpm/link/src/ios/unregisterNativeModule.js @@ -1,24 +1,25 @@ const xcode = require('xcode'); const path = require('path'); const fs = require('fs'); +const difference = require('lodash').difference; +const isEmpty = require('lodash').isEmpty; +const getGroup = require('./getGroup'); const getProducts = require('./getProducts'); const getHeadersInFolder = require('./getHeadersInFolder'); -const isEmpty = require('lodash').isEmpty; const getHeaderSearchPath = require('./getHeaderSearchPath'); const removeProjectFromProject = require('./removeProjectFromProject'); const removeProjectFromLibraries = require('./removeProjectFromLibraries'); const removeFromStaticLibraries = require('./removeFromStaticLibraries'); const removeFromHeaderSearchPaths = require('./removeFromHeaderSearchPaths'); -const removeSharedLibraries = require('./addSharedLibraries'); -const getGroup = require('./getGroup'); +const removeSharedLibraries = require('./removeSharedLibraries'); /** * Unregister native module IOS * * If library is already unlinked, this action is a no-op. */ -module.exports = function unregisterNativeModule(dependencyConfig, projectConfig) { +module.exports = function unregisterNativeModule(dependencyConfig, projectConfig, iOSDependencies) { const project = xcode.project(projectConfig.pbxprojPath).parseSync(); const dependencyProject = xcode.project(dependencyConfig.pbxprojPath).parseSync(); @@ -37,7 +38,15 @@ module.exports = function unregisterNativeModule(dependencyConfig, projectConfig }); }); - removeSharedLibraries(project, dependencyConfig.sharedLibraries); + const sharedLibraries = difference( + dependencyConfig.sharedLibraries, + iOSDependencies.reduce( + (libs, dependency) => libs.concat(dependency.sharedLibraries), + projectConfig.sharedLibraries + ) + ); + + removeSharedLibraries(project, sharedLibraries); const headers = getHeadersInFolder(dependencyConfig.folder); if (!isEmpty(headers)) { diff --git a/local-cli/rnpm/link/src/link.js b/local-cli/rnpm/link/src/link.js index 51261aa30..5362c7416 100644 --- a/local-cli/rnpm/link/src/link.js +++ b/local-cli/rnpm/link/src/link.js @@ -93,7 +93,7 @@ const linkAssets = (project, assets) => { * * If optional argument [packageName] is provided, it's the only one that's checked */ -module.exports = function link(config, args) { +module.exports = function link(args, config) { var project; try { project = config.getProjectConfig(); diff --git a/local-cli/rnpm/link/src/unlink.js b/local-cli/rnpm/link/src/unlink.js index e40b091e9..cf5ab9224 100644 --- a/local-cli/rnpm/link/src/unlink.js +++ b/local-cli/rnpm/link/src/unlink.js @@ -1,4 +1,3 @@ -const path = require('path'); const log = require('npmlog'); const getProjectDependencies = require('./getProjectDependencies'); @@ -9,7 +8,9 @@ const isInstalledIOS = require('./ios/isInstalled'); const unlinkAssetsAndroid = require('./android/unlinkAssets'); const unlinkAssetsIOS = require('./ios/unlinkAssets'); const getDependencyConfig = require('./getDependencyConfig'); +const compact = require('lodash').compact; const difference = require('lodash').difference; +const filter = require('lodash').filter; const isEmpty = require('lodash').isEmpty; const flatten = require('lodash').flatten; @@ -34,7 +35,7 @@ const unlinkDependencyAndroid = (androidProject, dependency, packageName) => { log.info(`Android module ${packageName} has been successfully unlinked`); }; -const unlinkDependencyIOS = (iOSProject, dependency, packageName) => { +const unlinkDependencyIOS = (iOSProject, dependency, packageName, iOSDependencies) => { if (!iOSProject || !dependency.ios) { return; } @@ -48,7 +49,7 @@ const unlinkDependencyIOS = (iOSProject, dependency, packageName) => { log.info(`Unlinking ${packageName} ios dependency`); - unregisterDependencyIOS(dependency.ios, iOSProject); + unregisterDependencyIOS(dependency.ios, iOSProject, iOSDependencies); log.info(`iOS module ${packageName} has been successfully unlinked`); }; @@ -59,7 +60,7 @@ const unlinkDependencyIOS = (iOSProject, dependency, packageName) => { * If optional argument [packageName] is provided, it's the only one * that's checked */ -module.exports = function unlink(config, args) { +module.exports = function unlink(args, config) { const packageName = args[0]; var project; @@ -85,10 +86,12 @@ module.exports = function unlink(config, args) { return Promise.reject(err); } - unlinkDependencyAndroid(project.android, dependency, packageName); - unlinkDependencyIOS(project.ios, dependency, packageName); - const allDependencies = getDependencyConfig(config, getProjectDependencies()); + const otherDependencies = filter(allDependencies, d => d.name !== packageName); + const iOSDependencies = compact(otherDependencies.map(d => d.config.ios)); + + unlinkDependencyAndroid(project.android, dependency, packageName); + unlinkDependencyIOS(project.ios, dependency, packageName, iOSDependencies); const assets = difference( dependency.assets, diff --git a/local-cli/rnpm/link/test/android/isInstalled.spec.js b/local-cli/rnpm/link/test/android/isInstalled.spec.js deleted file mode 100644 index bde18c09e..000000000 --- a/local-cli/rnpm/link/test/android/isInstalled.spec.js +++ /dev/null @@ -1,28 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); -const path = require('path'); -const isInstalled = require('../../src/android/isInstalled'); - -const projectConfig = { - buildGradlePath: 'build.gradle', -}; - -describe('android::isInstalled', () => { - before(() => mock({ - 'build.gradle': fs.readFileSync( - path.join(__dirname, '../fixtures/android/patchedBuild.gradle') - ), - })); - - it('should return true when project is already in build.gradle', () => - expect(isInstalled(projectConfig, 'test')).to.be.true - ); - - it('should return false when project is not in build.gradle', () => - expect(isInstalled(projectConfig, 'test2')).to.be.false - ); - - after(mock.restore); -}); diff --git a/local-cli/rnpm/link/test/android/patches/0.17/makeImportPatch.js b/local-cli/rnpm/link/test/android/patches/0.17/makeImportPatch.js deleted file mode 100644 index ed729defc..000000000 --- a/local-cli/rnpm/link/test/android/patches/0.17/makeImportPatch.js +++ /dev/null @@ -1,31 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); -const path = require('path'); -const makeImportPatch = require('../../../../src/android/patches/0.17/makeImportPatch'); -const applyPatch = require('../../../../src/android/patches/applyPatch'); - -const projectConfig = { - mainFilePath: 'MainActivity.java', -}; - -const packageImportPath = 'import some.example.project'; - -describe('makeImportPatch@0.17', () => { - before(() => mock({ - 'MainActivity.java': fs.readFileSync( - path.join(__dirname, '../../../fixtures/android/0.17/MainActivity.java') - ), - })); - - it('MainActivity contains a correct 0.17 import patch', () => { - const importPatch = makeImportPatch(packageImportPath); - - applyPatch('MainActivity.java', importPatch); - expect(fs.readFileSync('MainActivity.java', 'utf8')) - .to.have.string(importPatch.patch); - }); - - after(mock.restore); -}); diff --git a/local-cli/rnpm/link/test/android/patches/0.17/makePackagePatch.js b/local-cli/rnpm/link/test/android/patches/0.17/makePackagePatch.js deleted file mode 100644 index cbbb3f517..000000000 --- a/local-cli/rnpm/link/test/android/patches/0.17/makePackagePatch.js +++ /dev/null @@ -1,36 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); -const path = require('path'); -const makePackagePatch = require('../../../../src/android/patches/0.17/makePackagePatch'); -const applyPatch = require('../../../../src/android/patches/applyPatch'); - -const projectConfig = { - mainFilePath: 'MainActivity.java', -}; - -const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')'; -const name = 'some-library'; -const params = { - foo: 'foo', - bar: 'bar', -}; - -describe('makePackagePatch@0.17', () => { - before(() => mock({ - 'MainActivity.java': fs.readFileSync( - path.join(__dirname, '../../../fixtures/android/0.17/MainActivity.java') - ), - })); - - it('MainActivity contains a correct 0.17 package patch', () => { - const packagePatch = makePackagePatch(packageInstance, params, name); - - applyPatch('MainActivity.java', packagePatch); - expect(fs.readFileSync('MainActivity.java', 'utf8')) - .to.have.string(packagePatch.patch); - }); - - after(mock.restore); -}); diff --git a/local-cli/rnpm/link/test/android/patches/0.18/makeImportPatch.js b/local-cli/rnpm/link/test/android/patches/0.18/makeImportPatch.js deleted file mode 100644 index 0dd15c748..000000000 --- a/local-cli/rnpm/link/test/android/patches/0.18/makeImportPatch.js +++ /dev/null @@ -1,31 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); -const path = require('path'); -const makeImportPatch = require('../../../../src/android/patches/0.18/makeImportPatch'); -const applyPatch = require('../../../../src/android/patches/applyPatch'); - -const projectConfig = { - mainFilePath: 'MainActivity.java', -}; - -const packageImportPath = 'import some.example.project'; - -describe('makeImportPatch@0.18', () => { - before(() => mock({ - 'MainActivity.java': fs.readFileSync( - path.join(__dirname, '../../../fixtures/android/0.18/MainActivity.java') - ), - })); - - it('MainActivity contains a correct 0.18 import patch', () => { - const importPatch = makeImportPatch(packageImportPath); - - applyPatch('MainActivity.java', importPatch); - expect(fs.readFileSync('MainActivity.java', 'utf8')) - .to.have.string(importPatch.patch); - }); - - after(mock.restore); -}); diff --git a/local-cli/rnpm/link/test/android/patches/0.18/makePackagePatch.js b/local-cli/rnpm/link/test/android/patches/0.18/makePackagePatch.js deleted file mode 100644 index b3f46bf5f..000000000 --- a/local-cli/rnpm/link/test/android/patches/0.18/makePackagePatch.js +++ /dev/null @@ -1,36 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); -const path = require('path'); -const makePackagePatch = require('../../../../src/android/patches/0.18/makePackagePatch'); -const applyPatch = require('../../../../src/android/patches/applyPatch'); - -const projectConfig = { - mainFilePath: 'MainActivity.java', -}; - -const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')'; -const name = 'some-library'; -const params = { - foo: 'foo', - bar: 'bar', -}; - -describe('makePackagePatch@0.18', () => { - before(() => mock({ - 'MainActivity.java': fs.readFileSync( - path.join(__dirname, '../../../fixtures/android/0.18/MainActivity.java') - ), - })); - - it('MainActivity contains a correct 0.18 package patch', () => { - const packagePatch = makePackagePatch(packageInstance, params, name); - - applyPatch('MainActivity.java', packagePatch); - expect(fs.readFileSync('MainActivity.java', 'utf8')) - .to.have.string(packagePatch.patch); - }); - - after(mock.restore); -}); diff --git a/local-cli/rnpm/link/test/android/patches/0.20/makeImportPatch.js b/local-cli/rnpm/link/test/android/patches/0.20/makeImportPatch.js deleted file mode 100644 index 31b328261..000000000 --- a/local-cli/rnpm/link/test/android/patches/0.20/makeImportPatch.js +++ /dev/null @@ -1,31 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); -const path = require('path'); -const makeImportPatch = require('../../../../src/android/patches/0.20/makeImportPatch'); -const applyPatch = require('../../../../src/android/patches/applyPatch'); - -const projectConfig = { - mainFilePath: 'MainActivity.java', -}; - -const packageImportPath = 'import some.example.project'; - -describe('makeImportPatch@0.20', () => { - before(() => mock({ - 'MainActivity.java': fs.readFileSync( - path.join(__dirname, '../../../fixtures/android/0.20/MainActivity.java') - ), - })); - - it('MainActivity contains a correct 0.20 import patch', () => { - const importPatch = makeImportPatch(packageImportPath); - - applyPatch('MainActivity.java', importPatch); - expect(fs.readFileSync('MainActivity.java', 'utf8')) - .to.have.string(importPatch.patch); - }); - - after(mock.restore); -}); diff --git a/local-cli/rnpm/link/test/android/patches/0.20/makePackagePatch.js b/local-cli/rnpm/link/test/android/patches/0.20/makePackagePatch.js deleted file mode 100644 index fe8086ce8..000000000 --- a/local-cli/rnpm/link/test/android/patches/0.20/makePackagePatch.js +++ /dev/null @@ -1,36 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const mock = require('mock-fs'); -const fs = require('fs'); -const path = require('path'); -const makePackagePatch = require('../../../../src/android/patches/0.20/makePackagePatch'); -const applyPatch = require('../../../../src/android/patches/applyPatch'); - -const projectConfig = { - mainFilePath: 'MainActivity.java', -}; - -const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')'; -const name = 'some-library'; -const params = { - foo: 'foo', - bar: 'bar', -}; - -describe('makePackagePatch@0.20', () => { - before(() => mock({ - 'MainActivity.java': fs.readFileSync( - path.join(__dirname, '../../../fixtures/android/0.20/MainActivity.java') - ), - })); - - it('MainActivity contains a correct 0.20 package patch', () => { - const packagePatch = makePackagePatch(packageInstance, params, name); - - applyPatch('MainActivity.java', packagePatch); - expect(fs.readFileSync('MainActivity.java', 'utf8')) - .to.have.string(packagePatch.patch); - }); - - after(mock.restore); -}); diff --git a/local-cli/rnpm/link/test/android/patches/makeBuildPatch.spec.js b/local-cli/rnpm/link/test/android/patches/makeBuildPatch.spec.js deleted file mode 100644 index 51136a72e..000000000 --- a/local-cli/rnpm/link/test/android/patches/makeBuildPatch.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const makeBuildPatch = require('../../../src/android/patches/makeBuildPatch'); -const applyPatch = require('../../../src/android/patches/applyPatch'); - -const name = 'test'; - -describe('makeBuildPatch', () => { - it('should build a patch function', () => { - expect(makeBuildPatch(name)).to.be.an('object'); - }); - - it('should make a correct patch', () => { - expect(makeBuildPatch(name).patch) - .to.be.equal(` compile project(':${name}')\n`); - }); -}); diff --git a/local-cli/rnpm/link/test/getPrefix.spec.js b/local-cli/rnpm/link/test/getPrefix.spec.js deleted file mode 100644 index 1b5e72627..000000000 --- a/local-cli/rnpm/link/test/getPrefix.spec.js +++ /dev/null @@ -1,20 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const getMainActivityPatch = require('../src/android/getPrefix'); -const newPrefix = 'patches/0.18'; -const oldPrefix = 'patches/0.17'; - -describe('getPrefix', () => { - it('require a specific patch for react-native < 0.18', () => { - expect(getMainActivityPatch('0.17.0-rc')).to.equals(oldPrefix); - expect(getMainActivityPatch('0.17.1-rc2')).to.equals(oldPrefix); - expect(getMainActivityPatch('0.17.2')).to.equals(oldPrefix); - }); - - it('require a specific patch for react-native > 0.18', () => { - expect(getMainActivityPatch('0.19.0')).to.equals(newPrefix); - expect(getMainActivityPatch('0.19.0-rc')).to.equals(newPrefix); - expect(getMainActivityPatch('0.18.0-rc1')).to.equals(newPrefix); - expect(getMainActivityPatch('0.18.2')).to.equals(newPrefix); - }); -}); diff --git a/local-cli/rnpm/link/test/ios/addFileToProject.spec.js b/local-cli/rnpm/link/test/ios/addFileToProject.spec.js deleted file mode 100644 index 141d2ba71..000000000 --- a/local-cli/rnpm/link/test/ios/addFileToProject.spec.js +++ /dev/null @@ -1,22 +0,0 @@ -const chai = require('chai'); -const expect = chai.expect; -const xcode = require('xcode'); -const addFileToProject = require('../../src/ios/addFileToProject'); - -const project = xcode.project('test/fixtures/project.pbxproj'); - -describe('ios::addFileToProject', () => { - - beforeEach(() => { - project.parseSync(); - }); - - it('should add file to a project', () => { - const file = addFileToProject(project, '../fixtures/linearGradient.pbxproj'); - - expect( - project.pbxFileReferenceSection() - ).to.include.keys(file.fileRef); - }); - -}); diff --git a/local-cli/rnpm/link/unlink.js b/local-cli/rnpm/link/unlink.js new file mode 100644 index 000000000..56ca0ec67 --- /dev/null +++ b/local-cli/rnpm/link/unlink.js @@ -0,0 +1,5 @@ +module.exports = { + func: require('./src/unlink'), + description: 'unlink native dependency', + name: 'unlink ', +}; diff --git a/local-cli/runAndroid/runAndroid.js b/local-cli/runAndroid/runAndroid.js index 26a49cff2..dd7ada16c 100644 --- a/local-cli/runAndroid/runAndroid.js +++ b/local-cli/runAndroid/runAndroid.js @@ -12,63 +12,36 @@ const chalk = require('chalk'); const child_process = require('child_process'); const fs = require('fs'); const path = require('path'); -const parseCommandLine = require('../util/parseCommandLine'); const isPackagerRunning = require('../util/isPackagerRunning'); const Promise = require('promise'); const adb = require('./adb'); +// Verifies this is an Android project +function checkAndroid(root) { + return fs.existsSync(path.join(root, 'android/gradlew')); +} + /** * Starts the app on a connected Android emulator or device. */ -function runAndroid(argv, config) { - return new Promise((resolve, reject) => { - _runAndroid(argv, config, resolve, reject); - }); -} - -function _runAndroid(argv, config, resolve, reject) { - const args = parseCommandLine([{ - command: 'install-debug', - type: 'string', - required: false, - }, { - command: 'root', - type: 'string', - description: 'Override the root directory for the android build (which contains the android directory)', - }, { - command: 'flavor', - type: 'string', - required: false, - }, { - command: 'variant', - type: 'string', - required: false, - }], argv); - - args.root = args.root || ''; - - if (!checkAndroid(args)) { +function runAndroid(argv, config, args) { + if (!checkAndroid(args.root)) { console.log(chalk.red('Android project not found. Maybe run react-native android first?')); return; } - resolve(isPackagerRunning().then(result => { + return isPackagerRunning().then(result => { if (result === 'running') { - console.log(chalk.bold(`JS server already running.`)); + console.log(chalk.bold('JS server already running.')); } else if (result === 'unrecognized') { - console.warn(chalk.yellow(`JS server not recognized, continuing with build...`)); + console.warn(chalk.yellow('JS server not recognized, continuing with build...')); } else { // result == 'not_running' - console.log(chalk.bold(`Starting JS server...`)); + console.log(chalk.bold('Starting JS server...')); startServerInNewWindow(); } - run(args, reject); - })); -} - -// Verifies this is an Android project -function checkAndroid(args) { - return fs.existsSync(path.join(args.root, 'android/gradlew')); + return buildAndRun(args); + }); } function getAdbPath() { @@ -98,7 +71,7 @@ function tryRunAdbReverse() { } // Builds the app and runs it on a connected emulator / device. -function run(args, reject) { +function buildAndRun(args) { process.chdir(path.join(args.root, 'android')); try { tryRunAdbReverse(); @@ -108,23 +81,23 @@ function run(args, reject) { : './gradlew'; const gradleArgs = []; - if (args['variant']) { - gradleArgs.push('install' + - args['variant'][0].toUpperCase() + args['variant'].slice(1) - ); - } else if (args['flavor']) { - console.warn(chalk.yellow( - `--flavor has been deprecated. Use --variant instead` - )); - gradleArgs.push('install' + - args['flavor'][0].toUpperCase() + args['flavor'].slice(1) - ); + if (args.variant) { + gradleArgs.push('install' + + args.variant[0].toUpperCase() + args.variant.slice(1) + ); + } else if (args.flavor) { + console.warn(chalk.yellow( + '--flavor has been deprecated. Use --variant instead' + )); + gradleArgs.push('install' + + args.flavor[0].toUpperCase() + args.flavor.slice(1) + ); } else { - gradleArgs.push('installDebug'); + gradleArgs.push('installDebug'); } - if (args['install-debug']) { - gradleArgs.push(args['install-debug']); + if (args.installDebug) { + gradleArgs.push(args.installDebug); } console.log(chalk.bold( @@ -144,8 +117,7 @@ function run(args, reject) { // stderr is automatically piped from the gradle process, so the user // should see the error already, there is no need to do // `console.log(e.stderr)` - reject(); - return; + return Promise.reject(); } try { @@ -183,13 +155,12 @@ function run(args, reject) { } catch (e) { console.log(chalk.red( - `adb invocation failed. Do you have adb in your PATH?` + 'adb invocation failed. Do you have adb in your PATH?' )); // stderr is automatically piped from the gradle process, so the user // should see the error already, there is no need to do // `console.log(e.stderr)` - reject(); - return; + return Promise.reject(); } } @@ -224,4 +195,20 @@ function startServerInNewWindow() { } } -module.exports = runAndroid; +module.exports = { + name: 'run-android', + description: 'builds your app and starts it on a connected Android emulator or device', + func: runAndroid, + options: [{ + command: '--install-debug', + }, { + command: '--root [string]', + description: 'Override the root directory for the android build (which contains the android directory)', + default: '', + }, { + command: '--flavor [string]', + description: '--flavor has been deprecated. Use --variant instead', + }, { + command: '--variant [string]', + }], +}; diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index eb3378abb..8fdc83e82 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -11,46 +11,14 @@ const child_process = require('child_process'); const fs = require('fs'); const path = require('path'); -const parseCommandLine = require('../util/parseCommandLine'); const findXcodeProject = require('./findXcodeProject'); const parseIOSSimulatorsList = require('./parseIOSSimulatorsList'); -const Promise = require('promise'); -/** - * Starts the app on iOS simulator - */ -function runIOS(argv, config) { - return new Promise((resolve, reject) => { - _runIOS(argv, config, resolve, reject); - }); -} - -function _runIOS(argv, config, resolve, reject) { - const args = parseCommandLine([ - { - command: 'simulator', - description: 'Explicitly set simulator to use', - type: 'string', - required: false, - default: 'iPhone 6', - }, { - command: 'scheme', - description: 'Explicitly set Xcode scheme to use', - type: 'string', - required: false, - }, { - command: 'project-path', - description: 'Path relative to project root where the Xcode project (.xcodeproj) lives. The default is \'ios\'.', - type: 'string', - required: false, - default: 'ios', - } - ], argv); - - process.chdir(args['project-path']); +function runIOS(argv, config, args) { + process.chdir(args.projectPath); const xcodeProject = findXcodeProject(fs.readdirSync('.')); if (!xcodeProject) { - reject(new Error(`Could not find Xcode project files in ios folder`)); + throw new Error('Could not find Xcode project files in ios folder'); } const inferredSchemeName = path.basename(xcodeProject.name, path.extname(xcodeProject.name)); @@ -62,14 +30,14 @@ function _runIOS(argv, config, resolve, reject) { ); const selectedSimulator = matchingSimulator(simulators, args.simulator); if (!selectedSimulator) { - reject(new Error(`Cound't find ${args.simulator} simulator`)); + throw new Error(`Cound't find ${args.simulator} simulator`); } - const simulatorFullName = formattedSimulatorName(selectedSimulator) + const simulatorFullName = formattedSimulatorName(selectedSimulator); console.log(`Launching ${simulatorFullName}...`); try { child_process.spawnSync('xcrun', ['instruments', '-w', simulatorFullName]); - } catch(e) { + } catch (e) { // instruments always fail with 255 because it expects more arguments, // but we want it to only launch the simulator } @@ -81,42 +49,20 @@ function _runIOS(argv, config, resolve, reject) { '-derivedDataPath', 'build', ]; console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`); + child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'inherit'}); - let appPath = `build/Build/Products/Debug-iphonesimulator/${inferredSchemeName}.app`; - const xcodeBuildProcess = child_process.spawn('xcodebuild', xcodebuildArgs, { - stdio: [process.stdin, 'pipe', process.stderr] - }); + const appPath = `build/Build/Products/Debug-iphonesimulator/${inferredSchemeName}.app`; + console.log(`Installing ${appPath}`); + child_process.spawnSync('xcrun', ['simctl', 'install', 'booted', appPath], {stdio: 'inherit'}); - xcodeBuildProcess.stdout.on('data', (data) => { - process.stdout.write(data); + const bundleID = child_process.execFileSync( + '/usr/libexec/PlistBuddy', + ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')], + {encoding: 'utf8'} + ).trim(); - // search this part of the process output for a path to the generated app and replace default - const appPathFromLog = data.toString().match(/Touch (build\/Build\/Products\/.*\/.*\.app)/); - if (appPathFromLog) { - appPath = appPathFromLog[1]; - } - }); - - xcodeBuildProcess.on('close', (code) => { - if (code !== 0) { - reject(new Error(`xcodebuild process exited with code ${code}`)); - return; - } - - console.log(`Installing ${appPath}`); - child_process.spawnSync('xcrun', ['simctl', 'install', 'booted', appPath], {stdio: 'inherit'}); - - const bundleID = child_process.execFileSync( - '/usr/libexec/PlistBuddy', - ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')], - {encoding: 'utf8'} - ).trim(); - - console.log(`Launching ${bundleID}`); - child_process.spawnSync('xcrun', ['simctl', 'launch', 'booted', bundleID], {stdio: 'inherit'}); - - resolve(); - }); + console.log(`Launching ${bundleID}`); + child_process.spawnSync('xcrun', ['simctl', 'launch', 'booted', bundleID], {stdio: 'inherit'}); } function matchingSimulator(simulators, simulatorName) { @@ -131,4 +77,31 @@ function formattedSimulatorName(simulator) { return `${simulator.name} (${simulator.version})`; } -module.exports = runIOS; +module.exports = { + name: 'run-ios', + description: 'builds your app and starts it on iOS simulator', + func: runIOS, + examples: [ + { + desc: 'Run on a different simulator, e.g. iPhone 5', + cmd: 'react-native run-ios --simulator "iPhone 5"', + }, + { + desc: 'Pass a non-standard location of iOS directory', + cmd: 'react-native run-ios --project-path "./app/ios"', + }, + ], + options: [{ + command: '--simulator [string]', + description: 'Explicitly set simulator to use', + default: 'iPhone 6', + }, { + command: '--scheme [string]', + description: 'Explicitly set Xcode scheme to use', + }, { + command: '--project-path [string]', + description: 'Path relative to project root where the Xcode project ' + + '(.xcodeproj) lives. The default is \'ios\'.', + default: 'ios', + }] +}; diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 10e39b9df..fb3cec33f 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -89,7 +89,7 @@ function getPackagerServer(args, config) { 'aac', 'aiff', 'caf', 'm4a', 'mp3', 'wav', // Audio formats 'html', 'pdf', // Document formats ], - resetCache: args.resetCache || args['reset-cache'], + resetCache: args.resetCache, verbose: args.verbose, }); } diff --git a/local-cli/server/server.js b/local-cli/server/server.js index 7d1d6fc48..945accf85 100644 --- a/local-cli/server/server.js +++ b/local-cli/server/server.js @@ -10,82 +10,14 @@ const chalk = require('chalk'); const formatBanner = require('./formatBanner'); -const parseCommandLine = require('../util/parseCommandLine'); const path = require('path'); -const Promise = require('promise'); const runServer = require('./runServer'); /** * Starts the React Native Packager Server. */ -function server(argv, config) { - return new Promise((resolve, reject) => { - _server(argv, config, resolve, reject); - }); -} - -function _server(argv, config, resolve, reject) { - const args = parseCommandLine([{ - command: 'port', - default: 8081, - type: 'string', - }, { - command: 'host', - default: '', - type: 'string', - }, { - command: 'root', - type: 'string', - description: 'add another root(s) to be used by the packager in this project', - }, { - command: 'projectRoots', - type: 'string', - description: 'override the root(s) to be used by the packager', - },{ - command: 'assetRoots', - type: 'string', - description: 'specify the root directories of app assets' - }, { - command: 'skipflow', - description: 'Disable flow checks' - }, { - command: 'nonPersistent', - description: 'Disable file watcher' - }, { - command: 'transformer', - type: 'string', - default: null, - description: 'Specify a custom transformer to be used' - }, { - command: 'resetCache', - description: 'Removes cached files', - default: false, - }, { - command: 'reset-cache', - description: 'Removes cached files', - default: false, - }, { - command: 'verbose', - description: 'Enables logging', - default: false, - }]); - - args.projectRoots = args.projectRoots - ? argToArray(args.projectRoots) - : config.getProjectRoots(); - - if (args.root) { - const additionalRoots = argToArray(args.root); - additionalRoots.forEach(root => { - args.projectRoots.push(path.resolve(root)); - }); - } - - args.assetRoots = args.assetRoots - ? argToArray(args.assetRoots).map(dir => - path.resolve(process.cwd(), dir) - ) - : config.getAssetRoots(); +function server(argv, config, args) { + args.projectRoots = args.projectRoots.concat(args.root); console.log(formatBanner( 'Running packager on port ' + args.port + '.\n\n' + @@ -130,25 +62,50 @@ function _server(argv, config, resolve, reject) { process.exit(1); }); - // TODO: remove once we deprecate this arg - if (args.resetCache) { - console.log( - 'Please start using `--reset-cache` instead. ' + - 'We\'ll deprecate this argument soon.' - ); - } - - startServer(args, config); + runServer(args, config, () => console.log('\nReact packager ready.\n')); } -function startServer(args, config) { - runServer(args, config, () => - console.log('\nReact packager ready.\n') - ); -} - -function argToArray(arg) { - return Array.isArray(arg) ? arg : arg.split(','); -} - -module.exports = server; +module.exports = { + name: 'start', + func: server, + description: 'starts the webserver', + options: [{ + command: '--port [number]', + default: 8081, + parse: (val) => Number(val), + }, { + command: '--host [string]', + default: '', + }, { + command: '--root [list]', + description: 'add another root(s) to be used by the packager in this project', + parse: (val) => val.split(',').map(root => path.resolve(root)), + default: [], + }, { + command: '--projectRoots [list]', + description: 'override the root(s) to be used by the packager', + parse: (val) => val.split(','), + default: (config) => config.getProjectRoots(), + }, { + command: '--assetRoots [list]', + description: 'specify the root directories of app assets', + parse: (val) => val.split(',').map(dir => path.resolve(process.cwd(), dir)), + default: (config) => config.getAssetRoots(), + }, { + command: '--skipflow', + description: 'Disable flow checks' + }, { + command: '--nonPersistent', + description: 'Disable file watcher' + }, { + command: '--transformer [string]', + default: require.resolve('../../packager/transformer'), + description: 'Specify a custom transformer to be used (absolute path)' + }, { + command: '--reset-cache, --resetCache', + description: 'Removes cached files', + }, { + command: '--verbose', + description: 'Enables logging', + }], +}; diff --git a/local-cli/upgrade/upgrade.js b/local-cli/upgrade/upgrade.js index aaf6c01ce..82b3a83f9 100644 --- a/local-cli/upgrade/upgrade.js +++ b/local-cli/upgrade/upgrade.js @@ -15,7 +15,7 @@ const Promise = require('promise'); const yeoman = require('yeoman-environment'); const semver = require('semver'); -module.exports = function upgrade(args, config) { +function upgrade(args, config) { args = args || process.argv; const env = yeoman.createEnv(); const pak = JSON.parse(fs.readFileSync('package.json', 'utf8')); @@ -46,7 +46,7 @@ module.exports = function upgrade(args, config) { ); // >= v0.21.0, we require react to be a peer dependency - if (semver.gte(v, '0.21.0') && !pak.dependencies['react']) { + if (semver.gte(v, '0.21.0') && !pak.dependencies.react) { console.log( chalk.yellow( '\nYour \'package.json\' file doesn\'t seem to have \'react\' as a dependency.\n' + @@ -55,9 +55,9 @@ module.exports = function upgrade(args, config) { 'Just run \'npm install --save react\', then re-run \'react-native upgrade\'.\n' ) ); - return Promise.resolve(); + return; } - + if (semver.satisfies(v, '~0.26.0')) { console.log( chalk.yellow( @@ -96,4 +96,11 @@ module.exports = function upgrade(args, config) { env.register(generatorPath, 'react:app'); const generatorArgs = ['react:app', pak.name].concat(args); return new Promise((resolve) => env.run(generatorArgs, {upgrade: true}, resolve)); +} + +module.exports = { + name: 'upgrade', + description: 'upgrade your app\'s template files to the latest version; run this after ' + + 'updating the react-native version in your package.json and running npm install', + func: upgrade, }; diff --git a/local-cli/util/assertRequiredOptions.js b/local-cli/util/assertRequiredOptions.js new file mode 100644 index 000000000..28bbc9b34 --- /dev/null +++ b/local-cli/util/assertRequiredOptions.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +const { Option } = require('commander'); +const { camelCase } = require('lodash'); + +// Commander.js has a 2 years old open issue to support <...> syntax +// for options. Until that gets merged, we run the checks manually +// https://github.com/tj/commander.js/issues/230 +module.exports = function assertRequiredOptions(options, passedOptions) { + options.forEach(opt => { + const option = new Option(opt.command); + + if (!option.required) { + return; + } + + const name = camelCase(option.long); + + if (!passedOptions[name]) { + // Provide commander.js like error message + throw new Error(`error: option '${option.long}' missing`); + } + }); +}; diff --git a/local-cli/util/parseCommandLine.js b/local-cli/util/parseCommandLine.js index b373ddad4..10b8d3537 100644 --- a/local-cli/util/parseCommandLine.js +++ b/local-cli/util/parseCommandLine.js @@ -15,6 +15,9 @@ * description: 'Run in a web browser instead of iOS', * default: true * }]) + * + * NOTE: This file is used internally at Facebook and not in `local-cli` itself. + * No changes should be made to this file without prior discussion with FB team. */ 'use strict'; diff --git a/local-cli/version/version.js b/local-cli/version/version.js deleted file mode 100644 index 523172e5e..000000000 --- a/local-cli/version/version.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -var pkg = require('../../package'); -var Promise = require('promise'); - -/** - * Prints the version of react-native and exits. - */ -function version(argv, config) { - console.log(pkg.version); - return Promise.resolve(); -} - -module.exports = version; diff --git a/package.json b/package.json index 19fd4e10f..933ee1989 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,7 @@ "^[./a-zA-Z0-9$_-]+\\.png$": "RelativeImageStub" }, "testPathIgnorePatterns": [ - "/node_modules/", - "/local-cli/rnpm/" + "/node_modules/" ], "haste": { "defaultPlatform": "ios", @@ -145,6 +144,7 @@ "base64-js": "^0.0.8", "bser": "^1.0.2", "chalk": "^1.1.1", + "commander": "^2.9.0", "connect": "^2.8.3", "core-js": "^2.2.2", "debug": "^2.2.0", @@ -186,7 +186,7 @@ "wordwrap": "^1.0.0", "worker-farm": "^1.3.1", "ws": "^1.1.0", - "xcode": "^0.8.2", + "xcode": "^0.8.9", "xmldoc": "^0.4.0", "yargs": "^3.24.0", "yeoman-environment": "1.5.3", @@ -205,6 +205,7 @@ "jest": "latest", "jest-repl": "latest", "jest-runtime": "latest", + "mock-fs": "^3.11.0", "portfinder": "0.4.0", "react": "~15.3.0-rc.2", "shelljs": "0.6.0"