From e166a8d8b72263a5ab75f04871e7a5d2da9729e9 Mon Sep 17 00:00:00 2001
From: Tomasz Sapeta <1714764+tsapeta@users.noreply.github.com>
Date: Thu, 28 May 2020 16:28:41 +0200
Subject: [PATCH] Move react-native-unimodules to the monorepo (#8537)
---
.gitmodules | 3 -
packages/react-native-unimodules | 1 -
packages/react-native-unimodules/.eslintrc.js | 2 +
packages/react-native-unimodules/.npmignore | 4 +
packages/react-native-unimodules/CHANGELOG.md | 104 +++++++
packages/react-native-unimodules/LICENSE.md | 21 ++
packages/react-native-unimodules/README.md | 109 ++++++++
.../react-native-unimodules/babel.config.js | 2 +
.../react-native-unimodules/build/index.d.ts | 5 +
.../react-native-unimodules/build/index.js | 7 +
.../build/index.js.map | 1 +
packages/react-native-unimodules/cocoapods.rb | 127 +++++++++
.../react-native-unimodules/gradle.groovy | 260 ++++++++++++++++++
packages/react-native-unimodules/package.json | 62 +++++
.../scripts/postinstall.js | 16 ++
packages/react-native-unimodules/src/index.ts | 7 +
.../react-native-unimodules/tsconfig.json | 9 +
.../publish-packages/tasks/prepareParcels.ts | 3 +-
18 files changed, 737 insertions(+), 6 deletions(-)
delete mode 160000 packages/react-native-unimodules
create mode 100644 packages/react-native-unimodules/.eslintrc.js
create mode 100644 packages/react-native-unimodules/.npmignore
create mode 100644 packages/react-native-unimodules/CHANGELOG.md
create mode 100644 packages/react-native-unimodules/LICENSE.md
create mode 100644 packages/react-native-unimodules/README.md
create mode 100644 packages/react-native-unimodules/babel.config.js
create mode 100644 packages/react-native-unimodules/build/index.d.ts
create mode 100644 packages/react-native-unimodules/build/index.js
create mode 100644 packages/react-native-unimodules/build/index.js.map
create mode 100644 packages/react-native-unimodules/cocoapods.rb
create mode 100644 packages/react-native-unimodules/gradle.groovy
create mode 100644 packages/react-native-unimodules/package.json
create mode 100644 packages/react-native-unimodules/scripts/postinstall.js
create mode 100644 packages/react-native-unimodules/src/index.ts
create mode 100644 packages/react-native-unimodules/tsconfig.json
diff --git a/.gitmodules b/.gitmodules
index 2d53210f6498b..d64b459e63985 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,6 +6,3 @@
url = git@github.com:expo/react-native.git
branch = exp-latest
update = checkout
-[submodule "packages/react-native-unimodules"]
- path = packages/react-native-unimodules
- url = git@github.com:unimodules/react-native-unimodules.git
diff --git a/packages/react-native-unimodules b/packages/react-native-unimodules
deleted file mode 160000
index 68313e6a30159..0000000000000
--- a/packages/react-native-unimodules
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 68313e6a3015975428ef5e9914ba4587669c9516
diff --git a/packages/react-native-unimodules/.eslintrc.js b/packages/react-native-unimodules/.eslintrc.js
new file mode 100644
index 0000000000000..2720197860feb
--- /dev/null
+++ b/packages/react-native-unimodules/.eslintrc.js
@@ -0,0 +1,2 @@
+// @generated by expo-module-scripts
+module.exports = require('expo-module-scripts/eslintrc.base.js');
diff --git a/packages/react-native-unimodules/.npmignore b/packages/react-native-unimodules/.npmignore
new file mode 100644
index 0000000000000..85e65a234bcb8
--- /dev/null
+++ b/packages/react-native-unimodules/.npmignore
@@ -0,0 +1,4 @@
+# @generated by expo-module-scripts
+babel.config.js
+__tests__
+__mocks__
diff --git a/packages/react-native-unimodules/CHANGELOG.md b/packages/react-native-unimodules/CHANGELOG.md
new file mode 100644
index 0000000000000..218986d173602
--- /dev/null
+++ b/packages/react-native-unimodules/CHANGELOG.md
@@ -0,0 +1,104 @@
+# Changelog
+
+## 0.10.0
+
+### 📚 Library updates
+
+- Updated dependencies to match versions included in Expo SDK38.
+
+## 0.9.0
+
+### 📚 Library updates
+
+- Updated `@unimodules/react-native-adapter` to version `5.2.0`.
+
+## 0.8.1
+
+### 🎉 New features
+
+- Added `unimodules-app-loader` to dependencies.
+
+## 0.8.0
+
+### 🛠 Breaking changes
+
+- Updated core packages, please refer to [their changelogs](https://github.com/expo/expo/blob/master/CHANGELOG.md) to see the diff.
+- Removed `expo-app-loader-provider` from dependencies.
+
+### 🎉 New features
+
+- Added `expo-image-loader` to dependencies.
+
+### 🐛 Bug fixes
+
+- Fix `pod install --deployment` failing due to pathname object being used instead of a string. ([#96](https://github.com/unimodules/react-native-unimodules/pull/96) by [@tsapeta](https://github.com/tsapeta))
+
+## 0.7.0
+
+### 📚 Library updates
+
+- Updated `@unimodules/react-native-adapter` to version `5.0.0`.
+
+### 🛠 Breaking changes
+
+- Updated core packages, please refer to [their changelogs](https://github.com/expo/expo/blob/master/CHANGELOG.md) to see the diff.
+
+### 🎉 New features
+
+- Allow passing custom pod flags to the unimodules.
+
+## 0.6.0
+
+### 🛠 Breaking changes
+
+- Updated core packages, please refer to [their changelogs](https://github.com/expo/expo/blob/master/CHANGELOG.md) to see the diff.
+
+## 0.5.3
+
+## 0.5.2
+
+### 🐛 Bug fixes
+
+- Updated `@unimodules/core` to version `3.0.2` including proper ProGuard rules.
+
+## 0.5.0
+
+### 🛠 Breaking changes
+
+- Updated core packages, please refer to [their changelogs](https://github.com/expo/expo/blob/master/CHANGELOG.md) to see the diff
+
+## 0.4.2
+
+### 🐛 Bug fixes
+
+- Fixed MainApplication.kt not being recognized correctly. ([#46](https://github.com/unimodules/react-native-unimodules/pull/46) by [@geovannimp](https://github.com/geovannimp))
+
+## 0.4.1
+
+### 🐛 Bug fixes
+
+- Added support for Kotlin ([#39](https://github.com/unimodules/react-native-unimodules/pull/39) by [@bbarthec](https://github.com/bbarthec))
+
+## 0.4.0
+
+### 🛠 Breaking changes
+
+- Updated core packages, please refer to [their changelogs](https://github.com/expo/expo/blob/master/CHANGELOG.md) to see the diff
+
+### 🐛 Bug fixes
+
+- Support version tags when adding dependencies for unimodules
+
+## 0.3.1
+
+### 🐛 Bug fixes
+
+- Fixed TypeScript definitions of common unimodules not being exported. Thanks [@saadq](https://github.com/saadq)! ([#24](https://github.com/unimodules/react-native-unimodules/pull/24))
+- Fixed automatic installation script not finding unimodules when using CocoaPods' `--project-directory` flag. ([#31](https://github.com/unimodules/react-native-unimodules/pull/31))
+
+## 0.3.0
+
+### 🎉 New features
+
+- Automatically generated list of Android packages ([#28](https://github.com/unimodules/react-native-unimodules/pull/28))
+ As of this version, you no longer need to add new packages to your `MainApplication.java` file. Just use `new BasePackageList().getPackageList()` instead 🎉. `BasePackageList` is auto-generated with a list of installed unimodules found in your `node_modules` folder during Gradle's Sync operation.
diff --git a/packages/react-native-unimodules/LICENSE.md b/packages/react-native-unimodules/LICENSE.md
new file mode 100644
index 0000000000000..c68dc36280ae8
--- /dev/null
+++ b/packages/react-native-unimodules/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2019-present 650 Industries, Inc. (aka Expo)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/react-native-unimodules/README.md b/packages/react-native-unimodules/README.md
new file mode 100644
index 0000000000000..7c2e9013d924d
--- /dev/null
+++ b/packages/react-native-unimodules/README.md
@@ -0,0 +1,109 @@
+# react-native-unimodules
+
+This library contains the core unimodule infrastructure and a collection of unimodules and interfaces that are commonly depended on by other unimodules. You only need to install `react-native-unimodules` once and then you will be able to use [most of the packages from the Expo SDK](https://docs.expo.io/versions/latest/bare/unimodules-full-list/), like [expo-camera](https://docs.expo.io/versions/latest/sdk/camera/), [expo-media-library](https://docs.expo.io/versions/latest/sdk/media-library/) and many more, [in any React Native project](https://blog.expo.io/you-can-now-use-expo-apis-in-any-react-native-app-7c3a93041331).
+
+The easiest way to use the library is to initialize a project with it already installed: `npx create-react-native-app my-app`.
+
+> You can also use `expo-cli` to do this - run `npm i -g expo-cli` and then `expo init --template bare-minimum` or `expo init --template expo-template-bare-typescript` if you prefer TypeScript.
+
+If you have an existing project you'd like to install it into, please read the following instructions.
+
+## 📦 Installation
+
+**This project requires that you use CocoaPods on iOS**, to set it up see [this gist](https://gist.github.com/brentvatne/b0ea11a36dc423e441b7d36e36eb5a26), or relevant parts of the [this guide](https://facebook.github.io/react-native/docs/integration-with-existing-apps#3-install-cocoapods). React Native >= 0.60 ships with CocoaPods support by default, so this should be easy if you're already on that version.
+
+```bash
+npm install react-native-unimodules
+```
+
+Now you need to configure the library for iOS and/or Android.
+
+## 🍎 Configure iOS
+
+- Open `ios/Podfile` in your editor and make it look [like this one on react-native <= 0.59](https://gist.github.com/sjchmiela/6c079f2173938a9a61a7c6f053c45000) or [like this one on react-native >= 0.60](https://gist.github.com/brentvatne/d093e440698404803bd9c29d962949b0/revisions#diff-4a25b996826623c4a3a4910f47f10c30).
+- Run `npx pod-install` again
+- Update your `AppDelegate.h` and `AppDelegate.m` according to [to look like these](https://gist.github.com/brentvatne/1ece8c32a3c5c9d0ac3a470460c65603).
+ - If you use [`react-native-navigation`](https://github.com/wix/react-native-navigation), you will need to use its `bridgeManagerDelegate` option [like in this gist](https://gist.github.com/brentvatne/67909ec442121de22c9b81c629a99aa6).
+
+### Advanced configuration
+
+Need to customize node_modules path?
+
+
+If you need to customize the path to node_modules, for example because you are using yarn workspaces, then you can pass in a param for this: `use_unimodules!(modules_paths: ['./path/to/node_modules'])`
+
+
+
+
+Need to exclude some unimodules that are being automatically linked?
+
+
+If you need to exclude some of the unimodules that you are not using but they got installed by your other dependencies (like `expo`), then you can pass in `exclude` param for this. For example, if you want to exclude `expo-face-detector`, you may want to use this: `use_unimodules!(exclude: ['expo-face-detector'])`
+
+
+
+
+## 🤖 Configure Android
+
+**In `android/settings.gradle`**
+
+1. At the top add `apply from: '../node_modules/react-native-unimodules/gradle.groovy'`
+1. Then call `includeUnimodulesProjects()` on the next line.
+
+**In `android/app/build.gradle`**
+
+1. Add `apply from: '../../node_modules/react-native-unimodules/gradle.groovy'` anywhere before the `dependencies {}` block.
+1. Add `addUnimodulesDependencies()` inside `dependencies {}` block.
+1. We recommend you use Java 1.8, you can set this [like this](https://github.com/expo/expo/commit/e175f870418fc69e8c129168118264439d73d7cc).
+
+**In `android/build.gradle`**
+
+1. Update `minSdkVersion` to `21`.
+
+**In `MainApplication.java`**
+Make the changes outlined in the diff that correspondes to your react-native version.
+
+- [this diff for react-native <= 0.59](https://gist.github.com/mczernek/0670ec16ca6071796853a66d589b49a5/revisions#diff-a2e7ff8a82f1c4be06f8b8163f2afefa)
+- [this diff for react-native >= 0.60](https://gist.github.com/mczernek/9de9e184abc430e9e3508d26738c8a14/revisions#diff-a2e7ff8a82f1c4be06f8b8163f2afefa)
+
+### Advanced configuration
+
+Need to customize node_modules path?
+
+
+If you need to customize the path to node_modules, for example because you are using yarn workspaces, then you can pass in a param `modulesPaths` for both of these functions: `includeUnimodulesProjects([modulesPaths: ['./path/to/node_modules']])`, `addUnimodulesDependencies([modulesPaths: ['./path/to/node_modules']])`
+
+
+
+
+Need to exclude some unimodules that are being automatically linked?
+
+
+If you need to exclude some of the unimodules that you are not using but they got installed by your other dependencies (like `expo`), then you can pass in `exclude` param for this. For example, if you want to exclude `expo-face-detector`, you may want to use this: `addUnimodulesDependencies([exclude: ['expo-face-detector']])`
+
+
+
+
+Need to customize configuration of unimodule dependencies?
+
+
+You can also customize the configuration of the unimodules dependencies (the default is `implementation`, if you're using Gradle older than 3.0, you will need to set `configuration: "compile"` in `addUnimodulesDependencies`, like: `addUnimodulesDependencies([configuration: "compile"])`)
+
+
+
+
+# API
+
+It's possible that you will not have to use any of the code provided by this package directly, it may be used only by other Unimodules that you install.
+
+But it's likely that you will want to use something like FileSystem or Permissions, and to do that you can import the following modules like so:
+
+```js
+import { Asset, Constants, FileSystem, Permissions } from 'react-native-unimodules';
+```
+
+You can import them directly from the specific Unimodule package if you like, but your linter may complain about importing a transitive dependency.
+
+```js
+import * as Permissions from 'expo-permissions';
+```
diff --git a/packages/react-native-unimodules/babel.config.js b/packages/react-native-unimodules/babel.config.js
new file mode 100644
index 0000000000000..68c7d3192262e
--- /dev/null
+++ b/packages/react-native-unimodules/babel.config.js
@@ -0,0 +1,2 @@
+// @generated by expo-module-scripts
+module.exports = require('expo-module-scripts/babel.config.base');
diff --git a/packages/react-native-unimodules/build/index.d.ts b/packages/react-native-unimodules/build/index.d.ts
new file mode 100644
index 0000000000000..fbf40a5e30c51
--- /dev/null
+++ b/packages/react-native-unimodules/build/index.d.ts
@@ -0,0 +1,5 @@
+import { Asset } from 'expo-asset';
+import Constants from 'expo-constants';
+import * as FileSystem from 'expo-file-system';
+import * as Permissions from 'expo-permissions';
+export { Asset, Constants, FileSystem, Permissions };
diff --git a/packages/react-native-unimodules/build/index.js b/packages/react-native-unimodules/build/index.js
new file mode 100644
index 0000000000000..5555e4f69b5aa
--- /dev/null
+++ b/packages/react-native-unimodules/build/index.js
@@ -0,0 +1,7 @@
+// Override React Native's asset resolution for `Image` components
+import { Asset } from 'expo-asset';
+import Constants from 'expo-constants';
+import * as FileSystem from 'expo-file-system';
+import * as Permissions from 'expo-permissions';
+export { Asset, Constants, FileSystem, Permissions };
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/packages/react-native-unimodules/build/index.js.map b/packages/react-native-unimodules/build/index.js.map
new file mode 100644
index 0000000000000..b66e60a6a7c20
--- /dev/null
+++ b/packages/react-native-unimodules/build/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC","sourcesContent":["// Override React Native's asset resolution for `Image` components\nimport { Asset } from 'expo-asset';\nimport Constants from 'expo-constants';\nimport * as FileSystem from 'expo-file-system';\nimport * as Permissions from 'expo-permissions';\n\nexport { Asset, Constants, FileSystem, Permissions };\n"]}
\ No newline at end of file
diff --git a/packages/react-native-unimodules/cocoapods.rb b/packages/react-native-unimodules/cocoapods.rb
new file mode 100644
index 0000000000000..108b923f1d57d
--- /dev/null
+++ b/packages/react-native-unimodules/cocoapods.rb
@@ -0,0 +1,127 @@
+require 'json'
+require 'pathname'
+require 'optparse'
+
+def use_unimodules!(custom_options = {})
+ options = {
+ modules_paths: ['../node_modules'],
+ target: 'react-native',
+ exclude: [],
+ flags: {},
+ }.deep_merge(custom_options)
+
+ modules_paths = options.fetch(:modules_paths)
+ modules_to_exclude = options.fetch(:exclude)
+ target = options.fetch(:target)
+ flags = options.fetch(:flags)
+
+ unimodules = {}
+ unimodules_duplicates = []
+
+ project_directory = Pod::Config.instance.project_root
+
+ modules_paths.each { |module_path|
+ canonical_module_path = Pathname.new(File.join(project_directory, module_path)).cleanpath
+ glob_pattern = File.join(canonical_module_path, '**/*/**', 'unimodule.json')
+
+ Dir.glob(glob_pattern) { |module_config_path|
+ unimodule_json = JSON.parse(File.read(module_config_path))
+ directory = File.dirname(module_config_path)
+ platforms = unimodule_json['platforms'] || ['ios']
+ targets = unimodule_json['targets'] || ['react-native']
+
+ if unimodule_supports_platform(platforms, 'ios') && unimodule_supports_target(targets, target)
+ package_json_path = File.join(directory, 'package.json')
+ package_json = JSON.parse(File.read(package_json_path))
+ package_name = unimodule_json['name'] || package_json['name']
+
+ if !modules_to_exclude.include?(package_name)
+ unimodule_config = { 'subdirectory' => 'ios' }.merge(unimodule_json.fetch('ios', {}))
+ unimodule_version = package_json['version']
+
+ if unimodules[package_name]
+ unimodules_duplicates.push(package_name)
+ end
+
+ if !unimodules[package_name] || Gem::Version.new(unimodule_version) >= Gem::Version.new(unimodules[package_name][:version])
+ unimodules[package_name] = {
+ name: package_name,
+ directory: directory,
+ version: unimodule_version,
+ config: unimodule_config,
+ warned: false,
+ }
+ end
+ end
+ end
+ }
+ }
+
+ if unimodules.values.length > 0
+ puts brown 'Installing unimodules:'
+
+ unimodules.values.sort! { |x,y| x[:name] <=> y[:name] }.each { |unimodule|
+ directory = unimodule[:directory]
+ config = unimodule[:config]
+
+ subdirectory = config['subdirectory']
+ pod_name = config.fetch('podName', find_pod_name(directory, subdirectory))
+ podspec_directory = Pathname.new("#{directory}/#{subdirectory}").relative_path_from(project_directory)
+
+ puts " #{green unimodule[:name]}#{cyan "@"}#{magenta unimodule[:version]} from #{blue podspec_directory}"
+
+ pod_options = flags.merge({ path: podspec_directory.to_s })
+
+ pod "#{pod_name}", pod_options
+ }
+
+ if unimodules_duplicates.length > 0
+ puts
+ puts brown "Found some duplicated unimodule packages. Installed the ones with the highest version number."
+ puts brown "Make sure following dependencies of your project are resolving to one specific version:"
+
+ puts ' ' + unimodules_duplicates
+ .uniq
+ .map { |package_name| green(package_name) }
+ .join(', ')
+ end
+ else
+ puts
+ puts brown "No unimodules found. Are you sure you've installed JS dependencies before installing pods?"
+ end
+
+ puts
+end
+
+def find_pod_name(package_path, subdirectory)
+ podspec_path = Dir.glob(File.join(package_path, subdirectory, '*.podspec')).first
+ return podspec_path && File.basename(podspec_path).chomp('.podspec')
+end
+
+def unimodule_supports_platform(platforms, platform)
+ return platforms.class == Array && platforms.include?(platform)
+end
+
+def unimodule_supports_target(targets, target)
+ return targets.class == Array && targets.include?(target)
+end
+
+def green(message)
+ return "\e[32m#{message}\e[0m"
+end
+
+def brown(message)
+ return "\e[33m#{message}\e[0m"
+end
+
+def blue(message)
+ return "\e[34m#{message}\e[0m"
+end
+
+def magenta(message)
+ return "\e[35m#{message}\e[0m"
+end
+
+def cyan(message)
+ return "\e[36m#{message}\e[0m"
+end
diff --git a/packages/react-native-unimodules/gradle.groovy b/packages/react-native-unimodules/gradle.groovy
new file mode 100644
index 0000000000000..ef69c4b7e9f58
--- /dev/null
+++ b/packages/react-native-unimodules/gradle.groovy
@@ -0,0 +1,260 @@
+import groovy.json.JsonSlurper
+import org.gradle.util.VersionNumber
+
+import java.util.regex.Pattern
+
+class Unimodule {
+ String name
+ List platforms
+ List targets
+ List androidPackages
+ String directory
+ String version
+ String androidGroup
+ String androidSubdirectory
+
+ boolean supportsPlatform(String platform) {
+ return platforms instanceof List && platforms.contains(platform)
+ }
+
+ boolean supportsTarget(String target) {
+ return targets.size() == 0 || targets.contains(target)
+ }
+}
+
+def readPackageFromJavaOrKotlinFile(String filePath) {
+ def file = new File(filePath)
+ def fileReader = new BufferedReader(new FileReader(file))
+ def fileContent = ""
+ while ((fileContent = fileReader.readLine()) != null) {
+ def match = fileContent =~ /^package ([0-9a-zA-Z._]*);?$/
+ if (match.size() == 1 && match[0].size() == 2) {
+ fileReader.close()
+ return match[0][1]
+ }
+ }
+ fileReader.close()
+
+ throw new GradleException("Java or Kotlin file $file does not include package declaration")
+}
+
+def readFromBuildGradle(String file) {
+ def gradleFile = new File(file)
+ if (!gradleFile.exists()) {
+ return [:]
+ }
+ def fileReader = new BufferedReader(new FileReader(gradleFile))
+ def result = [:]
+ for (def line = fileReader.readLine(); line != null; line = fileReader.readLine()) {
+ def versionMatch = line.trim() =~ /^version ?= ?'([\w.-]+)'$/
+ def groupMatch = line.trim() =~ /^group ?= ?'([\w.]+)'$/
+ if (versionMatch.size() == 1 && versionMatch[0].size() == 2) {
+ result.version = versionMatch[0][1]
+ }
+ if (groupMatch.size() == 1 && groupMatch[0].size() == 2) {
+ result.group = groupMatch[0][1]
+ }
+ }
+ fileReader.close()
+ return result
+}
+
+def findDefaultBasePackage(String packageDir) {
+ def pathsJava = new FileNameFinder().getFileNames(packageDir, "android/src/**/*Package.java")
+ def pathsKt = new FileNameFinder().getFileNames(packageDir, "android/src/**/*Package.kt")
+ def paths = pathsJava + pathsKt
+
+ if (paths.size != 1) {
+ return []
+ }
+
+ def packageName = readPackageFromJavaOrKotlinFile(paths[0])
+ def className = new File(paths[0]).getName().split(Pattern.quote("."))[0]
+ return ["$packageName.$className"]
+}
+
+def generateBasePackageList(List unimodules) {
+ def findMainJavaApp = new FileNameFinder().getFileNames(rootProject.getProjectDir().getPath(), '**/MainApplication.java', '')
+ def findMainKtApp = new FileNameFinder().getFileNames(rootProject.getProjectDir().getPath(), '**/MainApplication.kt', '')
+
+ if (findMainJavaApp.size() != 1 && findMainKtApp.size() != 1) {
+ throw new GradleException("You need to have MainApplication in your project")
+ }
+
+ def findMainApp = (findMainJavaApp.size() == 1) ? findMainJavaApp : findMainKtApp
+ def mainAppDirectory = new File(findMainApp[0]).parentFile
+ def packageName = readPackageFromJavaOrKotlinFile(findMainApp[0])
+
+ def fileBuilder = new StringBuilder()
+ fileBuilder.append("package ${packageName}.generated;\n\n")
+
+ fileBuilder.append("import java.util.Arrays;\n")
+ fileBuilder.append("import java.util.List;\n")
+ fileBuilder.append("import org.unimodules.core.interfaces.Package;\n\n")
+
+ fileBuilder.append("public class BasePackageList {\n")
+ fileBuilder.append(" public List getPackageList() {\n")
+ fileBuilder.append(" return Arrays.asList(\n")
+ def isEmptyList = true
+ for (module in unimodules) {
+ for (pkg in module.androidPackages) {
+ fileBuilder.append(" new $pkg(),\n")
+ isEmptyList = false
+ }
+ }
+ if (!isEmptyList) {
+ fileBuilder.deleteCharAt(fileBuilder.length() - 2) // remove last comma in a list
+ }
+ fileBuilder.append(" );\n")
+ fileBuilder.append(" }\n")
+ fileBuilder.append("}\n")
+
+
+ new File(mainAppDirectory, "generated").mkdirs()
+ def javaFile = new File(mainAppDirectory, "generated/BasePackageList.java")
+ javaFile.createNewFile()
+ def javaFileWriter = new BufferedWriter(new FileWriter(javaFile))
+ javaFileWriter.write(fileBuilder.toString())
+ javaFileWriter.close()
+}
+
+
+def findUnimodules(String target, List exclude, List modulesPaths) {
+ def unimodules = [:]
+ def unimodulesDuplicates = []
+
+ for (modulesPath in modulesPaths) {
+ def baseDir = new File(rootProject.getBuildFile(), modulesPath).toString()
+ def moduleConfigPaths = new FileNameFinder().getFileNames(baseDir, '**/unimodule.json', '')
+
+ for (moduleConfigPath in moduleConfigPaths) {
+ def unimoduleConfig = new File(moduleConfigPath)
+ def unimoduleJson = new JsonSlurper().parseText(unimoduleConfig.text)
+ def directory = unimoduleConfig.getParent()
+ def buildGradle = readFromBuildGradle(new File(directory, "android/build.gradle").toString())
+ def packageJsonFile = new File(directory, 'package.json')
+ def packageJson = new JsonSlurper().parseText(packageJsonFile.text)
+
+ def unimodule = new Unimodule()
+ unimodule.name = unimoduleJson.name ?: packageJson.name
+ unimodule.directory = directory
+ unimodule.version = buildGradle.version ?: packageJson.version ?: "UNVERSIONED"
+ unimodule.androidGroup = buildGradle.group ?: "org.unimodules"
+ unimodule.androidSubdirectory = unimoduleJson.android?.subdirectory ?: "android"
+ unimodule.platforms = unimoduleJson.platforms != null ? unimoduleJson.platforms : []
+ assert unimodule.platforms instanceof List
+ unimodule.targets = unimoduleJson.targets != null ? unimoduleJson.targets : []
+ assert unimodule.targets instanceof List
+ unimodule.androidPackages = unimoduleJson.android?.packages != null ?
+ unimoduleJson.android.packages : findDefaultBasePackage(directory)
+ assert unimodule.androidPackages instanceof List
+
+ if (unimodule.supportsPlatform('android') && unimodule.supportsTarget(target)) {
+ if (!exclude.contains(unimodule.name)) {
+ if (unimodules[unimodule.name]) {
+ unimodulesDuplicates.add(unimodule.name)
+ }
+
+ if (!unimodules[unimodule.name] ||
+ VersionNumber.parse(unimodule.version) >= VersionNumber.parse(unimodules[unimodule.name].version)) {
+ unimodules[unimodule.name] = unimodule
+ }
+ }
+ }
+ }
+ }
+ return [
+ unimodules: unimodules.collect { entry -> entry.value },
+ duplicates: unimodulesDuplicates.unique()
+ ]
+}
+
+
+class Colors {
+ static final String NORMAL = "\u001B[0m"
+ static final String RED = "\u001B[31m"
+ static final String GREEN = "\u001B[32m"
+ static final String YELLOW = "\u001B[33m"
+ static final String MAGENTA = "\u001B[35m"
+}
+
+def addUnimodulesDependencies(String target, List exclude, List modulesPaths, Closure addUnimodule) {
+ if (!(new File(project.rootProject.projectDir.parentFile, 'package.json').exists())) {
+ // There's no package.json
+ throw new GradleException(
+ "'addUnimodulesDependencies()' is being used in a project that doesn't seem to be a React Native project."
+ )
+ }
+
+ def results = findUnimodules(target, exclude, modulesPaths)
+ def unimodules = results.unimodules
+ def duplicates = results.duplicates
+ generateBasePackageList(unimodules)
+
+ if (unimodules.size() > 0) {
+ println()
+ println Colors.YELLOW + 'Installing unimodules:' + Colors.NORMAL
+ for (unimodule in unimodules) {
+ println ' ' + Colors.GREEN + unimodule.name + Colors.YELLOW + '@' + Colors.RED + unimodule.version + Colors.NORMAL + ' from ' + Colors.MAGENTA + unimodule.directory + Colors.NORMAL
+ addUnimodule(unimodule)
+ }
+
+ if (duplicates.size() > 0) {
+ println()
+ println Colors.YELLOW + 'Found some duplicated unimodule packages. Installed the ones with the highest version number.' + Colors.NORMAL
+ println Colors.YELLOW + 'Make sure following dependencies of your project are resolving to one specific version:' + Colors.NORMAL
+
+ println ' ' + duplicates
+ .collect { unimoduleName -> Colors.GREEN + unimoduleName + Colors.NORMAL }
+ .join(', ')
+ }
+ } else {
+ println()
+ println Colors.YELLOW + "No unimodules found. Are you sure you've installed JS dependencies?" + Colors.NORMAL
+ }
+}
+
+ext.addUnimodulesDependencies = { Map customOptions = [:] ->
+ def options = [
+ modulesPaths : ['../../node_modules'],
+ configuration: 'implementation',
+ target : 'react-native',
+ exclude : [],
+ ] << customOptions
+
+ addUnimodulesDependencies(options.target, options.exclude, options.modulesPaths, {unimodule ->
+ Object dependency = project.project(':' + unimodule.name)
+ project.dependencies.add(options.configuration, dependency)
+ })
+}
+
+ext.addMavenUnimodulesDependencies = { Map customOptions = [:] ->
+ def options = [
+ modulesPaths : ['../../node_modules'],
+ configuration: 'implementation',
+ target : 'react-native',
+ exclude : [],
+ ] << customOptions
+
+ addUnimodulesDependencies(options.target, options.exclude, options.modulesPaths, {unimodule ->
+ project.dependencies.add(
+ options.configuration,
+ "${unimodule.androidGroup}:${unimodule.name}:${unimodule.version}"
+ )
+ })
+}
+
+ext.includeUnimodulesProjects = { Map customOptions = [:] ->
+ def options = [
+ modulesPaths: ['../../node_modules'],
+ target : 'react-native',
+ exclude : [],
+ ] << customOptions
+
+ def unimodules = findUnimodules(options.target, options.exclude, options.modulesPaths).unimodules
+
+ for (unimodule in unimodules) {
+ include ":${unimodule.name}"
+ project(":${unimodule.name}").projectDir = new File(unimodule.directory, unimodule.androidSubdirectory)
+ }
+}
diff --git a/packages/react-native-unimodules/package.json b/packages/react-native-unimodules/package.json
new file mode 100644
index 0000000000000..1add21bee0bf7
--- /dev/null
+++ b/packages/react-native-unimodules/package.json
@@ -0,0 +1,62 @@
+{
+ "name": "react-native-unimodules",
+ "version": "0.10.0",
+ "description": "This library contains the core unimodule infrastructure and a collection of unimodules and interfaces that are commonly depended on by other unimodules.",
+ "main": "build/index.js",
+ "types": "build/index.d.ts",
+ "private": false,
+ "scripts": {
+ "build": "expo-module build",
+ "clean": "expo-module clean",
+ "lint": "expo-module lint",
+ "test": "expo-module test",
+ "prepare": "expo-module prepare",
+ "prepublishOnly": "expo-module prepublishOnly",
+ "expo-module": "expo-module",
+ "postinstall": "node ./scripts/postinstall.js"
+ },
+ "keywords": [
+ "react-native",
+ "expo",
+ "modules",
+ "unimodules"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/expo/expo.git",
+ "directory": "packages/expo-sms"
+ },
+ "bugs": {
+ "url": "https://github.com/expo/expo/issues"
+ },
+ "author": "650 Industries, Inc.",
+ "license": "MIT",
+ "homepage": "https://docs.expo.io/versions/latest/sdk/sms/",
+ "jest": {
+ "preset": "expo-module-scripts/ios"
+ },
+ "dependencies": {
+ "@unimodules/core": "~5.2.0",
+ "@unimodules/react-native-adapter": "~5.3.0",
+ "chalk": "^2.4.2",
+ "expo-asset": "~8.1.6",
+ "expo-constants": "~9.1.0",
+ "expo-file-system": "~9.0.0",
+ "expo-image-loader": "~1.1.0",
+ "expo-permissions": "~8.2.0",
+ "unimodules-app-loader": "~1.1.0",
+ "unimodules-barcode-scanner-interface": "~5.2.0",
+ "unimodules-camera-interface": "~5.2.0",
+ "unimodules-constants-interface": "~5.2.0",
+ "unimodules-face-detector-interface": "~5.2.0",
+ "unimodules-file-system-interface": "~5.2.0",
+ "unimodules-font-interface": "~5.2.0",
+ "unimodules-image-loader-interface": "~5.2.0",
+ "unimodules-permissions-interface": "~5.2.0",
+ "unimodules-sensors-interface": "~5.2.0",
+ "unimodules-task-manager-interface": "~5.2.0"
+ },
+ "devDependencies": {
+ "expo-module-scripts": "~1.2.0"
+ }
+}
diff --git a/packages/react-native-unimodules/scripts/postinstall.js b/packages/react-native-unimodules/scripts/postinstall.js
new file mode 100644
index 0000000000000..1bfdeca50b748
--- /dev/null
+++ b/packages/react-native-unimodules/scripts/postinstall.js
@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+
+const chalk = require('chalk');
+const packageJson = require('../package.json');
+
+// Don't run the script when doing `yarn` or `npm install` in this package.
+if (process.env.PWD === process.env.INIT_CWD) {
+ process.exit(0);
+ return;
+}
+
+console.info(chalk.green(`
+Successfully installed ${chalk.red(packageJson.name)}. This package contains core unimodules that are commonly depended on by other unimodules. You will need to configure your project before using other unimodules like ${chalk.red('expo-camera')}, ${chalk.red('expo-media-library')} and others.
+See configuration guide:
+ ${chalk.blue(`https://www.npmjs.com/package/${packageJson.name}/v/${packageJson.version}`)}
+`));
diff --git a/packages/react-native-unimodules/src/index.ts b/packages/react-native-unimodules/src/index.ts
new file mode 100644
index 0000000000000..4b698a41cde81
--- /dev/null
+++ b/packages/react-native-unimodules/src/index.ts
@@ -0,0 +1,7 @@
+// Override React Native's asset resolution for `Image` components
+import { Asset } from 'expo-asset';
+import Constants from 'expo-constants';
+import * as FileSystem from 'expo-file-system';
+import * as Permissions from 'expo-permissions';
+
+export { Asset, Constants, FileSystem, Permissions };
diff --git a/packages/react-native-unimodules/tsconfig.json b/packages/react-native-unimodules/tsconfig.json
new file mode 100644
index 0000000000000..a24ec0ff2f600
--- /dev/null
+++ b/packages/react-native-unimodules/tsconfig.json
@@ -0,0 +1,9 @@
+// @generated by expo-module-scripts
+{
+ "extends": "expo-module-scripts/tsconfig.base",
+ "compilerOptions": {
+ "outDir": "./build"
+ },
+ "include": ["./src"],
+ "exclude": ["**/__mocks__/*", "**/__tests__/*"]
+}
diff --git a/tools/expotools/src/publish-packages/tasks/prepareParcels.ts b/tools/expotools/src/publish-packages/tasks/prepareParcels.ts
index 20973c20394be..ee465cd54a186 100644
--- a/tools/expotools/src/publish-packages/tasks/prepareParcels.ts
+++ b/tools/expotools/src/publish-packages/tasks/prepareParcels.ts
@@ -8,7 +8,6 @@ import { Task } from '../../TasksRunner';
import { CommandOptions, Parcel, TaskArgs } from '../types';
const { green } = chalk;
-const IGNORED_PACKAGES = ['react-native-unimodules'];
/**
* Gets a list of public packages in the monorepo, downloads `npm view` result of them,
@@ -38,7 +37,7 @@ export const prepareParcels = new Task(
const filteredPackages = allPackages.filter((pkg) => {
const isPrivate = pkg.packageJson.private;
const isIncluded = packageNames.length === 0 || packageNames.includes(pkg.packageName);
- return !isPrivate && isIncluded && !IGNORED_PACKAGES.includes(pkg.packageName);
+ return !isPrivate && isIncluded;
});
parcels.push(...(await Promise.all(filteredPackages.map(createParcelAsync))));