chore: add mobile app

This commit is contained in:
2026-02-07 22:33:02 +01:00
parent db34640acc
commit e89384ad4e
29327 changed files with 3886944 additions and 12 deletions
+2
View File
@@ -0,0 +1,2 @@
// @generated by expo-module-scripts
module.exports = require('expo-module-scripts/eslintrc.base.js');
+676
View File
@@ -0,0 +1,676 @@
# Changelog
## Unpublished
### 🛠 Breaking changes
### 🎉 New features
### 🐛 Bug fixes
### 💡 Others
## 3.0.24 — 2026-01-06
### 💡 Others
- [Android] Align `expo-gradle-plugin`'s CLI command to align with iOS invocation of `expo-modules-autolinking` ([#41264](https://github.com/expo/expo/pull/41264) by [@kitten](https://github.com/kitten))
## 3.0.23 — 2025-12-04
### 💡 Others
- Fallback to resolving modules from list of duplicates, if a search path module is invalid or fails to resolve ([#41309](https://github.com/expo/expo/pull/41309) by [@kitten](https://github.com/kitten))
## 3.0.22 — 2025-11-17
### 🐛 Bug fixes
- Fix [#40651](https://github.com/expo/expo/pull/40651) causing already read versions to be lost depending on traversal order ([#40912](https://github.com/expo/expo/pull/40912) by [@kitten](https://github.com/kitten))
- [Follow-up] Fix [#40601](https://github.com/expo/expo/pull/40601) assuming case-insensitive path for default derived podspec path in `react-native-config` resolution ([#40894](https://github.com/expo/expo/pull/40894) by [@kitten](https://github.com/kitten)) ([#40931](https://github.com/expo/expo/pull/40931) by [@kitten](https://github.com/kitten))
## 3.0.21 — 2025-11-07
### 🐛 Bug fixes
- Fix [#40601](https://github.com/expo/expo/pull/40601) assuming case-insensitive path for default derived podspec path in `react-native-config` resolution
## 3.0.20 — 2025-11-03
### 🐛 Bug fixes
- Sort results from file discovery to keep fingerprint stable ([#40601](https://github.com/expo/expo/pull/40601) by [@kitten](https://github.com/kitten))
### 💡 Others
- Refactor test suite and file discovery implementation to drop `glob` ([#40601](https://github.com/expo/expo/pull/40601) by [@kitten](https://github.com/kitten))
- Improve recursive dependency resolution performance ([#40651](https://github.com/expo/expo/pull/40651) by [@kitten](https://github.com/kitten))
## 3.0.19 — 2025-10-23
_This version does not introduce any user-facing changes._
## 3.0.18 — 2025-10-21
### 🐛 Bug fixes
- [Android] Fixed `library projects cannot set applicationIdSuffix`. ([#40477](https://github.com/expo/expo/pull/40477) by [@lukmccall](https://github.com/lukmccall))
## 3.0.17 — 2025-10-21
### 🐛 Bug fixes
- [iOS] Moved our special build phase script initialization from run_podfile_post_install_hooks -> perform_post_install_actions to fix issue with wrong UUIDs in Pods.pbproj file. ([#40572](https://github.com/expo/expo/pull/40572) by [@chrfalch](https://github.com/chrfalch))
- fix globMatchFunctorAllAsync to check if globbed path is a file to prevent errors ([#40437](https://github.com/expo/expo/pull/40437) by [@artus9033](https://github.com/artus9033)) ([#40501](https://github.com/expo/expo/pull/40501) by [@kitten](https://github.com/kitten))
## 3.0.16 — 2025-10-20
### 🐛 Bug fixes
- Ignore missing `package.json` name property when scanning dependencies ([#40367](https://github.com/expo/expo/pull/40367) by [@kitten](https://github.com/kitten))
- fix globMatchFunctorAllAsync to check if globbed path is a file to prevent errors ([#40437](https://github.com/expo/expo/pull/40437) by [@artus9033](https://github.com/artus9033))
## 3.0.15 — 2025-10-09
### 🐛 Bug fixes
- [iOS] Added build phase script for a workaround to autolinking-generated react-native-config output not being used in ReactCodegen script phase due to temp output directory. ([#40219](https://github.com/expo/expo/pull/40219) by [@chrfalch](https://github.com/chrfalch))
### 💡 Others
- Check `react-native` and `react-native-tvos` for duplicates in the verify command explicitly ([#40180](https://github.com/expo/expo/pull/40180) by [@kitten](https://github.com/kitten))
- [Android] Sync flavor dimensions and product flavors from app to expo module ([#40238](https://github.com/expo/expo/pull/40238) by [@kosmydel](https://github.com/kosmydel))
## 3.0.14 - 2025-10-01
### 💡 Others
- Always include autolinking for top-level `devDependencies` and memoize intermediate config loading. ([#39955](https://github.com/expo/expo/pull/39955) by [@kitten](https://github.com/kitten))
## 3.0.13 — 2025-09-22
### 🎉 New features
- Use app root to generate modules provider ([#39728](https://github.com/expo/expo/pull/39728) by [@gabrieldonadel](https://github.com/gabrieldonadel))
## 3.0.12 — 2025-09-18
### 💡 Others
- [iOS] Added support for passing pod targets that should be statically linked and not built as frameworks. ([#39742](https://github.com/expo/expo/pull/39742) by [@chrfalch](https://github.com/chrfalch))
- [Android] Migrated from `kotlinOptions` to `compilerOptions` DSL. ([#39794](https://github.com/expo/expo/pull/39794) by [@huextrat](https://github.com/huextrat))
## 3.0.11 — 2025-09-16
### 🐛 Bug fixes
- Regression: Support search paths and `nativeModulesDir` pointing directly at module folder ([#39669](https://github.com/expo/expo/pull/39669) by [@kitten](https://github.com/kitten))
- Mark `ios|macos|tvos` as supported when an Expo Module marks `apple` as a supported platform ([#39700](https://github.com/expo/expo/pull/39700) by [@kitten](https://github.com/kitten))
### 💡 Others
- Allow `expo-atlas` (devtool Expo Module) to be discovered in `devDependencies` ([#39688](https://github.com/expo/expo/pull/39688) by [@kitten](https://github.com/kitten))
- Allow resolving native modules via a `web` platform heuristic for autolinking module resolution in Expo CLI ([#39701](https://github.com/expo/expo/pull/39701) by [@kitten](https://github.com/kitten))
## 3.0.10 — 2025-09-10
_This version does not introduce any user-facing changes._
## 3.0.9 — 2025-09-10
### 💡 Others
- [iOS] Added support for pre-install step when USE_FRAMEWORKS is set in Podfile ([#39479](https://github.com/expo/expo/pull/39479) by [@chrfalch](https://github.com/chrfalch))
- Remove dependency on `find-up` ([#39470](https://github.com/expo/expo/pull/39470) by [@kitten](https://github.com/kitten))
- [iOS] Force codegen for `FBReactNativeSpec` when generated files are missing in React Native source ([#39512](https://github.com/expo/expo/pull/39512) by [@kitten](https://github.com/kitten))
## 3.0.8 — 2025-09-08
### 🐛 Bug fixes
- [Android] Fix `platformOptions` not being correctly assigned. ([#39445](https://github.com/expo/expo/pull/39445) by [@alanjhughes](https://github.com/alanjhughes))
## 3.0.7 — 2025-09-04
_This version does not introduce any user-facing changes._
## 3.0.6 — 2025-09-02
_This version does not introduce any user-facing changes._
## 3.0.5 — 2025-08-31
_This version does not introduce any user-facing changes._
## 3.0.4 — 2025-08-26
_This version does not introduce any user-facing changes._
## 3.0.3 — 2025-08-21
_This version does not introduce any user-facing changes._
## 3.0.2 — 2025-08-16
### 🐛 Bug fixes
- Regression: Use the command's root instead of the app's root when resolving extra build dependencies ([#38907](https://github.com/expo/expo/pull/38907) by [@kitten](https://github.com/kitten))
- [Android] Update resolveAppProjectConfigAsync to use sourceDir ([#39125](https://github.com/expo/expo/pull/39125) by [@gabrieldonadel](https://github.com/gabrieldonadel))
### 💡 Others
- Refactor command implementations and deprecate old Expo modules autolinking API ([#38907](https://github.com/expo/expo/pull/38907) by [@kitten](https://github.com/kitten))
- Add internal API to scan only for Expo modules ([#38909](https://github.com/expo/expo/pull/38909) by [@kitten](https://github.com/kitten))
- Expose `getLinkingImplementationForPlatform` and `PackageRevision` for Expo modules from internal autolinking API ([#38913](https://github.com/expo/expo/pull/38913) by [@kitten](https://github.com/kitten))
## 3.0.1 — 2025-08-15
_This version does not introduce any user-facing changes._
## 3.0.0 — 2025-08-13
### 🛠 Breaking changes
- Reimplement Turbo Modules and Expo Modules discovery algorithm. Native modules are now discovered according to Node resolution by default, which can be overridden to the old behaviour by specifying `searchPaths` manually. The default behaviour will recursively resolve Node `dependencies` and `peerDependencies` ([#38282](https://github.com/expo/expo/pull/38282) by [@kitten](https://github.com/kitten))
- Update `verify` command to check React Native modules as well, change `--json` output format, and accept `--verbose` option ([#38766](https://github.com/expo/expo/pull/38766) by [@kitten](https://github.com/kitten))
### 🎉 New features
- Add `--source-dir` option ([#38218](https://github.com/expo/expo/pull/38218) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- [iOS] Add `:projectRoot` option to `use_expo_modules!` ([#38210](https://github.com/expo/expo/pull/38210) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- [Android] Support auto-linking C++-only Turbo Modules on Android (as per `@react-native-community/cli-platform-android` changes) ([#38626](https://github.com/expo/expo/pull/38626) by [@kitten](https://github.com/kitten))
- Respect `expo.autolinking.exclude` option for React Native modules as well ([#38635](https://github.com/expo/expo/pull/38635) by [@kitten](https://github.com/kitten))
- Add `expo.autolinking.legacy_shallowReactNativeLinking` option to restore legacy behavior that doesn't autolink transitive React Native modules ([#38635](https://github.com/expo/expo/pull/38635) by [@kitten](https://github.com/kitten))
### 🐛 Bug fixes
- [Android] Improved erorr message when we don't support Kotlin version provided by the user. ([#37802](https://github.com/expo/expo/pull/37802) by [@lukmccall](https://github.com/lukmccall))
- Prevent Expo Modules from being detected as C++-only React Native modules ([#38658](https://github.com/expo/expo/pull/38658) by [@kitten](https://github.com/kitten))
- Ignore optional peer dependencies in dependency traversal ([#38713](https://github.com/expo/expo/pull/38713) by [@kitten](https://github.com/kitten))
### 💡 Others
- [iOS] Add support for user script sandboxing ([#38206](https://github.com/expo/expo/pull/38206) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- Refactor JSON loading in `findModules` algorithm path to use plain `fs`. ([#38202](https://github.com/expo/expo/pull/38202) by [@kitten](https://github.com/kitten))
- Add internal API for dual autolinking dependency resolution ([#38680](https://github.com/expo/expo/pull/38680) by [@kitten](https://github.com/kitten))
## 2.1.14 - 2025-07-07
### 🐛 Bug fixes
- Fixed breaking change for local AAR autolinking. ([#37882](https://github.com/expo/expo/pull/37882) by [@kudo](https://github.com/kudo))
- [Android] Fixed local aar files is not being linked correctly. ([#37280](https://github.com/expo/expo/pull/37280) by [@lukmccall](https://github.com/lukmccall))
## 2.1.13 - 2025-07-01
### 💡 Others
- Added `System.getenv()` syntax support to credentials for extraMavenRepos. ([#37343](https://github.com/expo/expo/pull/37343) by [@kudo](https://github.com/kudo))
## 2.1.12 - 2025-06-18
### 🐛 Bug fixes
- Fix updates native debug for iOS. ([#37323](https://github.com/expo/expo/pull/37323) by [@douglowder](https://github.com/douglowder))
## 2.1.11 - 2025-06-08
### 💡 Others
- Remove "Please" from warnings and errors ([#36862](https://github.com/expo/expo/pull/36862) by [@brentvatne](https://github.com/brentvatne))
- Added `--transitive-linking-dependencies` option to support react-native-edge-to-edge autolinking in CNG projects. ([#37194](https://github.com/expo/expo/pull/37194) by [@kudo](https://github.com/kudo))
## 2.1.10 — 2025-05-06
### 🐛 Bug fixes
- [Android] Fixed project properties were not being resolved correctly. ([#36666](https://github.com/expo/expo/pull/36666) by [@lukmccall](https://github.com/lukmccall))
## 2.1.9 — 2025-04-30
_This version does not introduce any user-facing changes._
## 2.1.8 — 2025-04-28
### 🐛 Bug fixes
- Fixed `react-native-config` linked result order. ([#36442](https://github.com/expo/expo/pull/36442) by [@kudo](https://github.com/kudo))
## 2.1.7 — 2025-04-25
_This version does not introduce any user-facing changes._
## 2.1.6 — 2025-04-23
_This version does not introduce any user-facing changes._
## 2.1.5 — 2025-04-21
### 🎉 New features
- Removed restriction preventing local expo modules from being excluded from autolinking. ([#36117](https://github.com/expo/expo/pull/36117) by [@wuguishifu](https://github.com/wuguishifu))
### 🐛 Bug fixes
- Fixed Android building error on Windows. ([#36179](https://github.com/expo/expo/pull/36179) by [@kudo](https://github.com/kudo))
## 2.1.4 — 2025-04-14
_This version does not introduce any user-facing changes._
## 2.1.3 — 2025-04-11
### 🎉 New features
- [Android] Support `android.enableEdgeToEdge` field in app config. ([#35958](https://github.com/expo/expo/pull/35958) by [@behenate](https://github.com/behenate))
## 2.1.2 — 2025-04-09
_This version does not introduce any user-facing changes._
## 2.1.1 — 2025-04-08
### 🐛 Bug fixes
- Fixed E2E test timeout. ([#35953](https://github.com/expo/expo/pull/35953) by [@kudo](https://github.com/kudo))
## 2.1.0 — 2025-04-04
### 🛠 Breaking changes
- Refactored how declaring multiple Android projects works. ([#35138](https://github.com/expo/expo/pull/35138) by [@lukmccall](https://github.com/lukmccall))
### 🎉 New features
- Added `coreFeatures` field. ([#34015](https://github.com/expo/expo/pull/34015) by [@lukmccall](https://github.com/lukmccall))
- Add macOS support. ([#35065](https://github.com/expo/expo/pull/35065) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- [Android] Added `expoAutolinking.useExpoVersionCatalog` and `expoAutolinking.reactNativeGradlePlugin`. ([#35789](https://github.com/expo/expo/pull/35789) by [@lukmccall](https://github.com/lukmccall))
### 💡 Others
- [Android] Introduced the Gradle plugin to improve the autolinking setup. ([#33402](https://github.com/expo/expo/pull/33402) by [@lukmccall](https://github.com/lukmccall))
- Drop `fs-extra` in favor of `fs`. ([#35036](https://github.com/expo/expo/pull/35036) by [@kitten](https://github.com/kitten))
- Drop `fast-glob` in favor of `glob`. ([#35082](https://github.com/expo/expo/pull/35082) by [@kitten](https://github.com/kitten))
- [Android] Added `publication` configuration. ([#35068](https://github.com/expo/expo/pull/35068) by [@lukmccall](https://github.com/lukmccall))
- Removed legacy `modulesClassNames` field. ([#35095](https://github.com/expo/expo/pull/35095) by [@lukmccall](https://github.com/lukmccall))
- [Android] Add a special case for autolinking `react-native-edge-to-edge` ([#35812](https://github.com/expo/expo/pull/35812) by [@behenate](https://github.com/behenate))
## 2.0.8 - 2025-02-19
_This version does not introduce any user-facing changes._
## 2.0.7 - 2025-01-20
_This version does not introduce any user-facing changes._
## 2.0.6 - 2025-01-19
### 🐛 Bug fixes
- Added Android `BaseReactPackage` for autolinking. ([#33773](https://github.com/expo/expo/pull/33773) by [@vonovak](https://github.com/vonovak))
- Resolve `reactNativePath` to its realpath to prevent incorrect relative paths from being generated for isolated dependencies. ([#34203](https://github.com/expo/expo/pull/34203) by [@kitten](https://github.com/kitten))
## 2.0.5 - 2025-01-10
_This version does not introduce any user-facing changes._
## 2.0.4 - 2024-12-10
### 🐛 Bug fixes
- Fix incorrect `__dirname` in `react-native-config.(js|ts)` ([#33532](https://github.com/expo/expo/pull/33532) by [@satya164](https://github.com/satya164))
### 💡 Others
- Added library `android.sourceDir` support for react-native-config. ([#33473](https://github.com/expo/expo/pull/33473) by [@kudo](https://github.com/kudo))
## 2.0.3 - 2024-12-02
_This version does not introduce any user-facing changes._
## 2.0.2 — 2024-11-13
### 🐛 Bug fixes
- Fixed autolinking when `react-native-config` doesn't specify local dependencies. ([#32841](https://github.com/expo/expo/pull/32841) by [@thespacemanatee](https://github.com/thespacemanatee))
## 2.0.1 — 2024-11-13
### 💡 Others
- Added local project dependencies support to `react-native-config` autolinking. ([#32821](https://github.com/expo/expo/pull/32821) by [@kudo](https://github.com/kudo))
## 2.0.0 — 2024-11-11
_This version does not introduce any user-facing changes._
## 2.0.0-preview.3 — 2024-11-04
### 🐛 Bug fixes
- Fix issue when no dependencies in a package. ([#32547](https://github.com/expo/expo/pull/32547) by [@douglowder](https://github.com/douglowder))
## 2.0.0-preview.2 — 2024-10-28
### 🐛 Bug fixes
- Fixed react-native core autolinking for react-native-unistyles on Android. ([#32375](https://github.com/expo/expo/pull/32375) by [@kudo](https://github.com/kudo))
## 2.0.0-preview.1 — 2024-10-25
### 🐛 Bug fixes
- Fixed build error from `gradleAarProjects`. ([#32349](https://github.com/expo/expo/pull/32349) by [@kudo](https://github.com/kudo))
## 2.0.0-preview.0 — 2024-10-22
### 🛠 Breaking changes
- Removed the deprecated `generate-package-list` command for Apple platforms. ([#31518](https://github.com/expo/expo/pull/31518) by [@kudo](https://github.com/kudo))
### 🎉 New features
- Added AAR files autolinking as Gradle projects. ([#30706](https://github.com/expo/expo/pull/30706) by [@kudo](https://github.com/kudo))
- Add support for react-native 0.76 ([#31593](https://github.com/expo/expo/pull/31593) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- Added Apple code sign entitlements to generated `ExpoModulesProvider.swift`. ([#31518](https://github.com/expo/expo/pull/31518) by [@kudo](https://github.com/kudo))
- Added `searchPaths` support to the `react-native-config`. ([#32153](https://github.com/expo/expo/pull/32153) by [@kudo](https://github.com/kudo))
### 🐛 Bug fixes
- [Android] Fixed autolinking of Maven AWS S3 repository. ([#30204](https://github.com/expo/expo/pull/30204) by [@ElielC](https://github.com/ElielC))
- [Android] Fixed autolinking when using Gradle Kotlin script. ([#30448](https://github.com/expo/expo/pull/30448) by [@amrfarid140](https://github.com/amrfarid140))
- Fixed core autolinking for react-native-maps. ([#31190](https://github.com/expo/expo/pull/31190) by [@kudo](https://github.com/kudo))
- Fixed broken `searchPaths` from package.json. ([#31196](https://github.com/expo/expo/pull/31196) by [@kudo](https://github.com/kudo))
- Fixed `react-native-config` error when running on CNG projects without Android native files. ([#31637](https://github.com/expo/expo/pull/31637) by [@kudo](https://github.com/kudo))
- Fixed `react-native-config` can't resolve version of the `@react-native-community/cli-platform-android`. ([#32205](https://github.com/expo/expo/pull/32205) by [@lukmccall](https://github.com/lukmccall))
### 💡 Others
- Removed `expo_patch_react_imports!` and align more stardard react-native project layout. ([#31699](https://github.com/expo/expo/pull/31699) by [@kudo](https://github.com/kudo))
- Exported a new `findProjectRootSync` API. ([#31966](https://github.com/expo/expo/pull/31966) by [@kudo](https://github.com/kudo))
## 1.11.2 - 2024-08-14
### 🎉 New features
- Added `react-native-config` command to support core autolinking for react-native. ([#29818](https://github.com/expo/expo/pull/29818) by [@kudo](https://github.com/kudo))
### 🐛 Bug fixes
- Added missing `project.android.packageName` in react-native-config for Android core autolinking. ([#30913](https://github.com/expo/expo/pull/30913) by [@kudo](https://github.com/kudo))
## 1.11.1 — 2024-04-23
_This version does not introduce any user-facing changes._
## 1.11.0 — 2024-04-18
### 🎉 New features
- Expand Android auto-linking to support new expo-build-properties ([#26895](https://github.com/expo/expo/pull/26895) by [@bpeltonc](https://github.com/bpeltonc))
### 🐛 Bug fixes
- Support custom debug build configuration for debugOnly pods (expo-dev-client for example) ([#28085](https://github.com/expo/expo/pull/28085) by [@Titozzz](https://github.com/Titozzz))
### 💡 Others
- Read `extraPods` from **Podfile.properties.json** and `extraMavenRepos` from **gradle.properties**. ([#28106](https://github.com/expo/expo/pull/28106) by [@kudo](https://github.com/kudo))
## 1.10.3 - 2024-02-06
### 🐛 Bug fixes
- Fixed generating a list of app delegate subscribers. ([#26851](https://github.com/expo/expo/pull/26851) by [@tsapeta](https://github.com/tsapeta))
## 1.10.2 - 2024-01-18
### 🐛 Bug fixes
- Fixed a list of packages to include in the generated modules provider for tvOS and macOS platforms. ([#26497](https://github.com/expo/expo/pull/26497) by [@tsapeta](https://github.com/tsapeta))
## 1.10.1 - 2024-01-18
### 🎉 New features
- Introduced a universal `"apple"` platform as a replacement for `"ios"`, `"macos"` and `"tvos"`. ([#26398](https://github.com/expo/expo/pull/26398) by [@tsapeta](https://github.com/tsapeta))
## 1.10.0 - 2024-01-10
### 🎉 New features
- Added support for macOS and tvOS targets. ([#26287](https://github.com/expo/expo/pull/26287) by [@tsapeta](https://github.com/tsapeta))
## 1.9.0 — 2023-12-12
### 🐛 Bug fixes
- [iOS] Resolve `expo-modules-autolinking` from `expo` in the generated project integrator. ([#25817](https://github.com/expo/expo/pull/25817) by [@byCedric](https://github.com/byCedric))
## 1.8.0 — 2023-11-14
### 🎉 New features
- Added Expo CLI devtools plugins support. ([#24649](https://github.com/expo/expo/pull/24649) by [@kudo](https://github.com/kudo))
## 1.7.0 — 2023-10-17
### 💡 Others
- Transpile for Node 18 (LTS). ([#24471](https://github.com/expo/expo/pull/24471) by [@EvanBacon](https://github.com/EvanBacon))
## 1.6.0 — 2023-09-15
### 🐛 Bug fixes
- Maintain hierarchical order when linking isolated modules ([#24351](https://github.com/expo/expo/pull/24351) by [@byCedric](https://github.com/byCedric))
### 💡 Others
- [iOS] Disable packager and bundle JS when EX_UPDATES_NATIVE_DEBUG set. ([#24366](https://github.com/expo/expo/pull/24366) by [@douglowder](https://github.com/douglowder))
## 1.5.2 — 2023-09-04
### 🐛 Bug fixes
- Add support for pnpm isolated modules ([#23867](https://github.com/expo/expo/pull/23867) by [@byCedric](https://github.com/byCedric))
- Resolve cli for isolated modules before running node scripts. ([#23926](https://github.com/expo/expo/pull/23926) by [@byCedric](https://github.com/byCedric))
### 💡 Others
- [Android] Made `generateExpoModulesPackageList` task cacheable. ([#23847](https://github.com/expo/expo/pull/23847) by [@lukmccall](https://github.com/lukmccall))
## 1.5.1 - 2023-08-22
### 🐛 Bug fixes
- Fixed `expo_patch_react_imports!` missing some lines with spaces before or after the imports. ([#23923](https://github.com/expo/expo/pull/23923) by [@liamjones](https://github.com/liamjones))
## 1.5.0 — 2023-06-21
### 🎉 New features
- Added support for React Native 0.72. ([#22588](https://github.com/expo/expo/pull/22588) by [@kudo](https://github.com/kudo))
- Added extra CocoaPods dependencies and Maven repositories from `expo-build-properties`. ([#22785](https://github.com/expo/expo/pull/22785) by [@kudo](https://github.com/kudo))
## 1.4.0 — 2023-06-13
### 🎉 New features
- Added support for React Native 0.72. ([#22588](https://github.com/expo/expo/pull/22588) by [@kudo](https://github.com/kudo))
## 1.3.0 — 2023-05-08
### 🎉 New features
- Generating `ExpoModulesProvider.swift` in the build phase script instead of only `pod install`. ([#21108](https://github.com/expo/expo/pull/21108) by [@tsapeta](https://github.com/tsapeta))
## 1.2.0 - 2023-04-13
### 🎉 New features
- Added Gradle plugin autolinking support for Android. ([#21377](https://github.com/expo/expo/pull/21377) by [@kudo](https://github.com/kudo))
## 1.1.2 — 2023-02-14
### 💡 Others
- Suppress node warnings about deprecated exports mapping in 3rd-party dependencies. ([#21222](https://github.com/expo/expo/pull/21222) by [@tsapeta](https://github.com/tsapeta))
## 1.1.1 — 2023-02-09
_This version does not introduce any user-facing changes._
## 1.1.0 — 2023-02-03
_This version does not introduce any user-facing changes._
## 1.0.2 — 2023-01-10
### 🐛 Bug fixes
- Replace deprecated `File.exists?` with `File.exist?` to fix usage with `ruby@3.2`. ([#20470](https://github.com/expo/expo/pull/20757) by [@KiwiKilian](https://github.com/kiwikilian))
## 1.0.1 — 2022-12-30
### 🐛 Bug fixes
- Added React Native 0.71 support. ([#20470](https://github.com/expo/expo/pull/20470) by [@kudo](https://github.com/kudo))
## 1.0.0 — 2022-11-03
_This version does not introduce any user-facing changes._
## 0.12.0 — 2022-10-25
### 🎉 New features
- Automatically use modular headers for pod dependencies when the package has Swift modules to link. ([#19443](https://github.com/expo/expo/pull/19443) by [@tsapeta](https://github.com/tsapeta))
### 💡 Others
- Bump `@tsconfig/node` to match other Expo Modules packages development setup. ([#19671](https://github.com/expo/expo/pull/19671) by [@Simek](https://github.com/Simek))
## 0.11.0 — 2022-10-06
### 🎉 New features
- Added `includeTests` option to `use_expo_modules!` to include test specs from autolinked modules. ([#18496](https://github.com/expo/expo/pull/18496) by [@tsapeta](https://github.com/tsapeta))
### 🐛 Bug fixes
- Fixed node executable resolution errors on iOS when `pod install` is executed from package.json `scripts`. ([#18580](https://github.com/expo/expo/pull/18580) by [@kudo](https://github.com/kudo))
## 0.10.1 — 2022-07-25
### 🎉 New features
- Added a feature to automatically generate `.xcode.env.local` with correct `$NODE_BINARY` path when running `pod install`. ([#18330](https://github.com/expo/expo/pull/18330) by [@kudo](https://github.com/kudo))
## 0.10.0 — 2022-07-07
### 🐛 Bug fixes
- Added support for React Native 0.69.x ([#17629](https://github.com/expo/expo/pull/17629) by [@kudo](https://github.com/kudo))
- Use regex to match ignored modules in `expo_patch_react_imports!` and fix iOS build errors when the project is inside `react-native` named folder. ([#17968](https://github.com/expo/expo/pull/17968) by [@dmnkgrc](https://github.com/dmnkgrc))
## 0.9.0 — 2022-06-23
### 🎉 New features
- The `searchPaths` and `nativeModulesDir` options now support direct paths to specific module directories. ([#17922](https://github.com/expo/expo/pull/17922) by [@barthap](https://github.com/barthap))
## 0.8.1 — 2022-05-12
### 🐛 Bug fixes
- Fixed an infinite loop when the **package.json** is placed at the root path. ([#17440](https://github.com/expo/expo/pull/17440) by [@tsapeta](https://github.com/tsapeta))
## 0.8.0 — 2022-05-06
### 🎉 New features
- Add `ios.debugOnly` to module config. ([#17331](https://github.com/expo/expo/pull/17331) by [@lukmccall](https://github.com/lukmccall))
- Setting `EXPO_CONFIGURATION_DEBUG` or `EXPO_CONFIGURATION_RELEASE` Swift flags on project targets. ([#17378](https://github.com/expo/expo/pull/17378) by [@tsapeta](https://github.com/tsapeta))
### 🐛 Bug fixes
- Fix debug-only modules weren't installed if the `DEBUG` flag wasn't present in `OTHER_SWIFT_FLAGS`. ([#17383](https://github.com/expo/expo/pull/17383) by [@lukmccall](https://github.com/lukmccall))
- Fix iOS build if project config name is other than RELEASE or DEBUG ([#17439](https://github.com/expo/expo/pull/17439) by [@uloco](https://github.com/uloco))
### 💡 Others
## 0.7.0 — 2022-04-18
- Update require logic to find transitive deps that would not be hoisted at the top of the monorepo ([#16419](https://github.com/expo/expo/pull/16419) by [@Titozzz](https://github.com/Titozzz))
- Fix `cannot cast object 'ExpoAutolinkingManager@' with class 'ExpoAutolinkingManager' to class 'ExpoAutolinkingManager'` on Android when a project is using `buildSrc`. ([#16545](https://github.com/expo/expo/pull/16545) by [@lukmccall](https://github.com/lukmccall))
### 🎉 New features
- Add `ios.swiftModuleName` to module config. ([#16260](https://github.com/expo/expo/pull/16260) by [@esamelson](https://github.com/esamelson))
- Added support for linking multiple podspecs and Gradle projects in a package. ([#16511](https://github.com/expo/expo/pull/16511) by [@kudo](https://github.com/kudo))
### 🐛 Bug fixes
- Fixed `expo_patch_react_imports!` not work when the app project is in a folder with spaces. ([#16794](https://github.com/expo/expo/pull/16794) by [@Kudo](https://github.com/Kudo))
## 0.6.0 — 2022-01-26
### ⚠️ Notices
- Expose `findModulesAsync` from `expo-modules-autolinking/build/autolinking` again. ([#15950](https://github.com/expo/expo/pull/15950) by [@EvanBacon](https://github.com/EvanBacon))
- Deprecated `modulesClassNames` in favor of `modules` in the Expo module config. ([#15852](https://github.com/expo/expo/pull/15852) by [@tsapeta](https://github.com/tsapeta))
## 0.5.5 — 2022-01-05
### 🐛 Bug fixes
- Fix `umbrella directory '../../Public/React-Core/React' not found` build error when in `use_frameworks!` mode. ([#15773](https://github.com/expo/expo/pull/15773) by [@kudo](https://github.com/kudo))
## 0.5.4 — 2021-12-29
### 🐛 Bug fixes
- Add `expo_patch_react_imports!` support for React-Native 0.66. ([#15724](https://github.com/expo/expo/pull/15724) by [@kudo](https://github.com/kudo))
## 0.5.3 — 2021-12-28
### 🐛 Bug fixes
- Fix `expo_patch_react_imports!` error when there are pods with absolute path. ([#15699](https://github.com/expo/expo/pull/15699) by [@kudo](https://github.com/kudo))
## 0.5.2 — 2021-12-22
### 🐛 Bug fixes
- Introduce `expo_patch_react_imports!` to transform double-quoted React imports into angle-brackets in order to fix third-party libraries incompatibility with SDK 44. ([#15655](https://github.com/expo/expo/pull/15655) by [@kudo](https://github.com/kudo))
## 0.5.1 — 2021-12-15
_This version does not introduce any user-facing changes._
## 0.5.0 — 2021-12-03
### 🎉 New features
- Patch React podspecs on the fly to support Swift integration. ([#15299](https://github.com/expo/expo/pull/15299) by [@kudo](https://github.com/kudo))
- Add `nativeModulesDir` option to specify app's custom native modules location. ([#15415](https://github.com/expo/expo/pull/15415) by [@barthap](https://github.com/barthap))
## 0.4.0 — 2021-11-17
### 🎉 New features
- Added "silent" property for silencing resolution warnings. ([#14891](https://github.com/expo/expo/pull/14891) by [@EvanBacon](https://github.com/EvanBacon))
- Listing module's app delegate subscribers in the generated `ExpoModulesProvider.swift`. ([#14867](https://github.com/expo/expo/pull/14867) by [@tsapeta](https://github.com/tsapeta))
- Search for Android package in the entire source code other than just `src` directory. ([#14883](https://github.com/expo/expo/pull/14883) by [@kudo](https://github.com/kudo))
- Introduce React Native bridge delegate handlers on iOS. ([#15138](https://github.com/expo/expo/pull/15138) by [@kudo](https://github.com/kudo))
### 🐛 Bug fixes
- Fix Gradle error when running Gradle from outside of the project directory. ([#15109](https://github.com/expo/expo/pull/15109) by [@kudo](https://github.com/kudo))
## 0.3.3 — 2021-10-21
### 🐛 Bug fixes
- Resolved race condition when generating `ExpoModulesProvider.swift`. ([#14822](https://github.com/expo/expo/pull/14822) by [@awinograd](https://github.com/awinograd))
+32
View File
@@ -0,0 +1,32 @@
<p>
<a href="https://docs.expo.dev/modules/autolinking/">
<img
src="../../.github/resources/expo-modules-autolinking.svg"
alt="expo-modules-autolinking"
height="64" />
</a>
</p>
Scripts that autolink Expo modules.
# API documentation
- [Documentation for the latest stable release](https://docs.expo.dev/modules/autolinking/)
# Installation in managed Expo projects
For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects &mdash; it is likely to be included in an upcoming Expo SDK release.
# Installation in bare React Native projects
For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
### Add the package to your npm dependencies
```
npm install expo-modules-autolinking
```
# Contributing
Contributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).
@@ -0,0 +1,26 @@
# expo-modules-plugin
This project contains two Gradle plugins that are used to inject the necessary dependencies and configurations into an Android project that uses Expo modules. It also provides a shared project that contains common code for both plugins.
### `expo-autolinking-settings-plugin`
The settings plugin is an entry point for our setup. It should be applied to the root `settings.gradle` file of the application.
Responsibilities:
- Add all modules into the project hierarchy; modules won't be added to the dependency graph. The `expo` package will depend on them rather than adding them directly to the app project.
- Add extra Maven repositories.
- Link and apply custom plugins.
- Expose autolinking configuration.
### `expo-autolinking-plugin`
This plugin shouldn't be applied directly by the end user. It'll be applied by the `expo` package.
Responsibilities:
- Ensure the dependencies are evaluated before the `expo` package.
- Add previously linked modules to the dependency graph.
- Create a task that will generate the package list file.
### `shared`
This project contains common code for both plugins.
@@ -0,0 +1,4 @@
plugins {
kotlin("jvm") version "2.1.20" apply false
id("java-gradle-plugin")
}
@@ -0,0 +1,41 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
kotlin("plugin.serialization") version "1.9.24"
}
repositories {
mavenCentral()
}
dependencies {
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
testImplementation("junit:junit:4.13.2")
testImplementation("com.google.truth:truth:1.1.2")
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
}
group = "expo.modules"
version = "1.0"
tasks.withType<Test>().configureEach {
testLogging {
exceptionFormat = TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
}
}
@@ -0,0 +1,83 @@
package expo.modules.plugin
/**
* Builder for creating command to run using `expo-modules-autolinking`.
*/
class AutolinkingCommandBuilder {
/**
* Command for finding and running `expo-modules-autolinking`.
*/
private val baseCommand = listOf(
"node",
"--no-warnings",
"--eval",
"require('expo/bin/autolinking')",
"expo-modules-autolinking"
)
private val platform = listOf(
"--platform",
"android"
)
private var autolinkingCommand = emptyList<String>()
private var useJson = emptyList<String>()
private val optionsMap = mutableMapOf<String, String>()
private var searchPaths = emptyList<String>()
/**
* Set the autolinking command to run.
*/
fun command(command: String) = apply {
autolinkingCommand = listOf(command)
}
/**
* Add an option to the command.
*/
fun option(key: String, value: String) = apply {
optionsMap[key] = value
}
/**
* Add a list of values as an option to the command.
*/
fun option(key: String, value: List<String>) = apply {
optionsMap[key] = value.joinToString(" ")
}
/**
* Whether it should output json.
*/
fun useJson() = apply {
useJson = listOf("--json")
}
/**
* Set the search paths for the autolinking script.
*/
fun searchPaths(paths: List<String>) = apply {
searchPaths = paths
}
fun useAutolinkingOptions(autolinkingOptions: AutolinkingOptions) = apply {
autolinkingOptions.ignorePaths?.let { option(IGNORE_PATHS_KEY, it) }
autolinkingOptions.exclude?.let { option(EXCLUDE_KEY, it) }
autolinkingOptions.searchPaths?.let { searchPaths(it) }
}
fun build(): List<String> {
val command = baseCommand +
autolinkingCommand +
platform +
useJson +
optionsMap.map { (key, value) -> listOf("--$key", value) }.flatMap { it } +
searchPaths
return Os.windowsAwareCommandLine(command)
}
companion object {
const val IGNORE_PATHS_KEY = "ignore-paths"
const val EXCLUDE_KEY = "exclude"
}
}
@@ -0,0 +1,43 @@
package expo.modules.plugin
import expo.modules.plugin.configuration.ExpoAutolinkingConfig
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.security.MessageDigest
@Serializable
data class AutolinkingOptions(
val searchPaths: List<String>? = null,
val ignorePaths: List<String>? = null,
val exclude: List<String>? = null
) {
fun toJson(): String {
return Json.encodeToString(AutolinkingOptions.serializer(), this)
}
companion object {
fun fromJson(jsonString: String): AutolinkingOptions {
return Json.decodeFromString(jsonString)
}
}
}
/**
* Extension that will be added to Gradle, making it possible to access the configuration in all projects.
*/
open class ExpoGradleExtension(
val config: ExpoAutolinkingConfig,
val options: AutolinkingOptions = AutolinkingOptions(),
val projectRoot: java.io.File,
) {
/**
* MD5 hash of the configuration.
* It can be used to determine if the configuration has changed.
*/
val hash: String
get() {
val stringifyConfig = config.toString()
val md = MessageDigest.getInstance("MD5")
return md.digest(stringifyConfig.toByteArray()).contentToString()
}
}
@@ -0,0 +1,13 @@
package expo.modules.plugin
object Os {
fun isWindows(): Boolean =
System.getProperty("os.name")?.lowercase()?.contains("windows") == true
fun windowsAwareCommandLine(args: List<String>): List<String> =
if (isWindows()) {
listOf("cmd", "/c") + args
} else {
args
}
}
@@ -0,0 +1,140 @@
package expo.modules.plugin.configuration
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
@Serializable
data class ExpoAutolinkingConfig(
val modules: List<ExpoModule> = emptyList(),
val extraDependencies: List<MavenRepo> = emptyList(),
val coreFeatures: List<String> = emptyList(),
val configuration: Configuration = Configuration()
) {
/**
* Returns all gradle projects from all modules.
*/
val allProjects: List<GradleProject>
get() = modules.flatMap { it.projects }
/**
* Returns all plugins from all modules.
*/
val allPlugins: List<GradlePlugin>
get() = modules.flatMap { it.plugins }
/**
* Returns all AAR projects from all modules.
*/
val allAarProjects: List<GradleAarProject>
get() = modules.flatMap { it.projects }.flatMap { it.aarProjects }
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
companion object {
private val jsonDecoder by lazy {
val module = SerializersModule {
polymorphicDefaultDeserializer(MavenCredentials::class) { MavenCredentialsSerializer }
}
Json {
// We don't want to fail on a unknown key
ignoreUnknownKeys = true
serializersModule = module
}
}
/**
* Decodes the `ExpoAutolinkingConfig` from given string.
*/
fun decodeFromString(input: String): ExpoAutolinkingConfig {
return jsonDecoder.decodeFromString(input)
}
}
}
@Serializable
data class Configuration(
val buildFromSource: List<String> = emptyList<String>()
) {
val buildFromSourceRegex by lazy {
buildFromSource.map { it.toRegex() }
}
}
/**
* Object representing a maven repository
*/
@Serializable
data class MavenRepo(
val url: String,
val credentials: MavenCredentials? = null,
val authentication: String? = null
)
/**
* Object representing a module.
*/
@Serializable
data class ExpoModule(
val packageName: String,
val packageVersion: String,
val projects: List<GradleProject> = emptyList(),
val plugins: List<GradlePlugin> = emptyList(),
)
@Serializable
data class Publication(
val groupId: String,
val artifactId: String,
val version: String,
val repository: String
)
/**
* Object representing a gradle project.
*/
@Serializable
data class GradleProject(
val name: String,
val sourceDir: String,
val publication: Publication? = null,
val aarProjects: List<GradleAarProject> = emptyList(),
val modules: List<String> = emptyList(),
val shouldUsePublicationScriptPath: String? = null,
@Transient val configuration: GradleProjectConfiguration = GradleProjectConfiguration()
) {
/**
* Returns whether the publication was defined and should be used.
*/
val usePublication: Boolean
get() = publication != null && configuration.shouldUsePublication
}
data class GradleProjectConfiguration(
var shouldUsePublication: Boolean = false
)
/**
* Object representing a gradle plugin
*/
@Serializable
data class GradlePlugin(
val id: String,
val group: String,
val sourceDir: String,
val applyToRootProject: Boolean = true
)
/**
* Object representing an gradle project containing AAR file
*/
@Serializable
data class GradleAarProject(
val name: String,
val aarFilePath: String,
val projectDir: String
)
@@ -0,0 +1,44 @@
package expo.modules.plugin.configuration
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonContentPolymorphicSerializer
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.jsonObject
/**
* Based type of maven credentials object.
*/
sealed interface MavenCredentials
@Serializable
data class BasicMavenCredentials(
val username: String,
val password: String
) : MavenCredentials
@Serializable
data class HttpHeaderMavenCredentials(
val name: String,
val value: String
) : MavenCredentials
@Serializable
data class AWSMavenCredentials(
val accessKey: String,
val secretKey: String,
val sessionToken: String? = null
) : MavenCredentials
/**
* Custom deserializer for [MavenCredentials].
* We need to use polymorphic deserialization because we have multiple types of credentials.
* It'll decide based on present fields which type of credentials it is.
*/
object MavenCredentialsSerializer : JsonContentPolymorphicSerializer<MavenCredentials>(MavenCredentials::class) {
override fun selectDeserializer(element: JsonElement) = when {
"username" in element.jsonObject && "password" in element.jsonObject -> BasicMavenCredentials.serializer()
"name" in element.jsonObject && "value" in element.jsonObject -> HttpHeaderMavenCredentials.serializer()
"accessKey" in element.jsonObject && "secretKey" in element.jsonObject -> AWSMavenCredentials.serializer()
else -> throw IllegalStateException("Unknown MavenCredentials type for $element")
}
}
@@ -0,0 +1,11 @@
package expo.modules.plugin.text
object Colors {
const val GREEN = "\u001B[32m"
const val YELLOW = "\u001B[33m"
const val RESET = "\u001B[0m"
}
fun Any?.withColor(color: String): String {
return "$color$this${Colors.RESET}"
}
@@ -0,0 +1,5 @@
package expo.modules.plugin.text
object Emojis {
const val INFORMATION = "\u2139\uFE0F"
}
@@ -0,0 +1,147 @@
package com.modules.plugin.connfiguration
import com.google.common.truth.Truth
import expo.modules.plugin.configuration.AWSMavenCredentials
import expo.modules.plugin.configuration.BasicMavenCredentials
import expo.modules.plugin.configuration.ExpoAutolinkingConfig
import expo.modules.plugin.configuration.HttpHeaderMavenCredentials
import org.junit.Test
class ExpoAutolinkingConfigTest {
@Test
fun `can deserialize config`() {
// language=JSON
val mockedConfig = """
{
"extraDependencies": [],
"modules": [
{
"packageName": "expo",
"packageVersion": "52.0.11",
"projects": [
{
"name": "expo",
"sourceDir": "/Users/lukasz/work/expo/packages/expo/android"
}
],
"modules": [
"expo.modules.fetch.ExpoFetchModule"
]
},
{
"packageName": "expo-network-addons",
"packageVersion": "0.7.0",
"projects": [
{
"name": "expo-network-addons",
"sourceDir": "/Users/lukasz/work/expo/packages/expo-network-addons/android"
}
],
"plugins": [
{
"id": "expo-network-addons-gradle-plugin",
"group": "expo.modules",
"sourceDir": "/Users/lukasz/work/expo/packages/expo-network-addons/expo-network-addons-gradle-plugin",
"applyToRootProject": true
}
],
"modules": []
}
]
}
""".trimIndent()
val config = ExpoAutolinkingConfig.decodeFromString(mockedConfig)
Truth.assertThat(config.allProjects.map { it.name })
.containsExactly("expo", "expo-network-addons")
val expoModule = config.modules.find { it.packageName == "expo" }
val expoNetworkAddonsModule = config.modules.find { it.packageName == "expo-network-addons" }
Truth.assertThat(expoModule).isNotNull()
Truth.assertThat(expoNetworkAddonsModule).isNotNull()
expoModule!!
expoNetworkAddonsModule!!
Truth.assertThat(expoModule.projects.firstOrNull()?.sourceDir)
.isEqualTo("/Users/lukasz/work/expo/packages/expo/android")
Truth.assertThat(expoModule.modules.firstOrNull())
.isEqualTo("expo.modules.fetch.ExpoFetchModule")
Truth.assertThat(expoNetworkAddonsModule.projects.firstOrNull()?.sourceDir)
.isEqualTo("/Users/lukasz/work/expo/packages/expo-network-addons/android")
Truth.assertThat(expoNetworkAddonsModule.plugins.firstOrNull()?.id)
.isEqualTo("expo-network-addons-gradle-plugin")
}
@Test
fun `can deserialize extra dependencies`() {
// language=JSON
val mockedConfig = """
{
"modules": [],
"extraDependencies": [
{
"url": "repo1",
"credentials": {
"username": "user",
"password": "password"
},
"authentication": "basic"
},
{
"url": "repo2",
"credentials": {
"name": "name",
"value": "value"
},
"authentication": "header"
},
{
"url": "repo3",
"credentials": {
"accessKey": "accessKey",
"secretKey": "secretKey"
},
"authentication": "digest"
}
]
}
""".trimIndent()
val config = ExpoAutolinkingConfig.decodeFromString(mockedConfig)
val repo1 = config.extraDependencies.find { it.url == "repo1" }
val repo2 = config.extraDependencies.find { it.url == "repo2" }
val repo3 = config.extraDependencies.find { it.url == "repo3" }
Truth.assertThat(repo1).isNotNull()
Truth.assertThat(repo2).isNotNull()
Truth.assertThat(repo3).isNotNull()
repo1!!
repo2!!
repo3!!
Truth.assertThat(repo1.authentication).isEqualTo("basic")
Truth.assertThat(repo1.credentials).isInstanceOf(BasicMavenCredentials::class.java)
val basicCredentials = repo1.credentials as BasicMavenCredentials
Truth.assertThat(basicCredentials.username).isEqualTo("user")
Truth.assertThat(basicCredentials.password).isEqualTo("password")
Truth.assertThat(repo2.authentication).isEqualTo("header")
Truth.assertThat(repo2.credentials).isInstanceOf(HttpHeaderMavenCredentials::class.java)
val headerCredentials = repo2.credentials as HttpHeaderMavenCredentials
Truth.assertThat(headerCredentials.name).isEqualTo("name")
Truth.assertThat(headerCredentials.value).isEqualTo("value")
Truth.assertThat(repo3.authentication).isEqualTo("digest")
Truth.assertThat(repo3.credentials).isInstanceOf(AWSMavenCredentials::class.java)
val awsCredentials = repo3.credentials as AWSMavenCredentials
Truth.assertThat(awsCredentials.accessKey).isEqualTo("accessKey")
Truth.assertThat(awsCredentials.secretKey).isEqualTo("secretKey")
}
}
@@ -0,0 +1,43 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
id("java-gradle-plugin")
}
repositories {
google()
mavenCentral()
}
dependencies {
implementation(project(":expo-autolinking-plugin-shared"))
implementation(gradleApi())
compileOnly("com.android.tools.build:gradle:8.5.0")
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
}
group = "expo.modules"
gradlePlugin {
plugins {
create("expoAutolinkingPlugin") {
id = "expo-autolinking"
implementationClass = "expo.modules.plugin.ExpoAutolinkingPlugin"
}
create("expoRootProjectPlugin") {
id = "expo-root-project"
implementationClass = "expo.modules.plugin.ExpoRootProjectPlugin"
}
}
}
@@ -0,0 +1,168 @@
package expo.modules.plugin
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.internal.tasks.factory.dependsOn
import expo.modules.plugin.text.Colors
import expo.modules.plugin.text.withColor
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import java.io.File
import java.nio.file.Paths
const val generatedPackageListNamespace = "expo.modules"
const val generatedPackageListFilename = "ExpoModulesPackageList.java"
const val generatedFilesSrcDir = "generated/expo/src/main/java"
open class ExpoAutolinkingPlugin : Plugin<Project> {
override fun apply(project: Project) {
val gradleExtension = project.gradle.extensions.findByType(ExpoGradleExtension::class.java)
?: throw IllegalStateException("`ExpoGradleExtension` not found. Please, make sure that `useExpoModules` was called in `settings.gradle`.")
val config = gradleExtension.config
project.logger.quiet("")
project.logger.quiet("Using expo modules")
val appProject = findAppProject(project.rootProject)
appProject?.let { copyAppDimensionsAndFlavorsToProject(project, it) }
val (prebuiltProjects, projects) = config.allProjects.partition { project ->
project.usePublication
}
project.withSubprojects(projects) { subproject ->
// Ensures that dependencies are resolved before the project is evaluated.
project.evaluationDependsOn(subproject.path)
// Adds the subproject as a dependency to the current project (expo package).
project.dependencies.add("api", subproject)
project.logger.quiet(" - ${subproject.name.withColor(Colors.GREEN)} (${subproject.version})")
}
prebuiltProjects.forEach { prebuiltProject ->
val publication = requireNotNull(prebuiltProject.publication)
project.dependencies.add("api", "${publication.groupId}:${publication.artifactId}:${publication.version}")
project.logger.quiet(" - ${"[\uD83D\uDCE6]".withColor(Colors.YELLOW)} ${prebuiltProject.name.withColor(Colors.GREEN)} (${publication.version})")
}
project.logger.quiet("")
// Creates a task that generates a list of expo modules.
val generatePackagesList = createGeneratePackagesListTask(project, gradleExtension.options, gradleExtension.hash, gradleExtension.projectRoot)
// Ensures that the task is executed before the build.
project.tasks
.named("preBuild", Task::class.java)
.dependsOn(generatePackagesList)
// Adds the generated file to the source set.
project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
ext
.sourceSets
.getByName("main")
.java
.srcDir(getPackageListDir(project))
}
}
fun getPackageListDir(project: Project): Provider<Directory> {
return project.layout.buildDirectory.dir(generatedFilesSrcDir)
}
fun getPackageListFile(project: Project): Provider<RegularFile> {
val packageListRelativePath = Paths.get(
generatedFilesSrcDir,
generatedPackageListNamespace.replace('.', '/'),
generatedPackageListFilename
).toString()
return project.layout.buildDirectory.file(packageListRelativePath)
}
fun createGeneratePackagesListTask(project: Project, options: AutolinkingOptions, hash: String, projectRoot: File): TaskProvider<GeneratePackagesListTask> {
return project.tasks.register("generatePackagesList", GeneratePackagesListTask::class.java) {
it.hash.set(hash)
it.namespace.set(generatedPackageListNamespace)
it.outputFile.set(getPackageListFile(project))
it.workingDir = projectRoot
// Serializes the autolinking options to JSON to pass them to the task.
// The types supported as a task input are limited to primitives, strings, and files.
it.options.set(options.toJson())
}
}
private fun findAppProject(root: Project): Project? {
return root.allprojects.firstOrNull { it.plugins.hasPlugin("com.android.application") }
}
private fun copyAppDimensionsAndFlavorsToProject(
project: Project,
appProject: Project
) {
val appAndroid = appProject.extensions.findByName("android") as? BaseExtension ?: run {
return
}
val consumerAndroid = project.extensions.findByName("android") as? BaseExtension ?: run {
return
}
val appDimensions = syncFlavorDimensions(project, consumerAndroid, appAndroid)
copyMissingProductFlavors(project, consumerAndroid, appAndroid, appDimensions)
}
private fun syncFlavorDimensions(
project: Project,
consumerAndroid: BaseExtension,
appAndroid: BaseExtension
): List<String> {
val appDimensions = appAndroid
.flavorDimensionList
.takeIf { it.isNotEmpty() }
?: return emptyList()
val consumerDimensions = (consumerAndroid.flavorDimensionList).toMutableList()
val dimensionsAdded = appDimensions.any { dimension ->
if (dimension !in consumerDimensions) {
consumerDimensions.add(dimension)
true
} else {
false
}
}
if (dimensionsAdded) {
consumerAndroid.flavorDimensions(*consumerDimensions.toTypedArray())
project.logger.quiet(" -> Copied/merged flavorDimensions: ${consumerDimensions.joinToString()}")
}
return appDimensions
}
private fun copyMissingProductFlavors(
project: Project,
consumerAndroid: BaseExtension,
appAndroid: BaseExtension,
appDimensions: List<String>
) {
val appFlavors = appAndroid.productFlavors
val consumerFlavors = consumerAndroid.productFlavors
val existingFlavorNames = consumerFlavors.map { it.name }.toSet()
appFlavors.forEach { appFlavor ->
if (appFlavor.name !in existingFlavorNames) {
val dimension = appFlavor.dimension ?: appDimensions.singleOrNull()
consumerFlavors.create(appFlavor.name).apply {
this.dimension = dimension
}
project.logger.quiet(" -> Created flavor '${appFlavor.name}' (dimension='$dimension') in :${project.path}")
}
}
}
}
@@ -0,0 +1,74 @@
package expo.modules.plugin
import expo.modules.plugin.text.Colors
import expo.modules.plugin.text.withColor
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.internal.extensions.core.extra
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class ExpoRootProjectPlugin : Plugin<Project> {
override fun apply(rootProject: Project) {
val versionCatalogs = rootProject.extensions.getByType(VersionCatalogsExtension::class.java)
val libs = versionCatalogs.find("expoLibs")
with(rootProject) {
defineDefaultProperties(libs)
}
}
}
fun Project.defineDefaultProperties(versionCatalogs: Optional<VersionCatalog>) {
// Android related
val buildTools = extra.setIfNotExist("buildToolsVersion") { versionCatalogs.getVersionOrDefault("buildTools", "35.0.0") }
val minSdk = extra.setIfNotExist("minSdkVersion") { Integer.parseInt(versionCatalogs.getVersionOrDefault("minSdk", "24")) }
val compileSdk = extra.setIfNotExist("compileSdkVersion") { Integer.parseInt(versionCatalogs.getVersionOrDefault("compileSdk", "35")) }
val targetSdk = extra.setIfNotExist("targetSdkVersion") { Integer.parseInt(versionCatalogs.getVersionOrDefault("targetSdk", "35")) }
val ndk = extra.setIfNotExist("ndkVersion") { versionCatalogs.getVersionOrDefault("ndkVersion", "27.1.12297006") }
// Kotlin related
val kotlin = extra.setIfNotExist("kotlinVersion") { versionCatalogs.getVersionOrDefault("kotlin", "2.0.21") }
val ksp = extra.setIfNotExist("kspVersion") {
versionCatalogs.getVersionOrDefault("ksp") {
try {
return@getVersionOrDefault KSPLookup.getValue(extra.get("kotlinVersion") as String)
} catch (e: Throwable) {
throw IllegalStateException(
"Can't find KSP version for Kotlin version '${extra.get("kotlinVersion")}'. You're probably using an unsupported version of Kotlin. Supported versions are: '${KSPLookup.keys.joinToString(", ")}'",
e
)
}
}
}
project.logger.quiet("""
${"[ExpoRootProject]".withColor(Colors.GREEN)} Using the following versions:
- buildTools: ${buildTools.withColor(Colors.GREEN)}
- minSdk: ${minSdk.withColor(Colors.GREEN)}
- compileSdk: ${compileSdk.withColor(Colors.GREEN)}
- targetSdk: ${targetSdk.withColor(Colors.GREEN)}
- ndk: ${ndk.withColor(Colors.GREEN)}
- kotlin: ${kotlin.withColor(Colors.GREEN)}
- ksp: ${ksp.withColor(Colors.GREEN)}
""".trimIndent())
}
inline fun ExtraPropertiesExtension.setIfNotExist(name: String, value: () -> Any): Any? {
if (!has(name)) {
set(name, value())
}
return get(name)
}
fun Optional<VersionCatalog>.getVersionOrDefault(name: String, default: String): String {
return getOrNull()?.findVersion(name)?.getOrNull()?.requiredVersion ?: default
}
fun Optional<VersionCatalog>.getVersionOrDefault(name: String, default: () -> String): String {
return getOrNull()?.findVersion(name)?.getOrNull()?.requiredVersion ?: default.invoke()
}
@@ -0,0 +1,54 @@
package expo.modules.plugin
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
/**
* Task that generates a list of packages that should be included in your app's runtime.
*/
abstract class GeneratePackagesListTask : Exec() {
init {
group = "expo"
}
/**
* Hash of the current configuration.
* Used to invalidate the task when the configuration changes.
*/
@get:Input
abstract val hash: Property<String>
/**
* Serialized autolinking options.
*/
@get:Input
abstract val options: Property<String>
/**
* Java package name under which the package list should be placed.
*/
@get:Input
abstract val namespace: Property<String>
/**
* The output file where the package list should be written.
*/
@get:OutputFile
abstract val outputFile: RegularFileProperty
override fun exec() {
val autolinkingOptions = AutolinkingOptions.fromJson(options.get())
commandLine(
AutolinkingCommandBuilder()
.command("generate-package-list")
.option("namespace", namespace.get())
.option("target", outputFile.get().asFile.absolutePath)
.useAutolinkingOptions(autolinkingOptions)
.build()
)
super.exec()
}
}
@@ -0,0 +1,17 @@
// Copyright 2015-present 650 Industries. All rights reserved.
// Generated using './scripts/generateKSPLookUp.js'
package expo.modules.plugin
val KSPLookup = mapOf(
"2.2.20" to "2.2.20-2.0.3",
"2.2.10" to "2.2.10-2.0.2",
"2.2.0" to "2.2.0-2.0.2",
"2.1.21" to "2.1.21-2.0.2",
"2.1.20" to "2.1.20-2.0.1",
"2.1.10" to "2.1.10-1.0.31",
"2.1.0" to "2.1.0-1.0.29",
"2.0.21" to "2.0.21-1.0.28",
"2.0.20" to "2.0.20-1.0.25",
"2.0.10" to "2.0.10-1.0.24",
"2.0.0" to "2.0.0-1.0.24"
)
@@ -0,0 +1,26 @@
package expo.modules.plugin
import expo.modules.plugin.configuration.GradleProject
import org.gradle.api.Project
internal fun Project.withSubproject(subprojectConfig: GradleProject, action: (subproject: Project) -> Unit) {
val subprojectPath = ":${subprojectConfig.name}"
val subproject = findProject(subprojectPath)
if (subproject == null) {
logger.warn("Couldn't find project ${subprojectConfig.name}. Please, make sure that `expo-autolinking-settings` plugin was applied in `settings.gradle`.")
return
}
// Prevent circular dependencies
if (subproject == this) {
return
}
action(subproject)
}
internal fun Project.withSubprojects(subprojectsConfig: List<GradleProject>, action: (subproject: Project) -> Unit) {
subprojectsConfig.forEach { subprojectConfig ->
withSubproject(subprojectConfig, action)
}
}
@@ -0,0 +1,53 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
id("java-gradle-plugin")
}
repositories {
google()
mavenCentral()
}
dependencies {
implementation(project(":expo-autolinking-plugin-shared"))
implementation(gradleApi())
compileOnly("com.android.tools.build:gradle:8.5.0")
testImplementation("junit:junit:4.13.2")
testImplementation("com.google.truth:truth:1.1.2")
testImplementation("io.mockk:mockk:1.14.2")
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
}
group = "expo.modules"
gradlePlugin {
plugins {
create("expoAutolinkingSettingsPlugin") {
id = "expo-autolinking-settings"
implementationClass = "expo.modules.plugin.ExpoAutolinkingSettingsPlugin"
}
}
}
tasks.withType<Test>().configureEach {
testLogging {
exceptionFormat = TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
}
}
@@ -0,0 +1,11 @@
package expo.modules.plugin
import expo.modules.plugin.configuration.ExpoAutolinkingConfig
import expo.modules.plugin.configuration.GradleProject
import org.gradle.api.Project
fun ExpoAutolinkingConfig.getConfigForProject(gradleProject: Project): GradleProject? {
return allProjects.firstOrNull {
it.name == gradleProject.name
}
}
@@ -0,0 +1,145 @@
package expo.modules.plugin
import org.gradle.api.Action
import org.gradle.api.initialization.Settings
import org.gradle.api.initialization.dsl.VersionCatalogBuilder
import org.gradle.api.model.ObjectFactory
import java.io.File
import javax.inject.Inject
open class ExpoAutolinkingSettingsExtension(
val settings: Settings,
@Inject val objects: ObjectFactory
) {
/**
* The root directory of the react native project.
* Should be used by projects that don't follow the /android folder structure.
*
* Defaults to `settings.rootDir`.
*/
var projectRoot: File = settings.rootDir
/**
* Command that should be provided to `react-native` to resolve the configuration.
*/
val rnConfigCommand by lazy {
val commandBuilder = AutolinkingCommandBuilder()
.command("react-native-config")
.useJson()
if (projectRoot != settings.rootDir) {
commandBuilder.option("project-root", projectRoot.absolutePath)
commandBuilder.option("source-dir", settings.rootDir.absolutePath)
}
commandBuilder.build()
}
/**
* A list of paths relative to the app's root directory where
* the autolinking script should search for Expo modules.
*/
var searchPaths: List<String>? = null
/**
* Paths to ignore when looking up for modules.
*/
var ignorePaths: List<String>? = null
/**
* Package names to exclude when looking up for modules.
*/
var exclude: List<String>? = null
/**
* The file pointing to the React Native Gradle plugin.
*/
val reactNativeGradlePlugin: File by lazy {
File(
settings.providers.exec { env ->
env.workingDir(projectRoot)
env.commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
}.standardOutput.asText.get().trim(),
).parentFile
}
/**
* The file pointing to the React Native root directory.
*/
val reactNative: File by lazy {
File(
settings.providers.exec { env ->
env.workingDir(projectRoot)
env.commandLine("node", "--print", "require.resolve('react-native/package.json')")
}.standardOutput.asText.get().trim(),
).parentFile
}
/**
* Uses Expo modules autolinking.
*/
fun useExpoModules() {
SettingsManager(
settings,
projectRoot,
searchPaths,
ignorePaths,
exclude
).useExpoModules()
}
fun useExpoVersionCatalog() {
useExpoVersionCatalog(
reactNativeVersionCatalog = null,
override = null
)
}
fun useExpoVersionCatalog(
override: Action<in VersionCatalogBuilder>
) {
useExpoVersionCatalog(
reactNativeVersionCatalog = null,
override = override
)
}
fun useExpoVersionCatalog(
reactNativeVersionCatalog: String?,
override: Action<in VersionCatalogBuilder>?
) {
val baseFile = if (reactNativeVersionCatalog != null) {
File(reactNativeVersionCatalog)
} else {
File(
reactNative,
"gradle/libs.versions.toml"
)
}
val catalogFile = objects.fileCollection().from(baseFile)
val properties = listOf(
"android.buildToolsVersion" to "buildTools",
"android.minSdkVersion" to "minSdk",
"android.compileSdkVersion" to "compileSdk",
"android.targetSdkVersion" to "targetSdk",
"android.kotlinVersion" to "kotlin"
)
settings.dependencyResolutionManagement {
it.versionCatalogs { spec ->
spec.create("expoLibs") { catalog ->
catalog.from(catalogFile)
properties.forEach { (propertyName, name) ->
val property = settings.providers.gradleProperty(propertyName)
if (property.isPresent) {
catalog.version(name, property.get())
}
}
override?.execute(catalog)
}
}
}
}
}
@@ -0,0 +1,49 @@
package expo.modules.plugin
import expo.modules.plugin.gradle.beforeRootProject
import org.gradle.api.Plugin
import org.gradle.api.initialization.Settings
import java.io.File
open class ExpoAutolinkingSettingsPlugin : Plugin<Settings> {
override fun apply(settings: Settings) {
// Adds a property to the settings that indicates that the `expo-autolinking-plugin` is available.
settings.gradle.extensions.extraProperties.set("expoAutolinkingSettingsPlugin", true)
// Creates an extension that allows users to link expo modules and add additional configuration.
settings.extensions.create("expoAutolinking", ExpoAutolinkingSettingsExtension::class.java, settings)
val expoGradlePluginsFile = getExpoGradlePluginsFile(settings)
// If the `expo-gradle-plugin` is available, it will be included in the settings.
// It won't be available in our test project or when we decide to prebuild plugin.
if (expoGradlePluginsFile.exists()) {
settings.gradle.beforeRootProject { rootProject ->
// Adds the `expo-autolinking-plugin` to the root project, so it will be available for all subprojects.
rootProject
.buildscript
.dependencies
.add("classpath", "expo.modules:expo-autolinking-plugin")
}
// Includes the `expo-gradle-plugin` subproject.
settings.includeBuild(
expoGradlePluginsFile.absolutePath
)
}
}
private fun getExpoGradlePluginsFile(settings: Settings): File {
val expoModulesAutolinkingPath =
settings.providers.exec { env ->
env.workingDir(settings.rootDir)
env.commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
}.standardOutput.asText.get().trim()
val expoAutolinkingDir = File(expoModulesAutolinkingPath).parentFile
return File(
expoAutolinkingDir,
"android/expo-gradle-plugin"
)
}
}
@@ -0,0 +1,174 @@
package expo.modules.plugin
import expo.modules.plugin.configuration.ExpoAutolinkingConfig
import expo.modules.plugin.configuration.GradleProject
import expo.modules.plugin.gradle.afterAndroidApplicationProject
import expo.modules.plugin.gradle.applyAarProject
import expo.modules.plugin.gradle.applyPlugin
import expo.modules.plugin.gradle.beforeProject
import expo.modules.plugin.gradle.beforeRootProject
import expo.modules.plugin.gradle.linkAarProject
import expo.modules.plugin.gradle.linkBuildDependence
import expo.modules.plugin.gradle.linkLocalMavenRepository
import expo.modules.plugin.gradle.linkMavenRepository
import expo.modules.plugin.gradle.linkPlugin
import expo.modules.plugin.gradle.linkProject
import expo.modules.plugin.text.Colors
import expo.modules.plugin.text.Emojis
import expo.modules.plugin.text.withColor
import groovy.lang.Binding
import groovy.lang.GroovyShell
import org.gradle.api.Project
import org.gradle.api.initialization.Settings
import org.gradle.api.logging.Logging
import org.gradle.internal.extensions.core.extra
import java.io.File
class SettingsManager(
val settings: Settings,
val projectRoot: File,
searchPaths: List<String>? = null,
ignorePaths: List<String>? = null,
exclude: List<String>? = null
) {
private val autolinkingOptions = AutolinkingOptions(
searchPaths,
ignorePaths,
exclude
)
private val groovyShell by lazy {
val binding = Binding()
binding.setVariable("providers", settings.providers)
GroovyShell(javaClass.classLoader, binding)
}
private val logger by lazy {
Logging.getLogger(Settings::class.java)
}
/**
* Resolved configuration from `expo-modules-autolinking`.
*/
private val config by lazy {
val command = AutolinkingCommandBuilder()
.command("resolve")
.useJson()
.useAutolinkingOptions(autolinkingOptions)
.build()
val result = settings.providers.exec { env ->
env.workingDir(projectRoot.absolutePath)
env.commandLine(command)
}.standardOutput.asText.get()
val decodedConfig = ExpoAutolinkingConfig.decodeFromString(result)
configurePublication(decodedConfig)
return@lazy decodedConfig
}
private fun configurePublication(config: ExpoAutolinkingConfig) {
config.allProjects.forEach { project ->
if (project.publication != null) {
val forceBuildFromSource = config.configuration.buildFromSourceRegex.any {
it.matches(project.name)
}
project.configuration.shouldUsePublication = !forceBuildFromSource && evaluateShouldUsePublicationScript(project)
}
}
}
private fun evaluateShouldUsePublicationScript(project: GradleProject): Boolean {
// If the path to the script is not defined, we assume that the publication should be used.
val scriptPath = project.shouldUsePublicationScriptPath
?: return true
val scriptFile = File(scriptPath)
// If the path is invalid, we assume that the publication should be used.
if (!scriptFile.exists()) {
logger.warn("[ExpoAutolinkingPlugin] The script file does not exist: $scriptPath")
return false
}
val result = groovyShell.run(scriptFile, emptyArray<String>())
return result as? Boolean == true
}
fun useExpoModules() {
link()
settings.gradle.beforeProject { project ->
// Adds precompiled artifacts
config.allAarProjects.filter { it.name == project.name }
.forEach(
project::applyAarProject
)
}
// Defines the required features for the core module
settings.gradle.beforeProject("expo-modules-core") { project ->
project.extra.set("coreFeatures", config.coreFeatures)
}
settings.gradle.beforeRootProject { rootProject: Project ->
val extraDependency = config.extraDependencies
extraDependency.forEach { mavenConfig ->
rootProject.logger.quiet("Adding extra maven repository: ${mavenConfig.url}")
}
rootProject.allprojects { project ->
extraDependency.forEach { mavenConfig ->
project.linkMavenRepository(mavenConfig)
}
}
config.allPlugins.forEach(rootProject::linkBuildDependence)
// Adds maven repositories for all projects that are using the publication.
// It most likely means that we will add "https://maven.pkg.github.com/expo/expo" to the repositories.
val localRepositories = config
.allProjects
.filter { it.usePublication && it.publication?.repository != "mavenLocal" }
.mapNotNull {
val publication = it.publication
?: return@mapNotNull null
"${it.sourceDir}/../${publication.repository}" to publication
}
.groupBy({ it.first }, { it.second })
rootProject.allprojects { project ->
localRepositories.forEach { (path, publications) ->
project.linkLocalMavenRepository(path, publications)
}
}
}
settings.gradle.afterAndroidApplicationProject { androidApplication ->
config
.allPlugins
.filter { it.applyToRootProject }
.forEach { plugin ->
androidApplication.logger.quiet(" ${Emojis.INFORMATION} ${"Applying gradle plugin".withColor(Colors.YELLOW)} '${plugin.id.withColor(Colors.GREEN)}'")
androidApplication.applyPlugin(plugin)
}
}
settings.gradle.extensions.create("expoGradle", ExpoGradleExtension::class.java, config, autolinkingOptions, projectRoot)
}
/**
* Links all projects, plugins and aar projects.
*/
private fun link() = with(config) {
allProjects.forEach { project ->
if (!project.usePublication) {
settings.linkProject(project)
}
}
allPlugins.forEach(settings::linkPlugin)
allAarProjects.forEach(settings::linkAarProject)
}
}
@@ -0,0 +1,38 @@
package expo.modules.plugin.gradle
import org.gradle.api.Project
import org.gradle.api.invocation.Gradle
/**
* Adds an action to be called immediately before a root project is evaluate.
*/
internal inline fun Gradle.beforeRootProject(crossinline action: (rootProject: Project) -> Unit) {
beforeProject { project ->
if (project !== project.rootProject) {
return@beforeProject
}
action(project)
}
}
/**
* Adds an action to be called before the given project is evaluated.
*/
internal inline fun Gradle.beforeProject(projectName: String, crossinline action: (project: Project) -> Unit) {
beforeProject { project ->
if (project.name == projectName) {
action(project)
}
}
}
/**
* Adds an action to be called immediately after an Android application project is evaluated.
*/
internal inline fun Gradle.afterAndroidApplicationProject(crossinline action: (androidApplication: Project) -> Unit) {
afterProject { project ->
if (project.plugins.hasPlugin("com.android.application")) {
action(project)
}
}
}
@@ -0,0 +1,75 @@
package expo.modules.plugin.gradle
import expo.modules.plugin.configuration.AWSMavenCredentials
import expo.modules.plugin.configuration.BasicMavenCredentials
import expo.modules.plugin.configuration.HttpHeaderMavenCredentials
import expo.modules.plugin.configuration.MavenCredentials
import expo.modules.plugin.utils.Env
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.api.credentials.AwsCredentials
import org.gradle.api.credentials.HttpHeaderCredentials
import org.gradle.internal.authentication.DefaultBasicAuthentication
import org.gradle.internal.authentication.DefaultDigestAuthentication
import org.gradle.internal.authentication.DefaultHttpHeaderAuthentication
internal fun MavenArtifactRepository.applyAuthentication(authenticationType: String?) {
if (authenticationType == null) {
return
}
authentication.add(
when (authenticationType) {
"basic" -> DefaultBasicAuthentication("basic")
"digest" -> DefaultDigestAuthentication("digest")
"header" -> DefaultHttpHeaderAuthentication("header")
else -> throw IllegalArgumentException("Unknown authentication type: $authenticationType")
}
)
}
internal fun MavenArtifactRepository.applyCredentials(mavenCredentials: MavenCredentials?) {
if (mavenCredentials == null) {
return
}
when (mavenCredentials) {
is BasicMavenCredentials -> {
val (username, password) = mavenCredentials
credentials { credentials ->
credentials.username = resolveEnvVar(username)
credentials.password = resolveEnvVar(password)
}
}
is HttpHeaderMavenCredentials -> {
val (name, value) = mavenCredentials
credentials(HttpHeaderCredentials::class.java) { credentials ->
credentials.name = resolveEnvVar(name)
credentials.value = resolveEnvVar(value)
}
}
is AWSMavenCredentials -> {
val (accessKey, secretKey, sessionToken) = mavenCredentials
credentials(AwsCredentials::class.java) { credentials ->
credentials.accessKey = resolveEnvVar(accessKey)
credentials.secretKey = resolveEnvVar(secretKey)
credentials.sessionToken = sessionToken?.let { resolveEnvVar(it) }
}
}
}
}
private val ENV_REGEX = """System\.getenv\(['"]([A-Za-z0-9_]+)['"]\)""".toRegex()
/**
* Utility function to substitute environment variables in strings.
* Supports patterns like System.getEnv('VAR_NAME') or System.getEnv("VAR_NAME")
*/
private fun resolveEnvVar(input: String): String {
return ENV_REGEX.replace(input) { match ->
val name = match.groupValues[1]
// Return original if env var not found
Env.getProcessEnv(name) ?: match.value
}
}
@@ -0,0 +1,43 @@
package expo.modules.plugin.gradle
import expo.modules.plugin.configuration.GradleAarProject
import expo.modules.plugin.configuration.GradlePlugin
import expo.modules.plugin.configuration.MavenRepo
import expo.modules.plugin.configuration.Publication
import org.gradle.api.Project
import java.io.File
internal fun Project.applyPlugin(plugin: GradlePlugin) {
plugins.apply(plugin.id)
}
internal fun Project.applyAarProject(aarProject: GradleAarProject) {
configurations.maybeCreate("default")
artifacts.add("default", File(aarProject.aarFilePath))
}
internal fun Project.linkBuildDependence(plugin: GradlePlugin) {
buildscript.dependencies.add("classpath", "${plugin.group}:${plugin.id}")
}
internal fun Project.linkLocalMavenRepository(path: String, publications: List<Publication>) {
repositories.mavenLocal { maven ->
maven.url = file(path).toURI()
maven.content { content ->
publications.forEach { publication ->
content.includeVersion(publication.groupId, publication.artifactId, publication.version)
}
}
}
}
internal fun Project.linkMavenRepository(mavenRepo: MavenRepo) {
val (url, credentials, authentication) = mavenRepo
repositories.maven { maven ->
maven.setUrl(url)
maven.applyCredentials(credentials)
maven.applyAuthentication(authentication)
}
}
@@ -0,0 +1,25 @@
package expo.modules.plugin.gradle
import expo.modules.plugin.configuration.GradleAarProject
import expo.modules.plugin.configuration.GradlePlugin
import expo.modules.plugin.configuration.GradleProject
import org.gradle.api.initialization.Settings
import java.io.File
internal fun Settings.linkProject(project: GradleProject) {
include(":${project.name}")
project(":${project.name}").projectDir = File(project.sourceDir)
}
internal fun Settings.linkPlugin(plugin: GradlePlugin) {
includeBuild(File(plugin.sourceDir))
}
internal fun Settings.linkAarProject(aarProject: GradleAarProject) {
include(":${aarProject.name}")
val projectDir = File(aarProject.projectDir)
if (!projectDir.exists()) {
projectDir.mkdirs()
}
project(":${aarProject.name}").projectDir = projectDir
}
@@ -0,0 +1,8 @@
package expo.modules.plugin.utils
internal object Env {
/**
* A wrapper around [System.getenv] that we can setup mock for testing.
*/
fun getProcessEnv(name: String): String? = System.getenv(name)
}
@@ -0,0 +1,190 @@
package expo.modules.plugin
import com.google.common.truth.Truth
import expo.modules.plugin.configuration.ExpoAutolinkingConfig
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
class ExpoAutolinkingSettingsPluginTest {
@JvmField
@Rule
var testProjectDir: TemporaryFolder = TemporaryFolder()
@Before
fun setUp() {
testProjectDir.root.removeRecursively()
testProjectDir.root.createProject()
}
@Test
fun `applies settings plugin`() {
val result = executeGradleRun()
Truth.assertThat(result.output).contains("BUILD SUCCESSFUL")
}
@Test
fun `injects expo gradle extension`() {
val result = executeGradleRun(":app:gradleExpoExtension")
val expoConfig = findPrefix("expoGradle=", result.output)
Truth.assertThat(expoConfig).isNotNull()
}
@Test
fun `returns correct config`() {
val result = executeGradleRun(":app:expoConfig")
val configStringFromPlugin = findPrefix("expoConfig=", result.output)
val configFromPlugin = ExpoAutolinkingConfig.decodeFromString(configStringFromPlugin!!)
val configStringFromAutolinking = testProjectDir.root.runCommand(
*AutolinkingCommandBuilder()
.command("resolve")
.useJson()
.build()
.toTypedArray()
)
val configFromAutolinking = ExpoAutolinkingConfig.decodeFromString(configStringFromAutolinking)
Truth.assertThat(configFromPlugin).isEqualTo(configFromAutolinking)
}
private fun executeGradleRun(task: String? = null): BuildResult =
GradleRunner
.create()
.withProjectDir(testProjectDir.root)
.apply {
if (task != null) {
withArguments(task)
}
}
.withPluginClasspath()
.build()
}
fun findPrefix(prefix: String, input: String): String? {
return input.lineSequence()
.map { it.trim() }
.find { it.startsWith(prefix) }
?.substringAfter(prefix)
?.takeIf { it.isNotBlank() }
}
/**
* Creates a new project with the following structure:
* <file>
* ├── app
* │ └── build.gradle
* ├── build.gradle
* ├── settings.gradle
* └── package.json
*/
private fun File.createProject() {
File(this, "app").mkdir()
val app = File(this, "app")
File(app, "build.gradle").writeText(
"""
task("gradleExpoExtension") {
doLast {
println("expoGradle=" + gradle.expoGradle)
}
}
task("expoConfig") {
doLast {
println("expoConfig=" + gradle.expoGradle.config.toJson())
}
}
""".trimIndent()
)
File(this, "build.gradle").writeText(
"""
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.6.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.24")
}
}
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}
}
""".trimIndent()
)
File(this, "settings.gradle").writeText(
"""
plugins {
id("expo-autolinking-settings")
}
expoAutolinking.useExpoModules()
include(":app")
""".trimIndent()
)
File(this, "package.json").writeText(
"""
{
"name": "test-project",
"dependencies": {
"expo": "52.0.5",
"expo-image-picker": "16.0.3"
}
}
""".trimIndent()
)
runCommand("npm", "install")
// Mocks the expo and expo-modules-core build.gradle files
// to avoid errors during the sync process.
File(this, "node_modules/expo/android/build.gradle").writeText(
"""
""".trimIndent()
)
File(this, "node_modules/expo-modules-core/android/build.gradle").writeText(
"""
""".trimIndent()
)
}
/**
* Runs a command in the current directory and returns the output as a string.
*/
private fun File.runCommand(vararg command: String): String {
val process = ProcessBuilder(*command)
.directory(this)
.start()
val inputStream = process.inputStream
process.waitFor()
return inputStream.use {
it.readAllBytes().toString(Charsets.UTF_8)
}
}
/**
* Removes the file and all its children
*/
private fun File.removeRecursively() =
this
.walkBottomUp()
.filter { it != this }
.forEach { it.deleteRecursively() }
@@ -0,0 +1,112 @@
package expo.modules.plugin
import com.google.common.truth.Truth
import expo.modules.plugin.configuration.AWSMavenCredentials
import expo.modules.plugin.configuration.BasicMavenCredentials
import expo.modules.plugin.configuration.HttpHeaderMavenCredentials
import expo.modules.plugin.gradle.applyCredentials
import expo.modules.plugin.utils.Env
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.unmockkObject
import org.gradle.api.credentials.AwsCredentials
import org.gradle.api.credentials.HttpHeaderCredentials
import org.gradle.testfixtures.ProjectBuilder
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.net.URI
class MavenArtifactRepositoryExtensionTest {
@Before
fun setUp() {
mockkObject(Env)
}
@After
fun tearDown() {
unmockkObject(Env)
}
@Test
fun `should apply credentials from string values`() {
val project = ProjectBuilder.builder().build()
val mavenRepo = project.repositories.maven {
it.url = URI("auth.maven.test")
it.applyCredentials(BasicMavenCredentials("username", "password"))
}
Truth.assertThat(mavenRepo.credentials.username).isEqualTo("username")
Truth.assertThat(mavenRepo.credentials.password).isEqualTo("password")
}
@Test
fun `should apply credentials from environment variables`() {
val project = ProjectBuilder.builder().build()
every { Env.getProcessEnv("envUsername") } returns "basic1"
every { Env.getProcessEnv("envPassword") } returns "basic2"
val mavenRepoBasic = project.repositories.maven {
it.url = URI("auth.maven.test")
it.applyCredentials(BasicMavenCredentials("System.getenv('envUsername')", "System.getenv(\"envPassword\")"))
}
Truth.assertThat(mavenRepoBasic.credentials.username).isEqualTo("basic1")
Truth.assertThat(mavenRepoBasic.credentials.password).isEqualTo("basic2")
every { Env.getProcessEnv("envName") } returns "httpHeader1"
every { Env.getProcessEnv("envValue") } returns "httpHeader2"
val mavenRepoHttpHeader = project.repositories.maven {
it.url = URI("auth.maven.test")
it.applyCredentials(HttpHeaderMavenCredentials("System.getenv('envName')", "System.getenv(\"envValue\")"))
}
val httpHeaderCredentials = mavenRepoHttpHeader.getCredentials(HttpHeaderCredentials::class.java)
Truth.assertThat(httpHeaderCredentials.name).isEqualTo("httpHeader1")
Truth.assertThat(httpHeaderCredentials.value).isEqualTo("httpHeader2")
every { Env.getProcessEnv("envAccessKey") } returns "aws1"
every { Env.getProcessEnv("envSecretKey") } returns "aws2"
every { Env.getProcessEnv("envSessionToken") } returns "aws3"
val mavenRepoAws = project.repositories.maven {
it.url = URI("auth.maven.test")
it.applyCredentials(AWSMavenCredentials(
"System.getenv('envAccessKey')",
"System.getenv(\"envSecretKey\")",
"System.getenv('envSessionToken')"))
}
val awsCredentials = mavenRepoAws.getCredentials(AwsCredentials::class.java)
Truth.assertThat(awsCredentials.accessKey).isEqualTo("aws1")
Truth.assertThat(awsCredentials.secretKey).isEqualTo("aws2")
Truth.assertThat(awsCredentials.sessionToken).isEqualTo("aws3")
}
@Test
fun `should fallback to original inputs if environment variables not found`() {
val project = ProjectBuilder.builder().build()
val mavenRepoBasic = project.repositories.maven {
it.url = URI("auth.maven.test")
it.applyCredentials(BasicMavenCredentials("System.getenv('envUsername')", "System.getenv(\"envPassword\")"))
}
Truth.assertThat(mavenRepoBasic.credentials.username).isEqualTo("System.getenv('envUsername')")
Truth.assertThat(mavenRepoBasic.credentials.password).isEqualTo("System.getenv(\"envPassword\")")
val mavenRepoHttpHeader = project.repositories.maven {
it.url = URI("auth.maven.test")
it.applyCredentials(HttpHeaderMavenCredentials("System.getenv('envName')", "System.getenv(\"envValue\")"))
}
val httpHeaderCredentials = mavenRepoHttpHeader.getCredentials(HttpHeaderCredentials::class.java)
Truth.assertThat(httpHeaderCredentials.name).isEqualTo("System.getenv('envName')")
Truth.assertThat(httpHeaderCredentials.value).isEqualTo("System.getenv(\"envValue\")")
val mavenRepoAws = project.repositories.maven {
it.url = URI("auth.maven.test")
it.applyCredentials(AWSMavenCredentials(
"System.getenv('envAccessKey')",
"System.getenv(\"envSecretKey\")",
"System.getenv('envSessionToken')"))
}
val awsCredentials = mavenRepoAws.getCredentials(AwsCredentials::class.java)
Truth.assertThat(awsCredentials.accessKey).isEqualTo("System.getenv('envAccessKey')")
Truth.assertThat(awsCredentials.secretKey).isEqualTo("System.getenv(\"envSecretKey\")")
Truth.assertThat(awsCredentials.sessionToken).isEqualTo("System.getenv('envSessionToken')")
}
}
@@ -0,0 +1,15 @@
pluginManagement {
repositories {
mavenCentral()
google()
gradlePluginPortal()
}
}
include(
":expo-autolinking-plugin-shared",
":expo-autolinking-settings-plugin",
":expo-autolinking-plugin"
)
rootProject.name = "expo-gradle-plugin"
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env node
'use strict';
// Have to force color support — logs wouldn't have colors when spawned by another process.
// It must be set before `supports-color` (`chalk` dependency) module is imported.
process.env.FORCE_COLOR = 'true';
require('../build')(process.argv.slice(2));
@@ -0,0 +1,82 @@
import { AndroidGradleAarProjectDescriptor, AndroidGradlePluginDescriptor, AndroidPublication, RawExpoModuleConfig, RawModuleConfigApple, SupportedPlatform } from './types';
export declare class ExpoAndroidProjectConfig {
name: string;
path: string;
modules?: string[] | undefined;
publication?: AndroidPublication | undefined;
gradleAarProjects?: AndroidGradleAarProjectDescriptor[] | undefined;
shouldUsePublicationScriptPath?: string | undefined;
/**
* Whether this project is the root one.
*/
isDefault: boolean;
constructor(name: string, path: string, modules?: string[] | undefined, publication?: AndroidPublication | undefined, gradleAarProjects?: AndroidGradleAarProjectDescriptor[] | undefined, shouldUsePublicationScriptPath?: string | undefined,
/**
* Whether this project is the root one.
*/
isDefault?: boolean);
}
/**
* A class that wraps the raw config (`expo-module.json` or `unimodule.json`).
*/
export declare class ExpoModuleConfig {
readonly rawConfig: RawExpoModuleConfig;
constructor(rawConfig: RawExpoModuleConfig);
/**
* Whether the module supports given platform.
*/
supportsPlatform(platform: SupportedPlatform): boolean;
/**
* Returns the generic config for all Apple platforms with a fallback to the legacy iOS config.
*/
getAppleConfig(): RawModuleConfigApple | null;
/**
* Returns a list of names of Swift native modules classes to put to the generated modules provider file.
*/
appleModules(): string[];
/**
* Returns a list of names of Swift classes that receives AppDelegate life-cycle events.
*/
appleAppDelegateSubscribers(): string[];
/**
* Returns a list of names of Swift classes that implement `ExpoReactDelegateHandler`.
*/
appleReactDelegateHandlers(): string[];
/**
* Returns podspec paths defined by the module author.
*/
applePodspecPaths(): string[];
/**
* Returns the product module names, if defined by the module author.
*/
appleSwiftModuleNames(): string[];
/**
* Returns whether this module will be added only to the debug configuration
*/
appleDebugOnly(): boolean;
/**
* Returns information about Android projects defined by the module author.
*/
androidProjects(defaultProjectName: string): ExpoAndroidProjectConfig[];
/**
* Returns gradle plugins descriptors defined by the module author.
*/
androidGradlePlugins(): AndroidGradlePluginDescriptor[];
/**
* Returns gradle projects containing AAR files defined by the module author.
*/
androidGradleAarProjects(): AndroidGradleAarProjectDescriptor[];
/**
* Returns the publication config for Android.
*/
androidPublication(): AndroidPublication | undefined;
/**
* Returns core features required by the module author.
*/
coreFeatures(): string[];
/**
* Returns serializable raw config.
*/
toJSON(): RawExpoModuleConfig;
}
export declare const discoverExpoModuleConfigAsync: (input: string, ...args: any[]) => Promise<any>;
@@ -0,0 +1,179 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.discoverExpoModuleConfigAsync = exports.ExpoModuleConfig = exports.ExpoAndroidProjectConfig = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const utils_1 = require("./utils");
function arrayize(value) {
if (Array.isArray(value)) {
return value;
}
return value != null ? [value] : [];
}
class ExpoAndroidProjectConfig {
name;
path;
modules;
publication;
gradleAarProjects;
shouldUsePublicationScriptPath;
isDefault;
constructor(name, path, modules, publication, gradleAarProjects, shouldUsePublicationScriptPath,
/**
* Whether this project is the root one.
*/
isDefault = false) {
this.name = name;
this.path = path;
this.modules = modules;
this.publication = publication;
this.gradleAarProjects = gradleAarProjects;
this.shouldUsePublicationScriptPath = shouldUsePublicationScriptPath;
this.isDefault = isDefault;
}
}
exports.ExpoAndroidProjectConfig = ExpoAndroidProjectConfig;
/**
* A class that wraps the raw config (`expo-module.json` or `unimodule.json`).
*/
class ExpoModuleConfig {
rawConfig;
constructor(rawConfig) {
this.rawConfig = rawConfig;
}
/**
* Whether the module supports given platform.
*/
supportsPlatform(platform) {
const supportedPlatforms = this.rawConfig.platforms ?? [];
if (platform === 'web') {
// Web platform is implicitly supported for autolinking resolution but has no special behavior
return true;
}
else if (platform === 'apple') {
// Apple platform is supported when any of iOS, macOS and tvOS is supported.
return supportedPlatforms.some((supportedPlatform) => {
return ['apple', 'ios', 'macos', 'tvos'].includes(supportedPlatform);
});
}
switch (platform) {
case 'ios':
case 'macos':
case 'tvos':
// ios|macos|tvos are supported when the module supports "apple" as a platform in general
return supportedPlatforms.includes(platform) || supportedPlatforms.includes('apple');
default:
return supportedPlatforms.includes(platform);
}
}
/**
* Returns the generic config for all Apple platforms with a fallback to the legacy iOS config.
*/
getAppleConfig() {
return this.rawConfig.apple ?? this.rawConfig.ios ?? null;
}
/**
* Returns a list of names of Swift native modules classes to put to the generated modules provider file.
*/
appleModules() {
const appleConfig = this.getAppleConfig();
return appleConfig?.modules ?? [];
}
/**
* Returns a list of names of Swift classes that receives AppDelegate life-cycle events.
*/
appleAppDelegateSubscribers() {
return this.getAppleConfig()?.appDelegateSubscribers ?? [];
}
/**
* Returns a list of names of Swift classes that implement `ExpoReactDelegateHandler`.
*/
appleReactDelegateHandlers() {
return this.getAppleConfig()?.reactDelegateHandlers ?? [];
}
/**
* Returns podspec paths defined by the module author.
*/
applePodspecPaths() {
return arrayize(this.getAppleConfig()?.podspecPath);
}
/**
* Returns the product module names, if defined by the module author.
*/
appleSwiftModuleNames() {
return arrayize(this.getAppleConfig()?.swiftModuleName);
}
/**
* Returns whether this module will be added only to the debug configuration
*/
appleDebugOnly() {
return this.getAppleConfig()?.debugOnly ?? false;
}
/**
* Returns information about Android projects defined by the module author.
*/
androidProjects(defaultProjectName) {
const androidProjects = [];
// Adding the "root" Android project - it might not be valide.
androidProjects.push(new ExpoAndroidProjectConfig(this.rawConfig.android?.name ?? defaultProjectName, this.rawConfig.android?.path ?? 'android', this.rawConfig.android?.modules, this.rawConfig.android?.publication, this.rawConfig.android?.gradleAarProjects, this.rawConfig.android?.shouldUsePublicationScriptPath, !this.rawConfig.android?.path // it's default project because path is not defined
));
this.rawConfig.android?.projects?.forEach((project) => {
androidProjects.push(new ExpoAndroidProjectConfig(project.name, project.path, project.modules, project.publication, project.gradleAarProjects, project.shouldUsePublicationScriptPath));
});
return androidProjects;
}
/**
* Returns gradle plugins descriptors defined by the module author.
*/
androidGradlePlugins() {
return arrayize(this.rawConfig.android?.gradlePlugins ?? []);
}
/**
* Returns gradle projects containing AAR files defined by the module author.
*/
androidGradleAarProjects() {
return arrayize(this.rawConfig.android?.gradleAarProjects ?? []);
}
/**
* Returns the publication config for Android.
*/
androidPublication() {
return this.rawConfig.android?.publication;
}
/**
* Returns core features required by the module author.
*/
coreFeatures() {
return arrayize(this.rawConfig.coreFeatures ?? []);
}
/**
* Returns serializable raw config.
*/
toJSON() {
return this.rawConfig;
}
}
exports.ExpoModuleConfig = ExpoModuleConfig;
/** Names of Expo Module config files (highest to lowest priority) */
const EXPO_MODULE_CONFIG_FILENAMES = ['expo-module.config.json', 'unimodule.json'];
exports.discoverExpoModuleConfigAsync = (0, utils_1.memoize)(async function discoverExpoModuleConfigAsync(directoryPath) {
for (let idx = 0; idx < EXPO_MODULE_CONFIG_FILENAMES.length; idx++) {
// TODO: Validate the raw config against a schema.
// TODO: Support for `*.js` files, not only static `*.json`.
const targetPath = path_1.default.join(directoryPath, EXPO_MODULE_CONFIG_FILENAMES[idx]);
let text;
try {
text = await fs_1.default.promises.readFile(targetPath, 'utf8');
}
catch {
// try the next file
continue;
}
return new ExpoModuleConfig(JSON.parse(text));
}
return null;
});
//# sourceMappingURL=ExpoModuleConfig.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
import { AutolinkingOptions } from '../commands/autolinkingOptions';
import { type DependencyResolution } from '../dependencies';
import { PackageRevision, SearchResults, SupportedPlatform } from '../types';
export declare function resolveExpoModule(resolution: DependencyResolution, platform: SupportedPlatform, excludeNames: Set<string>): Promise<PackageRevision | null>;
interface FindModulesParams {
appRoot: string;
autolinkingOptions: AutolinkingOptions & {
platform: SupportedPlatform;
};
}
/** Searches for modules to link based on given config. */
export declare function findModulesAsync({ appRoot, autolinkingOptions, }: FindModulesParams): Promise<SearchResults>;
export {};
@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveExpoModule = resolveExpoModule;
exports.findModulesAsync = findModulesAsync;
const ExpoModuleConfig_1 = require("../ExpoModuleConfig");
const dependencies_1 = require("../dependencies");
async function resolveExpoModule(resolution, platform, excludeNames) {
if (excludeNames.has(resolution.name)) {
return null;
}
const expoModuleConfig = await (0, ExpoModuleConfig_1.discoverExpoModuleConfigAsync)(resolution.path);
if (expoModuleConfig && expoModuleConfig.supportsPlatform(platform)) {
return {
name: resolution.name,
path: resolution.path,
version: resolution.version,
config: expoModuleConfig,
duplicates: resolution.duplicates?.map((duplicate) => ({
name: duplicate.name,
path: duplicate.path,
version: duplicate.version,
})) ?? [],
};
}
else {
return null;
}
}
/** Searches for modules to link based on given config. */
async function findModulesAsync({ appRoot, autolinkingOptions, }) {
const excludeNames = new Set(autolinkingOptions.exclude);
// custom native modules should be resolved first so that they can override other modules
const searchPaths = autolinkingOptions.nativeModulesDir
? [autolinkingOptions.nativeModulesDir, ...autolinkingOptions.searchPaths]
: autolinkingOptions.searchPaths;
return (0, dependencies_1.filterMapResolutionResult)((0, dependencies_1.mergeResolutionResults)(await Promise.all([
...searchPaths.map((searchPath) => (0, dependencies_1.scanDependenciesInSearchPath)(searchPath)),
(0, dependencies_1.scanDependenciesRecursively)(appRoot),
])), (resolution) => resolveExpoModule(resolution, autolinkingOptions.platform, excludeNames));
}
//# sourceMappingURL=findModules.js.map
@@ -0,0 +1 @@
{"version":3,"file":"findModules.js","sourceRoot":"","sources":["../../src/autolinking/findModules.ts"],"names":[],"mappings":";;AAWA,8CAyBC;AAQD,4CAoBC;AAhED,0DAAoE;AAEpE,kDAMyB;AAGlB,KAAK,UAAU,iBAAiB,CACrC,UAAgC,EAChC,QAA2B,EAC3B,YAAyB;IAEzB,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,gBAAgB,GAAG,MAAM,IAAA,gDAA6B,EAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9E,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpE,OAAO;YACL,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,MAAM,EAAE,gBAAgB;YACxB,UAAU,EACR,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBACzC,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,OAAO,EAAE,SAAS,CAAC,OAAO;aAC3B,CAAC,CAAC,IAAI,EAAE;SACZ,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAOD,0DAA0D;AACnD,KAAK,UAAU,gBAAgB,CAAC,EACrC,OAAO,EACP,kBAAkB,GACA;IAClB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAEzD,yFAAyF;IACzF,MAAM,WAAW,GAAG,kBAAkB,CAAC,gBAAgB;QACrD,CAAC,CAAC,CAAC,kBAAkB,CAAC,gBAAgB,EAAE,GAAG,kBAAkB,CAAC,WAAW,CAAC;QAC1E,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC;IAEnC,OAAO,IAAA,wCAAyB,EAC9B,IAAA,qCAAsB,EACpB,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAA,2CAA4B,EAAC,UAAU,CAAC,CAAC;QAC5E,IAAA,0CAA2B,EAAC,OAAO,CAAC;KACrC,CAAC,CACH,EACD,CAAC,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC,CACzF,CAAC;AACJ,CAAC","sourcesContent":["import { discoverExpoModuleConfigAsync } from '../ExpoModuleConfig';\nimport { AutolinkingOptions } from '../commands/autolinkingOptions';\nimport {\n type DependencyResolution,\n scanDependenciesRecursively,\n scanDependenciesInSearchPath,\n filterMapResolutionResult,\n mergeResolutionResults,\n} from '../dependencies';\nimport { PackageRevision, SearchResults, SupportedPlatform } from '../types';\n\nexport async function resolveExpoModule(\n resolution: DependencyResolution,\n platform: SupportedPlatform,\n excludeNames: Set<string>\n): Promise<PackageRevision | null> {\n if (excludeNames.has(resolution.name)) {\n return null;\n }\n const expoModuleConfig = await discoverExpoModuleConfigAsync(resolution.path);\n if (expoModuleConfig && expoModuleConfig.supportsPlatform(platform)) {\n return {\n name: resolution.name,\n path: resolution.path,\n version: resolution.version,\n config: expoModuleConfig,\n duplicates:\n resolution.duplicates?.map((duplicate) => ({\n name: duplicate.name,\n path: duplicate.path,\n version: duplicate.version,\n })) ?? [],\n };\n } else {\n return null;\n }\n}\n\ninterface FindModulesParams {\n appRoot: string;\n autolinkingOptions: AutolinkingOptions & { platform: SupportedPlatform };\n}\n\n/** Searches for modules to link based on given config. */\nexport async function findModulesAsync({\n appRoot,\n autolinkingOptions,\n}: FindModulesParams): Promise<SearchResults> {\n const excludeNames = new Set(autolinkingOptions.exclude);\n\n // custom native modules should be resolved first so that they can override other modules\n const searchPaths = autolinkingOptions.nativeModulesDir\n ? [autolinkingOptions.nativeModulesDir, ...autolinkingOptions.searchPaths]\n : autolinkingOptions.searchPaths;\n\n return filterMapResolutionResult(\n mergeResolutionResults(\n await Promise.all([\n ...searchPaths.map((searchPath) => scanDependenciesInSearchPath(searchPath)),\n scanDependenciesRecursively(appRoot),\n ])\n ),\n (resolution) => resolveExpoModule(resolution, autolinkingOptions.platform, excludeNames)\n );\n}\n"]}
@@ -0,0 +1,17 @@
import { ModuleDescriptor, SupportedPlatform } from '../types';
interface GeneratePackageListParams {
platform: SupportedPlatform;
targetPath: string;
namespace: string;
}
/** Generates a source file listing all packages to link (Android-only) */
export declare function generatePackageListAsync(modules: ModuleDescriptor[], params: GeneratePackageListParams): Promise<void>;
interface GenerateModulesProviderParams {
platform: SupportedPlatform;
targetPath: string;
entitlementPath: string | null;
}
/** Generates ExpoModulesProvider file listing all packages to link (Apple-only)
*/
export declare function generateModulesProviderAsync(modules: ModuleDescriptor[], params: GenerateModulesProviderParams): Promise<void>;
export {};
@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generatePackageListAsync = generatePackageListAsync;
exports.generateModulesProviderAsync = generateModulesProviderAsync;
const platforms_1 = require("../platforms");
/** Generates a source file listing all packages to link (Android-only) */
async function generatePackageListAsync(modules, params) {
const platformLinking = (0, platforms_1.getLinkingImplementationForPlatform)(params.platform);
if (!('generatePackageListAsync' in platformLinking)) {
throw new Error(`Generating package list is not available for platform "${params.platform}"`);
}
await platformLinking.generatePackageListAsync(modules, params.targetPath, params.namespace);
}
/** Generates ExpoModulesProvider file listing all packages to link (Apple-only)
*/
async function generateModulesProviderAsync(modules, params) {
const platformLinking = (0, platforms_1.getLinkingImplementationForPlatform)(params.platform);
if (!('generateModulesProviderAsync' in platformLinking)) {
throw new Error(`Generating modules provider is not available for platform "${params.platform}"`);
}
await platformLinking.generateModulesProviderAsync(modules, params.targetPath, params.entitlementPath);
}
//# sourceMappingURL=generatePackageList.js.map
@@ -0,0 +1 @@
{"version":3,"file":"generatePackageList.js","sourceRoot":"","sources":["../../src/autolinking/generatePackageList.ts"],"names":[],"mappings":";;AAUA,4DASC;AAUD,oEAeC;AA5CD,4CAAmE;AASnE,0EAA0E;AACnE,KAAK,UAAU,wBAAwB,CAC5C,OAA2B,EAC3B,MAAiC;IAEjC,MAAM,eAAe,GAAG,IAAA,+CAAmC,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,CAAC,CAAC,0BAA0B,IAAI,eAAe,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,0DAA0D,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;IAChG,CAAC;IACD,MAAM,eAAe,CAAC,wBAAwB,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;AAC/F,CAAC;AAQD;GACG;AACI,KAAK,UAAU,4BAA4B,CAChD,OAA2B,EAC3B,MAAqC;IAErC,MAAM,eAAe,GAAG,IAAA,+CAAmC,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,CAAC,CAAC,8BAA8B,IAAI,eAAe,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,8DAA8D,MAAM,CAAC,QAAQ,GAAG,CACjF,CAAC;IACJ,CAAC;IACD,MAAM,eAAe,CAAC,4BAA4B,CAChD,OAAgC,EAChC,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,eAAe,CACvB,CAAC;AACJ,CAAC","sourcesContent":["import { getLinkingImplementationForPlatform } from '../platforms';\nimport { ModuleDescriptor, ModuleDescriptorIos, SupportedPlatform } from '../types';\n\ninterface GeneratePackageListParams {\n platform: SupportedPlatform;\n targetPath: string;\n namespace: string;\n}\n\n/** Generates a source file listing all packages to link (Android-only) */\nexport async function generatePackageListAsync(\n modules: ModuleDescriptor[],\n params: GeneratePackageListParams\n) {\n const platformLinking = getLinkingImplementationForPlatform(params.platform);\n if (!('generatePackageListAsync' in platformLinking)) {\n throw new Error(`Generating package list is not available for platform \"${params.platform}\"`);\n }\n await platformLinking.generatePackageListAsync(modules, params.targetPath, params.namespace);\n}\n\ninterface GenerateModulesProviderParams {\n platform: SupportedPlatform;\n targetPath: string;\n entitlementPath: string | null;\n}\n\n/** Generates ExpoModulesProvider file listing all packages to link (Apple-only)\n */\nexport async function generateModulesProviderAsync(\n modules: ModuleDescriptor[],\n params: GenerateModulesProviderParams\n) {\n const platformLinking = getLinkingImplementationForPlatform(params.platform);\n if (!('generateModulesProviderAsync' in platformLinking)) {\n throw new Error(\n `Generating modules provider is not available for platform \"${params.platform}\"`\n );\n }\n await platformLinking.generateModulesProviderAsync(\n modules as ModuleDescriptorIos[],\n params.targetPath,\n params.entitlementPath\n );\n}\n"]}
@@ -0,0 +1,9 @@
import { AutolinkingOptions } from '../commands/autolinkingOptions';
import type { SupportedPlatform } from '../types';
interface GetConfigurationParams {
autolinkingOptions: AutolinkingOptions & {
platform: SupportedPlatform;
};
}
export declare function getConfiguration({ autolinkingOptions, }: GetConfigurationParams): Record<string, any> | undefined;
export {};
@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getConfiguration = getConfiguration;
const platforms_1 = require("../platforms");
function getConfiguration({ autolinkingOptions, }) {
const platformLinking = (0, platforms_1.getLinkingImplementationForPlatform)(autolinkingOptions.platform);
if ('getConfiguration' in platformLinking) {
return platformLinking.getConfiguration(autolinkingOptions);
}
else {
return undefined;
}
}
//# sourceMappingURL=getConfiguration.js.map
@@ -0,0 +1 @@
{"version":3,"file":"getConfiguration.js","sourceRoot":"","sources":["../../src/autolinking/getConfiguration.ts"],"names":[],"mappings":";;AAQA,4CASC;AAhBD,4CAAmE;AAOnE,SAAgB,gBAAgB,CAAC,EAC/B,kBAAkB,GACK;IACvB,MAAM,eAAe,GAAG,IAAA,+CAAmC,EAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACzF,IAAI,kBAAkB,IAAI,eAAe,EAAE,CAAC;QAC1C,OAAO,eAAe,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC","sourcesContent":["import { AutolinkingOptions } from '../commands/autolinkingOptions';\nimport { getLinkingImplementationForPlatform } from '../platforms';\nimport type { SupportedPlatform } from '../types';\n\ninterface GetConfigurationParams {\n autolinkingOptions: AutolinkingOptions & { platform: SupportedPlatform };\n}\n\nexport function getConfiguration({\n autolinkingOptions,\n}: GetConfigurationParams): Record<string, any> | undefined {\n const platformLinking = getLinkingImplementationForPlatform(autolinkingOptions.platform);\n if ('getConfiguration' in platformLinking) {\n return platformLinking.getConfiguration(autolinkingOptions);\n } else {\n return undefined;\n }\n}\n"]}
@@ -0,0 +1,23 @@
import { AutolinkingOptions } from '../commands/autolinkingOptions';
import { ExtraDependencies, ModuleDescriptor, SearchResults, SupportedPlatform } from '../types';
export { getConfiguration } from './getConfiguration';
export { generateModulesProviderAsync, generatePackageListAsync } from './generatePackageList';
/** @deprecated */
export interface SearchOptions extends Partial<AutolinkingOptions> {
projectRoot: string;
platform: SupportedPlatform;
[extra: string]: unknown;
}
/** @deprecated */
export interface ResolveOptions {
projectRoot: string;
platform: SupportedPlatform;
[extra: string]: unknown;
}
/** @deprecated */
declare function apiFindModulesAsync(providedOptions: SearchOptions): Promise<SearchResults>;
/** @deprecated */
declare function apiResolveExtraBuildDependenciesAsync(providedOptions: ResolveOptions): Promise<ExtraDependencies>;
/** @deprecated */
declare function apiResolveModulesAsync(searchResults: SearchResults, providedOptions: SearchOptions): Promise<ModuleDescriptor[]>;
export { apiFindModulesAsync as findModulesAsync, apiResolveExtraBuildDependenciesAsync as resolveExtraBuildDependenciesAsync, apiResolveModulesAsync as resolveModulesAsync, };
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generatePackageListAsync = exports.generateModulesProviderAsync = exports.getConfiguration = void 0;
exports.findModulesAsync = apiFindModulesAsync;
exports.resolveExtraBuildDependenciesAsync = apiResolveExtraBuildDependenciesAsync;
exports.resolveModulesAsync = apiResolveModulesAsync;
const autolinkingOptions_1 = require("../commands/autolinkingOptions");
const findModules_1 = require("./findModules");
const resolveModules_1 = require("./resolveModules");
var getConfiguration_1 = require("./getConfiguration");
Object.defineProperty(exports, "getConfiguration", { enumerable: true, get: function () { return getConfiguration_1.getConfiguration; } });
var generatePackageList_1 = require("./generatePackageList");
Object.defineProperty(exports, "generateModulesProviderAsync", { enumerable: true, get: function () { return generatePackageList_1.generateModulesProviderAsync; } });
Object.defineProperty(exports, "generatePackageListAsync", { enumerable: true, get: function () { return generatePackageList_1.generatePackageListAsync; } });
/** @deprecated */
async function apiFindModulesAsync(providedOptions) {
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)(providedOptions);
return (0, findModules_1.findModulesAsync)({
appRoot: await autolinkingOptionsLoader.getAppRoot(),
autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(providedOptions.platform),
});
}
/** @deprecated */
async function apiResolveExtraBuildDependenciesAsync(providedOptions) {
return (0, resolveModules_1.resolveExtraBuildDependenciesAsync)({
commandRoot: providedOptions.projectRoot,
platform: providedOptions.platform,
});
}
/** @deprecated */
async function apiResolveModulesAsync(searchResults, providedOptions) {
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)(providedOptions);
return (0, resolveModules_1.resolveModulesAsync)(searchResults, await autolinkingOptionsLoader.getPlatformOptions(providedOptions.platform));
}
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/autolinking/index.ts"],"names":[],"mappings":";;;AAsDyB,+CAAgB;AACE,mFAAkC;AACjD,qDAAmB;AAxD/C,uEAAoG;AAEpG,+CAAiD;AACjD,qDAA2F;AAE3F,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,6DAA+F;AAAtF,mIAAA,4BAA4B,OAAA;AAAE,+HAAA,wBAAwB,OAAA;AAgB/D,kBAAkB;AAClB,KAAK,UAAU,mBAAmB,CAAC,eAA8B;IAC/D,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC,eAAe,CAAC,CAAC;IACjF,OAAO,IAAA,8BAAgB,EAAC;QACtB,OAAO,EAAE,MAAM,wBAAwB,CAAC,UAAU,EAAE;QACpD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,eAAe,CAAC,QAAQ,CAAC;KAChG,CAAC,CAAC;AACL,CAAC;AAED,kBAAkB;AAClB,KAAK,UAAU,qCAAqC,CAClD,eAA+B;IAE/B,OAAO,IAAA,mDAAkC,EAAC;QACxC,WAAW,EAAE,eAAe,CAAC,WAAW;QACxC,QAAQ,EAAE,eAAe,CAAC,QAAQ;KACnC,CAAC,CAAC;AACL,CAAC;AAED,kBAAkB;AAClB,KAAK,UAAU,sBAAsB,CACnC,aAA4B,EAC5B,eAA8B;IAE9B,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC,eAAe,CAAC,CAAC;IACjF,OAAO,IAAA,oCAAmB,EACxB,aAAa,EACb,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,eAAe,CAAC,QAAQ,CAAC,CAC5E,CAAC;AACJ,CAAC","sourcesContent":["import { AutolinkingOptions, createAutolinkingOptionsLoader } from '../commands/autolinkingOptions';\nimport { ExtraDependencies, ModuleDescriptor, SearchResults, SupportedPlatform } from '../types';\nimport { findModulesAsync } from './findModules';\nimport { resolveExtraBuildDependenciesAsync, resolveModulesAsync } from './resolveModules';\n\nexport { getConfiguration } from './getConfiguration';\nexport { generateModulesProviderAsync, generatePackageListAsync } from './generatePackageList';\n\n/** @deprecated */\nexport interface SearchOptions extends Partial<AutolinkingOptions> {\n projectRoot: string;\n platform: SupportedPlatform;\n [extra: string]: unknown;\n}\n\n/** @deprecated */\nexport interface ResolveOptions {\n projectRoot: string;\n platform: SupportedPlatform;\n [extra: string]: unknown;\n}\n\n/** @deprecated */\nasync function apiFindModulesAsync(providedOptions: SearchOptions): Promise<SearchResults> {\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader(providedOptions);\n return findModulesAsync({\n appRoot: await autolinkingOptionsLoader.getAppRoot(),\n autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(providedOptions.platform),\n });\n}\n\n/** @deprecated */\nasync function apiResolveExtraBuildDependenciesAsync(\n providedOptions: ResolveOptions\n): Promise<ExtraDependencies> {\n return resolveExtraBuildDependenciesAsync({\n commandRoot: providedOptions.projectRoot,\n platform: providedOptions.platform,\n });\n}\n\n/** @deprecated */\nasync function apiResolveModulesAsync(\n searchResults: SearchResults,\n providedOptions: SearchOptions\n): Promise<ModuleDescriptor[]> {\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader(providedOptions);\n return resolveModulesAsync(\n searchResults,\n await autolinkingOptionsLoader.getPlatformOptions(providedOptions.platform)\n );\n}\n\nexport {\n apiFindModulesAsync as findModulesAsync,\n apiResolveExtraBuildDependenciesAsync as resolveExtraBuildDependenciesAsync,\n apiResolveModulesAsync as resolveModulesAsync,\n};\n"]}
@@ -0,0 +1,13 @@
import { AutolinkingOptions } from '../commands/autolinkingOptions';
import type { ExtraDependencies, ModuleDescriptor, SearchResults, SupportedPlatform } from '../types';
/** Resolves search results to a list of platform-specific configuration. */
export declare function resolveModulesAsync(searchResults: SearchResults, autolinkingOptions: AutolinkingOptions & {
platform: SupportedPlatform;
}): Promise<ModuleDescriptor[]>;
interface ResolveExtraBuildDependenciesParams {
commandRoot: string;
platform: SupportedPlatform;
}
/** Resolves the extra build dependencies for the project, such as additional Maven repositories or CocoaPods pods. */
export declare function resolveExtraBuildDependenciesAsync({ commandRoot, platform, }: ResolveExtraBuildDependenciesParams): Promise<ExtraDependencies>;
export {};
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveModulesAsync = resolveModulesAsync;
exports.resolveExtraBuildDependenciesAsync = resolveExtraBuildDependenciesAsync;
const platforms_1 = require("../platforms");
/** Resolves search results to a list of platform-specific configuration. */
async function resolveModulesAsync(searchResults, autolinkingOptions) {
const platformLinking = (0, platforms_1.getLinkingImplementationForPlatform)(autolinkingOptions.platform);
// Additional output property for Cocoapods flags
const extraOutput = { flags: autolinkingOptions.flags };
const moduleDescriptorList = await Promise.all(Object.entries(searchResults).map(async ([packageName, revision]) => {
const resolvedModule = await platformLinking.resolveModuleAsync(packageName, revision, extraOutput);
return resolvedModule
? {
...resolvedModule,
packageVersion: revision.version,
packageName: resolvedModule.packageName ?? packageName,
}
: null;
}));
return moduleDescriptorList
.filter((moduleDescriptor) => moduleDescriptor != null)
.sort((a, b) => a.packageName.localeCompare(b.packageName));
}
/** Resolves the extra build dependencies for the project, such as additional Maven repositories or CocoaPods pods. */
async function resolveExtraBuildDependenciesAsync({ commandRoot, platform, }) {
const platformLinking = (0, platforms_1.getLinkingImplementationForPlatform)(platform);
const extraDependencies = await platformLinking.resolveExtraBuildDependenciesAsync(
// NOTE: We assume we must be inside the native folder here
// The `resolve` command either is invoked in the CWD of `./{android,ios}` or has a `--project-root`
// that's in the native directory
commandRoot);
return extraDependencies ?? [];
}
//# sourceMappingURL=resolveModules.js.map
@@ -0,0 +1 @@
{"version":3,"file":"resolveModules.js","sourceRoot":"","sources":["../../src/autolinking/resolveModules.ts"],"names":[],"mappings":";;AAUA,kDA4BC;AAQD,gFAYC;AAzDD,4CAAmE;AAQnE,4EAA4E;AACrE,KAAK,UAAU,mBAAmB,CACvC,aAA4B,EAC5B,kBAAwE;IAExE,MAAM,eAAe,GAAG,IAAA,+CAAmC,EAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACzF,iDAAiD;IACjD,MAAM,WAAW,GAAG,EAAE,KAAK,EAAE,kBAAkB,CAAC,KAAK,EAAE,CAAC;IAExD,MAAM,oBAAoB,GAAG,MAAM,OAAO,CAAC,GAAG,CAC5C,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE;QAClE,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,kBAAkB,CAC7D,WAAW,EACX,QAAQ,EACR,WAAW,CACZ,CAAC;QACF,OAAO,cAAc;YACnB,CAAC,CAAC;gBACE,GAAG,cAAc;gBACjB,cAAc,EAAE,QAAQ,CAAC,OAAO;gBAChC,WAAW,EAAE,cAAc,CAAC,WAAW,IAAI,WAAW;aACvD;YACH,CAAC,CAAC,IAAI,CAAC;IACX,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,oBAAoB;SACxB,MAAM,CAAC,CAAC,gBAAgB,EAAE,EAAE,CAAC,gBAAgB,IAAI,IAAI,CAAC;SACtD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAChE,CAAC;AAOD,sHAAsH;AAC/G,KAAK,UAAU,kCAAkC,CAAC,EACvD,WAAW,EACX,QAAQ,GAC4B;IACpC,MAAM,eAAe,GAAG,IAAA,+CAAmC,EAAC,QAAQ,CAAC,CAAC;IACtE,MAAM,iBAAiB,GAAG,MAAM,eAAe,CAAC,kCAAkC;IAChF,2DAA2D;IAC3D,oGAAoG;IACpG,iCAAiC;IACjC,WAAW,CACZ,CAAC;IACF,OAAO,iBAAiB,IAAI,EAAE,CAAC;AACjC,CAAC","sourcesContent":["import { AutolinkingOptions } from '../commands/autolinkingOptions';\nimport { getLinkingImplementationForPlatform } from '../platforms';\nimport type {\n ExtraDependencies,\n ModuleDescriptor,\n SearchResults,\n SupportedPlatform,\n} from '../types';\n\n/** Resolves search results to a list of platform-specific configuration. */\nexport async function resolveModulesAsync(\n searchResults: SearchResults,\n autolinkingOptions: AutolinkingOptions & { platform: SupportedPlatform }\n): Promise<ModuleDescriptor[]> {\n const platformLinking = getLinkingImplementationForPlatform(autolinkingOptions.platform);\n // Additional output property for Cocoapods flags\n const extraOutput = { flags: autolinkingOptions.flags };\n\n const moduleDescriptorList = await Promise.all(\n Object.entries(searchResults).map(async ([packageName, revision]) => {\n const resolvedModule = await platformLinking.resolveModuleAsync(\n packageName,\n revision,\n extraOutput\n );\n return resolvedModule\n ? {\n ...resolvedModule,\n packageVersion: revision.version,\n packageName: resolvedModule.packageName ?? packageName,\n }\n : null;\n })\n );\n\n return moduleDescriptorList\n .filter((moduleDescriptor) => moduleDescriptor != null)\n .sort((a, b) => a.packageName.localeCompare(b.packageName));\n}\n\ninterface ResolveExtraBuildDependenciesParams {\n commandRoot: string;\n platform: SupportedPlatform;\n}\n\n/** Resolves the extra build dependencies for the project, such as additional Maven repositories or CocoaPods pods. */\nexport async function resolveExtraBuildDependenciesAsync({\n commandRoot,\n platform,\n}: ResolveExtraBuildDependenciesParams): Promise<ExtraDependencies> {\n const platformLinking = getLinkingImplementationForPlatform(platform);\n const extraDependencies = await platformLinking.resolveExtraBuildDependenciesAsync(\n // NOTE: We assume we must be inside the native folder here\n // The `resolve` command either is invoked in the CWD of `./{android,ios}` or has a `--project-root`\n // that's in the native directory\n commandRoot\n );\n return extraDependencies ?? [];\n}\n"]}
@@ -0,0 +1,50 @@
import commander from 'commander';
import { SupportedPlatform } from '../types';
export interface AutolinkingOptions {
/** Only scan direct "dependencies" of a project for React Native modules, rather than including transitive dependencies.
* @remarks
* Before SDK 54, React Native modules would only be linked if they were listed as dependencies
* of a project. However, in SDK 54+ transitive React Native modules dependencies are also
* auto-linked, unless this flag is enabled.
* @defaultValue `false`
*/
legacy_shallowReactNativeLinking: boolean;
/** Extra modules directories to search for native modules.
* @defaultValue `[]`
*/
searchPaths: string[];
/** Local native modules directory to add to autolinking.
* @defaultValue `"./modules"`
*/
nativeModulesDir: string | null;
/** Native modules to exclude from autolinking by name.
* @defaultValue `[]`
*/
exclude: string[];
/** A list of package names to opt out of prebuilt Expo modules (Android-only)
* @defaultValue `[]`
*/
buildFromSource?: string[];
/** CocoaPods flags to pass to each autolinked pod (Apple/iOS-only)
* @defaultValue `[]`
*/
flags?: Record<string, any>;
}
export declare const filterMapSearchPaths: (searchPaths: unknown, basePath: string) => string[] | undefined;
/** Common commandline arguments for autolinking commands (Not to be confused with `AutolinkingOptions` */
export interface AutolinkingCommonArguments {
projectRoot?: string | null;
searchPaths?: string[] | null;
exclude?: string[] | null;
platform?: SupportedPlatform | null;
}
export declare function registerAutolinkingArguments(command: commander.Command): commander.Command;
export interface LinkingOptionsLoader {
getCommandRoot(): string;
getAppRoot(): Promise<string>;
getPlatformOptions<T extends SupportedPlatform | undefined>(platform: T): Promise<AutolinkingOptions & {
platform: T;
}>;
getPlatformOptions(): Promise<AutolinkingOptions>;
}
export declare function createAutolinkingOptionsLoader(argumentsOptions?: AutolinkingCommonArguments): LinkingOptionsLoader;
@@ -0,0 +1,170 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.filterMapSearchPaths = void 0;
exports.registerAutolinkingArguments = registerAutolinkingArguments;
exports.createAutolinkingOptionsLoader = createAutolinkingOptionsLoader;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const isJSONObject = (x) => x != null && typeof x === 'object';
const resolvePathMaybe = (target, basePath) => {
if (typeof target !== 'string') {
return null;
}
let resolved = path_1.default.resolve(basePath, target);
if (fs_1.default.existsSync(resolved)) {
return resolved;
}
else if ((resolved = path_1.default.resolve(target)) && fs_1.default.existsSync(target)) {
// TODO(@kitten): This is here for legacy support. However, this *will* be inconsistent
// This relies on the current working directory, and hence, can behave differently depending
// on where the command was invoked.
return target;
}
else {
return null;
}
};
const filterMapSearchPaths = (searchPaths, basePath) => {
if (Array.isArray(searchPaths)) {
return searchPaths
.map((searchPath) => resolvePathMaybe(searchPath, basePath))
.filter((searchPath) => searchPath != null);
}
else {
return undefined;
}
};
exports.filterMapSearchPaths = filterMapSearchPaths;
const parsePackageJsonOptions = (packageJson, appRoot, platform) => {
const expo = isJSONObject(packageJson.expo) ? packageJson.expo : null;
const autolinkingOptions = expo && isJSONObject(expo.autolinking) ? expo.autolinking : null;
let platformOptions = null;
if (platform) {
platformOptions =
autolinkingOptions && isJSONObject(autolinkingOptions[platform])
? autolinkingOptions[platform]
: null;
if (!platformOptions && platform === 'apple') {
// NOTE: `platform: 'apple'` has a fallback on `ios`. This doesn't make much sense, since apple should
// be the base option for other apple platforms, but changing this now is a breaking change
platformOptions =
autolinkingOptions && isJSONObject(autolinkingOptions.ios) ? autolinkingOptions.ios : null;
}
}
const mergedOptions = { ...autolinkingOptions, ...platformOptions };
const outputOptions = {};
// legacy_shallowReactNativeLinking
if (mergedOptions.legacy_shallowReactNativeLinking != null) {
outputOptions.legacy_shallowReactNativeLinking =
!!mergedOptions.legacy_shallowReactNativeLinking;
}
// searchPaths
if (typeof mergedOptions.searchPaths === 'string' || Array.isArray(mergedOptions.searchPaths)) {
const rawSearchPaths = typeof mergedOptions.searchPaths === 'string'
? [mergedOptions.searchPaths]
: mergedOptions.searchPaths;
outputOptions.searchPaths = (0, exports.filterMapSearchPaths)(rawSearchPaths, appRoot);
}
// nativeModulesDir
if (typeof mergedOptions.nativeModulesDir === 'string') {
outputOptions.nativeModulesDir = resolvePathMaybe(mergedOptions.nativeModulesDir, appRoot);
}
// exclude
if (Array.isArray(mergedOptions.exclude)) {
outputOptions.exclude = mergedOptions.exclude.filter((x) => typeof x === 'string');
}
// buildFromSource
if (Array.isArray(mergedOptions.buildFromSource)) {
outputOptions.buildFromSource = mergedOptions.buildFromSource.filter((x) => typeof x === 'string');
}
// flags
if (isJSONObject(mergedOptions.flags)) {
outputOptions.flags = { ...mergedOptions.flags };
}
return outputOptions;
};
function registerAutolinkingArguments(command) {
return command
.option('-e, --exclude <exclude...>', 'Package names to exclude when looking up for modules.', (value, previous) => (previous ?? []).concat(value))
.option('-p, --platform [platform]', 'The platform that the resulting modules must support. Available options: "apple", "android"', 'apple')
.option(
// NOTE(@kitten): For backwards-compatibility, this is still called `project-root`, but it
// really is a replacement path for the current working directory. Henceforth called `commandRoot`
'--project-root <projectRoot>', 'The path to the root of the project. Defaults to current working directory', process.cwd());
}
const parseExtraArgumentsOptions = (args) => {
const cwd = process.cwd();
const platform = args.platform || undefined;
const commandRoot = resolvePathMaybe(args.projectRoot, cwd) || cwd;
const extraSearchPaths = (0, exports.filterMapSearchPaths)(args.searchPaths, commandRoot);
const extraExclude = args.exclude?.filter((name) => typeof name === 'string');
return {
platform,
commandRoot,
extraSearchPaths,
extraExclude,
};
};
const findPackageJsonPathAsync = async (commandRoot) => {
const root = commandRoot || process.cwd();
for (let dir = root; path_1.default.dirname(dir) !== dir; dir = path_1.default.dirname(dir)) {
const file = path_1.default.resolve(dir, 'package.json');
if (fs_1.default.existsSync(file)) {
return file;
}
}
throw new Error(`Couldn't find "package.json" up from path "${root}"`);
};
const loadPackageJSONAsync = async (packageJsonPath) => {
const packageJsonText = await fs_1.default.promises.readFile(packageJsonPath, 'utf8');
return JSON.parse(packageJsonText);
};
function createAutolinkingOptionsLoader(argumentsOptions) {
const extraArgumentsOptions = parseExtraArgumentsOptions(argumentsOptions ?? {});
const { commandRoot } = extraArgumentsOptions;
let _packageJsonPath$;
const getPackageJsonPath = () => {
return _packageJsonPath$ || (_packageJsonPath$ = findPackageJsonPathAsync(commandRoot));
};
let _packageJson$;
const getPackageJson = async () => _packageJson$ || (_packageJson$ = loadPackageJSONAsync(await getPackageJsonPath()));
const getAppRoot = async () => path_1.default.dirname(await getPackageJsonPath());
return {
getCommandRoot: () => commandRoot,
getAppRoot,
async getPlatformOptions(platform = extraArgumentsOptions.platform) {
const packageJson = await getPackageJson();
const appRoot = await getAppRoot();
const options = parsePackageJsonOptions(packageJson, appRoot, platform);
if (extraArgumentsOptions.extraSearchPaths) {
options.searchPaths = [
...extraArgumentsOptions.extraSearchPaths,
...(options.searchPaths ?? []),
];
}
if (extraArgumentsOptions.extraExclude) {
options.exclude = [...(options.exclude ?? []), ...extraArgumentsOptions.extraExclude];
}
return {
...normalizeAutolinkingOptions(options, appRoot),
platform,
};
},
};
}
const normalizeAutolinkingOptions = (options, appRoot) => {
return {
legacy_shallowReactNativeLinking: options.legacy_shallowReactNativeLinking ?? false,
searchPaths: options.searchPaths ?? [],
nativeModulesDir: options.nativeModulesDir
? (resolvePathMaybe(options.nativeModulesDir, appRoot) ?? null)
: (resolvePathMaybe('./modules', appRoot) ?? null),
exclude: options.exclude ?? [],
buildFromSource: options.buildFromSource,
flags: options.flags,
};
};
//# sourceMappingURL=autolinkingOptions.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
import commander from 'commander';
/** Generates a source file listing all packages to link in the runtime */
export declare function generateModulesProviderCommand(cli: commander.CommanderStatic): commander.Command;
@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateModulesProviderCommand = generateModulesProviderCommand;
const autolinkingOptions_1 = require("./autolinkingOptions");
const findModules_1 = require("../autolinking/findModules");
const generatePackageList_1 = require("../autolinking/generatePackageList");
const resolveModules_1 = require("../autolinking/resolveModules");
/** Generates a source file listing all packages to link in the runtime */
function generateModulesProviderCommand(cli) {
return (0, autolinkingOptions_1.registerAutolinkingArguments)(cli.command('generate-modules-provider [searchPaths...]'))
.option('-t, --target <path>', 'Path to the target file, where the package list should be written to.')
.option('--entitlement <path>', 'Path to the Apple code signing entitlements file.')
.option('-p, --packages <packages...>', 'Names of the packages to include in the generated modules provider.')
.option('--app-root <path>', 'Path to the app root directory.')
.action(async (searchPaths, commandArguments) => {
const platform = commandArguments.platform ?? 'apple';
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)({
...commandArguments,
searchPaths,
});
const autolinkingOptions = await autolinkingOptionsLoader.getPlatformOptions(platform);
const expoModulesSearchResults = await (0, findModules_1.findModulesAsync)({
autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),
appRoot: commandArguments.appRoot ?? (await autolinkingOptionsLoader.getAppRoot()),
});
const expoModulesResolveResults = await (0, resolveModules_1.resolveModulesAsync)(expoModulesSearchResults, autolinkingOptions);
const includeModules = new Set(commandArguments.packages ?? []);
const filteredModules = expoModulesResolveResults.filter((module) => includeModules.has(module.packageName));
await (0, generatePackageList_1.generateModulesProviderAsync)(filteredModules, {
platform,
targetPath: commandArguments.target,
entitlementPath: commandArguments.entitlement ?? null,
});
});
}
//# sourceMappingURL=generateModulesProviderCommand.js.map
@@ -0,0 +1 @@
{"version":3,"file":"generateModulesProviderCommand.js","sourceRoot":"","sources":["../../src/commands/generateModulesProviderCommand.ts"],"names":[],"mappings":";;AAmBA,wEA0CC;AA3DD,6DAI8B;AAC9B,4DAA8D;AAC9D,4EAAkF;AAClF,kEAAoE;AASpE,0EAA0E;AAC1E,SAAgB,8BAA8B,CAAC,GAA8B;IAC3E,OAAO,IAAA,iDAA4B,EAAC,GAAG,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;SAC3F,MAAM,CACL,qBAAqB,EACrB,uEAAuE,CACxE;SACA,MAAM,CAAC,sBAAsB,EAAE,mDAAmD,CAAC;SACnF,MAAM,CACL,8BAA8B,EAC9B,qEAAqE,CACtE;SACA,MAAM,CAAC,mBAAmB,EAAE,iCAAiC,CAAC;SAC9D,MAAM,CACL,KAAK,EAAE,WAA4B,EAAE,gBAAkD,EAAE,EAAE;QACzF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,IAAI,OAAO,CAAC;QACtD,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC;YAC9D,GAAG,gBAAgB;YACnB,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,kBAAkB,GAAG,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAEvF,MAAM,wBAAwB,GAAG,MAAM,IAAA,8BAAgB,EAAC;YACtD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC;YAC/E,OAAO,EAAE,gBAAgB,CAAC,OAAO,IAAI,CAAC,MAAM,wBAAwB,CAAC,UAAU,EAAE,CAAC;SACnF,CAAC,CAAC;QACH,MAAM,yBAAyB,GAAG,MAAM,IAAA,oCAAmB,EACzD,wBAAwB,EACxB,kBAAkB,CACnB,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,eAAe,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAClE,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CACvC,CAAC;QAEF,MAAM,IAAA,kDAA4B,EAAC,eAAe,EAAE;YAClD,QAAQ;YACR,UAAU,EAAE,gBAAgB,CAAC,MAAM;YACnC,eAAe,EAAE,gBAAgB,CAAC,WAAW,IAAI,IAAI;SACtD,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACN,CAAC","sourcesContent":["import commander from 'commander';\n\nimport {\n AutolinkingCommonArguments,\n createAutolinkingOptionsLoader,\n registerAutolinkingArguments,\n} from './autolinkingOptions';\nimport { findModulesAsync } from '../autolinking/findModules';\nimport { generateModulesProviderAsync } from '../autolinking/generatePackageList';\nimport { resolveModulesAsync } from '../autolinking/resolveModules';\n\ninterface GenerateModulesProviderArguments extends AutolinkingCommonArguments {\n target: string;\n entitlement?: string;\n packages?: string[] | null;\n appRoot?: string;\n}\n\n/** Generates a source file listing all packages to link in the runtime */\nexport function generateModulesProviderCommand(cli: commander.CommanderStatic) {\n return registerAutolinkingArguments(cli.command('generate-modules-provider [searchPaths...]'))\n .option(\n '-t, --target <path>',\n 'Path to the target file, where the package list should be written to.'\n )\n .option('--entitlement <path>', 'Path to the Apple code signing entitlements file.')\n .option(\n '-p, --packages <packages...>',\n 'Names of the packages to include in the generated modules provider.'\n )\n .option('--app-root <path>', 'Path to the app root directory.')\n .action(\n async (searchPaths: string[] | null, commandArguments: GenerateModulesProviderArguments) => {\n const platform = commandArguments.platform ?? 'apple';\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader({\n ...commandArguments,\n searchPaths,\n });\n const autolinkingOptions = await autolinkingOptionsLoader.getPlatformOptions(platform);\n\n const expoModulesSearchResults = await findModulesAsync({\n autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),\n appRoot: commandArguments.appRoot ?? (await autolinkingOptionsLoader.getAppRoot()),\n });\n const expoModulesResolveResults = await resolveModulesAsync(\n expoModulesSearchResults,\n autolinkingOptions\n );\n\n const includeModules = new Set(commandArguments.packages ?? []);\n const filteredModules = expoModulesResolveResults.filter((module) =>\n includeModules.has(module.packageName)\n );\n\n await generateModulesProviderAsync(filteredModules, {\n platform,\n targetPath: commandArguments.target,\n entitlementPath: commandArguments.entitlement ?? null,\n });\n }\n );\n}\n"]}
@@ -0,0 +1,6 @@
import commander from 'commander';
/** Generates a source file listing all packages to link.
* @privateRemarks
* This command is deprecated for apple platforms, use `generate-modules-provider` instead.
*/
export declare function generatePackageListCommand(cli: commander.CommanderStatic): commander.Command;
@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generatePackageListCommand = generatePackageListCommand;
const autolinkingOptions_1 = require("./autolinkingOptions");
const findModules_1 = require("../autolinking/findModules");
const generatePackageList_1 = require("../autolinking/generatePackageList");
const resolveModules_1 = require("../autolinking/resolveModules");
/** Generates a source file listing all packages to link.
* @privateRemarks
* This command is deprecated for apple platforms, use `generate-modules-provider` instead.
*/
function generatePackageListCommand(cli) {
return (0, autolinkingOptions_1.registerAutolinkingArguments)(cli.command('generate-package-list [searchPaths...]'))
.option('-t, --target <path>', 'Path to the target file, where the package list should be written to.')
.option('-n, --namespace <namespace>', 'Java package name under which the package list should be placed.')
.option('--empty', 'Whether to only generate an empty list. Might be used when the user opts-out of autolinking.', false)
.action(async (searchPaths, commandArguments) => {
const platform = commandArguments.platform ?? 'android';
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)({
...commandArguments,
searchPaths,
});
let expoModulesResolveResults = [];
if (!commandArguments.empty) {
const autolinkingOptions = await autolinkingOptionsLoader.getPlatformOptions(platform);
const expoModulesSearchResults = await (0, findModules_1.findModulesAsync)({
autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),
appRoot: await autolinkingOptionsLoader.getAppRoot(),
});
expoModulesResolveResults = await (0, resolveModules_1.resolveModulesAsync)(expoModulesSearchResults, autolinkingOptions);
}
await (0, generatePackageList_1.generatePackageListAsync)(expoModulesResolveResults, {
platform,
targetPath: commandArguments.target,
namespace: commandArguments.namespace,
});
});
}
//# sourceMappingURL=generatePackageListCommand.js.map
@@ -0,0 +1 @@
{"version":3,"file":"generatePackageListCommand.js","sourceRoot":"","sources":["../../src/commands/generatePackageListCommand.ts"],"names":[],"mappings":";;AAsBA,gEA4CC;AAhED,6DAI8B;AAC9B,4DAA8D;AAC9D,4EAA8E;AAC9E,kEAAoE;AASpE;;;GAGG;AACH,SAAgB,0BAA0B,CAAC,GAA8B;IACvE,OAAO,IAAA,iDAA4B,EAAC,GAAG,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;SACvF,MAAM,CACL,qBAAqB,EACrB,uEAAuE,CACxE;SACA,MAAM,CACL,6BAA6B,EAC7B,kEAAkE,CACnE;SACA,MAAM,CACL,SAAS,EACT,8FAA8F,EAC9F,KAAK,CACN;SACA,MAAM,CACL,KAAK,EAAE,WAA4B,EAAE,gBAA8C,EAAE,EAAE;QACrF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,IAAI,SAAS,CAAC;QACxD,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC;YAC9D,GAAG,gBAAgB;YACnB,WAAW;SACZ,CAAC,CAAC;QAEH,IAAI,yBAAyB,GAAuB,EAAE,CAAC;QACvD,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;YAC5B,MAAM,kBAAkB,GAAG,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YAEvF,MAAM,wBAAwB,GAAG,MAAM,IAAA,8BAAgB,EAAC;gBACtD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC;gBAC/E,OAAO,EAAE,MAAM,wBAAwB,CAAC,UAAU,EAAE;aACrD,CAAC,CAAC;YACH,yBAAyB,GAAG,MAAM,IAAA,oCAAmB,EACnD,wBAAwB,EACxB,kBAAkB,CACnB,CAAC;QACJ,CAAC;QAED,MAAM,IAAA,8CAAwB,EAAC,yBAAyB,EAAE;YACxD,QAAQ;YACR,UAAU,EAAE,gBAAgB,CAAC,MAAM;YACnC,SAAS,EAAE,gBAAgB,CAAC,SAAS;SACtC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACN,CAAC","sourcesContent":["import commander from 'commander';\n\nimport {\n AutolinkingCommonArguments,\n createAutolinkingOptionsLoader,\n registerAutolinkingArguments,\n} from './autolinkingOptions';\nimport { findModulesAsync } from '../autolinking/findModules';\nimport { generatePackageListAsync } from '../autolinking/generatePackageList';\nimport { resolveModulesAsync } from '../autolinking/resolveModules';\nimport type { ModuleDescriptor } from '../types';\n\ninterface GeneratePackageListArguments extends AutolinkingCommonArguments {\n target: string;\n namespace: string;\n empty: boolean;\n}\n\n/** Generates a source file listing all packages to link.\n * @privateRemarks\n * This command is deprecated for apple platforms, use `generate-modules-provider` instead.\n */\nexport function generatePackageListCommand(cli: commander.CommanderStatic) {\n return registerAutolinkingArguments(cli.command('generate-package-list [searchPaths...]'))\n .option(\n '-t, --target <path>',\n 'Path to the target file, where the package list should be written to.'\n )\n .option(\n '-n, --namespace <namespace>',\n 'Java package name under which the package list should be placed.'\n )\n .option(\n '--empty',\n 'Whether to only generate an empty list. Might be used when the user opts-out of autolinking.',\n false\n )\n .action(\n async (searchPaths: string[] | null, commandArguments: GeneratePackageListArguments) => {\n const platform = commandArguments.platform ?? 'android';\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader({\n ...commandArguments,\n searchPaths,\n });\n\n let expoModulesResolveResults: ModuleDescriptor[] = [];\n if (!commandArguments.empty) {\n const autolinkingOptions = await autolinkingOptionsLoader.getPlatformOptions(platform);\n\n const expoModulesSearchResults = await findModulesAsync({\n autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),\n appRoot: await autolinkingOptionsLoader.getAppRoot(),\n });\n expoModulesResolveResults = await resolveModulesAsync(\n expoModulesSearchResults,\n autolinkingOptions\n );\n }\n\n await generatePackageListAsync(expoModulesResolveResults, {\n platform,\n targetPath: commandArguments.target,\n namespace: commandArguments.namespace,\n });\n }\n );\n}\n"]}
@@ -0,0 +1,3 @@
import commander from 'commander';
/** The react-native-config command (like RN CLI linking) */
export declare function reactNativeConfigCommand(cli: commander.CommanderStatic): commander.Command;
@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.reactNativeConfigCommand = reactNativeConfigCommand;
const autolinkingOptions_1 = require("./autolinkingOptions");
const reactNativeConfig_1 = require("../reactNativeConfig");
/** The react-native-config command (like RN CLI linking) */
function reactNativeConfigCommand(cli) {
return (0, autolinkingOptions_1.registerAutolinkingArguments)(cli.command('react-native-config [searchPaths...]'))
.option('-p, --platform [platform]', 'The platform that the resulting modules must support. Available options: "android", "ios"', 'ios')
.option('--source-dir <sourceDir>', 'The path to the native source directory')
.option('-j, --json', 'Output results in the plain JSON format.', () => true, false)
.action(async (searchPaths, commandArguments) => {
// TODO(@kitten): Do we need to restrict this?
const platform = commandArguments.platform ?? 'ios';
if (platform !== 'android' && platform !== 'ios') {
throw new Error(`Unsupported platform: ${platform}`);
}
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)({
...commandArguments,
searchPaths,
});
const reactNativeConfig = await (0, reactNativeConfig_1.createReactNativeConfigAsync)({
autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),
appRoot: await autolinkingOptionsLoader.getAppRoot(),
// NOTE(@kitten): This is currently not validated, and assumed to be validated later
sourceDir: commandArguments.sourceDir ?? undefined,
});
if (commandArguments.json) {
console.log(JSON.stringify(reactNativeConfig));
}
else {
console.log(require('util').inspect(reactNativeConfig, false, null, true));
}
});
}
//# sourceMappingURL=reactNativeConfigCommand.js.map
@@ -0,0 +1 @@
{"version":3,"file":"reactNativeConfigCommand.js","sourceRoot":"","sources":["../../src/commands/reactNativeConfigCommand.ts"],"names":[],"mappings":";;AAeA,4DAkCC;AA/CD,6DAI8B;AAC9B,4DAAoE;AAOpE,4DAA4D;AAC5D,SAAgB,wBAAwB,CAAC,GAA8B;IACrE,OAAO,IAAA,iDAA4B,EAAC,GAAG,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC;SACrF,MAAM,CACL,2BAA2B,EAC3B,2FAA2F,EAC3F,KAAK,CACN;SACA,MAAM,CAAC,0BAA0B,EAAE,yCAAyC,CAAC;SAC7E,MAAM,CAAC,YAAY,EAAE,0CAA0C,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;SACnF,MAAM,CAAC,KAAK,EAAE,WAA4B,EAAE,gBAA4C,EAAE,EAAE;QAC3F,8CAA8C;QAC9C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,IAAI,KAAK,CAAC;QACpD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC;YAC9D,GAAG,gBAAgB;YACnB,WAAW;SACZ,CAAC,CAAC;QAEH,MAAM,iBAAiB,GAAG,MAAM,IAAA,gDAA4B,EAAC;YAC3D,kBAAkB,EAAE,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC;YAC/E,OAAO,EAAE,MAAM,wBAAwB,CAAC,UAAU,EAAE;YACpD,oFAAoF;YACpF,SAAS,EAAE,gBAAgB,CAAC,SAAS,IAAI,SAAS;SACnD,CAAC,CAAC;QAEH,IAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["import commander from 'commander';\n\nimport {\n AutolinkingCommonArguments,\n createAutolinkingOptionsLoader,\n registerAutolinkingArguments,\n} from './autolinkingOptions';\nimport { createReactNativeConfigAsync } from '../reactNativeConfig';\n\ninterface ReactNativeConfigArguments extends AutolinkingCommonArguments {\n sourceDir?: string | null;\n json?: boolean | null;\n}\n\n/** The react-native-config command (like RN CLI linking) */\nexport function reactNativeConfigCommand(cli: commander.CommanderStatic) {\n return registerAutolinkingArguments(cli.command('react-native-config [searchPaths...]'))\n .option(\n '-p, --platform [platform]',\n 'The platform that the resulting modules must support. Available options: \"android\", \"ios\"',\n 'ios'\n )\n .option('--source-dir <sourceDir>', 'The path to the native source directory')\n .option('-j, --json', 'Output results in the plain JSON format.', () => true, false)\n .action(async (searchPaths: string[] | null, commandArguments: ReactNativeConfigArguments) => {\n // TODO(@kitten): Do we need to restrict this?\n const platform = commandArguments.platform ?? 'ios';\n if (platform !== 'android' && platform !== 'ios') {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader({\n ...commandArguments,\n searchPaths,\n });\n\n const reactNativeConfig = await createReactNativeConfigAsync({\n autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),\n appRoot: await autolinkingOptionsLoader.getAppRoot(),\n // NOTE(@kitten): This is currently not validated, and assumed to be validated later\n sourceDir: commandArguments.sourceDir ?? undefined,\n });\n\n if (commandArguments.json) {\n console.log(JSON.stringify(reactNativeConfig));\n } else {\n console.log(require('util').inspect(reactNativeConfig, false, null, true));\n }\n });\n}\n"]}
@@ -0,0 +1,3 @@
import commander from 'commander';
/** Searches for available expo modules and resolves the results for given platform. */
export declare function resolveCommand(cli: commander.CommanderStatic): commander.Command;
@@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveCommand = resolveCommand;
const autolinkingOptions_1 = require("./autolinkingOptions");
const findModules_1 = require("../autolinking/findModules");
const getConfiguration_1 = require("../autolinking/getConfiguration");
const resolveModules_1 = require("../autolinking/resolveModules");
function hasCoreFeatures(module) {
return module.coreFeatures !== undefined;
}
/** Searches for available expo modules and resolves the results for given platform. */
function resolveCommand(cli) {
return (0, autolinkingOptions_1.registerAutolinkingArguments)(cli.command('resolve [searchPaths...]'))
.option('-j, --json', 'Output results in the plain JSON format.', () => true, false)
.action(async (searchPaths, commandArguments) => {
const platform = commandArguments.platform ?? 'apple';
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)({
...commandArguments,
searchPaths,
});
const autolinkingOptions = await autolinkingOptionsLoader.getPlatformOptions(platform);
const appRoot = await autolinkingOptionsLoader.getAppRoot();
const expoModulesSearchResults = await (0, findModules_1.findModulesAsync)({
autolinkingOptions,
appRoot,
});
const expoModulesResolveResults = await (0, resolveModules_1.resolveModulesAsync)(expoModulesSearchResults, autolinkingOptions);
const extraDependencies = await (0, resolveModules_1.resolveExtraBuildDependenciesAsync)({
commandRoot: autolinkingOptionsLoader.getCommandRoot(),
platform,
});
const configuration = (0, getConfiguration_1.getConfiguration)({ autolinkingOptions });
const coreFeatures = [
...expoModulesResolveResults.reduce((acc, module) => {
if (hasCoreFeatures(module)) {
const features = module.coreFeatures ?? [];
for (const feature of features) {
acc.add(feature);
}
return acc;
}
return acc;
}, new Set()),
];
if (commandArguments.json) {
console.log(JSON.stringify({
extraDependencies,
coreFeatures,
modules: expoModulesResolveResults,
...(configuration ? { configuration } : {}),
}));
}
else {
console.log(require('util').inspect({
extraDependencies,
coreFeatures,
modules: expoModulesResolveResults,
...(configuration ? { configuration } : {}),
}, false, null, true));
}
});
}
//# sourceMappingURL=resolveCommand.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
import commander from 'commander';
export declare function searchCommand(cli: commander.CommanderStatic): commander.Command;
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.searchCommand = searchCommand;
const autolinkingOptions_1 = require("./autolinkingOptions");
const findModules_1 = require("../autolinking/findModules");
function searchCommand(cli) {
return (0, autolinkingOptions_1.registerAutolinkingArguments)(cli.command('search [searchPaths...]'))
.option('-j, --json', 'Output results in the plain JSON format.', () => true, false)
.action(async (searchPaths, commandArguments) => {
const platform = commandArguments.platform ?? 'apple';
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)({
...commandArguments,
searchPaths,
});
const expoModulesSearchResults = await (0, findModules_1.findModulesAsync)({
autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),
appRoot: await autolinkingOptionsLoader.getAppRoot(),
});
if (commandArguments.json) {
console.log(JSON.stringify(expoModulesSearchResults));
}
else {
console.log(require('util').inspect(expoModulesSearchResults, false, null, true));
}
});
}
//# sourceMappingURL=searchCommand.js.map
@@ -0,0 +1 @@
{"version":3,"file":"searchCommand.js","sourceRoot":"","sources":["../../src/commands/searchCommand.ts"],"names":[],"mappings":";;AAaA,sCAqBC;AAhCD,6DAI8B;AAC9B,4DAA8D;AAM9D,SAAgB,aAAa,CAAC,GAA8B;IAC1D,OAAO,IAAA,iDAA4B,EAAC,GAAG,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;SACxE,MAAM,CAAC,YAAY,EAAE,0CAA0C,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;SACnF,MAAM,CAAC,KAAK,EAAE,WAA4B,EAAE,gBAAiC,EAAE,EAAE;QAChF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,IAAI,OAAO,CAAC;QACtD,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC;YAC9D,GAAG,gBAAgB;YACnB,WAAW;SACZ,CAAC,CAAC;QAEH,MAAM,wBAAwB,GAAG,MAAM,IAAA,8BAAgB,EAAC;YACtD,kBAAkB,EAAE,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,QAAQ,CAAC;YAC/E,OAAO,EAAE,MAAM,wBAAwB,CAAC,UAAU,EAAE;SACrD,CAAC,CAAC;QAEH,IAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,wBAAwB,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACpF,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["import commander from 'commander';\n\nimport {\n AutolinkingCommonArguments,\n createAutolinkingOptionsLoader,\n registerAutolinkingArguments,\n} from './autolinkingOptions';\nimport { findModulesAsync } from '../autolinking/findModules';\n\ninterface SearchArguments extends AutolinkingCommonArguments {\n json?: boolean | null;\n}\n\nexport function searchCommand(cli: commander.CommanderStatic) {\n return registerAutolinkingArguments(cli.command('search [searchPaths...]'))\n .option('-j, --json', 'Output results in the plain JSON format.', () => true, false)\n .action(async (searchPaths: string[] | null, commandArguments: SearchArguments) => {\n const platform = commandArguments.platform ?? 'apple';\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader({\n ...commandArguments,\n searchPaths,\n });\n\n const expoModulesSearchResults = await findModulesAsync({\n autolinkingOptions: await autolinkingOptionsLoader.getPlatformOptions(platform),\n appRoot: await autolinkingOptionsLoader.getAppRoot(),\n });\n\n if (commandArguments.json) {\n console.log(JSON.stringify(expoModulesSearchResults));\n } else {\n console.log(require('util').inspect(expoModulesSearchResults, false, null, true));\n }\n });\n}\n"]}
@@ -0,0 +1,13 @@
import commander from 'commander';
import { type ResolutionResult } from '../dependencies';
export declare function verifyCommand(cli: commander.CommanderStatic): commander.Command;
interface VerifyOptions {
appRoot: string;
verbose?: boolean;
json?: boolean;
}
/**
* Verifies the search results by checking whether there are no duplicates.
*/
export declare function verifySearchResults(results: ResolutionResult, options: VerifyOptions): Promise<void>;
export {};
@@ -0,0 +1,125 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyCommand = verifyCommand;
exports.verifySearchResults = verifySearchResults;
const chalk_1 = __importDefault(require("chalk"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const autolinkingOptions_1 = require("./autolinkingOptions");
const dependencies_1 = require("../dependencies");
// NOTE(@kitten): These are excluded explicitly, but we want to include them for the verify command explicitly
const INCLUDE_PACKAGES = ['react-native', 'react-native-tvos'];
function verifyCommand(cli) {
return (0, autolinkingOptions_1.registerAutolinkingArguments)(cli.command('verify'))
.option('-v, --verbose', 'Output all results instead of just warnings.', () => true, false)
.option('-j, --json', 'Output results in the plain JSON format.', () => true, false)
.option('-p, --platform [platform]', 'The platform to validate native modules for. Available options: "android", "ios", "both"', 'both')
.action(async (commandArguments) => {
const platforms = commandArguments.platform === 'both' ? ['android', 'ios'] : [commandArguments.platform];
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)(commandArguments);
const appRoot = await autolinkingOptionsLoader.getAppRoot();
const linker = (0, dependencies_1.makeCachedDependenciesLinker)({ projectRoot: appRoot });
const results = (0, dependencies_1.mergeResolutionResults)(await Promise.all(platforms.map((platform) => (0, dependencies_1.scanDependencyResolutionsForPlatform)(linker, platform, INCLUDE_PACKAGES))));
await verifySearchResults(results, {
appRoot,
verbose: !!commandArguments.verbose,
json: !!commandArguments.json,
});
});
}
/**
* Verifies the search results by checking whether there are no duplicates.
*/
async function verifySearchResults(results, options) {
const { appRoot } = options;
async function getHumanReadableDependency(dependency) {
let version = dependency.version || null;
if (!version) {
try {
const pkgContents = await fs_1.default.promises.readFile(path_1.default.join(dependency.path, 'package.json'), 'utf8');
const pkg = JSON.parse(pkgContents);
if (pkg && typeof pkg === 'object' && 'version' in pkg && typeof pkg.version === 'string') {
version = pkg.version;
}
}
catch (error) {
version = null;
}
}
const relative = path_1.default.relative(appRoot, dependency.originPath);
return version
? `${dependency.name}@${version} (at: ${relative})`
: `${dependency.name} at: ${relative}`;
}
const groups = {
reactNativeProjectConfig: [],
searchPaths: [],
dependencies: [],
duplicates: [],
};
for (const moduleName in results) {
const revision = results[moduleName];
if (!revision) {
continue;
}
else if (revision.duplicates?.length) {
groups.duplicates.push(revision);
}
else {
switch (revision.source) {
case 2 /* DependencyResolutionSource.RN_CLI_LOCAL */:
groups.reactNativeProjectConfig.push(revision);
break;
case 1 /* DependencyResolutionSource.SEARCH_PATH */:
groups.searchPaths.push(revision);
break;
case 0 /* DependencyResolutionSource.RECURSIVE_RESOLUTION */:
groups.dependencies.push(revision);
break;
}
}
}
if (options.json) {
console.log(JSON.stringify(groups));
return;
}
if (options.verbose) {
const sortResolutions = (resolutions) => [...resolutions].sort((a, b) => a.name.localeCompare(b.name));
if (groups.reactNativeProjectConfig.length) {
console.log(`🔎 Found ${groups.reactNativeProjectConfig.length} modules from React Native project config`);
for (const revision of sortResolutions(groups.reactNativeProjectConfig)) {
console.log(` - ${await getHumanReadableDependency(revision)}`);
}
}
if (groups.searchPaths.length) {
console.log(`🔎 Found ${groups.searchPaths.length} modules in search paths`);
for (const revision of sortResolutions(groups.searchPaths)) {
console.log(` - ${await getHumanReadableDependency(revision)}`);
}
}
console.log(`🔎 Found ${groups.dependencies.length} modules in dependencies`);
for (const revision of sortResolutions(groups.dependencies)) {
console.log(` - ${await getHumanReadableDependency(revision)}`);
}
}
if (groups.duplicates.length) {
for (const revision of groups.duplicates) {
console.warn(`⚠️ Found duplicate installations for ${chalk_1.default.green(revision.name)}`);
const revisions = [revision, ...(revision.duplicates ?? [])];
for (let idx = 0; idx < revisions.length; idx++) {
const prefix = idx !== revisions.length - 1 ? '├─' : '└─';
const duplicate = revisions[idx];
console.log(` ${prefix} ${await getHumanReadableDependency(duplicate)}`);
}
}
console.warn('⚠️ Multiple versions of the same module may introduce some side effects or compatibility issues.\n' +
`Resolve your dependency issues and deduplicate your dependencies. Learn more: https://expo.fyi/resolving-dependency-issues`);
}
else {
console.log('✅ Everything is fine!');
}
}
//# sourceMappingURL=verifyCommand.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,19 @@
import { PackageRevision, SupportedPlatform } from '../types';
import { type ResolutionResult } from './types';
import { RNConfigReactNativeProjectConfig } from '../reactNativeConfig';
export interface CachedDependenciesSearchOptions {
excludeNames: Set<string>;
searchPaths: string[];
}
export interface CachedDependenciesLinker {
getOptionsForPlatform(platform: SupportedPlatform): Promise<CachedDependenciesSearchOptions>;
loadReactNativeProjectConfig(): Promise<RNConfigReactNativeProjectConfig | null>;
scanDependenciesFromRNProjectConfig(): Promise<ResolutionResult>;
scanDependenciesRecursively(): Promise<ResolutionResult>;
scanDependenciesInSearchPath(searchPath: string): Promise<ResolutionResult>;
}
export declare function makeCachedDependenciesLinker(params: {
projectRoot: string;
}): CachedDependenciesLinker;
export declare function scanDependencyResolutionsForPlatform(linker: CachedDependenciesLinker, platform: SupportedPlatform, include?: string[]): Promise<ResolutionResult>;
export declare function scanExpoModuleResolutionsForPlatform(linker: CachedDependenciesLinker, platform: SupportedPlatform): Promise<Record<string, PackageRevision>>;
@@ -0,0 +1,116 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeCachedDependenciesLinker = makeCachedDependenciesLinker;
exports.scanDependencyResolutionsForPlatform = scanDependencyResolutionsForPlatform;
exports.scanExpoModuleResolutionsForPlatform = scanExpoModuleResolutionsForPlatform;
const fs_1 = __importDefault(require("fs"));
const resolution_1 = require("./resolution");
const rncliLocal_1 = require("./rncliLocal");
const scanning_1 = require("./scanning");
const utils_1 = require("./utils");
const findModules_1 = require("../autolinking/findModules");
const autolinkingOptions_1 = require("../commands/autolinkingOptions");
const reactNativeConfig_1 = require("../reactNativeConfig");
const config_1 = require("../reactNativeConfig/config");
function makeCachedDependenciesLinker(params) {
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)({
projectRoot: params.projectRoot,
});
let appRoot;
const getAppRoot = () => appRoot || (appRoot = autolinkingOptionsLoader.getAppRoot());
const dependenciesResultBySearchPath = new Map();
let reactNativeProjectConfig;
let reactNativeProjectConfigDependencies;
let recursiveDependencies;
return {
async getOptionsForPlatform(platform) {
const options = await autolinkingOptionsLoader.getPlatformOptions(platform);
return makeCachedDependenciesSearchOptions(options);
},
async loadReactNativeProjectConfig() {
if (reactNativeProjectConfig === undefined) {
reactNativeProjectConfig = (0, config_1.loadConfigAsync)(await getAppRoot());
}
return reactNativeProjectConfig;
},
async scanDependenciesFromRNProjectConfig() {
const reactNativeProjectConfig = await this.loadReactNativeProjectConfig();
return (reactNativeProjectConfigDependencies ||
(reactNativeProjectConfigDependencies = (0, rncliLocal_1.scanDependenciesFromRNProjectConfig)(await getAppRoot(), reactNativeProjectConfig)));
},
async scanDependenciesRecursively() {
return (recursiveDependencies ||
(recursiveDependencies = (0, resolution_1.scanDependenciesRecursively)(await getAppRoot())));
},
async scanDependenciesInSearchPath(searchPath) {
let result = dependenciesResultBySearchPath.get(searchPath);
if (!result) {
dependenciesResultBySearchPath.set(searchPath, (result = (0, scanning_1.scanDependenciesInSearchPath)(searchPath)));
}
return result;
},
};
}
async function scanDependencyResolutionsForPlatform(linker, platform, include) {
const { excludeNames, searchPaths } = await linker.getOptionsForPlatform(platform);
const includeNames = new Set(include);
const reactNativeProjectConfig = await linker.loadReactNativeProjectConfig();
const resolutions = (0, utils_1.mergeResolutionResults)(await Promise.all([
linker.scanDependenciesFromRNProjectConfig(),
...searchPaths.map((searchPath) => {
return linker.scanDependenciesInSearchPath(searchPath);
}),
linker.scanDependenciesRecursively(),
]));
const dependencies = await (0, utils_1.filterMapResolutionResult)(resolutions, async (resolution) => {
if (excludeNames.has(resolution.name)) {
return null;
}
else if (includeNames.has(resolution.name)) {
return resolution;
}
else if (resolution.source === 2 /* DependencyResolutionSource.RN_CLI_LOCAL */) {
// If the dependency was resolved frpom the React Native project config, we'll only
// attempt to resolve it as a React Native module
const reactNativeModuleDesc = await (0, reactNativeConfig_1.resolveReactNativeModule)(resolution, reactNativeProjectConfig, platform, excludeNames);
if (!reactNativeModuleDesc) {
return null;
}
}
else {
const [reactNativeModule, expoModule] = await Promise.all([
(0, reactNativeConfig_1.resolveReactNativeModule)(resolution, reactNativeProjectConfig, platform, excludeNames),
(0, findModules_1.resolveExpoModule)(resolution, platform, excludeNames),
]);
if (!reactNativeModule && !expoModule) {
return null;
}
}
return resolution;
});
return dependencies;
}
async function scanExpoModuleResolutionsForPlatform(linker, platform) {
const { excludeNames, searchPaths } = await linker.getOptionsForPlatform(platform);
const resolutions = (0, utils_1.mergeResolutionResults)(await Promise.all([
...searchPaths.map((searchPath) => {
return linker.scanDependenciesInSearchPath(searchPath);
}),
linker.scanDependenciesRecursively(),
].filter((x) => x != null)));
return await (0, utils_1.filterMapResolutionResult)(resolutions, async (resolution) => {
return !excludeNames.has(resolution.name)
? await (0, findModules_1.resolveExpoModule)(resolution, platform, excludeNames)
: null;
});
}
const makeCachedDependenciesSearchOptions = (options) => ({
excludeNames: new Set(options.exclude),
searchPaths: options.nativeModulesDir && fs_1.default.existsSync(options.nativeModulesDir)
? [options.nativeModulesDir, ...(options.searchPaths ?? [])]
: (options.searchPaths ?? []),
});
//# sourceMappingURL=CachedDependenciesLinker.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
export { scanDependenciesRecursively } from './resolution';
export { scanDependenciesInSearchPath } from './scanning';
export { scanDependenciesFromRNProjectConfig } from './rncliLocal';
export { filterMapResolutionResult, mergeResolutionResults } from './utils';
export * from './CachedDependenciesLinker';
export * from './types';
@@ -0,0 +1,29 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeResolutionResults = exports.filterMapResolutionResult = exports.scanDependenciesFromRNProjectConfig = exports.scanDependenciesInSearchPath = exports.scanDependenciesRecursively = void 0;
var resolution_1 = require("./resolution");
Object.defineProperty(exports, "scanDependenciesRecursively", { enumerable: true, get: function () { return resolution_1.scanDependenciesRecursively; } });
var scanning_1 = require("./scanning");
Object.defineProperty(exports, "scanDependenciesInSearchPath", { enumerable: true, get: function () { return scanning_1.scanDependenciesInSearchPath; } });
var rncliLocal_1 = require("./rncliLocal");
Object.defineProperty(exports, "scanDependenciesFromRNProjectConfig", { enumerable: true, get: function () { return rncliLocal_1.scanDependenciesFromRNProjectConfig; } });
var utils_1 = require("./utils");
Object.defineProperty(exports, "filterMapResolutionResult", { enumerable: true, get: function () { return utils_1.filterMapResolutionResult; } });
Object.defineProperty(exports, "mergeResolutionResults", { enumerable: true, get: function () { return utils_1.mergeResolutionResults; } });
__exportStar(require("./CachedDependenciesLinker"), exports);
__exportStar(require("./types"), exports);
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dependencies/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,2CAA2D;AAAlD,yHAAA,2BAA2B,OAAA;AACpC,uCAA0D;AAAjD,wHAAA,4BAA4B,OAAA;AACrC,2CAAmE;AAA1D,iIAAA,mCAAmC,OAAA;AAC5C,iCAA4E;AAAnE,kHAAA,yBAAyB,OAAA;AAAE,+GAAA,sBAAsB,OAAA;AAC1D,6DAA2C;AAC3C,0CAAwB","sourcesContent":["export { scanDependenciesRecursively } from './resolution';\nexport { scanDependenciesInSearchPath } from './scanning';\nexport { scanDependenciesFromRNProjectConfig } from './rncliLocal';\nexport { filterMapResolutionResult, mergeResolutionResults } from './utils';\nexport * from './CachedDependenciesLinker';\nexport * from './types';\n"]}
@@ -0,0 +1,10 @@
import { type ResolutionResult } from './types';
declare module 'node:module' {
function _nodeModulePaths(base: string): readonly string[];
}
interface ResolutionOptions {
shouldIncludeDependency?(name: string): boolean;
limitDepth?: number;
}
export declare function scanDependenciesRecursively(rawPath: string, { shouldIncludeDependency, limitDepth }?: ResolutionOptions): Promise<ResolutionResult>;
export {};
@@ -0,0 +1,137 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scanDependenciesRecursively = scanDependenciesRecursively;
const node_module_1 = __importDefault(require("node:module"));
const utils_1 = require("./utils");
// NOTE(@kitten): There's no need to search very deep for modules
// We don't expect native modules to be excessively nested in the dependency tree
const MAX_DEPTH = 8;
const createNodeModulePathsCreator = () => {
const _nodeModulePathCache = new Map();
return async function getNodeModulePaths(packagePath) {
const outputPaths = [];
const nodeModulePaths = node_module_1.default._nodeModulePaths(packagePath);
for (let idx = 0; idx < nodeModulePaths.length; idx++) {
const nodeModulePath = nodeModulePaths[idx];
let target = _nodeModulePathCache.get(nodeModulePath);
if (target === undefined) {
target = await (0, utils_1.maybeRealpath)(nodeModulePath);
if (idx !== 0) {
_nodeModulePathCache.set(nodeModulePath, target);
}
}
if (target != null) {
outputPaths.push(target);
}
}
return outputPaths;
};
};
async function resolveDependencies(packageJson, nodeModulePaths, depth, shouldIncludeDependency) {
const dependencies = Object.create(null);
if (packageJson.dependencies != null && typeof packageJson.dependencies === 'object') {
Object.assign(dependencies, packageJson.dependencies);
}
// NOTE(@kitten): Also traverse devDependencies for top-level package.json
if (depth === 0 &&
packageJson.devDependencies != null &&
typeof packageJson.devDependencies === 'object') {
Object.assign(dependencies, packageJson.devDependencies);
}
if (packageJson.peerDependencies != null && typeof packageJson.peerDependencies === 'object') {
const peerDependenciesMeta = packageJson.peerDependenciesMeta != null &&
typeof packageJson.peerDependenciesMeta === 'object'
? packageJson.peerDependenciesMeta
: undefined;
for (const dependencyName in packageJson.peerDependencies) {
// NOTE(@kitten): We only check peer dependencies because some package managers auto-install them
// which would mean they'd have no reference in any dependencies. However, optional peer dependencies
// don't auto-install and we can skip them
if (!isOptionalPeerDependencyMeta(peerDependenciesMeta, dependencyName)) {
dependencies[dependencyName] = '';
}
}
}
const resolveDependency = async (dependencyName) => {
for (let idx = 0; idx < nodeModulePaths.length; idx++) {
const originPath = (0, utils_1.fastJoin)(nodeModulePaths[idx], dependencyName);
const nodeModulePath = await (0, utils_1.maybeRealpath)(originPath);
if (nodeModulePath != null) {
return {
source: 0 /* DependencyResolutionSource.RECURSIVE_RESOLUTION */,
name: dependencyName,
version: '',
path: nodeModulePath,
originPath,
duplicates: null,
depth,
};
}
}
return null;
};
const modules = await Promise.all(Object.keys(dependencies)
.filter((dependencyName) => shouldIncludeDependency(dependencyName))
.map((dependencyName) => resolveDependency(dependencyName)));
return modules.filter((resolution) => resolution != null);
}
async function scanDependenciesRecursively(rawPath, { shouldIncludeDependency = utils_1.defaultShouldIncludeDependency, limitDepth } = {}) {
const rootPath = await (0, utils_1.maybeRealpath)(rawPath);
if (!rootPath) {
return {};
}
const _visitedPackagePaths = new Set();
const getNodeModulePaths = createNodeModulePathsCreator();
const maxDepth = limitDepth != null ? limitDepth : MAX_DEPTH;
const recurse = async (resolution, depth = 0) => {
const searchResults = Object.create(null);
if (_visitedPackagePaths.has(resolution.path)) {
return searchResults;
}
else {
_visitedPackagePaths.add(resolution.path);
}
const [nodeModulePaths, packageJson] = await Promise.all([
getNodeModulePaths(resolution.path),
(0, utils_1.loadPackageJson)((0, utils_1.fastJoin)(resolution.path, 'package.json')),
]);
if (!packageJson) {
return searchResults;
}
else {
resolution.version = packageJson.version || '';
}
const modules = await resolveDependencies(packageJson, nodeModulePaths, depth, shouldIncludeDependency);
for (let idx = 0; idx < modules.length; idx++) {
searchResults[modules[idx].name] = modules[idx];
}
if (depth + 1 < maxDepth) {
const childResults = await Promise.all(modules.map((resolution) => recurse(resolution, depth + 1)));
return (0, utils_1.mergeResolutionResults)(childResults, searchResults);
}
else {
return searchResults;
}
};
const searchResults = await recurse({
source: 0 /* DependencyResolutionSource.RECURSIVE_RESOLUTION */,
name: '',
version: '',
path: rootPath,
originPath: rawPath,
duplicates: null,
depth: -1,
});
return searchResults;
}
const isOptionalPeerDependencyMeta = (peerDependenciesMeta, packageName) => {
return (peerDependenciesMeta &&
peerDependenciesMeta[packageName] != null &&
typeof peerDependenciesMeta[packageName] === 'object' &&
'optional' in peerDependenciesMeta[packageName] &&
!!peerDependenciesMeta[packageName].optional);
};
//# sourceMappingURL=resolution.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
import { type ResolutionResult } from './types';
import { RNConfigReactNativeProjectConfig } from '../reactNativeConfig';
interface ResolutionOptions {
shouldIncludeDependency?(name: string): boolean;
}
export declare function scanDependenciesFromRNProjectConfig(rawPath: string, projectConfig: RNConfigReactNativeProjectConfig | null, { shouldIncludeDependency }?: ResolutionOptions): Promise<ResolutionResult>;
export {};
@@ -0,0 +1,38 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scanDependenciesFromRNProjectConfig = scanDependenciesFromRNProjectConfig;
const path_1 = __importDefault(require("path"));
const utils_1 = require("./utils");
async function scanDependenciesFromRNProjectConfig(rawPath, projectConfig, { shouldIncludeDependency = utils_1.defaultShouldIncludeDependency } = {}) {
const rootPath = await (0, utils_1.maybeRealpath)(rawPath);
const searchResults = Object.create(null);
if (!rootPath || !projectConfig || !projectConfig.dependencies) {
return searchResults;
}
for (const dependencyName in projectConfig.dependencies) {
if (!shouldIncludeDependency(dependencyName)) {
continue;
}
const dependencyConfig = projectConfig.dependencies[dependencyName];
if (dependencyConfig && dependencyConfig.root && typeof dependencyConfig.root === 'string') {
const originPath = path_1.default.resolve(rootPath, dependencyConfig.root);
const realPath = await (0, utils_1.maybeRealpath)(originPath);
if (realPath) {
searchResults[dependencyName] = {
source: 2 /* DependencyResolutionSource.RN_CLI_LOCAL */,
name: dependencyName,
version: '',
path: realPath,
originPath,
duplicates: null,
depth: 0,
};
}
}
}
return searchResults;
}
//# sourceMappingURL=rncliLocal.js.map
@@ -0,0 +1 @@
{"version":3,"file":"rncliLocal.js","sourceRoot":"","sources":["../../src/dependencies/rncliLocal.ts"],"names":[],"mappings":";;;;;AAUA,kFAkCC;AA5CD,gDAAwB;AAGxB,mCAAwE;AAOjE,KAAK,UAAU,mCAAmC,CACvD,OAAe,EACf,aAAsD,EACtD,EAAE,uBAAuB,GAAG,sCAA8B,KAAwB,EAAE;IAEpF,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAa,EAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAqB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5D,IAAI,CAAC,QAAQ,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC;QAC/D,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,KAAK,MAAM,cAAc,IAAI,aAAa,CAAC,YAAY,EAAE,CAAC;QACxD,IAAI,CAAC,uBAAuB,CAAC,cAAc,CAAC,EAAE,CAAC;YAC7C,SAAS;QACX,CAAC;QACD,MAAM,gBAAgB,GAAG,aAAa,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;QACpE,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,IAAI,IAAI,OAAO,gBAAgB,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3F,MAAM,UAAU,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACjE,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAa,EAAC,UAAU,CAAC,CAAC;YACjD,IAAI,QAAQ,EAAE,CAAC;gBACb,aAAa,CAAC,cAAc,CAAC,GAAG;oBAC9B,MAAM,iDAAyC;oBAC/C,IAAI,EAAE,cAAc;oBACpB,OAAO,EAAE,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,UAAU;oBACV,UAAU,EAAE,IAAI;oBAChB,KAAK,EAAE,CAAC;iBACT,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC","sourcesContent":["import path from 'path';\n\nimport { DependencyResolutionSource, type ResolutionResult } from './types';\nimport { defaultShouldIncludeDependency, maybeRealpath } from './utils';\nimport { RNConfigReactNativeProjectConfig } from '../reactNativeConfig';\n\ninterface ResolutionOptions {\n shouldIncludeDependency?(name: string): boolean;\n}\n\nexport async function scanDependenciesFromRNProjectConfig(\n rawPath: string,\n projectConfig: RNConfigReactNativeProjectConfig | null,\n { shouldIncludeDependency = defaultShouldIncludeDependency }: ResolutionOptions = {}\n): Promise<ResolutionResult> {\n const rootPath = await maybeRealpath(rawPath);\n const searchResults: ResolutionResult = Object.create(null);\n if (!rootPath || !projectConfig || !projectConfig.dependencies) {\n return searchResults;\n }\n\n for (const dependencyName in projectConfig.dependencies) {\n if (!shouldIncludeDependency(dependencyName)) {\n continue;\n }\n const dependencyConfig = projectConfig.dependencies[dependencyName];\n if (dependencyConfig && dependencyConfig.root && typeof dependencyConfig.root === 'string') {\n const originPath = path.resolve(rootPath, dependencyConfig.root);\n const realPath = await maybeRealpath(originPath);\n if (realPath) {\n searchResults[dependencyName] = {\n source: DependencyResolutionSource.RN_CLI_LOCAL,\n name: dependencyName,\n version: '',\n path: realPath,\n originPath,\n duplicates: null,\n depth: 0,\n };\n }\n }\n }\n\n return searchResults;\n}\n"]}
@@ -0,0 +1,6 @@
import { type ResolutionResult } from './types';
interface ResolutionOptions {
shouldIncludeDependency?(name: string): boolean;
}
export declare function scanDependenciesInSearchPath(rawPath: string, { shouldIncludeDependency }?: ResolutionOptions): Promise<ResolutionResult>;
export {};
@@ -0,0 +1,110 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scanDependenciesInSearchPath = scanDependenciesInSearchPath;
const fs_1 = __importDefault(require("fs"));
const utils_1 = require("./utils");
async function resolveDependency(basePath, dependencyName, shouldIncludeDependency) {
if (dependencyName && !shouldIncludeDependency(dependencyName)) {
return null;
}
const originPath = dependencyName ? (0, utils_1.fastJoin)(basePath, dependencyName) : basePath;
const realPath = await (0, utils_1.maybeRealpath)(originPath);
const packageJson = await (0, utils_1.loadPackageJson)((0, utils_1.fastJoin)(realPath || originPath, 'package.json'));
if (packageJson) {
return {
source: 1 /* DependencyResolutionSource.SEARCH_PATH */,
name: packageJson.name,
version: packageJson.version || '',
path: realPath || originPath,
originPath,
duplicates: null,
depth: 0,
};
}
else if (dependencyName && realPath) {
return {
source: 1 /* DependencyResolutionSource.SEARCH_PATH */,
name: dependencyName.toLowerCase(),
version: '',
path: realPath,
originPath,
duplicates: null,
depth: 0,
};
}
else {
return null;
}
}
async function scanDependenciesInSearchPath(rawPath, { shouldIncludeDependency = utils_1.defaultShouldIncludeDependency } = {}) {
const rootPath = await (0, utils_1.maybeRealpath)(rawPath);
const searchResults = Object.create(null);
if (!rootPath) {
return searchResults;
}
const resolvedDependencies = [];
const localModuleTarget = await (0, utils_1.maybeRealpath)((0, utils_1.fastJoin)(rootPath, 'package.json'));
if (localModuleTarget) {
// If we have a `package.json` file in the search path, we're already dealing with a node module
// and can skip the rest. This is a special case created by create-expo-module's `nativeModulesDir: ../`
const resolution = await resolveDependency(rootPath, null, shouldIncludeDependency);
if (resolution)
resolvedDependencies.push(resolution);
}
else {
const dirents = await fs_1.default.promises.readdir(rootPath, { withFileTypes: true });
await Promise.all(dirents.map(async (entry) => {
if (entry.isSymbolicLink()) {
const resolution = await resolveDependency(rootPath, entry.name, shouldIncludeDependency);
if (resolution)
resolvedDependencies.push(resolution);
}
else if (entry.isDirectory()) {
if (entry.name === 'node_modules') {
// Ignore nested node_modules folder
}
if (entry.name[0] === '.') {
// Ignore hidden folders
}
else if (entry.name[0] === '@') {
// NOTE: We don't expect @-scope folders to be symlinks
const entryPath = (0, utils_1.fastJoin)(rootPath, entry.name);
const childEntries = await fs_1.default.promises.readdir(entryPath, { withFileTypes: true });
await Promise.all(childEntries.map(async (child) => {
const dependencyName = `${entry.name}/${child.name}`;
if (child.isDirectory() || child.isSymbolicLink()) {
const resolution = await resolveDependency(rootPath, dependencyName, shouldIncludeDependency);
if (resolution)
resolvedDependencies.push(resolution);
}
}));
}
else {
const resolution = await resolveDependency(rootPath, entry.name, shouldIncludeDependency);
if (resolution)
resolvedDependencies.push(resolution);
}
}
}));
}
for (let idx = 0; idx < resolvedDependencies.length; idx++) {
const resolution = resolvedDependencies[idx];
const prevEntry = searchResults[resolution.name];
if (prevEntry != null && resolution.path !== prevEntry.path) {
(prevEntry.duplicates ?? (prevEntry.duplicates = [])).push({
name: resolution.name,
version: resolution.version,
path: resolution.path,
originPath: resolution.originPath,
});
}
else if (prevEntry == null) {
searchResults[resolution.name] = resolution;
}
}
return searchResults;
}
//# sourceMappingURL=scanning.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
export declare const enum DependencyResolutionSource {
RECURSIVE_RESOLUTION = 0,
SEARCH_PATH = 1,
RN_CLI_LOCAL = 2
}
export interface BaseDependencyResolution {
name: string;
version: string;
path: string;
originPath: string;
}
export interface DependencyResolution extends BaseDependencyResolution {
source: DependencyResolutionSource;
duplicates: BaseDependencyResolution[] | null;
depth: number;
[prop: string]: unknown;
}
export type ResolutionResult = Record<string, DependencyResolution | undefined>;
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/dependencies/types.ts"],"names":[],"mappings":"","sourcesContent":["export const enum DependencyResolutionSource {\n RECURSIVE_RESOLUTION,\n SEARCH_PATH,\n RN_CLI_LOCAL,\n}\n\nexport interface BaseDependencyResolution {\n name: string;\n version: string;\n path: string;\n originPath: string;\n}\n\nexport interface DependencyResolution extends BaseDependencyResolution {\n source: DependencyResolutionSource;\n duplicates: BaseDependencyResolution[] | null;\n depth: number;\n [prop: string]: unknown;\n}\n\nexport type ResolutionResult = Record<string, DependencyResolution | undefined>;\n"]}
@@ -0,0 +1,13 @@
import { type DependencyResolution, type ResolutionResult } from './types';
export declare function defaultShouldIncludeDependency(dependencyName: string): boolean;
export declare const fastJoin: (from: string, append: string) => string;
export declare const maybeRealpath: (target: string) => Promise<string | null>;
export type PackageJson = Record<string, unknown> & {
version?: string;
};
export declare const loadPackageJson: (input: string, ...args: any[]) => Promise<any>;
export declare function mergeWithDuplicate(a: DependencyResolution, b: DependencyResolution): DependencyResolution;
export declare function filterMapResolutionResult<T extends {
name: string;
}>(results: ResolutionResult, filterMap: (resolution: DependencyResolution) => Promise<T | null> | T | null): Promise<Record<string, T>>;
export declare function mergeResolutionResults(results: ResolutionResult[], base?: ResolutionResult): ResolutionResult;
@@ -0,0 +1,169 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadPackageJson = exports.maybeRealpath = exports.fastJoin = void 0;
exports.defaultShouldIncludeDependency = defaultShouldIncludeDependency;
exports.mergeWithDuplicate = mergeWithDuplicate;
exports.filterMapResolutionResult = filterMapResolutionResult;
exports.mergeResolutionResults = mergeResolutionResults;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const utils_1 = require("../utils");
const NODE_MODULES_PATTERN = `${path_1.default.sep}node_modules${path_1.default.sep}`;
// The default dependencies we exclude don't contain dependency chains leading to autolinked modules
function defaultShouldIncludeDependency(dependencyName) {
const scopeName = dependencyName[0] === '@' ? dependencyName.slice(1, dependencyName.indexOf('/')) : null;
if (scopeName === 'babel' ||
scopeName === 'types' ||
scopeName === 'eslint' ||
scopeName === 'typescript-eslint' ||
scopeName === 'testing-library' ||
scopeName === 'aws-crypto' ||
scopeName === 'aws-sdk') {
return false;
}
switch (dependencyName) {
case '@expo/cli':
case '@expo/config':
case '@expo/metro-config':
case '@expo/package-manager':
case '@expo/prebuild-config':
case '@expo/webpack-config':
case '@expo/env':
case '@react-native/codegen':
case '@react-native/community-cli-plugin':
case 'eslint':
case 'eslint-config-expo':
case 'eslint-plugin-expo':
case 'eslint-plugin-import':
case 'jest-expo':
case 'jest':
case 'metro':
case 'ts-node':
case 'typescript':
case 'webpack':
return false;
default:
return true;
}
}
exports.fastJoin = path_1.default.sep === '/'
? (from, append) => `${from}${path_1.default.sep}${append}`
: (from, append) => `${from}${path_1.default.sep}${append[0] === '@' ? append.replace('/', path_1.default.sep) : append}`;
const maybeRealpath = async (target) => {
try {
return await fs_1.default.promises.realpath(target);
}
catch {
return null;
}
};
exports.maybeRealpath = maybeRealpath;
exports.loadPackageJson = (0, utils_1.memoize)(async function loadPackageJson(jsonPath) {
try {
const packageJsonText = await fs_1.default.promises.readFile(jsonPath, 'utf8');
const json = JSON.parse(packageJsonText);
if (typeof json !== 'object' || json == null) {
return null;
}
return json;
}
catch {
return null;
}
});
function mergeWithDuplicate(a, b) {
let target;
let duplicate;
if (a.depth < b.depth) {
target = a;
duplicate = b;
}
else if (b.depth < a.depth) {
target = b;
duplicate = a;
}
else {
// If both are equal, then the shallowest path wins
const pathDepthA = a.originPath.split(NODE_MODULES_PATTERN).length;
const pathDepthB = b.originPath.split(NODE_MODULES_PATTERN).length;
if (pathDepthA < pathDepthB) {
target = a;
duplicate = b;
}
else if (pathDepthB < pathDepthA) {
target = b;
duplicate = a;
}
else {
target = a;
duplicate = b;
}
}
const duplicates = target.duplicates || (target.duplicates = []);
if (target.path !== duplicate.path) {
if (duplicates.every((parent) => parent.path !== duplicate.path)) {
duplicates.push({
name: duplicate.name,
version: duplicate.version,
path: duplicate.path,
originPath: duplicate.originPath,
});
}
}
else if (!target.version && duplicate.version) {
target.version = duplicate.version;
}
if (duplicate.duplicates?.length) {
duplicates.push(...duplicate.duplicates.filter((child) => duplicates.every((parent) => parent.path !== child.path)));
}
return target;
}
async function filterMapResolutionResult(results, filterMap) {
const resolutions = await Promise.all(Object.keys(results).map(async (key) => {
const resolution = results[key];
const result = resolution ? await filterMap(resolution) : null;
// If we failed to find a matching resolution from `searchPaths`, also try the other duplicates
// to see if the `searchPaths` result is not a module but another is
if (resolution?.source === 1 /* DependencyResolutionSource.SEARCH_PATH */ && !result) {
for (let idx = 0; resolution.duplicates && idx < resolution.duplicates.length; idx++) {
const duplicate = resolution.duplicates[idx];
const duplicateResult = await filterMap({ ...resolution, ...duplicate });
if (duplicateResult != null) {
return duplicateResult;
}
}
}
return result;
}));
const output = Object.create(null);
for (let idx = 0; idx < resolutions.length; idx++) {
const resolution = resolutions[idx];
if (resolution != null) {
output[resolution.name] = resolution;
}
}
return output;
}
function mergeResolutionResults(results, base) {
if (base == null && results.length === 1) {
return results[0];
}
const output = base == null ? Object.create(null) : base;
for (let idx = 0; idx < results.length; idx++) {
for (const key in results[idx]) {
const resolution = results[idx][key];
const prevResolution = output[key];
if (prevResolution != null) {
output[key] = mergeWithDuplicate(prevResolution, resolution);
}
else {
output[key] = resolution;
}
}
}
return output;
}
//# sourceMappingURL=utils.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
import { AutolinkingCommonArguments, AutolinkingOptions } from './commands/autolinkingOptions';
import { ModuleDescriptor, SupportedPlatform } from './types';
export * from './types';
export * from './autolinking';
export * from './platforms';
export { ResolutionResult, BaseDependencyResolution, DependencyResolution, DependencyResolutionSource, CachedDependenciesLinker, CachedDependenciesSearchOptions, makeCachedDependenciesLinker, scanDependencyResolutionsForPlatform, scanExpoModuleResolutionsForPlatform, } from './dependencies';
/** @deprecated */
export declare function mergeLinkingOptionsAsync<Options extends Partial<AutolinkingCommonArguments>>(argumentsOptions: Options): Promise<Options & AutolinkingOptions>;
interface QueryAutolinkingModulesFromProjectParams extends Partial<AutolinkingCommonArguments> {
platform: SupportedPlatform;
[extra: string]: unknown;
}
/** @deprecated */
export declare function queryAutolinkingModulesFromProjectAsync(projectRoot: string, options: QueryAutolinkingModulesFromProjectParams): Promise<ModuleDescriptor[]>;
/** @deprecated */
export declare function findProjectRootSync(cwd?: string): string;
/** @deprecated */
export declare function resolveSearchPathsAsync(searchPaths: string[] | null, cwd: string): Promise<string[]>;
+72
View File
@@ -0,0 +1,72 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scanExpoModuleResolutionsForPlatform = exports.scanDependencyResolutionsForPlatform = exports.makeCachedDependenciesLinker = void 0;
exports.mergeLinkingOptionsAsync = mergeLinkingOptionsAsync;
exports.queryAutolinkingModulesFromProjectAsync = queryAutolinkingModulesFromProjectAsync;
exports.findProjectRootSync = findProjectRootSync;
exports.resolveSearchPathsAsync = resolveSearchPathsAsync;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const findModules_1 = require("./autolinking/findModules");
const resolveModules_1 = require("./autolinking/resolveModules");
const autolinkingOptions_1 = require("./commands/autolinkingOptions");
__exportStar(require("./types"), exports);
__exportStar(require("./autolinking"), exports);
__exportStar(require("./platforms"), exports);
var dependencies_1 = require("./dependencies");
Object.defineProperty(exports, "makeCachedDependenciesLinker", { enumerable: true, get: function () { return dependencies_1.makeCachedDependenciesLinker; } });
Object.defineProperty(exports, "scanDependencyResolutionsForPlatform", { enumerable: true, get: function () { return dependencies_1.scanDependencyResolutionsForPlatform; } });
Object.defineProperty(exports, "scanExpoModuleResolutionsForPlatform", { enumerable: true, get: function () { return dependencies_1.scanExpoModuleResolutionsForPlatform; } });
/** @deprecated */
async function mergeLinkingOptionsAsync(argumentsOptions) {
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)(argumentsOptions);
return {
...argumentsOptions,
...(await autolinkingOptionsLoader.getPlatformOptions()),
projectRoot: autolinkingOptionsLoader.getAppRoot(),
};
}
/** @deprecated */
async function queryAutolinkingModulesFromProjectAsync(projectRoot, options) {
const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)({
...options,
// NOTE(@kitten): This has always been duplicated
projectRoot: options.projectRoot ?? projectRoot,
});
const appRoot = await autolinkingOptionsLoader.getAppRoot();
const autolinkingOptions = await autolinkingOptionsLoader.getPlatformOptions(options.platform);
const searchResults = await (0, findModules_1.findModulesAsync)({ appRoot, autolinkingOptions });
return await (0, resolveModules_1.resolveModulesAsync)(searchResults, autolinkingOptions);
}
/** @deprecated */
function findProjectRootSync(cwd = process.cwd()) {
for (let dir = cwd; path_1.default.dirname(dir) !== dir; dir = path_1.default.dirname(dir)) {
const file = path_1.default.resolve(dir, 'package.json');
if (fs_1.default.existsSync(file)) {
return file;
}
}
throw new Error(`Couldn't find "package.json" up from path "${cwd}"`);
}
/** @deprecated */
async function resolveSearchPathsAsync(searchPaths, cwd) {
return (0, autolinkingOptions_1.filterMapSearchPaths)(searchPaths, cwd) ?? [];
}
//# sourceMappingURL=exports.js.map
@@ -0,0 +1 @@
{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA8BA,4DASC;AAQD,0FAaC;AAGD,kDAQC;AAGD,0DAKC;AA/ED,4CAAoB;AACpB,gDAAwB;AAExB,2DAA6D;AAC7D,iEAAmE;AACnE,sEAKuC;AAGvC,0CAAwB;AACxB,gDAA8B;AAC9B,8CAA4B;AAE5B,+CAUwB;AAHtB,4HAAA,4BAA4B,OAAA;AAC5B,oIAAA,oCAAoC,OAAA;AACpC,oIAAA,oCAAoC,OAAA;AAGtC,kBAAkB;AACX,KAAK,UAAU,wBAAwB,CAC5C,gBAAyB;IAEzB,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC,gBAAgB,CAAC,CAAC;IAClF,OAAO;QACL,GAAG,gBAAgB;QACnB,GAAG,CAAC,MAAM,wBAAwB,CAAC,kBAAkB,EAAE,CAAC;QACxD,WAAW,EAAE,wBAAwB,CAAC,UAAU,EAAE;KACnD,CAAC;AACJ,CAAC;AAOD,kBAAkB;AACX,KAAK,UAAU,uCAAuC,CAC3D,WAAmB,EACnB,OAAiD;IAEjD,MAAM,wBAAwB,GAAG,IAAA,mDAA8B,EAAC;QAC9D,GAAG,OAAO;QACV,iDAAiD;QACjD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,WAAW;KAChD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAAC,UAAU,EAAE,CAAC;IAC5D,MAAM,kBAAkB,GAAG,MAAM,wBAAwB,CAAC,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/F,MAAM,aAAa,GAAG,MAAM,IAAA,8BAAgB,EAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9E,OAAO,MAAM,IAAA,oCAAmB,EAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;AACtE,CAAC;AAED,kBAAkB;AAClB,SAAgB,mBAAmB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC7D,KAAK,IAAI,GAAG,GAAG,GAAG,EAAE,cAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,GAAG,cAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC/C,IAAI,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8CAA8C,GAAG,GAAG,CAAC,CAAC;AACxE,CAAC;AAED,kBAAkB;AACX,KAAK,UAAU,uBAAuB,CAC3C,WAA4B,EAC5B,GAAW;IAEX,OAAO,IAAA,yCAAoB,EAAC,WAAW,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;AACtD,CAAC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { findModulesAsync } from './autolinking/findModules';\nimport { resolveModulesAsync } from './autolinking/resolveModules';\nimport {\n AutolinkingCommonArguments,\n AutolinkingOptions,\n createAutolinkingOptionsLoader,\n filterMapSearchPaths,\n} from './commands/autolinkingOptions';\nimport { ModuleDescriptor, SupportedPlatform } from './types';\n\nexport * from './types';\nexport * from './autolinking';\nexport * from './platforms';\n\nexport {\n ResolutionResult,\n BaseDependencyResolution,\n DependencyResolution,\n DependencyResolutionSource,\n CachedDependenciesLinker,\n CachedDependenciesSearchOptions,\n makeCachedDependenciesLinker,\n scanDependencyResolutionsForPlatform,\n scanExpoModuleResolutionsForPlatform,\n} from './dependencies';\n\n/** @deprecated */\nexport async function mergeLinkingOptionsAsync<Options extends Partial<AutolinkingCommonArguments>>(\n argumentsOptions: Options\n): Promise<Options & AutolinkingOptions> {\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader(argumentsOptions);\n return {\n ...argumentsOptions,\n ...(await autolinkingOptionsLoader.getPlatformOptions()),\n projectRoot: autolinkingOptionsLoader.getAppRoot(),\n };\n}\n\ninterface QueryAutolinkingModulesFromProjectParams extends Partial<AutolinkingCommonArguments> {\n platform: SupportedPlatform;\n [extra: string]: unknown;\n}\n\n/** @deprecated */\nexport async function queryAutolinkingModulesFromProjectAsync(\n projectRoot: string,\n options: QueryAutolinkingModulesFromProjectParams\n): Promise<ModuleDescriptor[]> {\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader({\n ...options,\n // NOTE(@kitten): This has always been duplicated\n projectRoot: options.projectRoot ?? projectRoot,\n });\n const appRoot = await autolinkingOptionsLoader.getAppRoot();\n const autolinkingOptions = await autolinkingOptionsLoader.getPlatformOptions(options.platform);\n const searchResults = await findModulesAsync({ appRoot, autolinkingOptions });\n return await resolveModulesAsync(searchResults, autolinkingOptions);\n}\n\n/** @deprecated */\nexport function findProjectRootSync(cwd: string = process.cwd()): string {\n for (let dir = cwd; path.dirname(dir) !== dir; dir = path.dirname(dir)) {\n const file = path.resolve(dir, 'package.json');\n if (fs.existsSync(file)) {\n return file;\n }\n }\n throw new Error(`Couldn't find \"package.json\" up from path \"${cwd}\"`);\n}\n\n/** @deprecated */\nexport async function resolveSearchPathsAsync(\n searchPaths: string[] | null,\n cwd: string\n): Promise<string[]> {\n return filterMapSearchPaths(searchPaths, cwd) ?? [];\n}\n"]}
@@ -0,0 +1 @@
export {};
+26
View File
@@ -0,0 +1,26 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = __importDefault(require("commander"));
const generateModulesProviderCommand_1 = require("./commands/generateModulesProviderCommand");
const generatePackageListCommand_1 = require("./commands/generatePackageListCommand");
const reactNativeConfigCommand_1 = require("./commands/reactNativeConfigCommand");
const resolveCommand_1 = require("./commands/resolveCommand");
const searchCommand_1 = require("./commands/searchCommand");
const verifyCommand_1 = require("./commands/verifyCommand");
async function main(args) {
const cli = commander_1.default
.version(require('expo-modules-autolinking/package.json').version)
.description('CLI command that searches for native modules to autolink them.');
(0, verifyCommand_1.verifyCommand)(cli);
(0, searchCommand_1.searchCommand)(cli);
(0, resolveCommand_1.resolveCommand)(cli);
(0, generatePackageListCommand_1.generatePackageListCommand)(cli);
(0, generateModulesProviderCommand_1.generateModulesProviderCommand)(cli);
(0, reactNativeConfigCommand_1.reactNativeConfigCommand)(cli);
await cli.parseAsync(args, { from: 'user' });
}
module.exports = main;
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,0DAAkC;AAElC,8FAA2F;AAC3F,sFAAmF;AACnF,kFAA+E;AAC/E,8DAA2D;AAC3D,4DAAyD;AACzD,4DAAyD;AAEzD,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,MAAM,GAAG,GAAG,mBAAS;SAClB,OAAO,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,OAAO,CAAC;SACjE,WAAW,CAAC,gEAAgE,CAAC,CAAC;IAEjF,IAAA,6BAAa,EAAC,GAAG,CAAC,CAAC;IACnB,IAAA,6BAAa,EAAC,GAAG,CAAC,CAAC;IACnB,IAAA,+BAAc,EAAC,GAAG,CAAC,CAAC;IACpB,IAAA,uDAA0B,EAAC,GAAG,CAAC,CAAC;IAChC,IAAA,+DAA8B,EAAC,GAAG,CAAC,CAAC;IACpC,IAAA,mDAAwB,EAAC,GAAG,CAAC,CAAC;IAE9B,MAAM,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC","sourcesContent":["import commander from 'commander';\n\nimport { generateModulesProviderCommand } from './commands/generateModulesProviderCommand';\nimport { generatePackageListCommand } from './commands/generatePackageListCommand';\nimport { reactNativeConfigCommand } from './commands/reactNativeConfigCommand';\nimport { resolveCommand } from './commands/resolveCommand';\nimport { searchCommand } from './commands/searchCommand';\nimport { verifyCommand } from './commands/verifyCommand';\n\nasync function main(args: string[]) {\n const cli = commander\n .version(require('expo-modules-autolinking/package.json').version)\n .description('CLI command that searches for native modules to autolink them.');\n\n verifyCommand(cli);\n searchCommand(cli);\n resolveCommand(cli);\n generatePackageListCommand(cli);\n generateModulesProviderCommand(cli);\n reactNativeConfigCommand(cli);\n\n await cli.parseAsync(args, { from: 'user' });\n}\n\nmodule.exports = main;\n"]}

Some files were not shown because too many files have changed in this diff Show More