From 4b7628adeaa2431ffe5d6fca10a35712ea567c24 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Thu, 7 May 2026 17:09:07 +0100 Subject: [PATCH 01/18] fix(brownfield/cli): Adjust iOS/Android library file discovery to remove symlink following (#44280) # Why `readdir`/`readdirSync` don't have a flag to turn off symlink-following. This makes the calls potentially dangerous, since they can enter uncontrolled directory traversals and infinite loops. While this shouldn't be an issue for the directory we're scanning here, it's just a few lines of code to replace this behaviour, so probably worth it. Discovered as part of #44279 # How - Replace `readdirSync(..., { recursive: true })` with manual directory traversal # Test Plan - See #44279 for tests first # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/expo-brownfield/CHANGELOG.md | 2 ++ .../cli/build/utils/android.js | 20 ++++++++++++++--- .../cli/build/utils/android.js.map | 2 +- .../expo-brownfield/cli/build/utils/ios.js | 20 ++++++++++++++--- .../cli/build/utils/ios.js.map | 2 +- .../expo-brownfield/cli/src/utils/android.ts | 22 ++++++++++++++----- packages/expo-brownfield/cli/src/utils/ios.ts | 22 ++++++++++++++----- 7 files changed, 72 insertions(+), 18 deletions(-) diff --git a/packages/expo-brownfield/CHANGELOG.md b/packages/expo-brownfield/CHANGELOG.md index 0aeff8ea7a5366..a0400f28e287c3 100644 --- a/packages/expo-brownfield/CHANGELOG.md +++ b/packages/expo-brownfield/CHANGELOG.md @@ -8,6 +8,8 @@ ### 🐛 Bug fixes +- Adjust CLI Android/iOS library file discovery to remove symlink following ([#44280](https://github.com/expo/expo/pull/44280) by [@kitten](https://github.com/kitten)) + ### 💡 Others ## 56.0.3 — 2026-05-06 diff --git a/packages/expo-brownfield/cli/build/utils/android.js b/packages/expo-brownfield/cli/build/utils/android.js index f1ef5510838479..698a03464924bf 100644 --- a/packages/expo-brownfield/cli/build/utils/android.js +++ b/packages/expo-brownfield/cli/build/utils/android.js @@ -25,9 +25,23 @@ const findBrownfieldLibrary = () => { .readdirSync(androidPath, { withFileTypes: true }) .filter((item) => item.isDirectory()); const brownfieldLibrary = subdirectories.find((directory) => { - const directoryPath = node_path_1.default.join(androidPath, directory.name); - const files = node_fs_1.default.readdirSync(directoryPath, { recursive: true }); - return files.some((file) => typeof file === 'string' && file.endsWith('ReactNativeHostManager.kt')); + const directoryPath = node_path_1.default.resolve(androidPath, directory.name); + const directories = [directoryPath]; + let target; + while ((target = directories.shift()) != null) { + const entries = node_fs_1.default.readdirSync(target, { withFileTypes: true }); + for (const entry of entries) { + const childPath = node_path_1.default.join(target, entry.name); + if (entry.isDirectory()) { + directories.push(childPath); + } + else if (entry.isFile()) { + if (entry.name === 'ReactNativeHostManager.kt') + return true; + } + } + } + return false; }); if (brownfieldLibrary) { return brownfieldLibrary.name; diff --git a/packages/expo-brownfield/cli/build/utils/android.js.map b/packages/expo-brownfield/cli/build/utils/android.js.map index ae3d662273d685..f5d243422f617d 100644 --- a/packages/expo-brownfield/cli/build/utils/android.js.map +++ b/packages/expo-brownfield/cli/build/utils/android.js.map @@ -1 +1 @@ -{"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/utils/android.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/utils/android.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-brownfield/cli/build/utils/ios.js b/packages/expo-brownfield/cli/build/utils/ios.js index 24fd2540eeb5c9..cb6e53b2aded0b 100644 --- a/packages/expo-brownfield/cli/build/utils/ios.js +++ b/packages/expo-brownfield/cli/build/utils/ios.js @@ -310,9 +310,23 @@ const findScheme = () => { .readdirSync(iosPath, { withFileTypes: true }) .filter((item) => item.isDirectory()); const scheme = subdirectories.find((directory) => { - const directoryPath = node_path_1.default.join(iosPath, directory.name); - const files = node_fs_1.default.readdirSync(directoryPath, { recursive: true }); - return files.some((file) => typeof file === 'string' && file.endsWith('ReactNativeHostManager.swift')); + const directoryPath = node_path_1.default.resolve(iosPath, directory.name); + const directories = [directoryPath]; + let target; + while ((target = directories.shift()) != null) { + const entries = node_fs_1.default.readdirSync(target, { withFileTypes: true }); + for (const entry of entries) { + const childPath = node_path_1.default.join(target, entry.name); + if (entry.isDirectory()) { + directories.push(childPath); + } + else if (entry.isFile()) { + if (entry.name === 'ReactNativeHostManager.swift') + return true; + } + } + } + return false; }); if (scheme) { return scheme.name; diff --git a/packages/expo-brownfield/cli/build/utils/ios.js.map b/packages/expo-brownfield/cli/build/utils/ios.js.map index d115474d166d81..bd4c3930d1e60b 100644 --- a/packages/expo-brownfield/cli/build/utils/ios.js.map +++ b/packages/expo-brownfield/cli/build/utils/ios.js.map @@ -1 +1 @@ -{"version":3,"file":"ios.js","sourceRoot":"","sources":["../../src/utils/ios.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;AAC1B,2DAA8C;AAC9C,sDAAyB;AACzB,0DAA6B;AAE7B,yCAAwC;AACxC,2CAA0C;AAC1C,oDAA+B;AAC/B,+CAIuB;AACvB,uCAAwC;AAGxC;;;;;;;;;;;GAWG;AACI,MAAM,wBAAwB,GAAG,CACtC,MAAiB,EACjB,cAA2B,EACjB,EAAE;IACZ,MAAM,eAAe,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACjG,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAA,6BAAQ,EAAC,aAAa,eAAe,GAAG,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,yFAAyF;QACzF,mDAAmD;QACnD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACjE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACf,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACjG,CAAC,CAAC;AA1BW,QAAA,wBAAwB,4BA0BnC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,oBAAoB,GAAG,CAAC,aAAqB,EAAY,EAAE;IAC/D,MAAM,IAAI,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,GAAG,aAAa,OAAO,CAAC;IACzC,IAAI,iBAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,CAAC,SAAiB,EAAE,IAAY,EAAiB,EAAE;IAClF,MAAM,UAAU,GAAG;QACjB,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,YAAY,CAAC;QACzC,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,EAAE,IAAI,EAAE,GAAG,IAAI,YAAY,CAAC;KAC5E,CAAC;IACF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,iBAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,CAAC;AAC1E,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,0BAA0B,GAAG,KAAK,EACtC,MAAiB,EACjB,IAAY,EACZ,IAAY,EACM,EAAE;IACpB,MAAM,eAAe,GAAG,wBAAwB,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtE,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAE5E,IAAI,CAAC,eAAe,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5C,OAAO,CAAC,IAAI,CACV,6CAA6C,IAAI,kBAAkB,MAAM,CAAC,MAAM,aAAa;YAC3F,0FAA0F;YAC1F,+EAA+E,IAAI,cAAc,IAAI,IAAI,CAC5G,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,cAAc,CAAC,CAAC;IAC1D,IAAI,iBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,iBAAE,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,GAAG;QACX,qBAAqB;QACrB,GAAG,oBAAoB,CAAC,eAAe,CAAC;QACxC,GAAG,oBAAoB,CAAC,kBAAkB,CAAC;QAC3C,SAAS;QACT,UAAU;KACX,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAA,qBAAU,EAAC,YAAY,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEK,MAAM,gBAAgB,GAAG,KAAK,EAAE,MAAiB,EAAE,EAAE;IAC1D,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,OAAO,IAAA,qBAAW,EAAC;QACjB,SAAS,EAAE,KAAK,IAAI,EAAE;YACpB,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACrC,OAAO;YACT,CAAC;YAED,iBAAE,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBAChD,MAAM,QAAQ,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC/C,iBAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;QACL,CAAC;QACD,aAAa,EAAE,mCAAmC;QAClD,cAAc,EAAE,0CAA0C;QAC1D,YAAY,EAAE,uCAAuC;KACtD,CAAC,CAAC;AACL,CAAC,CAAC;AArBW,QAAA,gBAAgB,oBAqB3B;AAEK,MAAM,cAAc,GAAG,KAAK,EAAE,MAAiB,EAAE,EAAE;IACxD,MAAM,IAAI,GAAG;QACX,YAAY;QACZ,MAAM,CAAC,SAAS;QAChB,SAAS;QACT,MAAM,CAAC,MAAM;QACb,kBAAkB;QAClB,MAAM,CAAC,eAAe;QACtB,cAAc;QACd,2BAA2B;QAC3B,cAAc;QACd,kCAAkC;QAClC,gBAAgB;QAChB,MAAM,CAAC,kBAAkB;QACzB,sEAAsE;QACtE,kEAAkE;QAClE,yEAAyE;QACzE,sEAAsE;QACtE,0CAA0C;KAC3C,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,OAAO,IAAA,qBAAW,EAAC;QACjB,SAAS,EAAE,GAAG,EAAE,CAAC,IAAA,qBAAU,EAAC,YAAY,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAC5E,aAAa,EAAE,wBAAwB;QACvC,cAAc,EAAE,+BAA+B;QAC/C,YAAY,EAAE,4BAA4B;QAC1C,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;AACL,CAAC,CAAC;AAjCW,QAAA,cAAc,kBAiCzB;AAEK,MAAM,gBAAgB,GAAG,KAAK,EAAE,MAAiB,EAAE,IAAY,EAAE,EAAE;IACxE,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAC;IAE9C,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,uBAAW,CAAC,CAAC;IAChD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,IAAI,iBAAE,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,MAAM,IAAA,qBAAW,EAAC;gBAChB,SAAS,EAAE,KAAK,IAAI,EAAE,CACpB,iBAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,WAAW,CAAC,IAAI,cAAc,CAAC,EAAE;oBACnF,KAAK,EAAE,IAAI;oBACX,SAAS,EAAE,IAAI;iBAChB,CAAC;gBACJ,aAAa,EAAE,WAAW,WAAW,CAAC,IAAI,gCAAgC;gBAC1E,cAAc,EAAE,WAAW,WAAW,CAAC,IAAI,uCAAuC;gBAClF,YAAY,EAAE,WAAW,WAAW,CAAC,IAAI,oCAAoC;gBAC7E,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,WAAW,CAAC,IAAI,KAAK,uBAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACxD,eAAQ,CAAC,MAAM,CAAC,gCAAgC,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QACtE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CACV,GAAG,WAAW,CAAC,IAAI,8BAA8B,WAAW,CAAC,IAAI,oCAAoC,CACtG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,kFAAkF;QAClF,sFAAsF;QACtF,uFAAuF;QACvF,MAAM,OAAO,GAAG,IAAA,yCAA2B,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAEtF,oFAAoF;QACpF,yFAAyF;QACzF,4FAA4F;QAC5F,2DAA2D;QAC3D,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACzC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAClC,MAAM,IAAA,iCAAmB,EAAC,MAAM,EAAE,MAAM,CAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5F,CAAC;YACD,MAAM,IAAA,qBAAW,EAAC;gBAChB,SAAS,EAAE,KAAK,IAAI,EAAE,CACpB,iBAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,EAAE,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,cAAc,CAAC,EAAE;oBACpF,KAAK,EAAE,IAAI;oBACX,SAAS,EAAE,IAAI;iBAChB,CAAC;gBACJ,aAAa,EAAE,WAAW,MAAM,CAAC,IAAI,gCAAgC;gBACrE,cAAc,EAAE,WAAW,MAAM,CAAC,IAAI,uCAAuC;gBAC7E,YAAY,EAAE,WAAW,MAAM,CAAC,IAAI,oCAAoC;gBACxE,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,iFAAiF;IACjF,qFAAqF;IACrF,qEAAqE;IACrE,MAAM,cAAc,GAAG,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,IAAA,gCAAwB,EAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACzE,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACtC,MAAM,IAAA,qBAAW,EAAC;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,0BAA0B,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;YAClE,aAAa,EAAE,yBAAyB,OAAO,oBAAoB;YACnE,cAAc,EAAE,yBAAyB,OAAO,2BAA2B;YAC3E,YAAY,EAAE,yBAAyB,OAAO,wBAAwB;YACtE,OAAO,EAAE,MAAM,CAAC,OAAO;SACxB,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;AA1EW,QAAA,gBAAgB,oBA0E3B;AAEF;;;;GAIG;AACH,MAAM,4BAA4B,GAAG,CAAC,MAAiB,EAAe,EAAE;IACtE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,IAAA,uCAAyB,GAAE,CAAC,CAAC,CAAC;IACjF,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,KAAK,MAAM,MAAM,IAAI,IAAA,yCAA2B,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC3F,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEK,MAAM,kBAAkB,GAAG,KAAK,EAAE,MAAiB,EAAmB,EAAE;IAC7E,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CACT,qCAAqC,MAAM,CAAC,MAAM,CAAC,WAAW,aAAa,MAAM,CAAC,SAAS,EAAE,CAC9F,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,MAAM,IAAA,qBAAW,EAAC;QACvB,SAAS,EAAE,KAAK,IAAI,EAAE;YACpB,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBACnC,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,WAAW,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC3E,MAAM,iBAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE1D,8BAA8B;YAC9B,MAAM,eAAe,GAAG,mBAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;YAC/D,MAAM,iBAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE9D,MAAM,IAAA,mCAA2B,EAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAEvD,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,aAAa,EAAE,2BAA2B;QAC1C,cAAc,EAAE,kCAAkC;QAClD,YAAY,EAAE,+BAA+B;QAC7C,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;AACL,CAAC,CAAC;AA9BW,QAAA,kBAAkB,sBA8B7B;AAEK,MAAM,iBAAiB,GAAG,KAAK,EAAE,MAAiB,EAAE,EAAU,EAAE,EAAE;IACvE,MAAM,aAAa,GAAG,GAAG,MAAM,CAAC,MAAM,cAAc,CAAC;IACrD,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAEhD,MAAM,IAAI,GAAG;QACX,qBAAqB;QACrB,GAAG,oBAAoB,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,YAAY,CAAC;QACtE,GAAG,oBAAoB,CAAC,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,YAAY,CAAC;QACzE,SAAS;QACT,UAAU;KACX,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,OAAO,IAAA,qBAAW,EAAC;QACjB,SAAS,EAAE,GAAG,EAAE,CAAC,IAAA,qBAAU,EAAC,YAAY,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAC5E,aAAa,EAAE,4CAA4C;QAC3D,cAAc,EAAE,mDAAmD;QACnE,YAAY,EAAE,gDAAgD;QAC9D,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;AACL,CAAC,CAAC;AAxBW,QAAA,iBAAiB,qBAwB5B;AAEK,MAAM,UAAU,GAAG,GAAuB,EAAE;IACjD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,eAAQ,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,cAAc,GAAG,iBAAE;aACtB,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aAC7C,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YAC/C,MAAM,aAAa,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACzD,MAAM,KAAK,GAAG,iBAAE,CAAC,WAAW,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,OAAO,KAAK,CAAC,IAAI,CACf,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CACpF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;QAED,eAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,eAAQ,CAAC,MAAM,CAAC,6BAA6B,EAAE,YAAY,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO;AACT,CAAC,CAAC;AA7BW,QAAA,UAAU,cA6BrB;AAEK,MAAM,aAAa,GAAG,CAAC,MAAe,EAAsB,EAAE;IACnE,mDAAmD;IACnD,8BAA8B;IAC9B,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,mCAAmC,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,eAAQ,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,KAAK,GAAG,iBAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3E,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,mBAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;QAED,eAAQ,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,eAAQ,CAAC,MAAM,CAAC,6BAA6B,EAAE,YAAY,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO;AACT,CAAC,CAAC;AA1BW,QAAA,aAAa,iBA0BxB;AAEK,MAAM,2BAA2B,GAAG,KAAK,EAAE,MAAiB,EAAE,WAAmB,EAAE,EAAE;IAC1F,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO;IACT,CAAC;IAED,MAAM,kBAAkB,GAAG,iBAAE,CAAC,UAAU,CAAC,uBAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,cAAc,GAAG;QACrB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QACjD,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE;QAC3C,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,uBAAW,CAAC,KAAK,EAAE,uBAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAClF,CAAC;IAEF,uFAAuF;IACvF,8FAA8F;IAC9F,4FAA4F;IAC5F,MAAM,kBAAkB,GAAG,MAAM,CAAC,YAAY;QAC5C,CAAC,CAAC,IAAA,yCAA2B,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACvF,IAAI;YACJ,OAAO,EAAE,CAAC,IAAI,CAAC;SAChB,CAAC,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;IAEP,0FAA0F;IAC1F,oFAAoF;IACpF,6DAA6D;IAC7D,MAAM,mBAAmB,GAAG,IAAA,gCAAwB,EAClD,MAAM,EACN,IAAI,GAAG,CAAC;QACN,MAAM,CAAC,MAAM;QACb,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;QACzC,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;KAC9C,CAAC,CACH,CAAC;IACF,MAAM,eAAe,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAEvF,MAAM,YAAY,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,kBAAkB,EAAE,GAAG,eAAe,CAAC,CAAC;IAEpF,2FAA2F;IAC3F,4FAA4F;IAC5F,mFAAmF;IACnF,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY;QAClC,CAAC,CAAC;YACE,IAAA,sBAAc,EACZ,MAAM,CAAC,MAAM,CAAC,WAAW,EACzB,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CACrC;SACF;QACH,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,IAAA,sBAAc,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAE3E,MAAM,QAAQ,GAAG;;;;aAIN,MAAM,CAAC,MAAM,CAAC,WAAW;kBACpB,CAAC,MAAM,IAAA,6BAAqB,EAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;EAE/D,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGnB,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAA,oBAAY,EAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;CAG9D,CAAC;IAEA,MAAM,iBAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,mBAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,QAAQ,CAAC,CAAC;AACjF,CAAC,CAAC;AAjEW,QAAA,2BAA2B,+BAiEtC;AAEK,MAAM,qBAAqB,GAAG,KAAK,EAAE,MAAiB,EAAqB,EAAE;IAClF,6DAA6D;IAC7D,MAAM,IAAI,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAE9F,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAU,EAAC,YAAY,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,MAAM,KAAK,GAAG,yCAAyC,CAAC;QACxD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAC9C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CACV,sFAAsF,CACvF,CAAC;IACJ,CAAC;IAED,wCAAwC;IACxC,OAAO,CAAC,YAAY,CAAC,CAAC;AACxB,CAAC,CAAC;AArBW,QAAA,qBAAqB,yBAqBhC;AAEK,MAAM,cAAc,GAAG,CAAC,IAAY,EAAE,OAAiB,EAAE,EAAE;IAChE,OAAO;iBACQ,IAAI;qBACA,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;SAChC,CAAC;AACV,CAAC,CAAC;AALW,QAAA,cAAc,kBAKzB;AAEK,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE;IAC3C,OAAO;iBACQ,IAAI;8BACS,IAAI;SACzB,CAAC;AACV,CAAC,CAAC;AALW,QAAA,YAAY,gBAKvB;AAEK,MAAM,sBAAsB,GAAG,CAAC,MAAiB,EAAE,EAAE;IAC1D,IAAI,CAAC;QACH,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,iBAAE,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,eAAQ,CAAC,MAAM,CAAC,uCAAuC,EAAE,YAAY,CAAC,CAAC;IACzE,CAAC;AACH,CAAC,CAAC;AATW,QAAA,sBAAsB,0BASjC;AAEK,MAAM,cAAc,GAAG,CAAC,MAAiB,EAAE,EAAE;IAClD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,2BAA2B,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,cAAc,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,iBAAiB,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,eAAe,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,eAAe,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,sBAAsB,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAElE,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,oBAAoB,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,kCAAkC,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAEjF,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC,CAAC;AAfW,QAAA,cAAc,kBAezB;AAEK,MAAM,cAAc,GAAG,KAAK,EAAE,MAAiB,EAAE,EAAE;IACxD,6BAA6B;IAC7B,MAAM,IAAA,wBAAgB,EAAC,MAAM,CAAC,CAAC;IAC/B,IAAA,8BAAsB,EAAC,MAAM,CAAC,CAAC;IAE/B,4CAA4C;IAC5C,MAAM,IAAA,yBAAiB,EAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,IAAA,wBAAgB,EAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;AACnD,CAAC,CAAC;AARW,QAAA,cAAc,kBAQzB;AAEK,MAAM,gBAAgB,GAAG,KAAK,EAAE,MAAiB,EAAE,EAAE;IAC1D,+CAA+C;IAC/C,MAAM,IAAA,wBAAgB,EAAC,MAAM,CAAC,CAAC;IAC/B,IAAA,8BAAsB,EAAC,MAAM,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,MAAM,IAAA,0BAAkB,EAAC,MAAM,CAAC,CAAC;IACrD,MAAM,gBAAgB,GAAG,mBAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAEhE,4CAA4C;IAC5C,MAAM,IAAA,yBAAiB,EAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAClD,MAAM,IAAA,wBAAgB,EAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AACnD,CAAC,CAAC;AAVW,QAAA,gBAAgB,oBAU3B"} \ No newline at end of file +{"version":3,"file":"ios.js","sourceRoot":"","sources":["../../src/utils/ios.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-brownfield/cli/src/utils/android.ts b/packages/expo-brownfield/cli/src/utils/android.ts index cb8f198df9657c..871e5ce7da7acd 100644 --- a/packages/expo-brownfield/cli/src/utils/android.ts +++ b/packages/expo-brownfield/cli/src/utils/android.ts @@ -23,11 +23,23 @@ export const findBrownfieldLibrary = (): string | undefined => { .readdirSync(androidPath, { withFileTypes: true }) .filter((item) => item.isDirectory()); const brownfieldLibrary = subdirectories.find((directory) => { - const directoryPath = path.join(androidPath, directory.name); - const files = fs.readdirSync(directoryPath, { recursive: true }); - return files.some( - (file) => typeof file === 'string' && file.endsWith('ReactNativeHostManager.kt') - ); + const directoryPath = path.resolve(androidPath, directory.name); + const directories = [directoryPath]; + + let target: string | undefined; + while ((target = directories.shift()) != null) { + const entries = fs.readdirSync(target, { withFileTypes: true }); + for (const entry of entries) { + const childPath = path.join(target, entry.name); + if (entry.isDirectory()) { + directories.push(childPath); + } else if (entry.isFile()) { + if (entry.name === 'ReactNativeHostManager.kt') return true; + } + } + } + + return false; }); if (brownfieldLibrary) { diff --git a/packages/expo-brownfield/cli/src/utils/ios.ts b/packages/expo-brownfield/cli/src/utils/ios.ts index ad6b8e16f9c8a4..fc2c9575e38e7f 100644 --- a/packages/expo-brownfield/cli/src/utils/ios.ts +++ b/packages/expo-brownfield/cli/src/utils/ios.ts @@ -352,11 +352,23 @@ export const findScheme = (): string | undefined => { .readdirSync(iosPath, { withFileTypes: true }) .filter((item) => item.isDirectory()); const scheme = subdirectories.find((directory) => { - const directoryPath = path.join(iosPath, directory.name); - const files = fs.readdirSync(directoryPath, { recursive: true }); - return files.some( - (file) => typeof file === 'string' && file.endsWith('ReactNativeHostManager.swift') - ); + const directoryPath = path.resolve(iosPath, directory.name); + const directories = [directoryPath]; + + let target: string | undefined; + while ((target = directories.shift()) != null) { + const entries = fs.readdirSync(target, { withFileTypes: true }); + for (const entry of entries) { + const childPath = path.join(target, entry.name); + if (entry.isDirectory()) { + directories.push(childPath); + } else if (entry.isFile()) { + if (entry.name === 'ReactNativeHostManager.swift') return true; + } + } + } + + return false; }); if (scheme) { From 19ad2f9f69e0d6ac0f078a37f30c4ac5d34a7954 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Thu, 7 May 2026 17:10:03 +0100 Subject: [PATCH 02/18] perf(cli): Reduce `withMetroErrorReportingResolver`'s memory pressure (#45446) # Why The current data structure accumulates duplicates over time and doesn't merge well, which can cause excessive GC runs and an unbounded increase in memory over time. # How - Restructure data structure to shed `Set` and replace `{ request, path }` structure - **NOTE:** This had nothing to merge on before - Reduce cost of `customResolverOptions` serialisation for keying - Add memoisation for previous map structure as a micro-opt # Test Plan - Existing tests (with changes to adjust the data structure) should pass as-is # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/@expo/cli/CHANGELOG.md | 1 + .../withMetroErrorReportingResolver.test.ts | 234 ++---------------- .../metro/withMetroErrorReportingResolver.ts | 93 ++++--- 3 files changed, 86 insertions(+), 242 deletions(-) diff --git a/packages/@expo/cli/CHANGELOG.md b/packages/@expo/cli/CHANGELOG.md index 9901eb7538b63e..3cd454f28ba875 100644 --- a/packages/@expo/cli/CHANGELOG.md +++ b/packages/@expo/cli/CHANGELOG.md @@ -14,6 +14,7 @@ - Bump to `@expo/xcpretty@^4.4.4` ([#45473](https://github.com/expo/expo/pull/45473) by [@EvanBacon](https://github.com/EvanBacon)) - Tweak dependency check message and placement on `expo start` ([#45487](https://github.com/expo/expo/pull/45487) by [@kitten](https://github.com/kitten)) +- Reduce memory pressure/usage from `withMetroErrorReportingResolver` ([#45446](https://github.com/expo/expo/pull/45446) by [@kitten](https://github.com/kitten)) ## 56.0.5 — 2026-05-06 diff --git a/packages/@expo/cli/src/start/server/metro/__tests__/withMetroErrorReportingResolver.test.ts b/packages/@expo/cli/src/start/server/metro/__tests__/withMetroErrorReportingResolver.test.ts index 101db5b7cc4b04..e86cc864dc54b6 100644 --- a/packages/@expo/cli/src/start/server/metro/__tests__/withMetroErrorReportingResolver.test.ts +++ b/packages/@expo/cli/src/start/server/metro/__tests__/withMetroErrorReportingResolver.test.ts @@ -25,28 +25,9 @@ it('adds import stack to error', () => { [ 'ios', // platform new Map([ - [ - '/project/a.js', - new Set([ - { - path: '/project/b.js', - request: 'b', - }, - ]), - ], - [ - '/project/b.js', - new Set([ - { - path: '/project/c.js', - request: 'c', - }, - ]), - ], - [ - '/project/c.js', // unresolved module - new Set<{ path: string; request: string }>(), - ], + ['/project/a.js', new Map([['/project/b.js', 'b']])], + ['/project/b.js', new Map([['/project/c.js', 'c']])], + ['/project/c.js', new Map()], ]), ], ]), @@ -90,24 +71,8 @@ it('adds import stack with circular dependencies to error', () => { [ 'ios', // platform new Map([ - [ - '/project/foo.js', - new Set([ - { - path: '/project/bar.js', - request: 'bar', - }, - ]), - ], - [ - '/project/bar.js', - new Set([ - { - path: '/project/foo.js', - request: 'foo', - }, - ]), - ], + ['/project/foo.js', new Map([['/project/bar.js', 'bar']])], + ['/project/bar.js', new Map([['/project/foo.js', 'foo']])], ]), ], ]), @@ -155,37 +120,10 @@ it('adds import stack with stack depth limit to error', () => { [ 'ios', // platform new Map([ - [ - '/project/a.js', - new Set([ - { - path: '/project/b.js', - request: 'b', - }, - ]), - ], - [ - '/project/b.js', - new Set([ - { - path: '/project/c.js', - request: 'c', - }, - ]), - ], - [ - '/project/c.js', - new Set([ - { - path: '/project/d.js', - request: 'd', - }, - ]), - ], - [ - '/project/d.js', // unresolved module - new Set<{ path: string; request: string }>(), - ], + ['/project/a.js', new Map([['/project/b.js', 'b']])], + ['/project/b.js', new Map([['/project/c.js', 'c']])], + ['/project/c.js', new Map([['/project/d.js', 'd']])], + ['/project/d.js', new Map()], ]), ], ]), @@ -230,37 +168,10 @@ it('adds import stack with stack count limit to error', () => { [ 'ios', // platform new Map([ - [ - '/project/node_modules/a.js', - new Set([ - { - path: '/project/b.js', - request: 'b', - }, - ]), - ], - [ - '/project/a.js', - new Set([ - { - path: '/project/b.js', - request: 'b', - }, - ]), - ], - [ - '/project/b.js', - new Set([ - { - path: '/project/c.js', - request: 'c', - }, - ]), - ], - [ - '/project/c.js', // unresolved module - new Set<{ path: string; request: string }>(), - ], + ['/project/node_modules/a.js', new Map([['/project/b.js', 'b']])], + ['/project/a.js', new Map([['/project/b.js', 'b']])], + ['/project/b.js', new Map([['/project/c.js', 'c']])], + ['/project/c.js', new Map()], ]), ], ]), @@ -304,94 +215,24 @@ it('prioritizes project stack over node_modules, circular deps, and depth limite 'ios', // platform new Map([ // Node modules stack - [ - '/project/node_modules/lib.js', - new Set([ - { - path: '/project/utils.js', - request: 'utils', - }, - ]), - ], + ['/project/node_modules/lib.js', new Map([['/project/utils.js', 'utils']])], // Circular dependency stack - [ - '/project/circular1.js', - new Set([ - { - path: '/project/circular2.js', - request: 'circular2', - }, - ]), - ], + ['/project/circular1.js', new Map([['/project/circular2.js', 'circular2']])], [ '/project/circular2.js', - new Set([ - { - path: '/project/circular1.js', - request: 'circular1', - }, - { - path: '/project/utils.js', - request: 'utils', - }, + new Map([ + ['/project/circular1.js', 'circular1'], + ['/project/utils.js', 'utils'], ]), ], // Deep stack that would hit depth limit - [ - '/project/deep1.js', - new Set([ - { - path: '/project/deep2.js', - request: 'deep2', - }, - ]), - ], - [ - '/project/deep2.js', - new Set([ - { - path: '/project/deep3.js', - request: 'deep3', - }, - ]), - ], - [ - '/project/deep3.js', - new Set([ - { - path: '/project/deep4.js', - request: 'deep4', - }, - ]), - ], - [ - '/project/deep4.js', - new Set([ - { - path: '/project/utils.js', - request: 'utils', - }, - ]), - ], + ['/project/deep1.js', new Map([['/project/deep2.js', 'deep2']])], + ['/project/deep2.js', new Map([['/project/deep3.js', 'deep3']])], + ['/project/deep3.js', new Map([['/project/deep4.js', 'deep4']])], + ['/project/deep4.js', new Map([['/project/utils.js', 'utils']])], // preferred project - [ - '/project/app.js', - new Set([ - { - path: '/project/utils.js', - request: 'utils', - }, - ]), - ], - [ - '/project/utils.js', - new Set([ - { - path: '/project/missing.js', - request: 'missing', - }, - ]), - ], + ['/project/app.js', new Map([['/project/utils.js', 'utils']])], + ['/project/utils.js', new Map([['/project/missing.js', 'missing']])], ]), ], ]), @@ -435,33 +276,12 @@ it('prioritizes projectRoot stack over server root stack', () => { 'ios', // platform new Map([ // Server root stack - [ - '/server-root/lib.js', - new Set([ - { - path: '/server-root/project/utils.js', - request: 'utils', - }, - ]), - ], + ['/server-root/lib.js', new Map([['/server-root/project/utils.js', 'utils']])], // Project root stack (should be preferred) - [ - '/server-root/project/app.js', - new Set([ - { - path: '/server-root/project/utils.js', - request: 'utils', - }, - ]), - ], + ['/server-root/project/app.js', new Map([['/server-root/project/utils.js', 'utils']])], [ '/server-root/project/utils.js', - new Set([ - { - path: '/server-root/project/missing.js', - request: 'missing', - }, - ]), + new Map([['/server-root/project/missing.js', 'missing']]), ], ]), ], diff --git a/packages/@expo/cli/src/start/server/metro/withMetroErrorReportingResolver.ts b/packages/@expo/cli/src/start/server/metro/withMetroErrorReportingResolver.ts index cf41f6ed8e4b95..853bf6ecfc2fe2 100644 --- a/packages/@expo/cli/src/start/server/metro/withMetroErrorReportingResolver.ts +++ b/packages/@expo/cli/src/start/server/metro/withMetroErrorReportingResolver.ts @@ -1,10 +1,10 @@ import type { ConfigT as MetroConfig } from '@expo/metro/metro-config'; +import canonicalize from '@expo/metro/metro-core/canonicalize'; import type { ResolutionContext } from '@expo/metro/metro-resolver'; import chalk from 'chalk'; import path from 'path'; import { stripVTControlCharacters } from 'util'; -import type { ExpoCustomMetroResolver } from './withMetroResolvers'; import { isPathInside } from '../../../utils/dir'; import { env } from '../../../utils/env'; @@ -25,27 +25,18 @@ export function withMetroErrorReportingResolver(config: MetroConfig): MetroConfi const mutateResolutionError = createMutateResolutionError(config, depGraph); + // Single-entry cache for the most recent (options, platform, origin) → deps map. + // Metro resolves depth-first, so the same origin repeats for consecutive calls. + let _prevOptions: Record | null | undefined; + let _prevPlatform: string | undefined; + let _prevOrigin: string | undefined; + let _prevDeps: Map | undefined; + return { ...config, resolver: { ...config.resolver, resolveRequest(context, moduleName, platform) { - const storeResult = (res: NonNullable>) => { - const inputPlatform = platform ?? 'null'; - - const key = optionsKeyForContext(context); - if (!depGraph.has(key)) depGraph.set(key, new Map()); - const mapByTarget = depGraph.get(key); - if (!mapByTarget!.has(inputPlatform)) mapByTarget!.set(inputPlatform, new Map()); - const mapByPlatform = mapByTarget!.get(inputPlatform); - if (!mapByPlatform!.has(context.originModulePath)) - mapByPlatform!.set(context.originModulePath, new Set()); - const setForModule = mapByPlatform!.get(context.originModulePath)!; - - const qualifiedModuleName = res?.type === 'sourceFile' ? res.filePath : moduleName; - setForModule.add({ path: qualifiedModuleName, request: moduleName }); - }; - // If the user defined a resolver, run it first and depend on the documented // chaining logic: https://facebook.github.io/metro/docs/resolution/#resolution-algorithm // @@ -58,7 +49,34 @@ export function withMetroErrorReportingResolver(config: MetroConfig): MetroConfi try { const firstResolver = originalResolveRequest ?? context.resolveRequest; const res = firstResolver(context, moduleName, platform); - storeResult(res); + + const inputPlatform = platform ?? 'null'; + let depsForModule: Map | undefined; + + if ( + context.customResolverOptions === _prevOptions && + inputPlatform === _prevPlatform && + context.originModulePath === _prevOrigin + ) { + depsForModule = _prevDeps!; + } else { + const key = optionsKeyForContext(context); + let mapByTarget = depGraph.get(key); + if (!mapByTarget) depGraph.set(key, (mapByTarget = new Map())); + let mapByPlatform = mapByTarget.get(inputPlatform); + if (!mapByPlatform) mapByTarget.set(inputPlatform, (mapByPlatform = new Map())); + depsForModule = mapByPlatform.get(context.originModulePath); + if (!depsForModule) + mapByPlatform.set(context.originModulePath, (depsForModule = new Map())); + _prevOptions = context.customResolverOptions; + _prevPlatform = inputPlatform; + _prevOrigin = context.originModulePath; + _prevDeps = depsForModule; + } + + const qualifiedModuleName = res?.type === 'sourceFile' ? res.filePath : moduleName; + depsForModule.set(qualifiedModuleName, moduleName); + return res; } catch (error: any) { throw mutateResolutionError(error, context, moduleName, platform); @@ -77,21 +95,28 @@ export type DepGraph = Map< Map< // origin module name string, - Set<{ - // required module name - path: string; - // This isn't entirely accurate since a module can be imported multiple times in a file, - // and use different names. But it's good enough for now. - request: string; - }> + // resolved path → import request + // This isn't entirely accurate since a module can be imported multiple times in a file, + // and use different names. But it's good enough for now. + Map > > >; -function optionsKeyForContext(context: ResolutionContext) { - const canonicalize: typeof import('@expo/metro/metro-core/canonicalize').default = require('@expo/metro/metro-core/canonicalize'); - // Compound key for the resolver cache - return JSON.stringify(context.customResolverOptions ?? {}, canonicalize) ?? ''; +const optionsKeyCache = new WeakMap, string>(); +const EMPTY_OPTIONS_KEY = '{}'; + +function optionsKeyForContext(context: ResolutionContext): string { + const options = context.customResolverOptions; + if (options == null) { + return EMPTY_OPTIONS_KEY; + } + let key = optionsKeyCache.get(options); + if (key == null) { + key = JSON.stringify(options, canonicalize) ?? EMPTY_OPTIONS_KEY; + optionsKeyCache.set(options, key); + } + return key; } interface ErrorWithExpoImportStack extends Error { @@ -129,15 +154,13 @@ export const createMutateResolutionError = return inverseOrigin; } - for (const [originKey, mapByTarget] of mapByPlatform) { - // search comparing origin to path - - const found = [...mapByTarget.values()].find((resolution) => resolution.path === origin); - if (found) { + for (const [originKey, depsMap] of mapByPlatform) { + const request = depsMap.get(origin); + if (request !== undefined) { inverseOrigin.push({ origin, previous: originKey, - request: found.request, + request, }); } } From 7d65b8146b4bf422a562417f2636adf678856b65 Mon Sep 17 00:00:00 2001 From: Aman Mittal Date: Thu, 7 May 2026 22:34:39 +0530 Subject: [PATCH 03/18] [docs] Add Expo Skills option to SDK upgrade guide (#45256) --- .../workflow/upgrading-expo-sdk-walkthrough.mdx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/pages/workflow/upgrading-expo-sdk-walkthrough.mdx b/docs/pages/workflow/upgrading-expo-sdk-walkthrough.mdx index 4af20d20fb1f55..24d67cfe6554ff 100644 --- a/docs/pages/workflow/upgrading-expo-sdk-walkthrough.mdx +++ b/docs/pages/workflow/upgrading-expo-sdk-walkthrough.mdx @@ -15,9 +15,15 @@ If you are looking to install a specific version of Expo Go, visit [expo.dev/go] ## How to upgrade to the latest SDK version +### Upgrade with an AI coding agent + +If you use an AI coding agent, install [Expo Skills](/skills/) and use the [`upgrading-expo` skill](/skills/#available-expo-skills). The skill provides guidelines for upgrading Expo SDK versions and fixing dependency issues. Review any proposed changes and check the SDK changelog for version-specific instructions. + +### Upgrade manually + -### Upgrade the Expo SDK +#### Upgrade the Expo SDK Install the new version of the Expo package: @@ -36,7 +42,7 @@ Depending on which SDK you're upgrading to, substitute `expo@^55.0.0` with the v -### Upgrade dependencies +#### Upgrade dependencies Upgrade all dependencies to match the installed SDK version. Then run [`expo-doctor`](/develop/tools/#expo-doctor) command to check for common problems. @@ -49,7 +55,7 @@ Upgrade all dependencies to match the installed SDK version. Then run [`expo-doc -### Update native projects +#### Update native projects - **If you use [Continuous Native Generation](/workflow/continuous-native-generation/)**: Delete the **android** and **ios** directories if you generated them for a previous SDK version in your local project directory. They'll be re-generated next time you run a build, either with `npx expo run:ios`, `npx expo prebuild`, or with EAS Build. - **If you don't use [Continuous Native Generation](/workflow/continuous-native-generation/)**: Run `npx pod-install` if you have an **ios** directory. Apply any relevant changes from the [Native project upgrade helper](/bare/upgrade/). Alternatively, you could consider [adopting prebuild](/guides/adopting-prebuild/) for easier upgrades in the future. @@ -58,7 +64,7 @@ Upgrade all dependencies to match the installed SDK version. Then run [`expo-doc -### Follow the release notes for any other instructions +#### Follow the release notes for any other instructions Read the [SDK changelogs](#sdk-changelogs) for the SDK version you are upgrading to. They contain important information about breaking changes, deprecations, and other changes that may affect your app. Refer to the "Upgrading your app" section at the bottom of the release notes page for any additional instructions. From 7d46c17da14dd30d463889963d7ece299a3f02bd Mon Sep 17 00:00:00 2001 From: Aman Mittal Date: Thu, 7 May 2026 22:34:59 +0530 Subject: [PATCH 04/18] [docs] Add Vale rule for the Prerequisites component (#45308) --- docs/.vale.ini | 4 ++++ docs/.vale/writing-styles/expo-docs/Prerequisites.yml | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 docs/.vale/writing-styles/expo-docs/Prerequisites.yml diff --git a/docs/.vale.ini b/docs/.vale.ini index 9e49e8827e826b..20d1f14808d938 100644 --- a/docs/.vale.ini +++ b/docs/.vale.ini @@ -29,3 +29,7 @@ BasedOnStyles = [**/pages/versions/latest/**] Vale = NO BasedOnStyles = + +# README.md is contributor docs, not user-facing pages, so the component does not apply there. +[**/README.md] +expo-docs.Prerequisites = NO diff --git a/docs/.vale/writing-styles/expo-docs/Prerequisites.yml b/docs/.vale/writing-styles/expo-docs/Prerequisites.yml new file mode 100644 index 00000000000000..bb733d93ba7f97 --- /dev/null +++ b/docs/.vale/writing-styles/expo-docs/Prerequisites.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Use the component instead of a markdown 'Prerequisites' heading with a bulleted checklist." +link: 'https://github.com/expo/expo/blob/main/docs/README.md#use-prerequisites-for-setup-checklists' +level: warning +scope: raw +raw: + - '\n#{2,4}\s+Prerequisites\s*\n+(?:[^\n]*\n){0,5}-\s' From 34663f3582c25136ae80f88230f45e661dc368b4 Mon Sep 17 00:00:00 2001 From: Aman Mittal Date: Thu, 7 May 2026 22:44:32 +0530 Subject: [PATCH 05/18] [docs] Update CodePush migration channel surfing verbiage (#45255) # Why Fix ENG-20848 # How - Update the CodePush migration conceptual differences section to account for Channel Surfing - Replace outdated wording that said release builds could not switch update streams - Link to the Channel Surfing docs for production-build runtime channel switching # Test Plan Proofread. # Checklist - [ ] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --------- Co-authored-by: Kadi Kraman --- docs/pages/eas-update/codepush.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pages/eas-update/codepush.mdx b/docs/pages/eas-update/codepush.mdx index 0ac91aef41dfcf..6fcee7015757c8 100644 --- a/docs/pages/eas-update/codepush.mdx +++ b/docs/pages/eas-update/codepush.mdx @@ -143,14 +143,14 @@ CodePush and EAS Update are both services that allow you to send hotfixes to the **CodePush has single streams of updates for deployments**. What this means is that you can point a build to a deployment, and it will pull updates from that. If you want to change the deployment that is targeted by a build, you can do this at runtime through a JavaScript API. -**EAS Update has multiple streams of updates** — one that correspond to your source control branches (called branches), and another called channels, which point to branches. The mapping between channels and branches is handled on the server side, and a channel can point to different branches for each runtime version (additionally, more advanced logic may be expressed, such as to support incremental rollouts). Builds are not directly associated with branches, but rather with channels. Each build points to a single channel, which is set at build time and cannot be modified at runtime. The reason for this is that it ensures that certain branches (for example: development, staging) don't automatically go out to production — your preview updates don't go to your production users. This helps you separate the two main uses of EAS Update: previews and production hotfixes. +**EAS Update has multiple streams of updates** — one that corresponds to your source control branches (called branches), and another called channels, which point to branches. The mapping between channels and branches is handled on the server side, and a channel can point to different branches for each runtime version (additionally, more advanced logic may be expressed, such as to support incremental rollouts). Builds are not directly associated with branches, but rather with channels. Each build points to a single channel by default. The reason for this is that it ensures that certain branches (for example: development, staging) don't automatically go out to production, so your preview updates don't go to your production users. This helps you separate the two main uses of EAS Update: previews and production hotfixes. -A key distinction between CodePush and EAS Update that can impact your release process is that **with CodePush, the client controls the target update deployment at runtime**, and **with EAS Update, it is controlled on the server side, by mapping channels to branches**. This means that you can't include code in your app using EAS Update to instruct it to load a different stream of updates depending on runtime criteria, such as the current user role (for example: distribute beta releases to employees) - it will only load the branch that is mapped on EAS Update servers to the corresponding channel (such as production or staging). +A key distinction between CodePush and EAS Update that can impact your release process is that **with CodePush, the client controls the target update deployment at runtime**, and **with EAS Update, the default path is controlled on the server side, by mapping channels to branches**. In the default EAS Update flow, a build requests updates for its configured channel, and EAS Update returns the latest compatible update from the branch mapped to that channel. -The ability to control the target deployment at runtime is commonly used with CodePush in staging environments to allow non-technical stakeholders to test features from a single build on Google Play Beta / TestFlight. The current alternative for this with EAS Update is to use [development builds](/eas-update/expo-dev-client/). We're currently working on providing a way to do this with release builds. +The ability to control the target deployment at runtime is commonly used with CodePush in staging environments to allow non-technical stakeholders to test features from a single build on Google Play Beta and TestFlight. With EAS Update, you can achieve the same via [channel surfing](/eas-update/override/#what-is-channel-surfing). This allows you to switch update channels in non-development builds at runtime. Development builds can also load updates from any compatible channel and are a good fit for developer-focused testing. From 81ea44508b1b1816dad4dfda191c318f5a7041c5 Mon Sep 17 00:00:00 2001 From: Gabriel Donadel Dall'Agnol Date: Thu, 7 May 2026 14:16:02 -0300 Subject: [PATCH 06/18] [templates][iOS] Enable EXPO_USE_PRECOMPILED_MODULES by default (#45505) # Why We're enabling prebuilds on iOS by default starting from SDK 56 # How Update the default template to enable `EXPO_USE_PRECOMPILED_MODULES` var by default # Test Plan run `pod install` inside BareExpo # Checklist - [ ] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- apps/bare-expo/ios/Podfile | 2 +- apps/minimal-tester/ios/Podfile | 2 +- templates/expo-template-bare-minimum/ios/Podfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/bare-expo/ios/Podfile b/apps/bare-expo/ios/Podfile index db408640868581..1744a544ce07ce 100644 --- a/apps/bare-expo/ios/Podfile +++ b/apps/bare-expo/ios/Podfile @@ -8,7 +8,7 @@ ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NET ENV['RCT_USE_RN_DEP'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true' ENV['RCT_USE_PREBUILT_RNCORE'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' -ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] == 'true' +ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false' platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4' diff --git a/apps/minimal-tester/ios/Podfile b/apps/minimal-tester/ios/Podfile index 27862a21161451..583272c6359023 100644 --- a/apps/minimal-tester/ios/Podfile +++ b/apps/minimal-tester/ios/Podfile @@ -16,7 +16,7 @@ ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NET ENV['RCT_USE_RN_DEP'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' ENV['RCT_USE_PREBUILT_RNCORE'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true' -ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] == 'true' +ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false' platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4' prepare_react_native_project! diff --git a/templates/expo-template-bare-minimum/ios/Podfile b/templates/expo-template-bare-minimum/ios/Podfile index 4faec65c1adb75..26d3e3c96fd274 100644 --- a/templates/expo-template-bare-minimum/ios/Podfile +++ b/templates/expo-template-bare-minimum/ios/Podfile @@ -16,7 +16,7 @@ ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NET ENV['RCT_USE_RN_DEP'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' ENV['RCT_USE_PREBUILT_RNCORE'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true' -ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] == 'true' +ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false' platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4' prepare_react_native_project! From e892633cb72b9c11ba678f985c332ef76146ae12 Mon Sep 17 00:00:00 2001 From: Aman Mittal Date: Thu, 7 May 2026 22:49:57 +0530 Subject: [PATCH 07/18] [docs] Add command-line Vale rule and fix adjective usage (#45262) --- docs/.vale/writing-styles/expo-docs/CommandLine.yml | 11 +++++++++++ docs/.vale/writing-styles/expo-docs/HeadingCase.yml | 1 + docs/pages/accounts/two-factor.mdx | 2 +- docs/pages/config-plugins/patch-project.mdx | 2 +- docs/pages/develop/tools.mdx | 2 +- docs/pages/eas-update/getting-started.mdx | 2 +- docs/pages/eas/hosting/get-started.mdx | 2 +- docs/pages/eas/metadata/index.mdx | 2 +- docs/pages/eas/workflows/syntax.mdx | 2 +- docs/pages/more/expo-cli.mdx | 2 +- docs/pages/more/glossary-of-terms.mdx | 2 +- .../push-notifications/sending-notifications.mdx | 2 +- docs/pages/troubleshooting/proxies.mdx | 6 +++--- docs/pages/tutorial/create-your-first-app.mdx | 2 +- .../tutorial/eas/configure-development-build.mdx | 2 +- 15 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 docs/.vale/writing-styles/expo-docs/CommandLine.yml diff --git a/docs/.vale/writing-styles/expo-docs/CommandLine.yml b/docs/.vale/writing-styles/expo-docs/CommandLine.yml new file mode 100644 index 00000000000000..e70e6a320d96fc --- /dev/null +++ b/docs/.vale/writing-styles/expo-docs/CommandLine.yml @@ -0,0 +1,11 @@ +extends: substitution +message: "Use '%s' instead of '%s' when the phrase modifies a noun." +level: warning +nonword: true +scope: ~text.frontmatter +action: + name: replace +swap: + '\bcommand line(?= (?:app|apps|application|applications|argument|arguments|client|clients|experience|flag|flags|interface|interfaces|option|options|program|programs|script|scripts|tool|tools|utility|utilities)\b)': command-line + '\bCommand line(?= (?:app|apps|application|applications|argument|arguments|client|clients|experience|flag|flags|interface|interfaces|option|options|program|programs|script|scripts|tool|tools|utility|utilities)\b)': Command-line + '\bCommand Line(?= (?:App|Apps|Application|Applications|Argument|Arguments|Client|Clients|Experience|Flag|Flags|Interface|Interfaces|Option|Options|Program|Programs|Script|Scripts|Tool|Utility|Utilities)\b)': Command-line diff --git a/docs/.vale/writing-styles/expo-docs/HeadingCase.yml b/docs/.vale/writing-styles/expo-docs/HeadingCase.yml index cd9b3891cca93c..8020ecf0736f8e 100644 --- a/docs/.vale/writing-styles/expo-docs/HeadingCase.yml +++ b/docs/.vale/writing-styles/expo-docs/HeadingCase.yml @@ -57,6 +57,7 @@ exceptions: - '.*CDN.*' - '.*Chrome.*' - '.*CLI.*' + - '.*TTI.*' - '.*Classic Updates.*' - '.*CNG.*' - '.*CocoaPods.*' diff --git a/docs/pages/accounts/two-factor.mdx b/docs/pages/accounts/two-factor.mdx index 3456750fdce4e4..8ca91ee83dcb70 100644 --- a/docs/pages/accounts/two-factor.mdx +++ b/docs/pages/accounts/two-factor.mdx @@ -3,7 +3,7 @@ title: Two-factor authentication description: Learn about how you leverage two-factor authentication (2FA) to secure your Expo account. --- -Two-factor authentication provides an extra layer of security when logging in to expo.dev, the Expo Go app, and command line tools. With two-factor authentication enabled, you will need to provide a short-lived code in addition to your username and password to access your account. +Two-factor authentication provides an extra layer of security when logging in to expo.dev, the Expo Go app, and command-line tools. With two-factor authentication enabled, you will need to provide a short-lived code in addition to your username and password to access your account. ## Enable two-factor authentication (2FA) diff --git a/docs/pages/config-plugins/patch-project.mdx b/docs/pages/config-plugins/patch-project.mdx index ce8223eccfbcce..5edb17f2582b59 100644 --- a/docs/pages/config-plugins/patch-project.mdx +++ b/docs/pages/config-plugins/patch-project.mdx @@ -15,7 +15,7 @@ This guide explains how to use `patch-project`, when to use it, and its limitati ## How patch-project works -`patch-project` uses an approach to generate and automatically apply patches, which is inspired by Git. Using this command line tool requires the following steps in your project: +`patch-project` uses an approach to generate and automatically apply patches, which is inspired by Git. Using this command-line tool requires the following steps in your project: ### Installation diff --git a/docs/pages/develop/tools.mdx b/docs/pages/develop/tools.mdx index 05747d8bee2dd6..3ec40dcb62460a 100644 --- a/docs/pages/develop/tools.mdx +++ b/docs/pages/develop/tools.mdx @@ -51,7 +51,7 @@ You can use `eas --help` in your terminal window to learn more about the availab ## Expo Doctor -Expo Doctor is a command line tool used to diagnose issues in your Expo project. To use it, run the following command in your project's root directory: +Expo Doctor is a command-line tool used to diagnose issues in your Expo project. To use it, run the following command in your project's root directory: diff --git a/docs/pages/eas-update/getting-started.mdx b/docs/pages/eas-update/getting-started.mdx index f6d40563ee0a28..a157c8a49195e8 100644 --- a/docs/pages/eas-update/getting-started.mdx +++ b/docs/pages/eas-update/getting-started.mdx @@ -64,7 +64,7 @@ Setting up EAS Update allows you to push critical bug fixes and improvements tha ## Install the latest EAS CLI -EAS CLI is the command line app you will use to interact with EAS services from your terminal. To install it, run the command: +EAS CLI is the command-line app you will use to interact with EAS services from your terminal. To install it, run the command: diff --git a/docs/pages/eas/hosting/get-started.mdx b/docs/pages/eas/hosting/get-started.mdx index bbeead466c1838..ef2293e02a6e19 100644 --- a/docs/pages/eas/hosting/get-started.mdx +++ b/docs/pages/eas/hosting/get-started.mdx @@ -41,7 +41,7 @@ This guide will walk you through the process of creating your first web deployme ## Install the latest EAS CLI -EAS CLI is the command line app you will use to interact with EAS services from your terminal. To install it, run the command: +EAS CLI is the command-line app you will use to interact with EAS services from your terminal. To install it, run the command: diff --git a/docs/pages/eas/metadata/index.mdx b/docs/pages/eas/metadata/index.mdx index 6df3507c7d9111..539c724aee2edb 100644 --- a/docs/pages/eas/metadata/index.mdx +++ b/docs/pages/eas/metadata/index.mdx @@ -14,7 +14,7 @@ import { Terminal } from '~/ui/components/Snippet'; > **important** **EAS Metadata** is in [beta](/more/release-statuses/#beta) and subject to breaking changes. -**EAS Metadata** is a command line tool from EAS (Expo Application Services) that enables you to automate and maintain your app store presence. +**EAS Metadata** is a command-line tool from EAS (Expo Application Services) that enables you to automate and maintain your app store presence. You need to provide a lot of information to multiple app stores before your users can use your app. This information is often about complex topics that don't apply to your app. You have to start a lengthy review process after providing the information. When the reviewer finds any issues in the information you provided, you need to restart this process. diff --git a/docs/pages/eas/workflows/syntax.mdx b/docs/pages/eas/workflows/syntax.mdx index 93f605358e66f5..5239c019b96e83 100644 --- a/docs/pages/eas/workflows/syntax.mdx +++ b/docs/pages/eas/workflows/syntax.mdx @@ -323,7 +323,7 @@ on: When running a workflow with inputs, you can provide them in several ways: -1. Command line flags: +1. Command-line flags: Default: `public` | -| `EDITOR` | **string** | Name of the editor to open when pressing O in the Terminal UI. This value is used across many command line tools. | +| `EDITOR` | **string** | Name of the editor to open when pressing O in the Terminal UI. This value is used across many command-line tools. | | `EXPO_EDITOR` | **string** | An Expo-specific version of the `EDITOR` variable which takes higher priority when defined. | | `EXPO_IMAGE_UTILS_NO_SHARP` | **boolean** | Disable the usage of global Sharp CLI installation in favor of the slower Jimp package for image manipulation. This is used in places like `npx expo prebuild` for generating app icons. | | `EXPO_TUNNEL_SUBDOMAIN` | **boolean** |
Disable using `exp.direct` as the hostname for `--tunnel` connections. This enables **https://** forwarding which can be used to test universal links on iOS. This may cause unexpected issues with `expo-linking` and Expo Go. Select the exact subdomain to use by passing a `string` value that is not one of: `true`, `false`, `1`, `0`. | diff --git a/docs/pages/more/glossary-of-terms.mdx b/docs/pages/more/glossary-of-terms.mdx index ecc618f54828ae..5a5a9af175d301 100644 --- a/docs/pages/more/glossary-of-terms.mdx +++ b/docs/pages/more/glossary-of-terms.mdx @@ -92,7 +92,7 @@ A standalone command-line tool (CLI) for bootstrapping new React Native apps wit ### create-expo-module -A standalone command line tool (CLI) for creating Expo modules and adding platform support to existing modules. See [`create-expo-module` reference](/more/create-expo-module/) for more information. +A standalone command-line tool (CLI) for creating Expo modules and adding platform support to existing modules. See [`create-expo-module` reference](/more/create-expo-module/) for more information. ### create-react-native-app diff --git a/docs/pages/push-notifications/sending-notifications.mdx b/docs/pages/push-notifications/sending-notifications.mdx index e17eaae9f0288f..0b8a22e95312a8 100644 --- a/docs/pages/push-notifications/sending-notifications.mdx +++ b/docs/pages/push-notifications/sending-notifications.mdx @@ -18,7 +18,7 @@ The [`expo-notifications`](/versions/latest/sdk/notifications) library provides ## Send push notifications using a server -After you setup your push notification credentials and add logic to get the `ExpoPushToken`, you can send it to the Expo API using an HTTPS POST request. You can do this by setting up a server with a database (or you can also write a command line tool to send them or send them straight from your app). +After you setup your push notification credentials and add logic to get the `ExpoPushToken`, you can send it to the Expo API using an HTTPS POST request. You can do this by setting up a server with a database (or you can also write a command-line tool to send them or send them straight from your app). The Expo team and community have taken care of creating back-ends for you in a few different languages: diff --git a/docs/pages/troubleshooting/proxies.mdx b/docs/pages/troubleshooting/proxies.mdx index f592886b9c4639..deba24148cf6fc 100644 --- a/docs/pages/troubleshooting/proxies.mdx +++ b/docs/pages/troubleshooting/proxies.mdx @@ -57,9 +57,9 @@ Now, in Charles under the "Help" menu > Install Charles Root Certificate, and th > **Technical note:** This whole process is required because the iOS Simulator is served a bum proxy certificate instead of the actual certificate, and doesn't allow it, for https://exp.host/ which is required to run Expo.
**Also note:** Configure applications that need internet access, such as Spotify, to use http://localhost:8888 as your proxy. Some apps, such as Chrome and Firefox, you can configure in the settings to use your "System Network Preferences" which will use Charles : 8888, or no proxy, depending on how you have your "Location" set in the Apple menu/network preferences. If you are set to "Automatic" no proxy is used, if it is set to "your proxy network" the proxy is used and Charles will need to be running. -## Command line application proxy configuration +## Command-line application proxy configuration -npm, git, Brew, Curl, and any other command line applications need proxy access too. +npm, git, Brew, Curl, and any other command-line applications need proxy access too. #### For npm @@ -81,7 +81,7 @@ Open `~/.gitconfig` and set proxy = http://localhost:8888 ``` -### For command line applications +### For command-line applications Depending on your shell, and config, Open `~/.bashrc`, `~/.bash_profile`, or `~/.zshrc` or wherever you set your shell variables and set: diff --git a/docs/pages/tutorial/create-your-first-app.mdx b/docs/pages/tutorial/create-your-first-app.mdx index a0b29ea5bf7459..400cbad003a34b 100644 --- a/docs/pages/tutorial/create-your-first-app.mdx +++ b/docs/pages/tutorial/create-your-first-app.mdx @@ -47,7 +47,7 @@ This tutorial assumes you are familiar with TypeScript and React. If you are not ## Initialize a new Expo app -We'll use [`create-expo-app`](/more/create-expo/) to initialize a new Expo app. It is a command line tool to create a new React Native project. Run the following command in your terminal: +We'll use [`create-expo-app`](/more/create-expo/) to initialize a new Expo app. It is a command-line tool to create a new React Native project. Run the following command in your terminal: From b3db98ae4e1a73d743cbf81599146a79423ee4b9 Mon Sep 17 00:00:00 2001 From: Jakub Tkacz <32908614+Ubax@users.noreply.github.com> Date: Thu, 7 May 2026 19:55:52 +0200 Subject: [PATCH 08/18] Upgrade react-native-screens to 4.25.0-beta.3 (#45482) # Why Another version - `4.25.0-beta.3` - of `react-native-screens` was released, with breaking change to native tabs state management. This should be the final version and if everything works correctly will be upgraded to `4.25.0` tomorrow. **Note**: Code bundled for our current beta version, will not align with the `4.25.0-beta.3` - react-native-screens needs to be aligned with router version # How # Test Plan 1. Bare expo 2. Router e2e 3. Expo go # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --------- Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com> --- apps/bare-expo/ios/Podfile.lock | 8 +- apps/bare-expo/package.json | 2 +- apps/brownfield-tester/expo-app/package.json | 2 +- apps/expo-go/package.json | 2 +- apps/native-component-list/package.json | 2 +- apps/notification-tester/package.json | 2 +- apps/observe-tester/package.json | 2 +- apps/router-e2e/package.json | 2 +- .../with-monorepo/apps/app-a/package.json | 2 +- .../with-monorepo/apps/app-b/package.json | 2 +- .../with-router-typed-routes/package.json | 2 +- .../cli/e2e/fixtures/with-router/package.json | 2 +- packages/expo-router/CHANGELOG.md | 2 + .../native-tabs/NativeTabsView.android.js | 2 +- .../native-tabs/NativeTabsView.android.js.map | 2 +- .../build/native-tabs/NativeTabsView.ios.js | 2 +- .../native-tabs/NativeTabsView.ios.js.map | 2 +- .../NativeTabsView.shared.d.ts.map | 2 +- .../native-tabs/NativeTabsView.shared.js | 5 +- .../native-tabs/NativeTabsView.shared.js.map | 2 +- .../expo-router/build/native-tabs/types.d.ts | 10 +-- .../build/native-tabs/types.d.ts.map | 2 +- .../build/native-tabs/types.js.map | 2 +- packages/expo-router/package.json | 6 +- .../native-tabs/NativeTabsView.android.tsx | 2 +- .../src/native-tabs/NativeTabsView.ios.tsx | 2 +- .../src/native-tabs/NativeTabsView.shared.tsx | 5 +- .../__tests__/NativeTabsView.test.android.tsx | 8 +- .../__tests__/NativeTabsView.test.ios.tsx | 15 ++-- .../native-tabs/__tests__/events.test.ios.tsx | 12 +-- .../__tests__/listeners.test.ios.tsx | 2 +- .../__tests__/navigation.test.ios.tsx | 2 +- .../native-tabs/__tests__/render.test.ios.tsx | 18 ++--- packages/expo-router/src/native-tabs/types.ts | 10 +-- packages/expo/bundledNativeModules.json | 2 +- pnpm-lock.yaml | 78 +++++++++---------- pnpm-workspace.yaml | 1 + templates/expo-template-default/package.json | 2 +- templates/expo-template-tabs/package.json | 2 +- 39 files changed, 119 insertions(+), 111 deletions(-) diff --git a/apps/bare-expo/ios/Podfile.lock b/apps/bare-expo/ios/Podfile.lock index 8f429dd6894b8f..c24f78da552495 100644 --- a/apps/bare-expo/ios/Podfile.lock +++ b/apps/bare-expo/ios/Podfile.lock @@ -3075,7 +3075,7 @@ PODS: - ReactNativeDependencies - RNWorklets - Yoga - - RNScreens (4.25.0-beta.1): + - RNScreens (4.25.0-beta.3): - hermes-engine - RCTRequired - RCTTypeSafety @@ -3097,9 +3097,9 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - ReactNativeDependencies - - RNScreens/common (= 4.25.0-beta.1) + - RNScreens/common (= 4.25.0-beta.3) - Yoga - - RNScreens/common (4.25.0-beta.1): + - RNScreens/common (4.25.0-beta.3): - hermes-engine - RCTRequired - RCTTypeSafety @@ -3485,7 +3485,7 @@ DEPENDENCIES: - "RNDateTimePicker (from `../../../node_modules/.pnpm/@react-native-community+datetimepicker@8.6.0_expo@packages+expo_react-native@0.85.3_@ba_fe22ba3f6bc184022828182340650ec6/node_modules/@react-native-community/datetimepicker`)" - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.30.0_react-native@0.85.3_@babel+core@7.29.0_@react-nativ_9a6358180c81a5519b6da847dcb246ed/node_modules/react-native-gesture-handler`)" - "RNReanimated (from `../../../node_modules/.pnpm/react-native-reanimated@4.3.0_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_c36a92bb9a27c676b0bae54fbc6a1908/node_modules/react-native-reanimated`)" - - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.1_react-native@0.85.3_@babel+core@7.29.0_@react-native_1106fa305397b6dce5495e57c42d635a/node_modules/react-native-screens`)" + - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.3_react-native@0.85.3_@babel+core@7.29.0_@react-native_d946f5d10f696c25c0f95066694ac89d/node_modules/react-native-screens`)" - "RNSVG (from `../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-pres_492c03827e778ae24445fe49da301b55/node_modules/react-native-svg`)" - "RNWorklets (from `../../../node_modules/.pnpm/react-native-worklets@0.8.3_patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89_42b4111e02dad0db2c0db5ed881424fc/node_modules/react-native-worklets`)" - TestExpoUi (from `../modules/test-expo-ui/ios`) diff --git a/apps/bare-expo/package.json b/apps/bare-expo/package.json index e94c4a8e20cd19..1b6aaa69cebfd6 100644 --- a/apps/bare-expo/package.json +++ b/apps/bare-expo/package.json @@ -89,7 +89,7 @@ "react-native-pager-view": "6.9.1", "react-native-reanimated": "4.3.0", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-svg": "15.15.4", "react-native-view-shot": "4.0.3", "react-native-webview": "13.16.1", diff --git a/apps/brownfield-tester/expo-app/package.json b/apps/brownfield-tester/expo-app/package.json index a23f5913c11f48..888d1bb6ed9dce 100644 --- a/apps/brownfield-tester/expo-app/package.json +++ b/apps/brownfield-tester/expo-app/package.json @@ -35,7 +35,7 @@ "react-native-worklets": "0.8.3", "react-native-reanimated": "~4.3.0", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.1", + "react-native-screens": "~4.25.0-beta.3", "react-native-web": "~0.21.0" }, "devDependencies": { diff --git a/apps/expo-go/package.json b/apps/expo-go/package.json index 70389145d6997f..182eb5905fbb8d 100644 --- a/apps/expo-go/package.json +++ b/apps/expo-go/package.json @@ -84,7 +84,7 @@ "react-native-reanimated": "4.3.0", "react-native-safe-area-context": "5.7.0", "react-native-svg": "15.15.4", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-view-shot": "4.0.3", "react-native-webview": "13.16.1", "react-native-worklets": "0.8.3" diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json index 0da51226d2e5fb..cface623ccf10a 100644 --- a/apps/native-component-list/package.json +++ b/apps/native-component-list/package.json @@ -153,7 +153,7 @@ "react-native-paper": "^5.12.5", "react-native-reanimated": "4.3.0", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-svg": "15.15.4", "react-native-view-shot": "4.0.3", "react-native-web": "~0.21.0", diff --git a/apps/notification-tester/package.json b/apps/notification-tester/package.json index fd5ac4bee520d4..3a14eb7e6682f3 100644 --- a/apps/notification-tester/package.json +++ b/apps/notification-tester/package.json @@ -41,7 +41,7 @@ "react": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.1" + "react-native-screens": "4.25.0-beta.3" }, "devDependencies": { "@types/jest": "^29.5.12", diff --git a/apps/observe-tester/package.json b/apps/observe-tester/package.json index 6d47c1a49eb814..cbea9345ca0509 100644 --- a/apps/observe-tester/package.json +++ b/apps/observe-tester/package.json @@ -43,7 +43,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.1" + "react-native-screens": "4.25.0-beta.3" }, "devDependencies": { "@expo/config": "workspace:*", diff --git a/apps/router-e2e/package.json b/apps/router-e2e/package.json index 3f89544fd0b818..d2a7dc20fe0cf7 100644 --- a/apps/router-e2e/package.json +++ b/apps/router-e2e/package.json @@ -78,7 +78,7 @@ "react-native": "0.85.3", "react-native-gesture-handler": "~2.30.0", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-web": "^0.21.0", "react-native-webview": "13.16.1" }, diff --git a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json index 5b10ba4c6fe2b3..4a4be8d398e25e 100644 --- a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-a/package.json @@ -13,7 +13,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.1", + "react-native-screens": "~4.25.0-beta.3", "react-native-web": "~0.21.0" } } diff --git a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json index 367b6d37c168b4..b2b3f0a8276a04 100644 --- a/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-monorepo/apps/app-b/package.json @@ -13,7 +13,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.1", + "react-native-screens": "~4.25.0-beta.3", "react-native-web": "~0.21.0" } } diff --git a/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json b/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json index 68701653c57555..365012c3b753aa 100644 --- a/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-router-typed-routes/package.json @@ -13,7 +13,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.1", + "react-native-screens": "~4.25.0-beta.3", "react-native-web": "~0.21.0" } } diff --git a/packages/@expo/cli/e2e/fixtures/with-router/package.json b/packages/@expo/cli/e2e/fixtures/with-router/package.json index 85ffbf3ef2fb57..4cf0c88b385c27 100644 --- a/packages/@expo/cli/e2e/fixtures/with-router/package.json +++ b/packages/@expo/cli/e2e/fixtures/with-router/package.json @@ -12,7 +12,7 @@ "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "~4.25.0-beta.1", + "react-native-screens": "~4.25.0-beta.3", "react-native-web": "~0.21.0" } } diff --git a/packages/expo-router/CHANGELOG.md b/packages/expo-router/CHANGELOG.md index 727fabd3aea34f..db4e1905c99d89 100644 --- a/packages/expo-router/CHANGELOG.md +++ b/packages/expo-router/CHANGELOG.md @@ -6,6 +6,8 @@ ### 🎉 New features +- Upgrade react-native-screens version to 4.25.0-beta.3. ([#45482](https://github.com/expo/expo/pull/45482) by [@Ubax](https://github.com/Ubax)) + ### 🐛 Bug fixes ### 💡 Others diff --git a/packages/expo-router/build/native-tabs/NativeTabsView.android.js b/packages/expo-router/build/native-tabs/NativeTabsView.android.js index 6e475db8a97244..f2954e46e2254a 100644 --- a/packages/expo-router/build/native-tabs/NativeTabsView.android.js +++ b/packages/expo-router/build/native-tabs/NativeTabsView.android.js @@ -35,7 +35,7 @@ function NativeTabsView(props) { // TODO(@ubax): Adjust docs and add support for tabBarRespectsIMEInsets , { // TODO(@ubax): Adjust docs and add support for tabBarRespectsIMEInsets - android: { ...rawAndroidProps }, tabBarHidden: props.hidden, ...rawHostRestProps, navState: { selectedScreenKey, provenance }, onTabSelected: onTabSelected, children: children })); + android: { ...rawAndroidProps }, tabBarHidden: props.hidden, ...rawHostRestProps, navStateRequest: { selectedScreenKey, baseProvenance: provenance }, onTabSelected: onTabSelected, children: children })); } function Screen(props) { const { options, androidAppearance, contentRenderer } = props; diff --git a/packages/expo-router/build/native-tabs/NativeTabsView.android.js.map b/packages/expo-router/build/native-tabs/NativeTabsView.android.js.map index 9f1ba62a4b7276..8c0a892f903a2e 100644 --- a/packages/expo-router/build/native-tabs/NativeTabsView.android.js.map +++ b/packages/expo-router/build/native-tabs/NativeTabsView.android.js.map @@ -1 +1 @@ -{"version":3,"file":"NativeTabsView.android.js","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.android.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { Tabs, type TabsScreenAppearanceAndroid } from 'react-native-screens';\nimport { SafeAreaView } from 'react-native-screens/experimental';\n\nimport {\n type InternalTabScreenProps as SharedInternalTabScreenProps,\n ScreenContent,\n useOnTabSelectedHandler,\n useSelectedScreenKey,\n useSharedScreenProps,\n} from './NativeTabsView.shared';\nimport { createAndroidScreenAppearance } from './appearance';\nimport { SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES, type NativeTabsViewProps } from './types';\nimport { convertOptionsIconToScreensPropsIcon } from './utils/optionsIconConverter';\n\nexport function NativeTabsView(props: NativeTabsViewProps) {\n const { disableIndicator, tabs, unstable_nativeProps } = props;\n const {\n android: rawAndroidProps,\n ios: _ignoredRawIosProps,\n ...rawHostRestProps\n } = unstable_nativeProps ?? {};\n\n const { selectedScreenKey, provenance } = useSelectedScreenKey(props);\n const onTabSelected = useOnTabSelectedHandler(props.onTabChange);\n\n // TODO(@ubax): add per screen labelVisibilityMode + validation function\n let labelVisibilityMode = props.labelVisibilityMode;\n if (labelVisibilityMode && !supportedTabBarItemLabelVisibilityModesSet.has(labelVisibilityMode)) {\n console.warn(\n `Unsupported labelVisibilityMode: ${labelVisibilityMode}. Supported values are: ${SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES.map((mode) => `\"${mode}\"`).join(', ')}`\n );\n labelVisibilityMode = undefined;\n }\n\n const androidAppearances = tabs.map((tab) =>\n createAndroidScreenAppearance({\n options: tab.options,\n tintColor: props.tintColor,\n rippleColor: props.rippleColor,\n disableIndicator,\n labelVisibilityMode,\n })\n );\n\n const children = tabs.map((tab, index) => (\n \n ));\n\n if (children.length === 0) {\n return null;\n }\n\n return (\n \n {children}\n \n );\n}\n\ninterface InternalTabScreenProps extends SharedInternalTabScreenProps {\n androidAppearance: TabsScreenAppearanceAndroid;\n}\n\nfunction Screen(props: InternalTabScreenProps) {\n const { options, androidAppearance, contentRenderer } = props;\n\n const shared = useSharedScreenProps(props);\n\n const androidIcon = convertOptionsIconToScreensPropsIcon(shared.icon);\n const androidSelectedIcon = convertOptionsIconToScreensPropsIcon(shared.selectedIcon);\n\n const content = ;\n const wrappedContent = useMemo(() => {\n if (!options.disableAutomaticContentInsets) {\n return (\n \n {content}\n \n );\n }\n return content;\n }, [content, options.disableAutomaticContentInsets]);\n\n return (\n \n {wrappedContent}\n \n );\n}\n\nconst supportedTabBarItemLabelVisibilityModesSet = new Set(\n SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES\n);\n"]} \ No newline at end of file +{"version":3,"file":"NativeTabsView.android.js","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.android.tsx"],"names":[],"mappings":";;AAeA,wCAyDC;;AAxED,iCAAgC;AAChC,+DAA8E;AAC9E,oEAAiE;AAEjE,mEAMiC;AACjC,6CAA6D;AAC7D,mCAAkG;AAClG,uEAAoF;AAEpF,SAAgB,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,oBAAoB,EAAE,GAAG,KAAK,CAAC;IAC/D,MAAM,EACJ,OAAO,EAAE,eAAe,EACxB,GAAG,EAAE,mBAAmB,EACxB,GAAG,gBAAgB,EACpB,GAAG,oBAAoB,IAAI,EAAE,CAAC;IAE/B,MAAM,EAAE,iBAAiB,EAAE,UAAU,EAAE,GAAG,IAAA,4CAAoB,EAAC,KAAK,CAAC,CAAC;IACtE,MAAM,aAAa,GAAG,IAAA,+CAAuB,EAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAEjE,wEAAwE;IACxE,IAAI,mBAAmB,GAAG,KAAK,CAAC,mBAAmB,CAAC;IACpD,IAAI,mBAAmB,IAAI,CAAC,0CAA0C,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAChG,OAAO,CAAC,IAAI,CACV,oCAAoC,mBAAmB,2BAA2B,qDAA6C,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxK,CAAC;QACF,mBAAmB,GAAG,SAAS,CAAC;IAClC,CAAC;IAED,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC1C,IAAA,0CAA6B,EAAC;QAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,gBAAgB;QAChB,mBAAmB;KACpB,CAAC,CACH,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CACxC,uBAAC,MAAM,IAEL,QAAQ,EAAE,GAAG,CAAC,QAAQ,EACtB,IAAI,EAAE,GAAG,CAAC,IAAI,EACd,OAAO,EAAE,GAAG,CAAC,OAAO,EACpB,SAAS,EAAE,iBAAiB,KAAK,GAAG,CAAC,QAAQ,EAC7C,iBAAiB,EAAE,kBAAkB,CAAC,KAAK,CAAE,EAC7C,eAAe,EAAE,GAAG,CAAC,eAAe,IAN/B,GAAG,CAAC,QAAQ,CAOjB,CACH,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CACL,uBAAC,2BAAI,CAAC,IAAI;IACR,uEAAuE;;QAAvE,uEAAuE;QACvE,OAAO,EAAE,EAAE,GAAG,eAAe,EAAE,EAC/B,YAAY,EAAE,KAAK,CAAC,MAAM,KACtB,gBAAgB,EACpB,eAAe,EAAE,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,EAClE,aAAa,EAAE,aAAa,YAC3B,QAAQ,GACC,CACb,CAAC;AACJ,CAAC;AAMD,SAAS,MAAM,CAAC,KAA6B;IAC3C,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IAE9D,MAAM,MAAM,GAAG,IAAA,4CAAoB,EAAC,KAAK,CAAC,CAAC;IAE3C,MAAM,WAAW,GAAG,IAAA,2DAAoC,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,mBAAmB,GAAG,IAAA,2DAAoC,EAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAEtF,MAAM,OAAO,GAAG,uBAAC,qCAAa,IAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,GAAI,CAAC;IACtF,MAAM,cAAc,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE;QAClC,IAAI,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC;YAC3C,OAAO,CACL,uBAAC,2BAAY;YACX,+FAA+F;;gBAA/F,+FAA+F;gBAC/F,WAAW,EAAE,KAAK,EAClB,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAClB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,YACtB,OAAO,GACK,CAChB,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAErD,OAAO,CACL,uBAAC,2BAAI,CAAC,MAAM,OACN,MAAM,CAAC,OAAO,EAClB,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,OAAO,EAAE;YACP,IAAI,EAAE,WAAW;YACjB,YAAY,EAAE,mBAAmB;YACjC,kBAAkB,EAAE,iBAAiB;YACrC,GAAG,MAAM,CAAC,sBAAsB;SACjC,EACD,KAAK,EAAE,MAAM,CAAC,KAAK,KACf,MAAM,CAAC,mBAAmB,EAC9B,SAAS,EAAE,MAAM,CAAC,SAAS,YAC1B,cAAc,GACH,CACf,CAAC;AACJ,CAAC;AAED,MAAM,0CAA0C,GAAG,IAAI,GAAG,CACxD,qDAA6C,CAC9C,CAAC","sourcesContent":["import { useMemo } from 'react';\nimport { Tabs, type TabsScreenAppearanceAndroid } from 'react-native-screens';\nimport { SafeAreaView } from 'react-native-screens/experimental';\n\nimport {\n type InternalTabScreenProps as SharedInternalTabScreenProps,\n ScreenContent,\n useOnTabSelectedHandler,\n useSelectedScreenKey,\n useSharedScreenProps,\n} from './NativeTabsView.shared';\nimport { createAndroidScreenAppearance } from './appearance';\nimport { SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES, type NativeTabsViewProps } from './types';\nimport { convertOptionsIconToScreensPropsIcon } from './utils/optionsIconConverter';\n\nexport function NativeTabsView(props: NativeTabsViewProps) {\n const { disableIndicator, tabs, unstable_nativeProps } = props;\n const {\n android: rawAndroidProps,\n ios: _ignoredRawIosProps,\n ...rawHostRestProps\n } = unstable_nativeProps ?? {};\n\n const { selectedScreenKey, provenance } = useSelectedScreenKey(props);\n const onTabSelected = useOnTabSelectedHandler(props.onTabChange);\n\n // TODO(@ubax): add per screen labelVisibilityMode + validation function\n let labelVisibilityMode = props.labelVisibilityMode;\n if (labelVisibilityMode && !supportedTabBarItemLabelVisibilityModesSet.has(labelVisibilityMode)) {\n console.warn(\n `Unsupported labelVisibilityMode: ${labelVisibilityMode}. Supported values are: ${SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES.map((mode) => `\"${mode}\"`).join(', ')}`\n );\n labelVisibilityMode = undefined;\n }\n\n const androidAppearances = tabs.map((tab) =>\n createAndroidScreenAppearance({\n options: tab.options,\n tintColor: props.tintColor,\n rippleColor: props.rippleColor,\n disableIndicator,\n labelVisibilityMode,\n })\n );\n\n const children = tabs.map((tab, index) => (\n \n ));\n\n if (children.length === 0) {\n return null;\n }\n\n return (\n \n {children}\n \n );\n}\n\ninterface InternalTabScreenProps extends SharedInternalTabScreenProps {\n androidAppearance: TabsScreenAppearanceAndroid;\n}\n\nfunction Screen(props: InternalTabScreenProps) {\n const { options, androidAppearance, contentRenderer } = props;\n\n const shared = useSharedScreenProps(props);\n\n const androidIcon = convertOptionsIconToScreensPropsIcon(shared.icon);\n const androidSelectedIcon = convertOptionsIconToScreensPropsIcon(shared.selectedIcon);\n\n const content = ;\n const wrappedContent = useMemo(() => {\n if (!options.disableAutomaticContentInsets) {\n return (\n \n {content}\n \n );\n }\n return content;\n }, [content, options.disableAutomaticContentInsets]);\n\n return (\n \n {wrappedContent}\n \n );\n}\n\nconst supportedTabBarItemLabelVisibilityModesSet = new Set(\n SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES\n);\n"]} \ No newline at end of file diff --git a/packages/expo-router/build/native-tabs/NativeTabsView.ios.js b/packages/expo-router/build/native-tabs/NativeTabsView.ios.js index 9cd46bd0445daf..f2bc6233d0b25a 100644 --- a/packages/expo-router/build/native-tabs/NativeTabsView.ios.js +++ b/packages/expo-router/build/native-tabs/NativeTabsView.ios.js @@ -43,7 +43,7 @@ function NativeTabsView(props) { tabBarControllerMode, bottomAccessory: bottomAccessoryFn, ...rawIosProps, - }, tabBarHidden: props.hidden, ...rawHostRestProps, navState: { selectedScreenKey, provenance }, onTabSelected: onTabSelected, children: children })); + }, tabBarHidden: props.hidden, ...rawHostRestProps, navStateRequest: { selectedScreenKey, baseProvenance: provenance }, onTabSelected: onTabSelected, children: children })); } function Screen(props) { const { options, standardAppearance, scrollEdgeAppearance, contentRenderer } = props; diff --git a/packages/expo-router/build/native-tabs/NativeTabsView.ios.js.map b/packages/expo-router/build/native-tabs/NativeTabsView.ios.js.map index 5e22e1f987ff68..d4fa9e223d0560 100644 --- a/packages/expo-router/build/native-tabs/NativeTabsView.ios.js.map +++ b/packages/expo-router/build/native-tabs/NativeTabsView.ios.js.map @@ -1 +1 @@ -{"version":3,"file":"NativeTabsView.ios.js","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.ios.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { SafeAreaProvider } from 'react-native-safe-area-context';\nimport { Tabs, type TabsHostProps, type TabsScreenAppearanceIOS } from 'react-native-screens';\n\nimport {\n type InternalTabScreenProps as SharedInternalTabScreenProps,\n ScreenContent,\n useOnTabSelectedHandler,\n useSelectedScreenKey,\n useSharedScreenProps,\n} from './NativeTabsView.shared';\nimport {\n createScrollEdgeAppearanceFromOptions,\n createStandardAppearanceFromOptions,\n} from './appearance';\nimport { NativeTabsBottomAccessory } from './common/elements';\nimport { SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS, type NativeTabsViewProps } from './types';\nimport { useBottomAccessoryFunctionFromBottomAccessories } from './utils/bottomAccessory';\nimport { convertOptionsIconToScreensPropsIcon } from './utils/optionsIconConverter';\nimport { getFirstChildOfType } from '../utils/children';\n\nexport function NativeTabsView(props: NativeTabsViewProps) {\n const { minimizeBehavior, tabs, sidebarAdaptable, nonTriggerChildren, unstable_nativeProps } =\n props;\n // `ios`/`android` are the only platform-nested keys on `TabsHostProps`. We drop the inactive\n // platform's slice so users writing universal code don't pass Android-only props to the iOS host.\n const {\n ios: rawIosProps,\n android: _ignoredRawAndroidProps,\n ...rawHostRestProps\n } = unstable_nativeProps ?? {};\n\n const { selectedScreenKey, provenance } = useSelectedScreenKey(props);\n const onTabSelected = useOnTabSelectedHandler(props.onTabChange);\n\n const iosAppearances = tabs.map((tab) => ({\n standardAppearance: createStandardAppearanceFromOptions(tab.options),\n scrollEdgeAppearance: createScrollEdgeAppearanceFromOptions(tab.options),\n }));\n\n const bottomAccessory = useMemo(\n () => getFirstChildOfType(nonTriggerChildren, NativeTabsBottomAccessory),\n [nonTriggerChildren]\n );\n\n const bottomAccessoryFn = useBottomAccessoryFunctionFromBottomAccessories(bottomAccessory);\n\n if (\n process.env.NODE_ENV !== 'production' &&\n bottomAccessory &&\n rawIosProps &&\n 'bottomAccessory' in rawIosProps\n ) {\n console.warn(\n ' is being overridden by `unstable_nativeProps.ios.bottomAccessory`. ' +\n 'Either remove the `` child or stop passing `ios.bottomAccessory` via `unstable_nativeProps`.'\n );\n }\n\n const children = tabs.map((tab, index) => (\n \n ));\n\n if (children.length === 0) {\n return null;\n }\n\n const tabBarControllerMode: NonNullable['tabBarControllerMode'] =\n sidebarAdaptable ? 'tabSidebar' : sidebarAdaptable === false ? 'tabBar' : 'automatic';\n\n return (\n \n {children}\n \n );\n}\n\ninterface InternalTabScreenProps extends SharedInternalTabScreenProps {\n standardAppearance: TabsScreenAppearanceIOS;\n scrollEdgeAppearance: TabsScreenAppearanceIOS;\n}\n\nfunction Screen(props: InternalTabScreenProps) {\n const { options, standardAppearance, scrollEdgeAppearance, contentRenderer } = props;\n\n const shared = useSharedScreenProps(props);\n\n const iosIcon = convertOptionsIconToScreensPropsIcon(\n shared.icon,\n standardAppearance?.stacked?.normal?.tabBarItemIconColor\n );\n const iosSelectedIcon = convertOptionsIconToScreensPropsIcon(\n shared.selectedIcon,\n standardAppearance?.stacked?.selected?.tabBarItemIconColor\n );\n\n const content = ;\n const wrappedContent = useMemo(() => {content}, [content]);\n\n return (\n \n {wrappedContent}\n \n );\n}\n\nconst supportedTabBarMinimizeBehaviorsSet = new Set(SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS);\n\nfunction TabsHostWrapper(props: TabsHostProps) {\n // TODO(@ubax): add function for validation\n let validatedIos = props.ios;\n if (validatedIos?.tabBarMinimizeBehavior) {\n if (!supportedTabBarMinimizeBehaviorsSet.has(validatedIos.tabBarMinimizeBehavior)) {\n console.warn(\n `Unsupported minimizeBehavior: ${validatedIos.tabBarMinimizeBehavior}. Supported values are: ${SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS.map((behavior) => `\"${behavior}\"`).join(', ')}`\n );\n validatedIos = { ...validatedIos, tabBarMinimizeBehavior: undefined };\n }\n }\n\n return ;\n}\n"]} \ No newline at end of file +{"version":3,"file":"NativeTabsView.ios.js","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.ios.tsx"],"names":[],"mappings":";;AAqBA,wCA0EC;;AA/FD,iCAAgC;AAChC,mFAAkE;AAClE,+DAA8F;AAE9F,mEAMiC;AACjC,6CAGsB;AACtB,gDAA8D;AAC9D,mCAAyF;AACzF,6DAA0F;AAC1F,uEAAoF;AACpF,gDAAwD;AAExD,SAAgB,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,GAC1F,KAAK,CAAC;IACR,6FAA6F;IAC7F,kGAAkG;IAClG,MAAM,EACJ,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,uBAAuB,EAChC,GAAG,gBAAgB,EACpB,GAAG,oBAAoB,IAAI,EAAE,CAAC;IAE/B,MAAM,EAAE,iBAAiB,EAAE,UAAU,EAAE,GAAG,IAAA,4CAAoB,EAAC,KAAK,CAAC,CAAC;IACtE,MAAM,aAAa,GAAG,IAAA,+CAAuB,EAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAEjE,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxC,kBAAkB,EAAE,IAAA,gDAAmC,EAAC,GAAG,CAAC,OAAO,CAAC;QACpE,oBAAoB,EAAE,IAAA,kDAAqC,EAAC,GAAG,CAAC,OAAO,CAAC;KACzE,CAAC,CAAC,CAAC;IAEJ,MAAM,eAAe,GAAG,IAAA,eAAO,EAC7B,GAAG,EAAE,CAAC,IAAA,8BAAmB,EAAC,kBAAkB,EAAE,oCAAyB,CAAC,EACxE,CAAC,kBAAkB,CAAC,CACrB,CAAC;IAEF,MAAM,iBAAiB,GAAG,IAAA,iEAA+C,EAAC,eAAe,CAAC,CAAC;IAE3F,IACE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QACrC,eAAe;QACf,WAAW;QACX,iBAAiB,IAAI,WAAW,EAChC,CAAC;QACD,OAAO,CAAC,IAAI,CACV,kGAAkG;YAChG,0HAA0H,CAC7H,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CACxC,uBAAC,MAAM,IAEL,QAAQ,EAAE,GAAG,CAAC,QAAQ,EACtB,IAAI,EAAE,GAAG,CAAC,IAAI,EACd,OAAO,EAAE,GAAG,CAAC,OAAO,EACpB,SAAS,EAAE,iBAAiB,KAAK,GAAG,CAAC,QAAQ,EAC7C,kBAAkB,EAAE,cAAc,CAAC,KAAK,CAAE,CAAC,kBAAkB,EAC7D,oBAAoB,EAAE,cAAc,CAAC,KAAK,CAAE,CAAC,oBAAoB,EACjE,eAAe,EAAE,GAAG,CAAC,eAAe,IAP/B,GAAG,CAAC,QAAQ,CAQjB,CACH,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,oBAAoB,GACxB,gBAAgB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;IAExF,OAAO,CACL,uBAAC,eAAe,IACd,GAAG,EAAE;YACH,eAAe,EAAE,KAAK,CAAC,SAAS;YAChC,sBAAsB,EAAE,gBAAgB;YACxC,oBAAoB;YACpB,eAAe,EAAE,iBAAiB;YAClC,GAAG,WAAW;SACf,EACD,YAAY,EAAE,KAAK,CAAC,MAAM,KACtB,gBAAgB,EACpB,eAAe,EAAE,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,EAClE,aAAa,EAAE,aAAa,YAC3B,QAAQ,GACO,CACnB,CAAC;AACJ,CAAC;AAOD,SAAS,MAAM,CAAC,KAA6B;IAC3C,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IAErF,MAAM,MAAM,GAAG,IAAA,4CAAoB,EAAC,KAAK,CAAC,CAAC;IAE3C,MAAM,OAAO,GAAG,IAAA,2DAAoC,EAClD,MAAM,CAAC,IAAI,EACX,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,CACzD,CAAC;IACF,MAAM,eAAe,GAAG,IAAA,2DAAoC,EAC1D,MAAM,CAAC,YAAY,EACnB,kBAAkB,EAAE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,CAC3D,CAAC;IAEF,MAAM,OAAO,GAAG,uBAAC,qCAAa,IAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,GAAI,CAAC;IACtF,MAAM,cAAc,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,uBAAC,iDAAgB,cAAE,OAAO,GAAoB,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEhG,OAAO,CACL,uBAAC,2BAAI,CAAC,MAAM,OACN,MAAM,CAAC,OAAO,EAClB,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,GAAG,EAAE;YACH,IAAI,EAAE,OAAO;YACb,YAAY,EAAE,eAAe;YAC7B,kBAAkB;YAClB,oBAAoB;YACpB,UAAU,EAAE,OAAO,CAAC,IAAI;YACxB,gDAAgD,EAAE,CAAC,OAAO,CAAC,6BAA6B;YACxF,GAAG,MAAM,CAAC,kBAAkB;SAC7B,EACD,KAAK,EAAE,MAAM,CAAC,KAAK,KACf,MAAM,CAAC,mBAAmB,EAC9B,SAAS,EAAE,MAAM,CAAC,SAAS,YAC1B,cAAc,GACH,CACf,CAAC;AACJ,CAAC;AAED,MAAM,mCAAmC,GAAG,IAAI,GAAG,CAAS,4CAAoC,CAAC,CAAC;AAElG,SAAS,eAAe,CAAC,KAAoB;IAC3C,2CAA2C;IAC3C,IAAI,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC;IAC7B,IAAI,YAAY,EAAE,sBAAsB,EAAE,CAAC;QACzC,IAAI,CAAC,mCAAmC,CAAC,GAAG,CAAC,YAAY,CAAC,sBAAsB,CAAC,EAAE,CAAC;YAClF,OAAO,CAAC,IAAI,CACV,iCAAiC,YAAY,CAAC,sBAAsB,2BAA2B,4CAAoC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpL,CAAC;YACF,YAAY,GAAG,EAAE,GAAG,YAAY,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC;QACxE,CAAC;IACH,CAAC;IAED,OAAO,uBAAC,2BAAI,CAAC,IAAI,OAAK,KAAK,EAAE,GAAG,EAAE,YAAY,GAAI,CAAC;AACrD,CAAC","sourcesContent":["import { useMemo } from 'react';\nimport { SafeAreaProvider } from 'react-native-safe-area-context';\nimport { Tabs, type TabsHostProps, type TabsScreenAppearanceIOS } from 'react-native-screens';\n\nimport {\n type InternalTabScreenProps as SharedInternalTabScreenProps,\n ScreenContent,\n useOnTabSelectedHandler,\n useSelectedScreenKey,\n useSharedScreenProps,\n} from './NativeTabsView.shared';\nimport {\n createScrollEdgeAppearanceFromOptions,\n createStandardAppearanceFromOptions,\n} from './appearance';\nimport { NativeTabsBottomAccessory } from './common/elements';\nimport { SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS, type NativeTabsViewProps } from './types';\nimport { useBottomAccessoryFunctionFromBottomAccessories } from './utils/bottomAccessory';\nimport { convertOptionsIconToScreensPropsIcon } from './utils/optionsIconConverter';\nimport { getFirstChildOfType } from '../utils/children';\n\nexport function NativeTabsView(props: NativeTabsViewProps) {\n const { minimizeBehavior, tabs, sidebarAdaptable, nonTriggerChildren, unstable_nativeProps } =\n props;\n // `ios`/`android` are the only platform-nested keys on `TabsHostProps`. We drop the inactive\n // platform's slice so users writing universal code don't pass Android-only props to the iOS host.\n const {\n ios: rawIosProps,\n android: _ignoredRawAndroidProps,\n ...rawHostRestProps\n } = unstable_nativeProps ?? {};\n\n const { selectedScreenKey, provenance } = useSelectedScreenKey(props);\n const onTabSelected = useOnTabSelectedHandler(props.onTabChange);\n\n const iosAppearances = tabs.map((tab) => ({\n standardAppearance: createStandardAppearanceFromOptions(tab.options),\n scrollEdgeAppearance: createScrollEdgeAppearanceFromOptions(tab.options),\n }));\n\n const bottomAccessory = useMemo(\n () => getFirstChildOfType(nonTriggerChildren, NativeTabsBottomAccessory),\n [nonTriggerChildren]\n );\n\n const bottomAccessoryFn = useBottomAccessoryFunctionFromBottomAccessories(bottomAccessory);\n\n if (\n process.env.NODE_ENV !== 'production' &&\n bottomAccessory &&\n rawIosProps &&\n 'bottomAccessory' in rawIosProps\n ) {\n console.warn(\n ' is being overridden by `unstable_nativeProps.ios.bottomAccessory`. ' +\n 'Either remove the `` child or stop passing `ios.bottomAccessory` via `unstable_nativeProps`.'\n );\n }\n\n const children = tabs.map((tab, index) => (\n \n ));\n\n if (children.length === 0) {\n return null;\n }\n\n const tabBarControllerMode: NonNullable['tabBarControllerMode'] =\n sidebarAdaptable ? 'tabSidebar' : sidebarAdaptable === false ? 'tabBar' : 'automatic';\n\n return (\n \n {children}\n \n );\n}\n\ninterface InternalTabScreenProps extends SharedInternalTabScreenProps {\n standardAppearance: TabsScreenAppearanceIOS;\n scrollEdgeAppearance: TabsScreenAppearanceIOS;\n}\n\nfunction Screen(props: InternalTabScreenProps) {\n const { options, standardAppearance, scrollEdgeAppearance, contentRenderer } = props;\n\n const shared = useSharedScreenProps(props);\n\n const iosIcon = convertOptionsIconToScreensPropsIcon(\n shared.icon,\n standardAppearance?.stacked?.normal?.tabBarItemIconColor\n );\n const iosSelectedIcon = convertOptionsIconToScreensPropsIcon(\n shared.selectedIcon,\n standardAppearance?.stacked?.selected?.tabBarItemIconColor\n );\n\n const content = ;\n const wrappedContent = useMemo(() => {content}, [content]);\n\n return (\n \n {wrappedContent}\n \n );\n}\n\nconst supportedTabBarMinimizeBehaviorsSet = new Set(SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS);\n\nfunction TabsHostWrapper(props: TabsHostProps) {\n // TODO(@ubax): add function for validation\n let validatedIos = props.ios;\n if (validatedIos?.tabBarMinimizeBehavior) {\n if (!supportedTabBarMinimizeBehaviorsSet.has(validatedIos.tabBarMinimizeBehavior)) {\n console.warn(\n `Unsupported minimizeBehavior: ${validatedIos.tabBarMinimizeBehavior}. Supported values are: ${SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS.map((behavior) => `\"${behavior}\"`).join(', ')}`\n );\n validatedIos = { ...validatedIos, tabBarMinimizeBehavior: undefined };\n }\n }\n\n return ;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-router/build/native-tabs/NativeTabsView.shared.d.ts.map b/packages/expo-router/build/native-tabs/NativeTabsView.shared.d.ts.map index 91ef5c43934b55..804c881e6d7766 100644 --- a/packages/expo-router/build/native-tabs/NativeTabsView.shared.d.ts.map +++ b/packages/expo-router/build/native-tabs/NativeTabsView.shared.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"NativeTabsView.shared.d.ts","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.shared.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAIrE,wBAAgB,oBAAoB,CAAC,EACnC,YAAY,EACZ,UAAU,EACV,IAAI,GACL,EAAE,IAAI,CAAC,mBAAmB,EAAE,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC,GAAG;IACrE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,CAgBA;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,mBAAmB,CAAC,aAAa,CAAC,GAC9C,WAAW,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAO7C;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IAEb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,eAAe,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;CACxC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,sBAAsB;;mBAgBV,UAAU,GAAG,MAAM;;;;;;;;;;;;;;;;gCAN3D,CAAC;yBACkC,CAAC;2BAIc,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;EAUlE;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,eAAe,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;CACxC,2CAcA"} \ No newline at end of file +{"version":3,"file":"NativeTabsView.shared.d.ts","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.shared.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAIrE,wBAAgB,oBAAoB,CAAC,EACnC,YAAY,EACZ,UAAU,EACV,IAAI,GACL,EAAE,IAAI,CAAC,mBAAmB,EAAE,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC,GAAG;IACrE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,CAgBA;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,mBAAmB,CAAC,aAAa,CAAC,GAC9C,WAAW,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAU7C;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IAEb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,eAAe,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;CACxC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,sBAAsB;;mBAgBV,UAAU,GAAG,MAAM;;;;;;;;;;;;;;;;gCAZhE,CAAC;yBAGN,CAAA;2BAGE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;EAeR;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,eAAe,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;CACxC,2CAcA"} \ No newline at end of file diff --git a/packages/expo-router/build/native-tabs/NativeTabsView.shared.js b/packages/expo-router/build/native-tabs/NativeTabsView.shared.js index 95f739981f6bf0..f482b017132457 100644 --- a/packages/expo-router/build/native-tabs/NativeTabsView.shared.js +++ b/packages/expo-router/build/native-tabs/NativeTabsView.shared.js @@ -23,7 +23,10 @@ function useSelectedScreenKey({ focusedIndex, provenance, tabs, }) { }; } function useOnTabSelectedHandler(onTabChange) { - return (0, react_1.useCallback)(({ nativeEvent: { selectedScreenKey, provenance, isNativeAction } }) => { + return (0, react_1.useCallback)(({ nativeEvent: { selectedScreenKey, provenance, actionOrigin } }) => { + // Treat anything other than a JS-driven echo as a native action so the + // navigator emits `tabPress` and dispatches `JUMP_TO`. + const isNativeAction = actionOrigin !== 'programmatic-js'; onTabChange({ selectedKey: selectedScreenKey, provenance, isNativeAction }); }, [onTabChange]); } diff --git a/packages/expo-router/build/native-tabs/NativeTabsView.shared.js.map b/packages/expo-router/build/native-tabs/NativeTabsView.shared.js.map index 77404ef40baf2e..19f3fb51cda620 100644 --- a/packages/expo-router/build/native-tabs/NativeTabsView.shared.js.map +++ b/packages/expo-router/build/native-tabs/NativeTabsView.shared.js.map @@ -1 +1 @@ -{"version":3,"file":"NativeTabsView.shared.js","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.shared.tsx"],"names":[],"mappings":";;AAQA,oDAuBC;AAED,0DASC;AAeD,oDAyBC;AAED,sCAoBC;;AAxGD,iCAAsE;AACtE,+CAAoC;AAIpC,uCAAqD;AACrD,uDAAsD;AAEtD,SAAgB,oBAAoB,CAAC,EACnC,YAAY,EACZ,UAAU,EACV,IAAI,GAC8D;IAIlE,MAAM,WAAW,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IAC9F,MAAM,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAC1E,IAAA,wBAAgB,EAAC,WAAW,CAAC,CAAC;IAEhC,8DAA8D;IAC9D,oFAAoF;IACpF,wFAAwF;IACxF,2BAA2B;IAC3B,MAAM,4BAA4B,GAChC,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,YAAY,CAAC;IAE3E,OAAO;QACL,iBAAiB,EAAE,IAAI,CAAC,4BAA4B,CAAE,CAAC,QAAQ;QAC/D,UAAU,EAAE,kBAAkB;KAC/B,CAAC;AACJ,CAAC;AAED,SAAgB,uBAAuB,CACrC,WAA+C;IAE/C,OAAO,IAAA,mBAAW,EAChB,CAAC,EAAE,WAAW,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE;QACrE,WAAW,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;IAC9E,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;AACJ,CAAC;AAeD,SAAgB,oBAAoB,CAAC,KAA6B;IAChE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC;IACpC,MAAM,EACJ,GAAG,EAAE,kBAAkB,EACvB,OAAO,EAAE,sBAAsB,EAC/B,GAAG,mBAAmB,EACvB,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IAE9B,oEAAoE;IACpE,MAAM,IAAI,GAAG,IAAA,4BAAqB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,YAAY,GAAG,IAAA,4BAAqB,EAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAEjE,OAAO;QACL,OAAO;QACP,gGAAgG;QAChG,aAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAwB;QACvE,KAAK;QACL,kBAAkB;QAClB,sBAAsB;QACtB,mBAAmB;QACnB,SAAS,EAAE,QAAQ;QACnB,IAAI;QACJ,YAAY;KACb,CAAC;AACJ,CAAC;AAED,SAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,eAAe,GAIhB;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,iBAAQ,GAAE,CAAC;IAC9B,OAAO,CACL,uBAAC,mBAAI;IACH,+FAA+F;;QAA/F,+FAA+F;QAC/F,WAAW,EAAE,KAAK,EAClB,KAAK,EAAE;YACL,EAAE,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE;YACtC,OAAO,CAAC,YAAY;YACpB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE;SACtD,YACA,eAAe,EAAE,GACb,CACR,CAAC;AACJ,CAAC","sourcesContent":["import React, { useCallback, useDeferredValue, useMemo } from 'react';\nimport { View } from 'react-native';\nimport type { TabsHostProps } from 'react-native-screens';\n\nimport type { NativeTabOptions, NativeTabsViewProps } from './types';\nimport { useAwaitedScreensIcon } from './utils/icon';\nimport { useTheme } from '../react-navigation/native';\n\nexport function useSelectedScreenKey({\n focusedIndex,\n provenance,\n tabs,\n}: Pick): {\n selectedScreenKey: string;\n provenance: number;\n} {\n const stableState = useMemo(() => ({ focusedIndex, provenance }), [focusedIndex, provenance]);\n const { focusedIndex: deferredFocusedIndex, provenance: deferredProvenance } =\n useDeferredValue(stableState);\n\n // We need to check if the deferred index is not out of bounds\n // This can happen when the focused index is the last tab, and user removes that tab\n // In that case the deferred index will still point to the last tab, but after re-render\n // it will be out of bounds\n const inBoundsDeferredFocusedIndex =\n deferredFocusedIndex < tabs.length ? deferredFocusedIndex : focusedIndex;\n\n return {\n selectedScreenKey: tabs[inBoundsDeferredFocusedIndex]!.routeKey,\n provenance: deferredProvenance,\n };\n}\n\nexport function useOnTabSelectedHandler(\n onTabChange: NativeTabsViewProps['onTabChange']\n): NonNullable {\n return useCallback>(\n ({ nativeEvent: { selectedScreenKey, provenance, isNativeAction } }) => {\n onTabChange({ selectedKey: selectedScreenKey, provenance, isNativeAction });\n },\n [onTabChange]\n );\n}\n\n/**\n * Cross-platform fields used to render a single tab screen. Each platform\n * extends this with its own appearance fields.\n */\nexport interface InternalTabScreenProps {\n routeKey: string;\n name: string;\n // TODO(@ubax): https://linear.app/expo/issue/ENG-20736/remove-pointerevents-from-nativetabsview\n isFocused: boolean;\n options: NativeTabOptions;\n contentRenderer: () => React.ReactNode;\n}\n\nexport function useSharedScreenProps(props: InternalTabScreenProps) {\n const { options, isFocused, name, routeKey } = props;\n const title = options.title ?? name;\n const {\n ios: nativeIosOverrides,\n android: nativeAndroidOverrides,\n ...nativeRestOverrides\n } = options.nativeProps ?? {};\n\n // We need to await the icon, as VectorIcon will load asynchronously\n const icon = useAwaitedScreensIcon(options.icon);\n const selectedIcon = useAwaitedScreensIcon(options.selectedIcon);\n\n return {\n options,\n // TODO(@ubax): https://linear.app/expo/issue/ENG-20736/remove-pointerevents-from-nativetabsview\n pointerEvents: (isFocused ? 'box-none' : 'none') as 'box-none' | 'none',\n title,\n nativeIosOverrides,\n nativeAndroidOverrides,\n nativeRestOverrides,\n screenKey: routeKey,\n icon,\n selectedIcon,\n };\n}\n\nexport function ScreenContent({\n options,\n contentRenderer,\n}: {\n options: NativeTabOptions;\n contentRenderer: () => React.ReactNode;\n}) {\n const { colors } = useTheme();\n return (\n \n {contentRenderer()}\n \n );\n}\n"]} \ No newline at end of file +{"version":3,"file":"NativeTabsView.shared.js","sourceRoot":"","sources":["../../src/native-tabs/NativeTabsView.shared.tsx"],"names":[],"mappings":";;AAQA,oDAuBC;AAED,0DAYC;AAeD,oDAyBC;AAED,sCAoBC;;AA3GD,iCAAsE;AACtE,+CAAoC;AAIpC,uCAAqD;AACrD,uDAAsD;AAEtD,SAAgB,oBAAoB,CAAC,EACnC,YAAY,EACZ,UAAU,EACV,IAAI,GAC8D;IAIlE,MAAM,WAAW,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IAC9F,MAAM,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAC1E,IAAA,wBAAgB,EAAC,WAAW,CAAC,CAAC;IAEhC,8DAA8D;IAC9D,oFAAoF;IACpF,wFAAwF;IACxF,2BAA2B;IAC3B,MAAM,4BAA4B,GAChC,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,YAAY,CAAC;IAE3E,OAAO;QACL,iBAAiB,EAAE,IAAI,CAAC,4BAA4B,CAAE,CAAC,QAAQ;QAC/D,UAAU,EAAE,kBAAkB;KAC/B,CAAC;AACJ,CAAC;AAED,SAAgB,uBAAuB,CACrC,WAA+C;IAE/C,OAAO,IAAA,mBAAW,EAChB,CAAC,EAAE,WAAW,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE;QACnE,uEAAuE;QACvE,uDAAuD;QACvD,MAAM,cAAc,GAAG,YAAY,KAAK,iBAAiB,CAAC;QAC1D,WAAW,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;IAC9E,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;AACJ,CAAC;AAeD,SAAgB,oBAAoB,CAAC,KAA6B;IAChE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC;IACpC,MAAM,EACJ,GAAG,EAAE,kBAAkB,EACvB,OAAO,EAAE,sBAAsB,EAC/B,GAAG,mBAAmB,EACvB,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IAE9B,oEAAoE;IACpE,MAAM,IAAI,GAAG,IAAA,4BAAqB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,YAAY,GAAG,IAAA,4BAAqB,EAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAEjE,OAAO;QACL,OAAO;QACP,gGAAgG;QAChG,aAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAwB;QACvE,KAAK;QACL,kBAAkB;QAClB,sBAAsB;QACtB,mBAAmB;QACnB,SAAS,EAAE,QAAQ;QACnB,IAAI;QACJ,YAAY;KACb,CAAC;AACJ,CAAC;AAED,SAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,eAAe,GAIhB;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,iBAAQ,GAAE,CAAC;IAC9B,OAAO,CACL,uBAAC,mBAAI;IACH,+FAA+F;;QAA/F,+FAA+F;QAC/F,WAAW,EAAE,KAAK,EAClB,KAAK,EAAE;YACL,EAAE,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE;YACtC,OAAO,CAAC,YAAY;YACpB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE;SACtD,YACA,eAAe,EAAE,GACb,CACR,CAAC;AACJ,CAAC","sourcesContent":["import React, { useCallback, useDeferredValue, useMemo } from 'react';\nimport { View } from 'react-native';\nimport type { TabsHostProps } from 'react-native-screens';\n\nimport type { NativeTabOptions, NativeTabsViewProps } from './types';\nimport { useAwaitedScreensIcon } from './utils/icon';\nimport { useTheme } from '../react-navigation/native';\n\nexport function useSelectedScreenKey({\n focusedIndex,\n provenance,\n tabs,\n}: Pick): {\n selectedScreenKey: string;\n provenance: number;\n} {\n const stableState = useMemo(() => ({ focusedIndex, provenance }), [focusedIndex, provenance]);\n const { focusedIndex: deferredFocusedIndex, provenance: deferredProvenance } =\n useDeferredValue(stableState);\n\n // We need to check if the deferred index is not out of bounds\n // This can happen when the focused index is the last tab, and user removes that tab\n // In that case the deferred index will still point to the last tab, but after re-render\n // it will be out of bounds\n const inBoundsDeferredFocusedIndex =\n deferredFocusedIndex < tabs.length ? deferredFocusedIndex : focusedIndex;\n\n return {\n selectedScreenKey: tabs[inBoundsDeferredFocusedIndex]!.routeKey,\n provenance: deferredProvenance,\n };\n}\n\nexport function useOnTabSelectedHandler(\n onTabChange: NativeTabsViewProps['onTabChange']\n): NonNullable {\n return useCallback>(\n ({ nativeEvent: { selectedScreenKey, provenance, actionOrigin } }) => {\n // Treat anything other than a JS-driven echo as a native action so the\n // navigator emits `tabPress` and dispatches `JUMP_TO`.\n const isNativeAction = actionOrigin !== 'programmatic-js';\n onTabChange({ selectedKey: selectedScreenKey, provenance, isNativeAction });\n },\n [onTabChange]\n );\n}\n\n/**\n * Cross-platform fields used to render a single tab screen. Each platform\n * extends this with its own appearance fields.\n */\nexport interface InternalTabScreenProps {\n routeKey: string;\n name: string;\n // TODO(@ubax): https://linear.app/expo/issue/ENG-20736/remove-pointerevents-from-nativetabsview\n isFocused: boolean;\n options: NativeTabOptions;\n contentRenderer: () => React.ReactNode;\n}\n\nexport function useSharedScreenProps(props: InternalTabScreenProps) {\n const { options, isFocused, name, routeKey } = props;\n const title = options.title ?? name;\n const {\n ios: nativeIosOverrides,\n android: nativeAndroidOverrides,\n ...nativeRestOverrides\n } = options.nativeProps ?? {};\n\n // We need to await the icon, as VectorIcon will load asynchronously\n const icon = useAwaitedScreensIcon(options.icon);\n const selectedIcon = useAwaitedScreensIcon(options.selectedIcon);\n\n return {\n options,\n // TODO(@ubax): https://linear.app/expo/issue/ENG-20736/remove-pointerevents-from-nativetabsview\n pointerEvents: (isFocused ? 'box-none' : 'none') as 'box-none' | 'none',\n title,\n nativeIosOverrides,\n nativeAndroidOverrides,\n nativeRestOverrides,\n screenKey: routeKey,\n icon,\n selectedIcon,\n };\n}\n\nexport function ScreenContent({\n options,\n contentRenderer,\n}: {\n options: NativeTabOptions;\n contentRenderer: () => React.ReactNode;\n}) {\n const { colors } = useTheme();\n return (\n \n {contentRenderer()}\n \n );\n}\n"]} \ No newline at end of file diff --git a/packages/expo-router/build/native-tabs/types.d.ts b/packages/expo-router/build/native-tabs/types.d.ts index e2b8b5e5f3b1dd..eed7178eea60f7 100644 --- a/packages/expo-router/build/native-tabs/types.d.ts +++ b/packages/expo-router/build/native-tabs/types.d.ts @@ -19,7 +19,7 @@ export type NativeScreenProps = Partial>; /** * Props passed to the underlying tab host implementation in `react-native-screens`. */ -export type NativeTabsHostNativeProps = Partial>; +export type NativeTabsHostNativeProps = Partial>; export interface NativeTabOptions extends DefaultRouterOptions { icon?: SymbolOrImageSource; selectedIcon?: SymbolOrImageSource; @@ -263,10 +263,10 @@ export interface OnTabChangeEventPayload { /** * The provenance value reported by the native side for this selection. * - * The navigator echoes this back via `navState.provenance` on subsequent - * JS-driven updates so the native side can distinguish stale updates from - * fresh ones. See `TabsHostNavState` in `react-native-screens` for the full - * contract. + * The navigator echoes this back via `navStateRequest.baseProvenance` on + * subsequent JS-driven updates so the native side can distinguish stale + * updates from fresh ones. See `TabsHostNavStateRequest` in + * `react-native-screens` for the full contract. */ provenance: number; isNativeAction: boolean; diff --git a/packages/expo-router/build/native-tabs/types.d.ts.map b/packages/expo-router/build/native-tabs/types.d.ts.map index b0ddfcf64d6c45..686581c960085b 100644 --- a/packages/expo-router/build/native-tabs/types.d.ts.map +++ b/packages/expo-router/build/native-tabs/types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/native-tabs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,KAAK,EACV,UAAU,EACV,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,KAAK,EACV,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,SAAS,EACT,eAAe,EACf,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAEpC;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE;QAAE,IAAI,EAAE;YAAE,kBAAkB,EAAE,QAAQ,CAAA;SAAE,CAAC;QAAC,iBAAiB,EAAE,KAAK,CAAA;KAAE,CAAC;CAChF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC;AAE5E;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAC7C,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,eAAe,GAAG,UAAU,CAAC,CAC/D,CAAC;AAEF,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC5D,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,IAAI,CAAC,EAAE,wBAAwB,CAAC;IAChC,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC/B,4BAA4B,CAAC,EAAE,UAAU,CAAC;IAC1C,oBAAoB,CAAC,EAAE,UAAU,CAAC;IAClC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,uBAAuB,CAAC,EAAE;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,+BAA+B,CAAC,EAAE;QAChC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,eAAe,CAAC,gBAAgB,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,YAAY,CAAC,EAAE,IAAI,CACjB,SAAS,EACP,iBAAiB,GACjB,8BAA8B,GAC9B,SAAS,GACT,YAAY,GACZ,eAAe,GACf,aAAa,GACb,cAAc,GACd,cAAc,GACd,iBAAiB,GACjB,mBAAmB,GACnB,eAAe,GACf,kBAAkB,GAClB,oBAAoB,GACpB,YAAY,GACZ,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,GACd,cAAc,GACd,YAAY,GACZ,gBAAgB,GAChB,eAAe,GACf,KAAK,CACR,CAAC;CACH;AAED,MAAM,MAAM,mBAAmB,GAC3B;IACE;;;OAGG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACD;IACE;;OAEG;IACH,GAAG,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAChE;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CACzC,CAAC;AAEN,MAAM,MAAM,oBAAoB,GAAG,IAAI,CACrC,SAAS,EACT,YAAY,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CACjE,CAAC;AAEF,eAAO,MAAM,sBAAsB,8dAuBzB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3E,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IAExD;;OAEG;IACH,UAAU,CAAC,EACP,SAAS,CAAC,oBAAoB,CAAC,GAC/B;QACE,OAAO,CAAC,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC;QAC1C,QAAQ,CAAC,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC;KAC5C,CAAC;IACN;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,GAAG;QAAE,OAAO,CAAC,EAAE,UAAU,CAAC;QAAC,QAAQ,CAAC,EAAE,UAAU,CAAA;KAAE,CAAC;IACzE;;;;OAIG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B;;OAEG;IACH,oBAAoB,CAAC,EAAE,UAAU,CAAC;IAClC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAGjB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,gBAAgB,CAAC,EAAE,gCAAgC,CAAC;IACpD;;;;OAIG;IACH,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB;;;;OAIG;IACH,uBAAuB,CAAC,EAAE;QACxB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAG3B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IACnD;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,uCAAuC,CAAC;IAC9D;;;;OAIG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,UAAU,CAAC;IAE5B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,eAAe,CAAC,EACZ,eAAe,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,2BAA2B,CAAC,GAC/E,CAAC,CAAC,IAAI,EAAE;QACN,KAAK,EAAE,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;KACzC,KAAK,eAAe,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,2BAA2B,CAAC,CAAC,CAAC;IAC3F;;;;;;;;OAQG;IACH,oBAAoB,CAAC,EAAE,yBAAyB,CAAC;CAClD;AAED,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,kBAAkB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACtC;AACD,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,mBACf,SAAQ,IAAI,CACV,uBAAuB,EACrB,YAAY,GACZ,WAAW,GACX,iBAAiB,GACjB,sBAAsB,GACtB,YAAY,GACZ,gBAAgB,GAChB,gBAAgB,CACnB;IACD,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,qBAAqB,EAAE,CAAC;IAC9B,WAAW,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;CACxC;AAED,eAAO,MAAM,6CAA6C,uDAKhD,CAAC;AAEX;;;;GAIG;AACH,MAAM,MAAM,uCAAuC,GACjD,CAAC,OAAO,6CAA6C,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,eAAO,MAAM,oCAAoC,+DAKvC,CAAC;AAEX;;;;GAIG;AACH,MAAM,MAAM,gCAAgC,GAC1C,CAAC,OAAO,oCAAoC,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,iBAAiB,CAAC;IACzC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,wBAAwB,CAAC;IAChC;;;;;;;;;;;;;;;OAeG;IACH,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC;;;;OAIG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAChD;;;;;;OAMG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAS,CAAC,EACN,eAAe,CAAC,eAAe,EAAE,YAAY,CAAC,GAC9C,CAAC,CAAC,IAAI,EAAE;QACN,KAAK,EAAE,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;KACzC,KAAK,eAAe,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC;CAC3D;AAED,QAAA,MAAM,4BAA4B,0JAaxB,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/native-tabs/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-router/build/native-tabs/types.js.map b/packages/expo-router/build/native-tabs/types.js.map index 012a9311894a03..eafa617b1b8e7a 100644 --- a/packages/expo-router/build/native-tabs/types.js.map +++ b/packages/expo-router/build/native-tabs/types.js.map @@ -1 +1 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/native-tabs/types.ts"],"names":[],"mappings":";;;AAmIa,QAAA,sBAAsB,GAAG;IACpC,MAAM;IACN,eAAe;IACf,YAAY;IACZ,OAAO;IACP,MAAM;IACN,SAAS;IACT,WAAW;IACX,yBAAyB;IACzB,oBAAoB;IACpB,gBAAgB;IAChB,qBAAqB;IACrB,sBAAsB;IACtB,8BAA8B;IAC9B,yBAAyB;IACzB,qBAAqB;IACrB,0BAA0B;IAC1B,2BAA2B;IAC3B,6BAA6B;IAC7B,wBAAwB;IACxB,oBAAoB;IACpB,yBAAyB;IACzB,0BAA0B;CAClB,CAAC;AAqOE,QAAA,6CAA6C,GAAG;IAC3D,MAAM;IACN,UAAU;IACV,SAAS;IACT,WAAW;CACH,CAAC;AAUE,QAAA,oCAAoC,GAAG;IAClD,WAAW;IACX,OAAO;IACP,cAAc;IACd,YAAY;CACJ,CAAC;AAiIX,MAAM,4BAA4B,GAAG;IACnC,WAAW;IACX,UAAU;IACV,WAAW;IACX,WAAW;IACX,UAAU;IACV,SAAS;IACT,MAAM;IACN,YAAY;IACZ,YAAY;IACZ,SAAS;IACT,QAAQ;IACR,UAAU;CACF,CAAC","sourcesContent":["import type { PropsWithChildren } from 'react';\nimport type {\n ColorValue,\n ImageSourcePropType,\n StyleProp,\n TextStyle,\n ViewStyle,\n} from 'react-native';\nimport type { TabsHostProps, TabsScreenProps } from 'react-native-screens';\nimport type { SFSymbol } from 'sf-symbols-typescript';\n\nimport type {\n DefaultRouterOptions,\n EventMapBase,\n NavigationState,\n ParamListBase,\n RouteProp,\n ScreenListeners,\n TabNavigationState,\n} from '../react-navigation/native';\n\n/**\n * Event map for `NativeTabs` navigation events.\n * Only `tabPress` is currently supported.\n */\nexport type NativeTabNavigationEventMap = {\n tabPress: { data: { __internalTabsType: 'native' }; canPreventDefault: false };\n};\n\nexport type NativeScreenProps = Partial>;\n\n/**\n * Props passed to the underlying tab host implementation in `react-native-screens`.\n */\nexport type NativeTabsHostNativeProps = Partial<\n Omit\n>;\n\nexport interface NativeTabOptions extends DefaultRouterOptions {\n icon?: SymbolOrImageSource;\n selectedIcon?: SymbolOrImageSource;\n title?: string;\n badgeValue?: string;\n selectedLabelStyle?: NativeTabsLabelStyle;\n labelStyle?: NativeTabsLabelStyle;\n role?: NativeTabsTabBarItemRole;\n selectedIconColor?: ColorValue;\n selectedBadgeBackgroundColor?: ColorValue;\n badgeBackgroundColor?: ColorValue;\n badgeTextColor?: ColorValue;\n backgroundColor?: ColorValue;\n blurEffect?: NativeTabsBlurEffect;\n shadowColor?: ColorValue;\n iconColor?: ColorValue;\n disableTransparentOnScrollEdge?: boolean;\n titlePositionAdjustment?: {\n horizontal?: number;\n vertical?: number;\n };\n selectedTitlePositionAdjustment?: {\n horizontal?: number;\n vertical?: number;\n };\n indicatorColor?: ColorValue;\n hidden?: boolean;\n specialEffects?: TabsScreenProps['specialEffects'];\n nativeProps?: NativeScreenProps;\n disableAutomaticContentInsets?: boolean;\n contentStyle?: Pick<\n ViewStyle,\n | 'backgroundColor'\n | 'experimental_backgroundImage'\n | 'padding'\n | 'paddingTop'\n | 'paddingBottom'\n | 'paddingLeft'\n | 'paddingRight'\n | 'paddingBlock'\n | 'paddingBlockEnd'\n | 'paddingBlockStart'\n | 'paddingInline'\n | 'paddingInlineEnd'\n | 'paddingInlineStart'\n | 'paddingEnd'\n | 'paddingHorizontal'\n | 'paddingVertical'\n | 'paddingStart'\n | 'alignContent'\n | 'alignItems'\n | 'justifyContent'\n | 'flexDirection'\n | 'gap'\n >;\n}\n\nexport type SymbolOrImageSource =\n | {\n /**\n * The name of the SF Symbol to use as an icon.\n * @platform iOS\n */\n sf?: SFSymbol;\n /**\n * The name of the iOS asset catalog image to use as an icon.\n * @platform iOS\n */\n xcasset?: string;\n /**\n * The name of the drawable resource to use as an icon.\n * @platform android\n */\n drawable?: string;\n }\n | {\n /**\n * The image source to use as an icon.\n */\n src?: ImageSourcePropType | Promise;\n /**\n * Controls how the icon is rendered on iOS.\n * @platform ios\n * @default 'template'\n */\n renderingMode?: 'template' | 'original';\n };\n\nexport type NativeTabsLabelStyle = Pick<\n TextStyle,\n 'fontFamily' | 'fontSize' | 'fontStyle' | 'fontWeight' | 'color'\n>;\n\nexport const SUPPORTED_BLUR_EFFECTS = [\n 'none',\n 'systemDefault',\n 'extraLight',\n 'light',\n 'dark',\n 'regular',\n 'prominent',\n 'systemUltraThinMaterial',\n 'systemThinMaterial',\n 'systemMaterial',\n 'systemThickMaterial',\n 'systemChromeMaterial',\n 'systemUltraThinMaterialLight',\n 'systemThinMaterialLight',\n 'systemMaterialLight',\n 'systemThickMaterialLight',\n 'systemChromeMaterialLight',\n 'systemUltraThinMaterialDark',\n 'systemThinMaterialDark',\n 'systemMaterialDark',\n 'systemThickMaterialDark',\n 'systemChromeMaterialDark',\n] as const;\n\n/**\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uiblureffect/style)\n */\nexport type NativeTabsBlurEffect = (typeof SUPPORTED_BLUR_EFFECTS)[number];\n\nexport interface NativeTabsProps extends PropsWithChildren {\n // #region common props\n /**\n * The style of the every tab label in the tab bar.\n */\n labelStyle?:\n | StyleProp\n | {\n default?: StyleProp;\n selected?: StyleProp;\n };\n /**\n * The color of every tab icon in the tab bar.\n */\n iconColor?: ColorValue | { default?: ColorValue; selected?: ColorValue };\n /**\n * The tint color of the tab icon.\n *\n * Can be overridden by icon color and label color for each tab individually.\n */\n tintColor?: ColorValue;\n /**\n * The background color of the tab bar.\n */\n backgroundColor?: ColorValue;\n /**\n * The background color of every badge in the tab bar.\n */\n badgeBackgroundColor?: ColorValue;\n /**\n * When set to `true`, hides the tab bar.\n *\n * @default false\n */\n hidden?: boolean;\n // #endregion common props\n // #region iOS props\n /**\n * Specifies the minimize behavior for the tab bar.\n *\n * Available starting from iOS 26.\n *\n * The following values are currently supported:\n *\n * - `automatic` - resolves to the system default minimize behavior\n * - `never` - the tab bar does not minimize\n * - `onScrollDown` - the tab bar minimizes when scrolling down and\n * expands when scrolling back up\n * - `onScrollUp` - the tab bar minimizes when scrolling up and expands\n * when scrolling back down\n *\n * @see The supported values correspond to the official [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbarcontroller/minimizebehavior).\n *\n * @default automatic\n *\n * @platform iOS 26+\n */\n minimizeBehavior?: NativeTabsTabBarMinimizeBehavior;\n /**\n * The blur effect applied to the tab bar.\n *\n * @platform iOS\n */\n blurEffect?: NativeTabsBlurEffect;\n /**\n * The color of the shadow.\n *\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uibarappearance/shadowcolor)\n *\n * @platform iOS\n */\n shadowColor?: ColorValue;\n /**\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbaritem/titlepositionadjustment)\n *\n * @platform iOS\n */\n titlePositionAdjustment?: {\n horizontal?: number;\n vertical?: number;\n };\n /**\n * When set to `true`, the tab bar will not become transparent when scrolled to the edge.\n *\n * @platform iOS\n */\n disableTransparentOnScrollEdge?: boolean;\n /**\n * When set to `true`, enables the sidebarAdaptable tab bar style on iPadOS and macOS. This prop has no effect on iPhone.\n *\n * @platform iOS 18+\n */\n sidebarAdaptable?: boolean;\n // #endregion iOS props\n // #region android props\n /**\n * Disables the active indicator for the tab bar.\n *\n * @platform android\n */\n disableIndicator?: boolean;\n /**\n * The behavior when navigating back with the back button.\n *\n * @platform android\n */\n backBehavior?: 'none' | 'initialRoute' | 'history';\n /**\n * The visibility mode of the tab item label.\n *\n * @see [Material Components documentation](https://github.com/material-components/material-components-android/blob/master/docs/components/BottomNavigation.md#making-navigation-bar-accessible)\n *\n * @platform android\n */\n labelVisibilityMode?: NativeTabsTabBarItemLabelVisibilityMode;\n /**\n * The color of the ripple effect when the tab is pressed.\n *\n * @platform android\n */\n rippleColor?: ColorValue;\n /**\n * The color of the tab indicator.\n *\n * @platform android\n * @platform web\n */\n indicatorColor?: ColorValue;\n /**\n * The color of the badge text.\n *\n * @platform android\n * @platform web\n */\n badgeTextColor?: ColorValue;\n // #endregion android props\n /**\n * Listeners for navigation events on all tabs.\n *\n * Supported events:\n * - `tabPress` - called when a tab is pressed\n * - `focus` - called when the screen comes into focus\n * - `blur` - called when the screen loses focus\n *\n * @example\n * ```tsx\n * {\n * console.log('Any tab pressed');\n * },\n * }}\n * >\n * ...\n * \n * ```\n */\n screenListeners?:\n | ScreenListeners, NativeTabNavigationEventMap>\n | ((prop: {\n route: RouteProp;\n }) => ScreenListeners, NativeTabNavigationEventMap>);\n /**\n * Props passed to the underlying native tab host implementation in `react-native-screens`.\n * Use this to configure props that are not directly exposed by Expo Router.\n *\n * > **Note**: This is an unstable API and may change or be removed in minor versions.\n *\n * @platform android\n * @platform ios\n */\n unstable_nativeProps?: NativeTabsHostNativeProps;\n}\n\nexport interface InternalNativeTabsProps extends NativeTabsProps {\n nonTriggerChildren?: React.ReactNode;\n}\nexport interface OnTabChangeEventPayload {\n /**\n * The route key of the tab the native side has just selected.\n */\n selectedKey: string;\n /**\n * The provenance value reported by the native side for this selection.\n *\n * The navigator echoes this back via `navState.provenance` on subsequent\n * JS-driven updates so the native side can distinguish stale updates from\n * fresh ones. See `TabsHostNavState` in `react-native-screens` for the full\n * contract.\n */\n provenance: number;\n // TODO(@ubax): consider renaming this field\n isNativeAction: boolean;\n}\n\nexport interface NativeTabsViewProps\n extends Omit<\n InternalNativeTabsProps,\n | 'labelStyle'\n | 'iconColor'\n | 'backgroundColor'\n | 'badgeBackgroundColor'\n | 'blurEffect'\n | 'indicatorColor'\n | 'badgeTextColor'\n > {\n focusedIndex: number;\n /**\n * Provenance counter associated with the currently rendered `focusedIndex`.\n */\n provenance: number;\n tabs: NativeTabsViewTabItem[];\n onTabChange: (event: OnTabChangeEventPayload) => void;\n}\n\nexport interface NativeTabsViewTabItem {\n options: NativeTabOptions;\n routeKey: string;\n name: string;\n contentRenderer: () => React.ReactNode;\n}\n\nexport const SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES = [\n 'auto',\n 'selected',\n 'labeled',\n 'unlabeled',\n] as const;\n\n/**\n * @see [Material Components documentation](https://github.com/material-components/material-components-android/blob/master/docs/components/BottomNavigation.md#making-navigation-bar-accessible)\n *\n * @platform android\n */\nexport type NativeTabsTabBarItemLabelVisibilityMode =\n (typeof SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES)[number];\n\nexport const SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS = [\n 'automatic',\n 'never',\n 'onScrollDown',\n 'onScrollUp',\n] as const;\n\n/**\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbarcontroller/minimizebehavior)\n *\n * @platform iOS 26\n */\nexport type NativeTabsTabBarMinimizeBehavior =\n (typeof SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS)[number];\n\nexport interface NativeTabTriggerProps {\n /**\n * The name of the route.\n *\n * This is required when used inside a Layout component.\n *\n * When used in a route it has no effect.\n */\n name?: string;\n /**\n * If true, the tab will be hidden from the tab bar.\n *\n * > **Note**: Marking a tab as `hidden` means it cannot be navigated to in any way.\n *\n * > **Note**: Dynamically hiding tabs will remount the navigator and the state will be reset.\n */\n hidden?: boolean;\n /**\n * Props passed to the underlying native tab screen implementation.\n * Use this to configure props not directly exposed by Expo Router, but available in `react-native-screens`.\n *\n * > **Note**: This will override any other props set by Expo Router and may lead to unexpected behavior.\n *\n * > **Note**: This is an unstable API and may change or be removed in minor versions.\n *\n * @platform android\n * @platform iOS\n */\n unstable_nativeProps?: NativeScreenProps;\n /**\n * If true, the tab will not pop stack to the root when selected again.\n *\n * @default false\n * @platform iOS\n */\n disablePopToTop?: boolean;\n /**\n * If true, the tab will not scroll to the top when selected again.\n * @default false\n *\n * @platform iOS\n */\n disableScrollToTop?: boolean;\n /**\n * The children of the trigger.\n *\n * Use `Icon`, `Label`, and `Badge` components to customize the tab.\n */\n children?: React.ReactNode;\n /**\n * System-provided tab bar item with predefined icon and title\n *\n * Uses Apple's built-in tab bar items (e.g., bookmarks, contacts, downloads) with\n * standard iOS styling and localized titles. Custom `icon` or `selectedIcon`\n * properties will override the system icon, but the system-defined title cannot\n * be customized.\n *\n * @see The supported values correspond to the official [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbaritem/systemitem).\n * @platform ios\n */\n role?: NativeTabsTabBarItemRole;\n /**\n * The default behavior differs between iOS and Android.\n *\n * On **Android**, the content of a native tabs screen is automatically wrapped in a `SafeAreaView`,\n * and the **bottom** inset is applied. Other insets must be handled manually.\n *\n * On **iOS**, the first scroll view nested inside a native tabs screen has\n * [automatic content inset adjustment](https://reactnative.dev/docs/scrollview#contentinsetadjustmentbehavior-ios) enabled\n *\n * When this property is set to `true`, automatic content inset adjustment is disabled for the screen\n * and must be managed manually. You can use `SafeAreaView` from `react-native-screens/experimental`\n * to handle safe area insets.\n *\n * @platform android\n * @platform ios\n */\n disableAutomaticContentInsets?: boolean;\n /**\n * The style applied to the content of the tab\n *\n * Note: Only certain style properties are supported.\n */\n contentStyle?: NativeTabOptions['contentStyle'];\n /**\n * When set to `true`, the tab bar will not become transparent when scrolled to the edge.\n *\n * When set on a trigger, it takes precedence over the value set on `NativeTabs`.\n *\n * @platform iOS\n */\n disableTransparentOnScrollEdge?: boolean;\n /**\n * Listeners for navigation events on this tab.\n *\n * Supported events:\n * - `tabPress` - called when this tab is pressed\n * - `focus` - called when this screen comes into focus\n * - `blur` - called when this screen loses focus\n *\n * @example\n * ```tsx\n * {\n * console.log('Home tab pressed');\n * },\n * }}\n * />\n * ```\n */\n listeners?:\n | ScreenListeners\n | ((prop: {\n route: RouteProp;\n }) => ScreenListeners);\n}\n\nconst SUPPORTED_TAB_BAR_ITEM_ROLES = [\n 'bookmarks',\n 'contacts',\n 'downloads',\n 'favorites',\n 'featured',\n 'history',\n 'more',\n 'mostRecent',\n 'mostViewed',\n 'recents',\n 'search',\n 'topRated',\n] as const;\n\nexport type NativeTabsTabBarItemRole = (typeof SUPPORTED_TAB_BAR_ITEM_ROLES)[number];\n"]} \ No newline at end of file +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/native-tabs/types.ts"],"names":[],"mappings":";;;AAmIa,QAAA,sBAAsB,GAAG;IACpC,MAAM;IACN,eAAe;IACf,YAAY;IACZ,OAAO;IACP,MAAM;IACN,SAAS;IACT,WAAW;IACX,yBAAyB;IACzB,oBAAoB;IACpB,gBAAgB;IAChB,qBAAqB;IACrB,sBAAsB;IACtB,8BAA8B;IAC9B,yBAAyB;IACzB,qBAAqB;IACrB,0BAA0B;IAC1B,2BAA2B;IAC3B,6BAA6B;IAC7B,wBAAwB;IACxB,oBAAoB;IACpB,yBAAyB;IACzB,0BAA0B;CAClB,CAAC;AAqOE,QAAA,6CAA6C,GAAG;IAC3D,MAAM;IACN,UAAU;IACV,SAAS;IACT,WAAW;CACH,CAAC;AAUE,QAAA,oCAAoC,GAAG;IAClD,WAAW;IACX,OAAO;IACP,cAAc;IACd,YAAY;CACJ,CAAC;AAiIX,MAAM,4BAA4B,GAAG;IACnC,WAAW;IACX,UAAU;IACV,WAAW;IACX,WAAW;IACX,UAAU;IACV,SAAS;IACT,MAAM;IACN,YAAY;IACZ,YAAY;IACZ,SAAS;IACT,QAAQ;IACR,UAAU;CACF,CAAC","sourcesContent":["import type { PropsWithChildren } from 'react';\nimport type {\n ColorValue,\n ImageSourcePropType,\n StyleProp,\n TextStyle,\n ViewStyle,\n} from 'react-native';\nimport type { TabsHostProps, TabsScreenProps } from 'react-native-screens';\nimport type { SFSymbol } from 'sf-symbols-typescript';\n\nimport type {\n DefaultRouterOptions,\n EventMapBase,\n NavigationState,\n ParamListBase,\n RouteProp,\n ScreenListeners,\n TabNavigationState,\n} from '../react-navigation/native';\n\n/**\n * Event map for `NativeTabs` navigation events.\n * Only `tabPress` is currently supported.\n */\nexport type NativeTabNavigationEventMap = {\n tabPress: { data: { __internalTabsType: 'native' }; canPreventDefault: false };\n};\n\nexport type NativeScreenProps = Partial>;\n\n/**\n * Props passed to the underlying tab host implementation in `react-native-screens`.\n */\nexport type NativeTabsHostNativeProps = Partial<\n Omit\n>;\n\nexport interface NativeTabOptions extends DefaultRouterOptions {\n icon?: SymbolOrImageSource;\n selectedIcon?: SymbolOrImageSource;\n title?: string;\n badgeValue?: string;\n selectedLabelStyle?: NativeTabsLabelStyle;\n labelStyle?: NativeTabsLabelStyle;\n role?: NativeTabsTabBarItemRole;\n selectedIconColor?: ColorValue;\n selectedBadgeBackgroundColor?: ColorValue;\n badgeBackgroundColor?: ColorValue;\n badgeTextColor?: ColorValue;\n backgroundColor?: ColorValue;\n blurEffect?: NativeTabsBlurEffect;\n shadowColor?: ColorValue;\n iconColor?: ColorValue;\n disableTransparentOnScrollEdge?: boolean;\n titlePositionAdjustment?: {\n horizontal?: number;\n vertical?: number;\n };\n selectedTitlePositionAdjustment?: {\n horizontal?: number;\n vertical?: number;\n };\n indicatorColor?: ColorValue;\n hidden?: boolean;\n specialEffects?: TabsScreenProps['specialEffects'];\n nativeProps?: NativeScreenProps;\n disableAutomaticContentInsets?: boolean;\n contentStyle?: Pick<\n ViewStyle,\n | 'backgroundColor'\n | 'experimental_backgroundImage'\n | 'padding'\n | 'paddingTop'\n | 'paddingBottom'\n | 'paddingLeft'\n | 'paddingRight'\n | 'paddingBlock'\n | 'paddingBlockEnd'\n | 'paddingBlockStart'\n | 'paddingInline'\n | 'paddingInlineEnd'\n | 'paddingInlineStart'\n | 'paddingEnd'\n | 'paddingHorizontal'\n | 'paddingVertical'\n | 'paddingStart'\n | 'alignContent'\n | 'alignItems'\n | 'justifyContent'\n | 'flexDirection'\n | 'gap'\n >;\n}\n\nexport type SymbolOrImageSource =\n | {\n /**\n * The name of the SF Symbol to use as an icon.\n * @platform iOS\n */\n sf?: SFSymbol;\n /**\n * The name of the iOS asset catalog image to use as an icon.\n * @platform iOS\n */\n xcasset?: string;\n /**\n * The name of the drawable resource to use as an icon.\n * @platform android\n */\n drawable?: string;\n }\n | {\n /**\n * The image source to use as an icon.\n */\n src?: ImageSourcePropType | Promise;\n /**\n * Controls how the icon is rendered on iOS.\n * @platform ios\n * @default 'template'\n */\n renderingMode?: 'template' | 'original';\n };\n\nexport type NativeTabsLabelStyle = Pick<\n TextStyle,\n 'fontFamily' | 'fontSize' | 'fontStyle' | 'fontWeight' | 'color'\n>;\n\nexport const SUPPORTED_BLUR_EFFECTS = [\n 'none',\n 'systemDefault',\n 'extraLight',\n 'light',\n 'dark',\n 'regular',\n 'prominent',\n 'systemUltraThinMaterial',\n 'systemThinMaterial',\n 'systemMaterial',\n 'systemThickMaterial',\n 'systemChromeMaterial',\n 'systemUltraThinMaterialLight',\n 'systemThinMaterialLight',\n 'systemMaterialLight',\n 'systemThickMaterialLight',\n 'systemChromeMaterialLight',\n 'systemUltraThinMaterialDark',\n 'systemThinMaterialDark',\n 'systemMaterialDark',\n 'systemThickMaterialDark',\n 'systemChromeMaterialDark',\n] as const;\n\n/**\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uiblureffect/style)\n */\nexport type NativeTabsBlurEffect = (typeof SUPPORTED_BLUR_EFFECTS)[number];\n\nexport interface NativeTabsProps extends PropsWithChildren {\n // #region common props\n /**\n * The style of the every tab label in the tab bar.\n */\n labelStyle?:\n | StyleProp\n | {\n default?: StyleProp;\n selected?: StyleProp;\n };\n /**\n * The color of every tab icon in the tab bar.\n */\n iconColor?: ColorValue | { default?: ColorValue; selected?: ColorValue };\n /**\n * The tint color of the tab icon.\n *\n * Can be overridden by icon color and label color for each tab individually.\n */\n tintColor?: ColorValue;\n /**\n * The background color of the tab bar.\n */\n backgroundColor?: ColorValue;\n /**\n * The background color of every badge in the tab bar.\n */\n badgeBackgroundColor?: ColorValue;\n /**\n * When set to `true`, hides the tab bar.\n *\n * @default false\n */\n hidden?: boolean;\n // #endregion common props\n // #region iOS props\n /**\n * Specifies the minimize behavior for the tab bar.\n *\n * Available starting from iOS 26.\n *\n * The following values are currently supported:\n *\n * - `automatic` - resolves to the system default minimize behavior\n * - `never` - the tab bar does not minimize\n * - `onScrollDown` - the tab bar minimizes when scrolling down and\n * expands when scrolling back up\n * - `onScrollUp` - the tab bar minimizes when scrolling up and expands\n * when scrolling back down\n *\n * @see The supported values correspond to the official [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbarcontroller/minimizebehavior).\n *\n * @default automatic\n *\n * @platform iOS 26+\n */\n minimizeBehavior?: NativeTabsTabBarMinimizeBehavior;\n /**\n * The blur effect applied to the tab bar.\n *\n * @platform iOS\n */\n blurEffect?: NativeTabsBlurEffect;\n /**\n * The color of the shadow.\n *\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uibarappearance/shadowcolor)\n *\n * @platform iOS\n */\n shadowColor?: ColorValue;\n /**\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbaritem/titlepositionadjustment)\n *\n * @platform iOS\n */\n titlePositionAdjustment?: {\n horizontal?: number;\n vertical?: number;\n };\n /**\n * When set to `true`, the tab bar will not become transparent when scrolled to the edge.\n *\n * @platform iOS\n */\n disableTransparentOnScrollEdge?: boolean;\n /**\n * When set to `true`, enables the sidebarAdaptable tab bar style on iPadOS and macOS. This prop has no effect on iPhone.\n *\n * @platform iOS 18+\n */\n sidebarAdaptable?: boolean;\n // #endregion iOS props\n // #region android props\n /**\n * Disables the active indicator for the tab bar.\n *\n * @platform android\n */\n disableIndicator?: boolean;\n /**\n * The behavior when navigating back with the back button.\n *\n * @platform android\n */\n backBehavior?: 'none' | 'initialRoute' | 'history';\n /**\n * The visibility mode of the tab item label.\n *\n * @see [Material Components documentation](https://github.com/material-components/material-components-android/blob/master/docs/components/BottomNavigation.md#making-navigation-bar-accessible)\n *\n * @platform android\n */\n labelVisibilityMode?: NativeTabsTabBarItemLabelVisibilityMode;\n /**\n * The color of the ripple effect when the tab is pressed.\n *\n * @platform android\n */\n rippleColor?: ColorValue;\n /**\n * The color of the tab indicator.\n *\n * @platform android\n * @platform web\n */\n indicatorColor?: ColorValue;\n /**\n * The color of the badge text.\n *\n * @platform android\n * @platform web\n */\n badgeTextColor?: ColorValue;\n // #endregion android props\n /**\n * Listeners for navigation events on all tabs.\n *\n * Supported events:\n * - `tabPress` - called when a tab is pressed\n * - `focus` - called when the screen comes into focus\n * - `blur` - called when the screen loses focus\n *\n * @example\n * ```tsx\n * {\n * console.log('Any tab pressed');\n * },\n * }}\n * >\n * ...\n * \n * ```\n */\n screenListeners?:\n | ScreenListeners, NativeTabNavigationEventMap>\n | ((prop: {\n route: RouteProp;\n }) => ScreenListeners, NativeTabNavigationEventMap>);\n /**\n * Props passed to the underlying native tab host implementation in `react-native-screens`.\n * Use this to configure props that are not directly exposed by Expo Router.\n *\n * > **Note**: This is an unstable API and may change or be removed in minor versions.\n *\n * @platform android\n * @platform ios\n */\n unstable_nativeProps?: NativeTabsHostNativeProps;\n}\n\nexport interface InternalNativeTabsProps extends NativeTabsProps {\n nonTriggerChildren?: React.ReactNode;\n}\nexport interface OnTabChangeEventPayload {\n /**\n * The route key of the tab the native side has just selected.\n */\n selectedKey: string;\n /**\n * The provenance value reported by the native side for this selection.\n *\n * The navigator echoes this back via `navStateRequest.baseProvenance` on\n * subsequent JS-driven updates so the native side can distinguish stale\n * updates from fresh ones. See `TabsHostNavStateRequest` in\n * `react-native-screens` for the full contract.\n */\n provenance: number;\n // TODO(@ubax): consider renaming this field\n isNativeAction: boolean;\n}\n\nexport interface NativeTabsViewProps\n extends Omit<\n InternalNativeTabsProps,\n | 'labelStyle'\n | 'iconColor'\n | 'backgroundColor'\n | 'badgeBackgroundColor'\n | 'blurEffect'\n | 'indicatorColor'\n | 'badgeTextColor'\n > {\n focusedIndex: number;\n /**\n * Provenance counter associated with the currently rendered `focusedIndex`.\n */\n provenance: number;\n tabs: NativeTabsViewTabItem[];\n onTabChange: (event: OnTabChangeEventPayload) => void;\n}\n\nexport interface NativeTabsViewTabItem {\n options: NativeTabOptions;\n routeKey: string;\n name: string;\n contentRenderer: () => React.ReactNode;\n}\n\nexport const SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES = [\n 'auto',\n 'selected',\n 'labeled',\n 'unlabeled',\n] as const;\n\n/**\n * @see [Material Components documentation](https://github.com/material-components/material-components-android/blob/master/docs/components/BottomNavigation.md#making-navigation-bar-accessible)\n *\n * @platform android\n */\nexport type NativeTabsTabBarItemLabelVisibilityMode =\n (typeof SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES)[number];\n\nexport const SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS = [\n 'automatic',\n 'never',\n 'onScrollDown',\n 'onScrollUp',\n] as const;\n\n/**\n * @see [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbarcontroller/minimizebehavior)\n *\n * @platform iOS 26\n */\nexport type NativeTabsTabBarMinimizeBehavior =\n (typeof SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS)[number];\n\nexport interface NativeTabTriggerProps {\n /**\n * The name of the route.\n *\n * This is required when used inside a Layout component.\n *\n * When used in a route it has no effect.\n */\n name?: string;\n /**\n * If true, the tab will be hidden from the tab bar.\n *\n * > **Note**: Marking a tab as `hidden` means it cannot be navigated to in any way.\n *\n * > **Note**: Dynamically hiding tabs will remount the navigator and the state will be reset.\n */\n hidden?: boolean;\n /**\n * Props passed to the underlying native tab screen implementation.\n * Use this to configure props not directly exposed by Expo Router, but available in `react-native-screens`.\n *\n * > **Note**: This will override any other props set by Expo Router and may lead to unexpected behavior.\n *\n * > **Note**: This is an unstable API and may change or be removed in minor versions.\n *\n * @platform android\n * @platform iOS\n */\n unstable_nativeProps?: NativeScreenProps;\n /**\n * If true, the tab will not pop stack to the root when selected again.\n *\n * @default false\n * @platform iOS\n */\n disablePopToTop?: boolean;\n /**\n * If true, the tab will not scroll to the top when selected again.\n * @default false\n *\n * @platform iOS\n */\n disableScrollToTop?: boolean;\n /**\n * The children of the trigger.\n *\n * Use `Icon`, `Label`, and `Badge` components to customize the tab.\n */\n children?: React.ReactNode;\n /**\n * System-provided tab bar item with predefined icon and title\n *\n * Uses Apple's built-in tab bar items (e.g., bookmarks, contacts, downloads) with\n * standard iOS styling and localized titles. Custom `icon` or `selectedIcon`\n * properties will override the system icon, but the system-defined title cannot\n * be customized.\n *\n * @see The supported values correspond to the official [Apple documentation](https://developer.apple.com/documentation/uikit/uitabbaritem/systemitem).\n * @platform ios\n */\n role?: NativeTabsTabBarItemRole;\n /**\n * The default behavior differs between iOS and Android.\n *\n * On **Android**, the content of a native tabs screen is automatically wrapped in a `SafeAreaView`,\n * and the **bottom** inset is applied. Other insets must be handled manually.\n *\n * On **iOS**, the first scroll view nested inside a native tabs screen has\n * [automatic content inset adjustment](https://reactnative.dev/docs/scrollview#contentinsetadjustmentbehavior-ios) enabled\n *\n * When this property is set to `true`, automatic content inset adjustment is disabled for the screen\n * and must be managed manually. You can use `SafeAreaView` from `react-native-screens/experimental`\n * to handle safe area insets.\n *\n * @platform android\n * @platform ios\n */\n disableAutomaticContentInsets?: boolean;\n /**\n * The style applied to the content of the tab\n *\n * Note: Only certain style properties are supported.\n */\n contentStyle?: NativeTabOptions['contentStyle'];\n /**\n * When set to `true`, the tab bar will not become transparent when scrolled to the edge.\n *\n * When set on a trigger, it takes precedence over the value set on `NativeTabs`.\n *\n * @platform iOS\n */\n disableTransparentOnScrollEdge?: boolean;\n /**\n * Listeners for navigation events on this tab.\n *\n * Supported events:\n * - `tabPress` - called when this tab is pressed\n * - `focus` - called when this screen comes into focus\n * - `blur` - called when this screen loses focus\n *\n * @example\n * ```tsx\n * {\n * console.log('Home tab pressed');\n * },\n * }}\n * />\n * ```\n */\n listeners?:\n | ScreenListeners\n | ((prop: {\n route: RouteProp;\n }) => ScreenListeners);\n}\n\nconst SUPPORTED_TAB_BAR_ITEM_ROLES = [\n 'bookmarks',\n 'contacts',\n 'downloads',\n 'favorites',\n 'featured',\n 'history',\n 'more',\n 'mostRecent',\n 'mostViewed',\n 'recents',\n 'search',\n 'topRated',\n] as const;\n\nexport type NativeTabsTabBarItemRole = (typeof SUPPORTED_TAB_BAR_ITEM_ROLES)[number];\n"]} \ No newline at end of file diff --git a/packages/expo-router/package.json b/packages/expo-router/package.json index 23a9d5510912cd..37e63a7130401d 100644 --- a/packages/expo-router/package.json +++ b/packages/expo-router/package.json @@ -100,7 +100,7 @@ "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, @@ -143,7 +143,7 @@ "react-native-gesture-handler": "~2.30.0", "react-native-reanimated": "~4.3.0", "react-native-safe-area-context": "~5.6.2", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-web": "~0.21.0", "react-server-dom-webpack": "~19.0.4", "tsd": "^0.33.0" @@ -172,7 +172,7 @@ "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", "react-native-drawer-layout": "^4.2.2", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", diff --git a/packages/expo-router/src/native-tabs/NativeTabsView.android.tsx b/packages/expo-router/src/native-tabs/NativeTabsView.android.tsx index 14b69b4fbec75d..3c5dd89318df76 100644 --- a/packages/expo-router/src/native-tabs/NativeTabsView.android.tsx +++ b/packages/expo-router/src/native-tabs/NativeTabsView.android.tsx @@ -65,7 +65,7 @@ export function NativeTabsView(props: NativeTabsViewProps) { android={{ ...rawAndroidProps }} tabBarHidden={props.hidden} {...rawHostRestProps} - navState={{ selectedScreenKey, provenance }} + navStateRequest={{ selectedScreenKey, baseProvenance: provenance }} onTabSelected={onTabSelected}> {children} diff --git a/packages/expo-router/src/native-tabs/NativeTabsView.ios.tsx b/packages/expo-router/src/native-tabs/NativeTabsView.ios.tsx index 14af7b78deb205..00f5fbcf58b76b 100644 --- a/packages/expo-router/src/native-tabs/NativeTabsView.ios.tsx +++ b/packages/expo-router/src/native-tabs/NativeTabsView.ios.tsx @@ -88,7 +88,7 @@ export function NativeTabsView(props: NativeTabsViewProps) { }} tabBarHidden={props.hidden} {...rawHostRestProps} - navState={{ selectedScreenKey, provenance }} + navStateRequest={{ selectedScreenKey, baseProvenance: provenance }} onTabSelected={onTabSelected}> {children} diff --git a/packages/expo-router/src/native-tabs/NativeTabsView.shared.tsx b/packages/expo-router/src/native-tabs/NativeTabsView.shared.tsx index 319cae84e7a023..65d40ee543ccab 100644 --- a/packages/expo-router/src/native-tabs/NativeTabsView.shared.tsx +++ b/packages/expo-router/src/native-tabs/NativeTabsView.shared.tsx @@ -35,7 +35,10 @@ export function useOnTabSelectedHandler( onTabChange: NativeTabsViewProps['onTabChange'] ): NonNullable { return useCallback>( - ({ nativeEvent: { selectedScreenKey, provenance, isNativeAction } }) => { + ({ nativeEvent: { selectedScreenKey, provenance, actionOrigin } }) => { + // Treat anything other than a JS-driven echo as a native action so the + // navigator emits `tabPress` and dispatches `JUMP_TO`. + const isNativeAction = actionOrigin !== 'programmatic-js'; onTabChange({ selectedKey: selectedScreenKey, provenance, isNativeAction }); }, [onTabChange] diff --git a/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.android.tsx b/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.android.tsx index fb2d6e8edf81a9..adb9afc86350df 100644 --- a/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.android.tsx +++ b/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.android.tsx @@ -73,10 +73,10 @@ describe('unstable_nativeProps', () => { expect(TabsHost.mock.calls[0][0].tabBarHidden).toBe(false); }); - it('does not let raw props override navState or onTabSelected', () => { + it('does not let raw props override navStateRequest or onTabSelected', () => { const userOnTabSelected = jest.fn(); const rawProps = { - navState: { selectedScreenKey: 'foo', provenance: 999 }, + navStateRequest: { selectedScreenKey: 'foo', baseProvenance: 999 }, onTabSelected: userOnTabSelected, } as unknown as NativeTabsProps['unstable_nativeProps']; renderRouter({ @@ -90,9 +90,9 @@ describe('unstable_nativeProps', () => { expect(screen.getByTestId('index')).toBeVisible(); expect(TabsHost).toHaveBeenCalledTimes(1); - expect(TabsHost.mock.calls[0][0].navState).toEqual({ + expect(TabsHost.mock.calls[0][0].navStateRequest).toEqual({ selectedScreenKey: expect.not.stringMatching('foo'), - provenance: 0, + baseProvenance: 0, }); expect(TabsHost.mock.calls[0][0].onTabSelected).not.toBe(userOnTabSelected); expect(TabsHost.mock.calls[0][0].onTabSelected).toBeInstanceOf(Function); diff --git a/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.ios.tsx b/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.ios.tsx index e8669aa3708141..4b59a59310e64c 100644 --- a/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.ios.tsx +++ b/packages/expo-router/src/native-tabs/__tests__/NativeTabsView.test.ios.tsx @@ -147,12 +147,13 @@ describe('unstable_nativeProps', () => { expect(TabsHost.mock.calls[0][0].tabBarHidden).toBe(false); }); - it('does not let raw props override navState or onTabSelected', () => { + it('does not let raw props override navStateRequest or onTabSelected', () => { const userOnTabSelected = jest.fn(); - // Cast to bypass the type — navState/onTabSelected are intentionally excluded - // from NativeTabsHostNativeProps, but a user could still pass them at runtime. + // Cast to bypass the type — navStateRequest/onTabSelected are intentionally + // excluded from NativeTabsHostNativeProps, but a user could still pass them + // at runtime. const rawProps = { - navState: { selectedScreenKey: 'foo', provenance: 999 }, + navStateRequest: { selectedScreenKey: 'foo', baseProvenance: 999 }, onTabSelected: userOnTabSelected, } as unknown as NativeTabsProps['unstable_nativeProps']; renderRouter({ @@ -166,10 +167,10 @@ describe('unstable_nativeProps', () => { expect(screen.getByTestId('index')).toBeVisible(); expect(TabsHost).toHaveBeenCalledTimes(1); - // navState should be the router-managed one (initial provenance is 0, screenKey is the route key, not "foo") - expect(TabsHost.mock.calls[0][0].navState).toEqual({ + // navStateRequest should be the router-managed one (initial baseProvenance is 0, screenKey is the route key, not "foo") + expect(TabsHost.mock.calls[0][0].navStateRequest).toEqual({ selectedScreenKey: expect.not.stringMatching('foo'), - provenance: 0, + baseProvenance: 0, }); // onTabSelected should be the router-managed handler, not the user's spy expect(TabsHost.mock.calls[0][0].onTabSelected).not.toBe(userOnTabSelected); diff --git a/packages/expo-router/src/native-tabs/__tests__/events.test.ios.tsx b/packages/expo-router/src/native-tabs/__tests__/events.test.ios.tsx index 1a5f8bd338c16d..49a7592945e73f 100644 --- a/packages/expo-router/src/native-tabs/__tests__/events.test.ios.tsx +++ b/packages/expo-router/src/native-tabs/__tests__/events.test.ios.tsx @@ -110,7 +110,7 @@ it('emits tabPress event onNativeFocusChange', () => { provenance: 0, isRepeated: false, hasTriggeredSpecialEffect: false, - isNativeAction: true, + actionOrigin: 'user', }, } as NativeSyntheticEvent); @@ -127,7 +127,7 @@ it('emits tabPress event onNativeFocusChange', () => { provenance: 0, isRepeated: false, hasTriggeredSpecialEffect: false, - isNativeAction: true, + actionOrigin: 'user', }, } as NativeSyntheticEvent); @@ -144,7 +144,7 @@ it('emits tabPress event onNativeFocusChange', () => { provenance: 0, isRepeated: false, hasTriggeredSpecialEffect: false, - isNativeAction: true, + actionOrigin: 'user', }, } as NativeSyntheticEvent); @@ -218,7 +218,7 @@ it('does not pop stack on repeated tab press', async () => { provenance: 0, isRepeated: false, hasTriggeredSpecialEffect: false, - isNativeAction: true, + actionOrigin: 'user', }, } as NativeSyntheticEvent); @@ -235,7 +235,7 @@ it('does not pop stack on repeated tab press', async () => { provenance: 0, isRepeated: false, hasTriggeredSpecialEffect: false, - isNativeAction: true, + actionOrigin: 'user', }, } as NativeSyntheticEvent); @@ -260,7 +260,7 @@ it('does not pop stack on repeated tab press', async () => { provenance: 0, isRepeated: true, hasTriggeredSpecialEffect: true, - isNativeAction: true, + actionOrigin: 'user', }, } as NativeSyntheticEvent); diff --git a/packages/expo-router/src/native-tabs/__tests__/listeners.test.ios.tsx b/packages/expo-router/src/native-tabs/__tests__/listeners.test.ios.tsx index afb86dec588d0e..a2e7a77ac021c2 100644 --- a/packages/expo-router/src/native-tabs/__tests__/listeners.test.ios.tsx +++ b/packages/expo-router/src/native-tabs/__tests__/listeners.test.ios.tsx @@ -62,7 +62,7 @@ function tabSelectedEvent(selectedScreenKey: string): NativeSyntheticEvent; } diff --git a/packages/expo-router/src/native-tabs/__tests__/navigation.test.ios.tsx b/packages/expo-router/src/native-tabs/__tests__/navigation.test.ios.tsx index ce4bf8974b1c26..9ddafb54e5a985 100644 --- a/packages/expo-router/src/native-tabs/__tests__/navigation.test.ios.tsx +++ b/packages/expo-router/src/native-tabs/__tests__/navigation.test.ios.tsx @@ -41,7 +41,7 @@ describe('Native Bottom Tabs Navigation', () => { function lastHostSelectedKey() { const calls = TabsHost.mock.calls; - return calls[calls.length - 1][0].navState.selectedScreenKey; + return calls[calls.length - 1][0].navStateRequest.selectedScreenKey; } function expectIndexTabFocused(renderNumber = 1) { diff --git a/packages/expo-router/src/native-tabs/__tests__/render.test.ios.tsx b/packages/expo-router/src/native-tabs/__tests__/render.test.ios.tsx index 858d4d6d1a711f..0cbfc88b67684d 100644 --- a/packages/expo-router/src/native-tabs/__tests__/render.test.ios.tsx +++ b/packages/expo-router/src/native-tabs/__tests__/render.test.ios.tsx @@ -173,7 +173,7 @@ describe('First focused tab', () => { expect(TabsScreen.mock.calls[0][0].screenKey).toMatch(/^index-[-\w]+/); expect(TabsScreen.mock.calls[1][0].screenKey).toMatch(/^second-[-\w]+/); expect(TabsHost).toHaveBeenCalledTimes(1); - expect(TabsHost.mock.calls[0][0].navState.selectedScreenKey).toMatch(/^index-[-\w]+/); + expect(TabsHost.mock.calls[0][0].navStateRequest.selectedScreenKey).toMatch(/^index-[-\w]+/); }); it('index tab is focused when it is second tab', () => { @@ -194,7 +194,7 @@ describe('First focused tab', () => { expect(TabsScreen.mock.calls[0][0].screenKey).toMatch(/^second-[-\w]+/); expect(TabsScreen.mock.calls[1][0].screenKey).toMatch(/^index-[-\w]+/); expect(TabsHost).toHaveBeenCalledTimes(1); - expect(TabsHost.mock.calls[0][0].navState.selectedScreenKey).toMatch(/^index-[-\w]+/); + expect(TabsHost.mock.calls[0][0].navStateRequest.selectedScreenKey).toMatch(/^index-[-\w]+/); }); describe('First tab is used, when index is hidden', () => { @@ -279,7 +279,7 @@ describe('First focused tab', () => { expect(TabsScreen.mock.calls[0][0].screenKey).toMatch(/^first-[-\w]+/); expect(TabsScreen.mock.calls[1][0].screenKey).toMatch(/^second-[-\w]+/); expect(TabsHost).toHaveBeenCalledTimes(1); - expect(TabsHost.mock.calls[0][0].navState.selectedScreenKey).toMatch(/^second-[-\w]+/); + expect(TabsHost.mock.calls[0][0].navStateRequest.selectedScreenKey).toMatch(/^second-[-\w]+/); }); it('Correct tab is shown, when index does not exist, redirect is set in layout and +not-found is specified', () => { @@ -308,7 +308,7 @@ describe('First focused tab', () => { expect(TabsScreen.mock.calls[0][0].screenKey).toMatch(/^first-[-\w]+/); expect(TabsScreen.mock.calls[1][0].screenKey).toMatch(/^second-[-\w]+/); expect(TabsHost).toHaveBeenCalledTimes(1); - expect(TabsHost.mock.calls[0][0].navState.selectedScreenKey).toMatch(/^second-[-\w]+/); + expect(TabsHost.mock.calls[0][0].navStateRequest.selectedScreenKey).toMatch(/^second-[-\w]+/); }); it('404 is shown, when index does not exist, redirect is set in layout and no +not-found is specified', () => { @@ -367,7 +367,7 @@ describe('First focused tab', () => { expect(TabsScreen.mock.calls[0][0].screenKey).toMatch(/^index-[-\w]+/); expect(TabsScreen.mock.calls[1][0].screenKey).toMatch(/^second-[-\w]+/); expect(TabsHost).toHaveBeenCalledTimes(1); - expect(TabsHost.mock.calls[0][0].navState.selectedScreenKey).toMatch(/^index-[-\w]+/); + expect(TabsHost.mock.calls[0][0].navStateRequest.selectedScreenKey).toMatch(/^index-[-\w]+/); TabsScreen.mockClear(); TabsHost.mockClear(); @@ -379,8 +379,8 @@ describe('First focused tab', () => { expect(TabsScreen.mock.calls[2][0].screenKey).toMatch(/^index-[-\w]+/); expect(TabsScreen.mock.calls[3][0].screenKey).toMatch(/^second-[-\w]+/); expect(TabsHost).toHaveBeenCalledTimes(2); - expect(TabsHost.mock.calls[0][0].navState.selectedScreenKey).toMatch(/^index-[-\w]+/); - expect(TabsHost.mock.calls[1][0].navState.selectedScreenKey).toMatch(/^second-[-\w]+/); + expect(TabsHost.mock.calls[0][0].navStateRequest.selectedScreenKey).toMatch(/^index-[-\w]+/); + expect(TabsHost.mock.calls[1][0].navStateRequest.selectedScreenKey).toMatch(/^second-[-\w]+/); TabsScreen.mockClear(); TabsHost.mockClear(); @@ -394,8 +394,8 @@ describe('First focused tab', () => { expect(TabsScreen.mock.calls[0][0].screenKey).toMatch(/^index-[-\w]+/); expect(TabsScreen.mock.calls[1][0].screenKey).toMatch(/^index-[-\w]+/); expect(TabsHost).toHaveBeenCalledTimes(2); - expect(TabsHost.mock.calls[0][0].navState.selectedScreenKey).toMatch(/^index-[-\w]+/); - expect(TabsHost.mock.calls[1][0].navState.selectedScreenKey).toMatch(/^index-[-\w]+/); + expect(TabsHost.mock.calls[0][0].navStateRequest.selectedScreenKey).toMatch(/^index-[-\w]+/); + expect(TabsHost.mock.calls[1][0].navStateRequest.selectedScreenKey).toMatch(/^index-[-\w]+/); }); }); diff --git a/packages/expo-router/src/native-tabs/types.ts b/packages/expo-router/src/native-tabs/types.ts index f6eb345d2e3e2d..07f5b4e421691f 100644 --- a/packages/expo-router/src/native-tabs/types.ts +++ b/packages/expo-router/src/native-tabs/types.ts @@ -33,7 +33,7 @@ export type NativeScreenProps = Partial>; * Props passed to the underlying tab host implementation in `react-native-screens`. */ export type NativeTabsHostNativeProps = Partial< - Omit + Omit >; export interface NativeTabOptions extends DefaultRouterOptions { @@ -344,10 +344,10 @@ export interface OnTabChangeEventPayload { /** * The provenance value reported by the native side for this selection. * - * The navigator echoes this back via `navState.provenance` on subsequent - * JS-driven updates so the native side can distinguish stale updates from - * fresh ones. See `TabsHostNavState` in `react-native-screens` for the full - * contract. + * The navigator echoes this back via `navStateRequest.baseProvenance` on + * subsequent JS-driven updates so the native side can distinguish stale + * updates from fresh ones. See `TabsHostNavStateRequest` in + * `react-native-screens` for the full contract. */ provenance: number; // TODO(@ubax): consider renaming this field diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json index 12091e15d5e2ff..50c67cd1a29c79 100644 --- a/packages/expo/bundledNativeModules.json +++ b/packages/expo/bundledNativeModules.json @@ -107,7 +107,7 @@ "react-native-pager-view": "8.0.1", "react-native-worklets": "0.8.3", "react-native-reanimated": "4.3.0", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-safe-area-context": "~5.7.0", "react-native-svg": "15.15.4", "react-native-view-shot": "4.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4141f5a3f8dc6..ab6fcacf52c733 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,13 +117,13 @@ importers: version: 2.5.7(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(633131474e82e5574bc67e118af8f548) + version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/native': specifier: ^7.1.33 version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native-stack': specifier: ^7.14.5 - version: 7.14.5(633131474e82e5574bc67e118af8f548) + version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) '@shopify/flash-list': specifier: 2.0.2 version: 2.0.2(@babel/runtime@7.29.2)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -230,8 +230,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-svg: specifier: 15.15.4 version: 15.15.4(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -320,7 +320,7 @@ importers: version: 15.1.1(expo-font@packages+expo-font)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(633131474e82e5574bc67e118af8f548) + version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/elements': specifier: ^2.9.10 version: 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -391,8 +391,8 @@ importers: specifier: ~5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: ~4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-web: specifier: ~0.21.0 version: 0.21.2(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -660,8 +660,8 @@ importers: specifier: 5.7.0 version: 5.7.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-svg: specifier: 15.15.4 version: 15.15.4(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -808,10 +808,10 @@ importers: version: 2.5.7(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(633131474e82e5574bc67e118af8f548) + version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/drawer': specifier: ^7.9.4 - version: 7.9.4(06cd6af1ec31f8f1b39f9b8461a7aa05) + version: 7.9.4(c0dc5da1e8398d864ae0e610dbbe7d7a) '@react-navigation/elements': specifier: ^2.9.10 version: 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -820,10 +820,10 @@ importers: version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native-stack': specifier: ^7.14.5 - version: 7.14.5(633131474e82e5574bc67e118af8f548) + version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/stack': specifier: ^7.8.5 - version: 7.8.5(68076f2f113de8ba6ccf68ffa0bba08d) + version: 7.8.5(5f603fd5b7fdee282854d7921c603411) '@shopify/flash-list': specifier: 2.0.2 version: 2.0.2(@babel/runtime@7.29.2)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1119,8 +1119,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-svg: specifier: 15.15.4 version: 15.15.4(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1242,7 +1242,7 @@ importers: version: link:../../packages/expo-ui '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(633131474e82e5574bc67e118af8f548) + version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/native': specifier: ^7.1.33 version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1301,8 +1301,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) test-suite: specifier: workspace:* version: link:../test-suite @@ -1327,13 +1327,13 @@ importers: version: 15.1.1(expo-font@packages+expo-font)(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/bottom-tabs': specifier: ^7.15.5 - version: 7.15.5(633131474e82e5574bc67e118af8f548) + version: 7.15.5(e6b77e6971707d55b305242378ff9e6b) '@react-navigation/native': specifier: ^7.1.33 version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native-stack': specifier: ^7.14.5 - version: 7.14.5(633131474e82e5574bc67e118af8f548) + version: 7.14.5(e6b77e6971707d55b305242378ff9e6b) expo: specifier: workspace:* version: link:../../packages/expo @@ -1404,8 +1404,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) devDependencies: '@expo/config': specifier: workspace:* @@ -1474,8 +1474,8 @@ importers: specifier: 5.6.2 version: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: - specifier: 4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-web: specifier: ^0.21.0 version: 0.21.2(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1570,7 +1570,7 @@ importers: version: 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/stack': specifier: ^7.8.5 - version: 7.8.5(68076f2f113de8ba6ccf68ffa0bba08d) + version: 7.8.5(5f603fd5b7fdee282854d7921c603411) async-retry: specifier: ^1.1.4 version: 1.3.3 @@ -5144,8 +5144,8 @@ importers: specifier: ^4.2.2 version: 4.2.2(12841549544ec276029c710fd46ea421) react-native-screens: - specifier: 4.25.0-beta.1 - version: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: 4.25.0-beta.3 + version: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) server-only: specifier: ^0.0.1 version: 0.0.1 @@ -14172,8 +14172,8 @@ packages: react: 19.2.3 react-native: 0.85.3 - react-native-screens@4.25.0-beta.1: - resolution: {integrity: sha512-UBJmva20ew9Z+BC/uZe5eAu8ccmhiRBH/YscWXR1DNSlRS3vxvt3n3UH3zn3t/jL0MW6gVvrIwIxVmjaA+C/lg==} + react-native-screens@4.25.0-beta.3: + resolution: {integrity: sha512-LU5e8hlXvzQI3Ps8OGsG9pm/+FOY3XnNB2IKAsEkBgpJOyiZdVwkCogF/kM7XSzW6rG21Hib9CLMri6J4SpXCA==} peerDependencies: react: 19.2.3 react-native: 0.85.3 @@ -18837,9 +18837,7 @@ snapshots: metro-runtime: 0.84.4 transitivePeerDependencies: - '@babel/core' - - bufferutil - supports-color - - utf-8-validate '@react-native/normalize-colors@0.74.89': {} @@ -18867,7 +18865,7 @@ snapshots: transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/bottom-tabs@7.15.5(633131474e82e5574bc67e118af8f548)': + '@react-navigation/bottom-tabs@7.15.5(e6b77e6971707d55b305242378ff9e6b)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18875,7 +18873,7 @@ snapshots: react: 19.2.3 react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -18892,7 +18890,7 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.3) use-sync-external-store: 1.6.0(react@19.2.3) - '@react-navigation/drawer@7.9.4(06cd6af1ec31f8f1b39f9b8461a7aa05)': + '@react-navigation/drawer@7.9.4(c0dc5da1e8398d864ae0e610dbbe7d7a)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18903,7 +18901,7 @@ snapshots: react-native-gesture-handler: 2.30.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-reanimated: 4.3.0(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) use-latest-callback: 0.2.6(react@19.2.3) transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -18920,7 +18918,7 @@ snapshots: optionalDependencies: '@react-native-masked-view/masked-view': 0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - '@react-navigation/native-stack@7.14.5(633131474e82e5574bc67e118af8f548)': + '@react-navigation/native-stack@7.14.5(e6b77e6971707d55b305242378ff9e6b)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18928,7 +18926,7 @@ snapshots: react: 19.2.3 react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) sf-symbols-typescript: 2.2.0 warn-once: 0.1.1 transitivePeerDependencies: @@ -18948,7 +18946,7 @@ snapshots: dependencies: nanoid: 3.3.11 - '@react-navigation/stack@7.8.5(68076f2f113de8ba6ccf68ffa0bba08d)': + '@react-navigation/stack@7.8.5(5f603fd5b7fdee282854d7921c603411)': dependencies: '@react-navigation/elements': 2.9.10(@react-native-masked-view/masked-view@0.3.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(@react-navigation/native@7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native-safe-area-context@5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) '@react-navigation/native': 7.1.33(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -18957,7 +18955,7 @@ snapshots: react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: 2.30.0(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) - react-native-screens: 4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-screens: 4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) use-latest-callback: 0.2.6(react@19.2.3) transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -25335,7 +25333,7 @@ snapshots: react-native: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) warn-once: 0.1.1 - react-native-screens@4.25.0-beta.1(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3): + react-native-screens@4.25.0-beta.3(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3): dependencies: react: 19.2.3 react-freeze: 1.0.4(react@19.2.3) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bd8b68b1ffef79..bf4a82a95616e0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -46,3 +46,4 @@ minimumReleaseAgeExclude: - 'react-native' - multitars - 'react-native-worklets' + - 'react-native-screens' diff --git a/templates/expo-template-default/package.json b/templates/expo-template-default/package.json index 53b81916a6c325..61542483b76bdd 100644 --- a/templates/expo-template-default/package.json +++ b/templates/expo-template-default/package.json @@ -33,7 +33,7 @@ "react-native-worklets": "0.8.3", "react-native-reanimated": "4.3.0", "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-web": "~0.21.0" }, "devDependencies": { diff --git a/templates/expo-template-tabs/package.json b/templates/expo-template-tabs/package.json index 2299f855450938..a26973b199436f 100644 --- a/templates/expo-template-tabs/package.json +++ b/templates/expo-template-tabs/package.json @@ -26,7 +26,7 @@ "react-native-worklets": "0.8.3", "react-native-reanimated": "4.3.0", "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "4.25.0-beta.1", + "react-native-screens": "4.25.0-beta.3", "react-native-web": "~0.21.0" }, "devDependencies": { From 5154f23dad1c9a2ab58d5a697940519e4a334b29 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Thu, 7 May 2026 19:02:30 +0100 Subject: [PATCH 09/18] fix(metro-config): Fall back to our Babel `getCacheKey` function for custom Babel transformers (#45495) # Why The `getCacheKey` function on Babel transformers is new, and is probably missing from a lot of wrappers that use our transformer. We should fall back to ours when it's missing, since the alternative is that no cache key gets generated for a user's Babel config. # How - Check if we have a Babel config and fall back to our Babel transformer's `getCacheKey` if the transform is missing one > [!NOTE] > We should aim to also move reanimated/worklets version to `babel-preset-expo`'s `getCacheKey`. It's currently lacking one and we should somehow embed it, and check what the right approach is. Getting these versions out of the Metro config (which is then sourced into its `getCacheKey` seems better # Test Plan - Manually verified with custom transformer # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/@expo/metro-config/CHANGELOG.md | 1 + .../build/transform-worker/metro-transform-worker.js | 8 +++++++- .../transform-worker/metro-transform-worker.js.map | 2 +- .../src/transform-worker/metro-transform-worker.ts | 10 +++++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/@expo/metro-config/CHANGELOG.md b/packages/@expo/metro-config/CHANGELOG.md index 793461c7b8cb57..2bd4d9e4e41100 100644 --- a/packages/@expo/metro-config/CHANGELOG.md +++ b/packages/@expo/metro-config/CHANGELOG.md @@ -11,6 +11,7 @@ ### 💡 Others - Drop obsolete `EXPO_USE_EXOTIC` flag warning ([#45494](https://github.com/expo/expo/pull/45494) by [@kitten](https://github.com/kitten)) +- Fall back to our own Babel cache key with custom Babel transformer ([#45495](https://github.com/expo/expo/pull/45495) by [@kitten](https://github.com/kitten)) ## 56.0.3 — 2026-05-06 diff --git a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js index ca262b2bbc8d00..3ff83c984d035e 100644 --- a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js +++ b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js @@ -628,7 +628,13 @@ function getCacheKey(config, opts) { require.resolve('@expo/metro/metro/ModuleGraph/worker/JsFileWrapping'), ...metroTransformPlugins.getTransformPluginCacheKeyFiles(), ]); - const babelTransformer = require(babelTransformerPath); + let babelTransformer = require(babelTransformerPath); + // NOTE(@kitten): Many custom Babel transformers won't have `getCacheKey` yet and won't + // pass ours through. We should still try to derive a cache key though, since the default + // looks at a user's Babel config, if they have one + if (config.extendsBabelConfigPath && !babelTransformer.getCacheKey) { + babelTransformer = require('../babel-transformer'); + } const babelTransformerCacheKey = babelTransformer.getCacheKey ? babelTransformer.getCacheKey({ projectRoot: opts?.projectRoot, diff --git a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map index a29cbaab1efe42..35b6601c3edcff 100644 --- a/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map +++ b/packages/@expo/metro-config/build/transform-worker/metro-transform-worker.js.map @@ -1 +1 @@ -{"version":3,"file":"metro-transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/metro-transform-worker.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"metro-transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/metro-transform-worker.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts b/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts index 117db919606f12..06af106b1f7e5a 100644 --- a/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts +++ b/packages/@expo/metro-config/src/transform-worker/metro-transform-worker.ts @@ -846,7 +846,15 @@ export function getCacheKey( ...metroTransformPlugins.getTransformPluginCacheKeyFiles(), ]); - const babelTransformer: BabelTransformer = require(babelTransformerPath); + let babelTransformer: BabelTransformer = require(babelTransformerPath); + + // NOTE(@kitten): Many custom Babel transformers won't have `getCacheKey` yet and won't + // pass ours through. We should still try to derive a cache key though, since the default + // looks at a user's Babel config, if they have one + if (config.extendsBabelConfigPath && !babelTransformer.getCacheKey) { + babelTransformer = require('../babel-transformer'); + } + const babelTransformerCacheKey = babelTransformer.getCacheKey ? babelTransformer.getCacheKey({ projectRoot: opts?.projectRoot, From 89ddd0ba3c476266e18f6428ae61c470fd3a1750 Mon Sep 17 00:00:00 2001 From: HubertBer <115428831+HubertBer@users.noreply.github.com> Date: Thu, 7 May 2026 20:04:10 +0200 Subject: [PATCH 10/18] `expo-type-information` - reading types of Swift expo modules, generating typescript types. (#44442) --- .../build/getStructure.d.ts | 3 - .../build/getStructure.d.ts.map | 1 - .../build/getStructure.js | 244 --- .../build/getStructure.js.map | 1 - .../expo-modules-test-core/build/index.js | 34 +- .../expo-modules-test-core/build/index.js.map | 2 +- .../expo-modules-test-core/build/mockgen.d.ts | 4 - .../build/mockgen.d.ts.map | 1 - .../expo-modules-test-core/build/mockgen.js | 391 ---- .../build/mockgen.js.map | 1 - .../build/types.d.ts.map | 1 - .../expo-modules-test-core/build/types.js.map | 1 - packages/expo-modules-test-core/package.json | 8 +- .../src/getStructure.ts | 299 ---- packages/expo-modules-test-core/src/index.ts | 34 +- .../expo-modules-test-core/src/mockgen.ts | 525 ------ packages/expo-type-information/README.md | 1 + packages/expo-type-information/bin/cli.js | 2 + packages/expo-type-information/build/cli.d.ts | 1 + packages/expo-type-information/build/cli.js | 35 + .../expo-type-information/build/cli.js.map | 1 + .../build/commands/commandUtils.d.ts | 46 + .../build/commands/commandUtils.js | 274 +++ .../build/commands/commandUtils.js.map | 1 + .../generateJSXIntrinsicsCommand.d.ts | 2 + .../commands/generateJSXIntrinsicsCommand.js | 28 + .../generateJSXIntrinsicsCommand.js.map | 1 + .../commands/generateMocksForFileCommand.d.ts | 2 + .../commands/generateMocksForFileCommand.js | 22 + .../generateMocksForFileCommand.js.map | 1 + .../commands/generateModuleTypesCommand.d.ts | 2 + .../commands/generateModuleTypesCommand.js | 32 + .../generateModuleTypesCommand.js.map | 1 + .../commands/generateViewTypesCommand.d.ts | 2 + .../commands/generateViewTypesCommand.js | 28 + .../commands/generateViewTypesCommand.js.map | 1 + .../inlineModulesInterfaceCommand.d.ts | 2 + .../commands/inlineModulesInterfaceCommand.js | 129 ++ .../inlineModulesInterfaceCommand.js.map | 1 + .../commands/moduleInterfaceCommand.d.ts | 2 + .../build/commands/moduleInterfaceCommand.js | 46 + .../commands/moduleInterfaceCommand.js.map | 1 + .../commands/shortModuleInterfaceCommand.d.ts | 2 + .../commands/shortModuleInterfaceCommand.js | 17 + .../shortModuleInterfaceCommand.js.map | 1 + .../commands/typeInformationCommand.d.ts | 2 + .../build/commands/typeInformationCommand.js | 24 + .../commands/typeInformationCommand.js.map | 1 + .../expo-type-information/build/index.d.ts | 3 + packages/expo-type-information/build/index.js | 28 + .../expo-type-information/build/index.js.map | 1 + .../expo-type-information/build/mockgen.d.ts | 4 + .../expo-type-information/build/mockgen.js | 204 +++ .../build/mockgen.js.map | 1 + .../swift/sourcekittenTypeInformation.d.ts | 6 + .../swift/sourcekittenTypeInformation.js | 875 +++++++++ .../swift/sourcekittenTypeInformation.js.map | 1 + .../build/typeInformation.d.ts | 209 +++ .../build/typeInformation.js | 157 ++ .../build/typeInformation.js.map | 1 + .../build/types.d.ts | 16 +- .../build/types.js | 0 .../expo-type-information/build/types.js.map | 1 + .../build/typescriptGeneration.d.ts | 61 + .../build/typescriptGeneration.js | 696 ++++++++ .../build/typescriptGeneration.js.map | 1 + .../expo-type-information/build/utils.d.ts | 6 + packages/expo-type-information/build/utils.js | 44 + .../expo-type-information/build/utils.js.map | 1 + packages/expo-type-information/jest.config.js | 6 + packages/expo-type-information/package.json | 47 + packages/expo-type-information/src/cli.ts | 38 + .../src/commands/commandUtils.ts | 352 ++++ .../commands/generateJSXIntrinsicsCommand.ts | 38 + .../commands/generateMocksForFileCommand.ts | 30 + .../commands/generateModuleTypesCommand.ts | 39 + .../src/commands/generateViewTypesCommand.ts | 39 + .../commands/inlineModulesInterfaceCommand.ts | 175 ++ .../src/commands/moduleInterfaceCommand.ts | 56 + .../commands/shortModuleInterfaceCommand.ts | 26 + .../src/commands/typeInformationCommand.ts | 35 + packages/expo-type-information/src/index.ts | 9 + packages/expo-type-information/src/mockgen.ts | 338 ++++ .../src/swift/sourcekittenTypeInformation.ts | 1173 ++++++++++++ .../src/typeInformation.ts | 326 ++++ .../src/types.ts | 15 +- .../src/typescriptGeneration.ts | 1179 ++++++++++++ packages/expo-type-information/src/utils.ts | 44 + .../tests/TestModule.swift | 175 ++ .../typeInformation.test.ts.snap | 1578 +++++++++++++++++ .../tests/typeInformation.test.ts | 134 ++ packages/expo-type-information/tsconfig.json | 11 + pnpm-lock.yaml | 60 + 93 files changed, 8981 insertions(+), 1519 deletions(-) delete mode 100644 packages/expo-modules-test-core/build/getStructure.d.ts delete mode 100644 packages/expo-modules-test-core/build/getStructure.d.ts.map delete mode 100644 packages/expo-modules-test-core/build/getStructure.js delete mode 100644 packages/expo-modules-test-core/build/getStructure.js.map delete mode 100644 packages/expo-modules-test-core/build/mockgen.d.ts delete mode 100644 packages/expo-modules-test-core/build/mockgen.d.ts.map delete mode 100644 packages/expo-modules-test-core/build/mockgen.js delete mode 100644 packages/expo-modules-test-core/build/mockgen.js.map delete mode 100644 packages/expo-modules-test-core/build/types.d.ts.map delete mode 100644 packages/expo-modules-test-core/build/types.js.map delete mode 100644 packages/expo-modules-test-core/src/getStructure.ts delete mode 100644 packages/expo-modules-test-core/src/mockgen.ts create mode 100644 packages/expo-type-information/README.md create mode 100755 packages/expo-type-information/bin/cli.js create mode 100644 packages/expo-type-information/build/cli.d.ts create mode 100644 packages/expo-type-information/build/cli.js create mode 100644 packages/expo-type-information/build/cli.js.map create mode 100644 packages/expo-type-information/build/commands/commandUtils.d.ts create mode 100644 packages/expo-type-information/build/commands/commandUtils.js create mode 100644 packages/expo-type-information/build/commands/commandUtils.js.map create mode 100644 packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js create mode 100644 packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js.map create mode 100644 packages/expo-type-information/build/commands/generateMocksForFileCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/generateMocksForFileCommand.js create mode 100644 packages/expo-type-information/build/commands/generateMocksForFileCommand.js.map create mode 100644 packages/expo-type-information/build/commands/generateModuleTypesCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/generateModuleTypesCommand.js create mode 100644 packages/expo-type-information/build/commands/generateModuleTypesCommand.js.map create mode 100644 packages/expo-type-information/build/commands/generateViewTypesCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/generateViewTypesCommand.js create mode 100644 packages/expo-type-information/build/commands/generateViewTypesCommand.js.map create mode 100644 packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js create mode 100644 packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js.map create mode 100644 packages/expo-type-information/build/commands/moduleInterfaceCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/moduleInterfaceCommand.js create mode 100644 packages/expo-type-information/build/commands/moduleInterfaceCommand.js.map create mode 100644 packages/expo-type-information/build/commands/shortModuleInterfaceCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js create mode 100644 packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js.map create mode 100644 packages/expo-type-information/build/commands/typeInformationCommand.d.ts create mode 100644 packages/expo-type-information/build/commands/typeInformationCommand.js create mode 100644 packages/expo-type-information/build/commands/typeInformationCommand.js.map create mode 100644 packages/expo-type-information/build/index.d.ts create mode 100644 packages/expo-type-information/build/index.js create mode 100644 packages/expo-type-information/build/index.js.map create mode 100644 packages/expo-type-information/build/mockgen.d.ts create mode 100644 packages/expo-type-information/build/mockgen.js create mode 100644 packages/expo-type-information/build/mockgen.js.map create mode 100644 packages/expo-type-information/build/swift/sourcekittenTypeInformation.d.ts create mode 100644 packages/expo-type-information/build/swift/sourcekittenTypeInformation.js create mode 100644 packages/expo-type-information/build/swift/sourcekittenTypeInformation.js.map create mode 100644 packages/expo-type-information/build/typeInformation.d.ts create mode 100644 packages/expo-type-information/build/typeInformation.js create mode 100644 packages/expo-type-information/build/typeInformation.js.map rename packages/{expo-modules-test-core => expo-type-information}/build/types.d.ts (84%) rename packages/{expo-modules-test-core => expo-type-information}/build/types.js (100%) create mode 100644 packages/expo-type-information/build/types.js.map create mode 100644 packages/expo-type-information/build/typescriptGeneration.d.ts create mode 100644 packages/expo-type-information/build/typescriptGeneration.js create mode 100644 packages/expo-type-information/build/typescriptGeneration.js.map create mode 100644 packages/expo-type-information/build/utils.d.ts create mode 100644 packages/expo-type-information/build/utils.js create mode 100644 packages/expo-type-information/build/utils.js.map create mode 100644 packages/expo-type-information/jest.config.js create mode 100644 packages/expo-type-information/package.json create mode 100644 packages/expo-type-information/src/cli.ts create mode 100644 packages/expo-type-information/src/commands/commandUtils.ts create mode 100644 packages/expo-type-information/src/commands/generateJSXIntrinsicsCommand.ts create mode 100644 packages/expo-type-information/src/commands/generateMocksForFileCommand.ts create mode 100644 packages/expo-type-information/src/commands/generateModuleTypesCommand.ts create mode 100644 packages/expo-type-information/src/commands/generateViewTypesCommand.ts create mode 100644 packages/expo-type-information/src/commands/inlineModulesInterfaceCommand.ts create mode 100644 packages/expo-type-information/src/commands/moduleInterfaceCommand.ts create mode 100644 packages/expo-type-information/src/commands/shortModuleInterfaceCommand.ts create mode 100644 packages/expo-type-information/src/commands/typeInformationCommand.ts create mode 100644 packages/expo-type-information/src/index.ts create mode 100644 packages/expo-type-information/src/mockgen.ts create mode 100644 packages/expo-type-information/src/swift/sourcekittenTypeInformation.ts create mode 100644 packages/expo-type-information/src/typeInformation.ts rename packages/{expo-modules-test-core => expo-type-information}/src/types.ts (86%) create mode 100644 packages/expo-type-information/src/typescriptGeneration.ts create mode 100644 packages/expo-type-information/src/utils.ts create mode 100644 packages/expo-type-information/tests/TestModule.swift create mode 100644 packages/expo-type-information/tests/__snapshots__/typeInformation.test.ts.snap create mode 100644 packages/expo-type-information/tests/typeInformation.test.ts create mode 100644 packages/expo-type-information/tsconfig.json diff --git a/packages/expo-modules-test-core/build/getStructure.d.ts b/packages/expo-modules-test-core/build/getStructure.d.ts deleted file mode 100644 index 35108abab295c5..00000000000000 --- a/packages/expo-modules-test-core/build/getStructure.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { OutputModuleDefinition } from './types'; -export declare function getAllExpoModulesInWorkingDirectory(): OutputModuleDefinition[]; -//# sourceMappingURL=getStructure.d.ts.map \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/getStructure.d.ts.map b/packages/expo-modules-test-core/build/getStructure.d.ts.map deleted file mode 100644 index 60a23841f98f09..00000000000000 --- a/packages/expo-modules-test-core/build/getStructure.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"getStructure.d.ts","sourceRoot":"","sources":["../src/getStructure.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAKV,sBAAsB,EAEvB,MAAM,SAAS,CAAC;AAyRjB,wBAAgB,mCAAmC,6BAGlD"} \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/getStructure.js b/packages/expo-modules-test-core/build/getStructure.js deleted file mode 100644 index 4acdfc0b639e96..00000000000000 --- a/packages/expo-modules-test-core/build/getStructure.js +++ /dev/null @@ -1,244 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getAllExpoModulesInWorkingDirectory = getAllExpoModulesInWorkingDirectory; -// convert requires above to imports -const child_process_1 = require("child_process"); -const fs_1 = __importDefault(require("fs")); -const glob_1 = require("glob"); -const xml_js_1 = __importDefault(require("xml-js")); -const yaml_1 = __importDefault(require("yaml")); -const rootDir = process.cwd(); -const pattern = `${rootDir}/**/*.swift`; -function getStructureFromFile(file) { - const command = 'sourcekitten structure --file ' + file.path; - try { - const output = (0, child_process_1.execSync)(command); - return JSON.parse(output.toString()); - } - catch (error) { - console.error('An error occurred while executing the command:', error); - } -} -// find an object with "key.typename" : "ModuleDefinition" somewhere in the structure and return it -function findModuleDefinitionInStructure(structure) { - if (!structure) { - return null; - } - if (structure?.['key.typename'] === 'ModuleDefinition') { - const root = structure?.['key.substructure']; - if (!root) { - console.warn('Found ModuleDefinition but it is malformed'); - } - return root; - } - const substructure = structure['key.substructure']; - if (Array.isArray(substructure) && substructure.length > 0) { - for (const child of substructure) { - let result = null; - result = findModuleDefinitionInStructure(child); - if (result) { - return result; - } - } - } - return null; -} -// Read string straight from file – needed since we can't get cursorinfo for modulename -function getIdentifierFromOffsetObject(offsetObject, file) { - // adding 1 and removing 1 to get rid of quotes - return file.content - .substring(offsetObject['key.offset'], offsetObject['key.offset'] + offsetObject['key.length']) - .replaceAll('"', ''); -} -function maybeUnwrapXMLStructs(type) { - if (!type) { - return type; - } - if (typeof type === 'string') { - return type; - } - if (type['_text']) { - return type['_text']; - } - if (type['ref.struct']) { - return maybeUnwrapXMLStructs(type['ref.struct']); - } - return type; -} -function maybeWrapArray(itemOrItems) { - if (!itemOrItems) { - return null; - } - if (Array.isArray(itemOrItems)) { - return itemOrItems; - } - else { - return [itemOrItems]; - } -} -function parseXMLAnnotatedDeclarations(cursorInfoOutput) { - const xml = cursorInfoOutput['key.fully_annotated_decl']; - if (!xml) { - return null; - } - const parsed = xml_js_1.default.xml2js(xml, { compact: true }); - const parameters = maybeWrapArray(parsed?.['decl.function.free']?.['decl.var.parameter'])?.map((p) => ({ - name: maybeUnwrapXMLStructs(p['decl.var.parameter.argument_label']), - typename: maybeUnwrapXMLStructs(p['decl.var.parameter.type']), - })) ?? []; - const returnType = maybeUnwrapXMLStructs(parsed?.['decl.function.free']?.['decl.function.returntype']); - return { parameters, returnType }; -} -let cachedSDKPath = null; -function getSDKPath() { - if (cachedSDKPath) { - return cachedSDKPath; - } - const sdkPath = (0, child_process_1.execSync)('xcrun --sdk iphoneos --show-sdk-path').toString().trim(); - cachedSDKPath = sdkPath; - return cachedSDKPath; -} -// Read type description with sourcekitten, works only for variables -function getTypeFromOffsetObject(offsetObject, file) { - if (!offsetObject) { - return null; - } - const request = { - 'key.request': 'source.request.cursorinfo', - 'key.sourcefile': file.path, - 'key.offset': offsetObject['key.offset'], - 'key.compilerargs': [file.path, '-target', 'arm64-apple-ios', '-sdk', getSDKPath()], - }; - const yamlRequest = yaml_1.default.stringify(request, { - defaultStringType: 'QUOTE_DOUBLE', - lineWidth: 0, - defaultKeyType: 'PLAIN', - // needed since behaviour of sourcekitten is not consistent - }).replace('"source.request.cursorinfo"', 'source.request.cursorinfo'); - const command = 'sourcekitten request --yaml "' + yamlRequest.replaceAll('"', '\\"') + '"'; - try { - const output = (0, child_process_1.execSync)(command, { stdio: 'pipe' }); - return parseXMLAnnotatedDeclarations(JSON.parse(output.toString())); - } - catch (error) { - console.error('An error occurred while executing the command:', error); - } - return null; -} -function hasSubstructure(structureObject) { - return structureObject?.['key.substructure'] && structureObject['key.substructure'].length > 0; -} -function parseClosureTypes(structureObject) { - const closure = structureObject['key.substructure']?.find((s) => s['key.kind'] === 'source.lang.swift.expr.closure'); - if (!closure) { - return null; - } - const parameters = closure['key.substructure'] - ?.filter((s) => s['key.kind'] === 'source.lang.swift.decl.var.parameter') - .map((p) => ({ name: p['key.name'], typename: p['key.typename'] })); - const returnType = closure?.['key.typename'] ?? 'unknown'; - return { parameters, returnType }; -} -// Used for functions,async functions, all of shape Identifier(name, closure or function) -function findNamedDefinitionsOfType(type, moduleDefinition, file) { - const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type); - return definitionsOfType.reduce((acc, d) => { - const definitionParams = d['key.substructure']; - if (definitionParams[0] == null) { - return acc; - } - const name = getIdentifierFromOffsetObject(definitionParams[0], file); - let types = null; - if (definitionParams[1] == null) { - acc.push({ name, types }); - return acc; - } - if (hasSubstructure(definitionParams[1])) { - types = parseClosureTypes(definitionParams[1]); - } - else { - types = getTypeFromOffsetObject(definitionParams[1], file); - } - acc.push({ name, types }); - return acc; - }, []); -} -// Used for events -function findGroupedDefinitionsOfType(type, moduleDefinition, file) { - const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type); - return definitionsOfType.flatMap((d) => { - const definitionParams = d['key.substructure']; - return definitionParams.map((d) => ({ name: getIdentifierFromOffsetObject(d, file) })); - }); -} -function findAndParseNestedClassesOfType(moduleDefinition, file, type) { - // we support reading definitions from closure only - const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type); - return definitionsOfType - .map((df) => { - const nestedModuleDefinition = df['key.substructure']?.[1]?.['key.substructure']?.[0]?.['key.substructure']?.[0]?.['key.substructure']; - const nameStructure = df['key.substructure']?.[0]; - if (!nestedModuleDefinition || !nameStructure) { - console.warn('Could not parse definition'); - return null; - } - const name = getIdentifierFromOffsetObject(nameStructure, file).replace('.self', ''); - // let's drop nested view field and classes (are null anyways) - const { views: _, classes: _2, ...definition } = parseModuleDefinition(nestedModuleDefinition, file); - return { ...definition, name }; - }) - .flatMap((f) => (f ? [f] : [])); -} -function omitParamsFromClosureArguments(definitions, paramsToOmit) { - return definitions.map((d) => ({ - ...d, - types: { - ...d.types, - parameters: d.types?.parameters?.filter((t, idx) => !paramsToOmit.includes(t.name)) ?? [], - }, - })); -} -// Some blocks have additional modifiers like runOnQueue – we may need to do additional traversing to get to the function definition -function parseBlockModifiers(structureObject) { - if (structureObject['key.name']?.includes('runOnQueue')) { - const structure = structureObject['key.substructure'][0]; - if (structure != null) { - return structure; - } - } - return structureObject; -} -function parseModuleDefinition(moduleDefinition, file) { - const preparedModuleDefinition = moduleDefinition.map(parseBlockModifiers); - const parsedDefinition = { - name: findNamedDefinitionsOfType('Name', preparedModuleDefinition, file)[0]?.name ?? '', - functions: findNamedDefinitionsOfType('Function', preparedModuleDefinition, file), - asyncFunctions: omitParamsFromClosureArguments(findNamedDefinitionsOfType('AsyncFunction', preparedModuleDefinition, file), ['promise']), - events: findGroupedDefinitionsOfType('Events', preparedModuleDefinition, file), - properties: findNamedDefinitionsOfType('Property', preparedModuleDefinition, file), - props: omitParamsFromClosureArguments(findNamedDefinitionsOfType('Prop', preparedModuleDefinition, file), ['view']), - constants: findNamedDefinitionsOfType('Constant', preparedModuleDefinition, file), - views: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'View'), - classes: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'Class'), - }; - return parsedDefinition; -} -function findModuleDefinitionsInFiles(files) { - const modules = []; - for (const path of files) { - const file = { path, content: fs_1.default.readFileSync(path, 'utf8') }; - const definition = findModuleDefinitionInStructure(getStructureFromFile(file)); - if (definition) { - modules.push(parseModuleDefinition(definition, file)); - } - } - return modules; -} -function getAllExpoModulesInWorkingDirectory() { - const files = (0, glob_1.globSync)(pattern); - return findModuleDefinitionsInFiles(files); -} -//# sourceMappingURL=getStructure.js.map \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/getStructure.js.map b/packages/expo-modules-test-core/build/getStructure.js.map deleted file mode 100644 index ccc3dff62d9698..00000000000000 --- a/packages/expo-modules-test-core/build/getStructure.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"getStructure.js","sourceRoot":"","sources":["../src/getStructure.ts"],"names":[],"mappings":"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","sourcesContent":["// convert requires above to imports\nimport { execSync } from 'child_process';\nimport fsNode from 'fs';\nimport { globSync } from 'glob';\nimport XML from 'xml-js';\nimport YAML from 'yaml';\n\nimport type {\n Closure,\n CursorInfoOutput,\n FileType,\n FullyAnnotatedDecl,\n OutputModuleDefinition,\n Structure,\n} from './types';\n\nconst rootDir = process.cwd();\nconst pattern = `${rootDir}/**/*.swift`;\n\nfunction getStructureFromFile(file: FileType) {\n const command = 'sourcekitten structure --file ' + file.path;\n\n try {\n const output = execSync(command);\n return JSON.parse(output.toString());\n } catch (error) {\n console.error('An error occurred while executing the command:', error);\n }\n}\n// find an object with \"key.typename\" : \"ModuleDefinition\" somewhere in the structure and return it\nfunction findModuleDefinitionInStructure(structure: Structure): Structure[] | null {\n if (!structure) {\n return null;\n }\n if (structure?.['key.typename'] === 'ModuleDefinition') {\n const root = structure?.['key.substructure'];\n if (!root) {\n console.warn('Found ModuleDefinition but it is malformed');\n }\n return root;\n }\n const substructure = structure['key.substructure'];\n if (Array.isArray(substructure) && substructure.length > 0) {\n for (const child of substructure) {\n let result = null;\n result = findModuleDefinitionInStructure(child);\n if (result) {\n return result;\n }\n }\n }\n return null;\n}\n\n// Read string straight from file – needed since we can't get cursorinfo for modulename\nfunction getIdentifierFromOffsetObject(offsetObject: Structure, file: FileType) {\n // adding 1 and removing 1 to get rid of quotes\n return file.content\n .substring(offsetObject['key.offset'], offsetObject['key.offset'] + offsetObject['key.length'])\n .replaceAll('\"', '');\n}\n\nfunction maybeUnwrapXMLStructs(type: string | Partial<{ _text: string; 'ref.struct': string }>) {\n if (!type) {\n return type;\n }\n if (typeof type === 'string') {\n return type;\n }\n if (type['_text']) {\n return type['_text'];\n }\n if (type['ref.struct']) {\n return maybeUnwrapXMLStructs(type['ref.struct']);\n }\n return type;\n}\n\nfunction maybeWrapArray(itemOrItems: T[] | T | null) {\n if (!itemOrItems) {\n return null;\n }\n if (Array.isArray(itemOrItems)) {\n return itemOrItems;\n } else {\n return [itemOrItems];\n }\n}\n\nfunction parseXMLAnnotatedDeclarations(cursorInfoOutput: CursorInfoOutput) {\n const xml = cursorInfoOutput['key.fully_annotated_decl'];\n if (!xml) {\n return null;\n }\n const parsed = XML.xml2js(xml, { compact: true }) as FullyAnnotatedDecl;\n\n const parameters =\n maybeWrapArray(parsed?.['decl.function.free']?.['decl.var.parameter'])?.map((p) => ({\n name: maybeUnwrapXMLStructs(p['decl.var.parameter.argument_label']),\n typename: maybeUnwrapXMLStructs(p['decl.var.parameter.type']),\n })) ?? [];\n const returnType = maybeUnwrapXMLStructs(\n parsed?.['decl.function.free']?.['decl.function.returntype']\n );\n return { parameters, returnType };\n}\n\nlet cachedSDKPath: string | null = null;\nfunction getSDKPath() {\n if (cachedSDKPath) {\n return cachedSDKPath;\n }\n const sdkPath = execSync('xcrun --sdk iphoneos --show-sdk-path').toString().trim();\n cachedSDKPath = sdkPath;\n return cachedSDKPath;\n}\n\n// Read type description with sourcekitten, works only for variables\nfunction getTypeFromOffsetObject(offsetObject: Structure, file: FileType) {\n if (!offsetObject) {\n return null;\n }\n const request = {\n 'key.request': 'source.request.cursorinfo',\n 'key.sourcefile': file.path,\n 'key.offset': offsetObject['key.offset'],\n 'key.compilerargs': [file.path, '-target', 'arm64-apple-ios', '-sdk', getSDKPath()],\n };\n const yamlRequest = YAML.stringify(request, {\n defaultStringType: 'QUOTE_DOUBLE',\n lineWidth: 0,\n defaultKeyType: 'PLAIN',\n // needed since behaviour of sourcekitten is not consistent\n } as any).replace('\"source.request.cursorinfo\"', 'source.request.cursorinfo');\n\n const command = 'sourcekitten request --yaml \"' + yamlRequest.replaceAll('\"', '\\\\\"') + '\"';\n try {\n const output = execSync(command, { stdio: 'pipe' });\n return parseXMLAnnotatedDeclarations(JSON.parse(output.toString()));\n } catch (error) {\n console.error('An error occurred while executing the command:', error);\n }\n return null;\n}\n\nfunction hasSubstructure(structureObject: Structure) {\n return structureObject?.['key.substructure'] && structureObject['key.substructure'].length > 0;\n}\n\nfunction parseClosureTypes(structureObject: Structure) {\n const closure = structureObject['key.substructure']?.find(\n (s) => s['key.kind'] === 'source.lang.swift.expr.closure'\n );\n if (!closure) {\n return null;\n }\n const parameters = closure['key.substructure']\n ?.filter((s) => s['key.kind'] === 'source.lang.swift.decl.var.parameter')\n .map((p) => ({ name: p['key.name'], typename: p['key.typename'] }));\n\n const returnType = closure?.['key.typename'] ?? 'unknown';\n return { parameters, returnType };\n}\n\n// Used for functions,async functions, all of shape Identifier(name, closure or function)\nfunction findNamedDefinitionsOfType(type: string, moduleDefinition: Structure[], file: FileType) {\n const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type);\n\n return definitionsOfType.reduce<\n { name: string; types: ReturnType }[]\n >((acc, d) => {\n const definitionParams = d['key.substructure'];\n\n if (definitionParams[0] == null) {\n return acc;\n }\n\n const name = getIdentifierFromOffsetObject(definitionParams[0], file);\n let types = null;\n\n if (definitionParams[1] == null) {\n acc.push({ name, types });\n return acc;\n }\n\n if (hasSubstructure(definitionParams[1])) {\n types = parseClosureTypes(definitionParams[1]);\n } else {\n types = getTypeFromOffsetObject(definitionParams[1], file);\n }\n\n acc.push({ name, types });\n return acc;\n }, []);\n}\n\n// Used for events\nfunction findGroupedDefinitionsOfType(type: string, moduleDefinition: Structure[], file: FileType) {\n const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type);\n return definitionsOfType.flatMap((d) => {\n const definitionParams = d['key.substructure'];\n return definitionParams.map((d) => ({ name: getIdentifierFromOffsetObject(d, file) }));\n });\n}\nfunction findAndParseNestedClassesOfType(\n moduleDefinition: Structure[],\n file: FileType,\n type: string\n) {\n // we support reading definitions from closure only\n const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type);\n return definitionsOfType\n .map((df) => {\n const nestedModuleDefinition =\n df['key.substructure']?.[1]?.['key.substructure']?.[0]?.['key.substructure']?.[0]?.[\n 'key.substructure'\n ];\n const nameStructure = df['key.substructure']?.[0];\n if (!nestedModuleDefinition || !nameStructure) {\n console.warn('Could not parse definition');\n return null;\n }\n const name = getIdentifierFromOffsetObject(nameStructure, file).replace('.self', '');\n // let's drop nested view field and classes (are null anyways)\n const {\n views: _,\n classes: _2,\n ...definition\n } = parseModuleDefinition(nestedModuleDefinition, file);\n return { ...definition, name };\n })\n .flatMap((f) => (f ? [f] : []));\n}\n\nfunction omitParamsFromClosureArguments(\n definitions: T[],\n paramsToOmit: string[]\n) {\n return definitions.map((d) => ({\n ...d,\n types: {\n ...d.types,\n parameters: d.types?.parameters?.filter((t, idx) => !paramsToOmit.includes(t.name)) ?? [],\n },\n }));\n}\n\n// Some blocks have additional modifiers like runOnQueue – we may need to do additional traversing to get to the function definition\nfunction parseBlockModifiers(structureObject: Structure) {\n if (structureObject['key.name']?.includes('runOnQueue')) {\n const structure = structureObject['key.substructure'][0];\n if (structure != null) {\n return structure;\n }\n }\n return structureObject;\n}\n\nfunction parseModuleDefinition(\n moduleDefinition: Structure[],\n file: FileType\n): OutputModuleDefinition {\n const preparedModuleDefinition = moduleDefinition.map(parseBlockModifiers);\n const parsedDefinition = {\n name: findNamedDefinitionsOfType('Name', preparedModuleDefinition, file)[0]?.name ?? '',\n functions: findNamedDefinitionsOfType('Function', preparedModuleDefinition, file),\n asyncFunctions: omitParamsFromClosureArguments(\n findNamedDefinitionsOfType('AsyncFunction', preparedModuleDefinition, file),\n ['promise']\n ),\n events: findGroupedDefinitionsOfType('Events', preparedModuleDefinition, file),\n properties: findNamedDefinitionsOfType('Property', preparedModuleDefinition, file),\n props: omitParamsFromClosureArguments(\n findNamedDefinitionsOfType('Prop', preparedModuleDefinition, file),\n ['view']\n ),\n constants: findNamedDefinitionsOfType('Constant', preparedModuleDefinition, file),\n views: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'View'),\n classes: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'Class'),\n };\n return parsedDefinition;\n}\n\nfunction findModuleDefinitionsInFiles(files: string[]) {\n const modules = [];\n for (const path of files) {\n const file = { path, content: fsNode.readFileSync(path, 'utf8') };\n const definition = findModuleDefinitionInStructure(getStructureFromFile(file));\n if (definition) {\n modules.push(parseModuleDefinition(definition, file));\n }\n }\n return modules;\n}\n\nexport function getAllExpoModulesInWorkingDirectory() {\n const files = globSync(pattern);\n return findModuleDefinitionsInFiles(files);\n}\n"]} \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/index.js b/packages/expo-modules-test-core/build/index.js index fa6651365c4b2c..4ab243a6dbd4eb 100644 --- a/packages/expo-modules-test-core/build/index.js +++ b/packages/expo-modules-test-core/build/index.js @@ -1,21 +1,23 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const getStructure_1 = require("./getStructure"); -const mockgen_1 = require("./mockgen"); +const expo_type_information_1 = require("expo-type-information"); const command = process.argv[2]; -if (command === 'generate-js-mocks') { - const modules = (0, getStructure_1.getAllExpoModulesInWorkingDirectory)(); - (0, mockgen_1.generateMocks)(modules); -} -else if (command === 'generate-ts-mocks') { - const modules = (0, getStructure_1.getAllExpoModulesInWorkingDirectory)(); - (0, mockgen_1.generateMocks)(modules, 'typescript'); -} -else if (command === 'get-mocks-structure') { - const modules = (0, getStructure_1.getAllExpoModulesInWorkingDirectory)(); - console.log(JSON.stringify(modules, null, 2)); -} -else { - console.log('Command not recognized\n\nAvailable commands are:\n- generate-js-mocks\n- generate-ts-mocks\n- get-mocks-structure'); +async function main(args) { + if (command === 'generate-js-mocks') { + const modules = await (0, expo_type_information_1.getAllExpoModulesInWorkingDirectory)(); + (0, expo_type_information_1.generateMocks)(modules); + } + else if (command === 'generate-ts-mocks') { + const modules = await (0, expo_type_information_1.getAllExpoModulesInWorkingDirectory)(); + (0, expo_type_information_1.generateMocks)(modules, 'typescript'); + } + else if (command === 'get-mocks-structure') { + const modules = await (0, expo_type_information_1.getAllExpoModulesInWorkingDirectory)(); + console.log(JSON.stringify(modules, null, 2)); + } + else { + console.log('Command not recognized\n\nAvailable commands are:\n- generate-js-mocks\n- generate-ts-mocks\n- get-mocks-structure'); + } } +main(process.argv.slice(2)); //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/index.js.map b/packages/expo-modules-test-core/build/index.js.map index ebb2a0b77690b7..b963f012c597ae 100644 --- a/packages/expo-modules-test-core/build/index.js.map +++ b/packages/expo-modules-test-core/build/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,iDAAqE;AACrE,uCAA0C;AAE1C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,IAAA,kDAAmC,GAAE,CAAC;IACtD,IAAA,uBAAa,EAAC,OAAO,CAAC,CAAC;AACzB,CAAC;KAAM,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAA,kDAAmC,GAAE,CAAC;IACtD,IAAA,uBAAa,EAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AACvC,CAAC;KAAM,IAAI,OAAO,KAAK,qBAAqB,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAA,kDAAmC,GAAE,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,GAAG,CACT,oHAAoH,CACrH,CAAC;AACJ,CAAC","sourcesContent":["import { getAllExpoModulesInWorkingDirectory } from './getStructure';\nimport { generateMocks } from './mockgen';\n\nconst command = process.argv[2];\n\nif (command === 'generate-js-mocks') {\n const modules = getAllExpoModulesInWorkingDirectory();\n generateMocks(modules);\n} else if (command === 'generate-ts-mocks') {\n const modules = getAllExpoModulesInWorkingDirectory();\n generateMocks(modules, 'typescript');\n} else if (command === 'get-mocks-structure') {\n const modules = getAllExpoModulesInWorkingDirectory();\n console.log(JSON.stringify(modules, null, 2));\n} else {\n console.log(\n 'Command not recognized\\n\\nAvailable commands are:\\n- generate-js-mocks\\n- generate-ts-mocks\\n- get-mocks-structure'\n );\n}\n"]} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,iEAA2F;AAC3F,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,IAAA,2DAAmC,GAAE,CAAC;QAC5D,IAAA,qCAAa,EAAC,OAAO,CAAC,CAAC;IACzB,CAAC;SAAM,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,IAAA,2DAAmC,GAAE,CAAC;QAC5D,IAAA,qCAAa,EAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACvC,CAAC;SAAM,IAAI,OAAO,KAAK,qBAAqB,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM,IAAA,2DAAmC,GAAE,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CACT,oHAAoH,CACrH,CAAC;IACJ,CAAC;AACH,CAAC;AAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC","sourcesContent":["import { generateMocks, getAllExpoModulesInWorkingDirectory } from 'expo-type-information';\nconst command = process.argv[2];\n\nasync function main(args: string[]) {\n if (command === 'generate-js-mocks') {\n const modules = await getAllExpoModulesInWorkingDirectory();\n generateMocks(modules);\n } else if (command === 'generate-ts-mocks') {\n const modules = await getAllExpoModulesInWorkingDirectory();\n generateMocks(modules, 'typescript');\n } else if (command === 'get-mocks-structure') {\n const modules = await getAllExpoModulesInWorkingDirectory();\n console.log(JSON.stringify(modules, null, 2));\n } else {\n console.log(\n 'Command not recognized\\n\\nAvailable commands are:\\n- generate-js-mocks\\n- generate-ts-mocks\\n- get-mocks-structure'\n );\n }\n}\n\nmain(process.argv.slice(2));\n"]} \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/mockgen.d.ts b/packages/expo-modules-test-core/build/mockgen.d.ts deleted file mode 100644 index 1c58522e2845f3..00000000000000 --- a/packages/expo-modules-test-core/build/mockgen.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env node -import { OutputModuleDefinition } from './types'; -export declare function generateMocks(modules: OutputModuleDefinition[], outputLanguage?: 'javascript' | 'typescript'): Promise; -//# sourceMappingURL=mockgen.d.ts.map \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/mockgen.d.ts.map b/packages/expo-modules-test-core/build/mockgen.d.ts.map deleted file mode 100644 index bf858d45f900ca..00000000000000 --- a/packages/expo-modules-test-core/build/mockgen.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mockgen.d.ts","sourceRoot":"","sources":["../src/mockgen.ts"],"names":[],"mappings":";AAQA,OAAO,EAIL,sBAAsB,EAEvB,MAAM,SAAS,CAAC;AAudjB,wBAAsB,aAAa,CACjC,OAAO,EAAE,sBAAsB,EAAE,EACjC,cAAc,GAAE,YAAY,GAAG,YAA2B,iBAqC3D"} \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/mockgen.js b/packages/expo-modules-test-core/build/mockgen.js deleted file mode 100644 index 934c2e11729e04..00000000000000 --- a/packages/expo-modules-test-core/build/mockgen.js +++ /dev/null @@ -1,391 +0,0 @@ -#!/usr/bin/env node -'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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateMocks = generateMocks; -const fs_1 = __importDefault(require("fs")); -const path_1 = __importDefault(require("path")); -const prettier = __importStar(require("prettier")); -const typescript_1 = __importDefault(require("typescript")); -const directoryPath = process.cwd(); -/* -We receive types from SourceKitten and `getStructure` like so (examples): -[AcceptedTypes]?, UIColor?, [String: Any] - -We need to parse them first to TS nodes in `mapSwiftTypeToTsType` with the following helper functions. -*/ -function isSwiftArray(type) { - // This can also be an object, but we check that first, so if it's not an object and is wrapped with [] it's an array. - return type.startsWith('[') && type.endsWith(']'); -} -function maybeUnwrapSwiftArray(type) { - const isArray = isSwiftArray(type); - if (!isArray) { - return type; - } - const innerType = type.substring(1, type.length - 1); - return innerType; -} -function isSwiftOptional(type) { - return type.endsWith('?'); -} -function maybeUnwrapSwiftOptional(type) { - const isOptional = isSwiftOptional(type); - if (!isOptional) { - return type; - } - const innerType = type.substring(0, type.length - 1); - return innerType; -} -function isSwiftDictionary(type) { - return (type.startsWith('[') && - type.endsWith(']') && - findRootColonInDictionary(type.substring(1, type.length - 1)) >= 0); -} -function isEither(type) { - return type.startsWith('Either<'); -} -// "Either" -> ["TypeOne", "TypeTwo"] -function maybeUnwrapEither(type) { - if (!isEither(type)) { - return [type]; - } - const innerType = type.substring(7, type.length - 1); - return innerType.split(',').map((t) => t.trim()); -} -/* -The Swift object type can have nested objects as the type of it's values (or maybe even keys). -[String: [String: Any]] - -We can't use regex to find the root colon, so this is the safest way – by counting brackets. -*/ -function findRootColonInDictionary(type) { - let colonIndex = -1; - let openBracketsCount = 0; - for (let i = 0; i < type.length; i++) { - if (type[i] === '[') { - openBracketsCount++; - } - else if (type[i] === ']') { - openBracketsCount--; - } - else if (type[i] === ':' && openBracketsCount === 0) { - colonIndex = i; - break; - } - } - return colonIndex; -} -function unwrapSwiftDictionary(type) { - const innerType = type.substring(1, type.length - 1); - const colonPosition = findRootColonInDictionary(innerType); - return { - key: innerType.slice(0, colonPosition).trim(), - value: innerType.slice(colonPosition + 1).trim(), - }; -} -/* -Main function that converts a string representation of a Swift type to a TypeScript compiler API node AST. -We can pass those types straight to a TypeScript printer (a function that converts AST to text). -*/ -function mapSwiftTypeToTsType(type) { - if (!type) { - return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.VoidKeyword); - } - if (isSwiftOptional(type)) { - return typescript_1.default.factory.createUnionTypeNode([ - mapSwiftTypeToTsType(maybeUnwrapSwiftOptional(type)), - typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.UndefinedKeyword), - ]); - } - if (isSwiftDictionary(type)) { - const { key, value } = unwrapSwiftDictionary(type); - const keyType = mapSwiftTypeToTsType(key); - const valueType = mapSwiftTypeToTsType(value); - const indexSignature = typescript_1.default.factory.createIndexSignature(undefined, [typescript_1.default.factory.createParameterDeclaration(undefined, undefined, 'key', undefined, keyType)], valueType); - const typeLiteralNode = typescript_1.default.factory.createTypeLiteralNode([indexSignature]); - return typeLiteralNode; - } - if (isSwiftArray(type)) { - return typescript_1.default.factory.createArrayTypeNode(mapSwiftTypeToTsType(maybeUnwrapSwiftArray(type))); - } - // Custom handling for the Either convertible - if (isEither(type)) { - return typescript_1.default.factory.createUnionTypeNode(maybeUnwrapEither(type).map((t) => mapSwiftTypeToTsType(t))); - } - switch (type) { - // Our custom representation for types that we have no type hints for. Not necessairly Swift any. - case 'unknown': - return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword); - case 'String': - return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.StringKeyword); - case 'Bool': - return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.BooleanKeyword); - case 'Int': - case 'Float': - case 'Double': - return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword); - case 'Any': // Swift Any type - return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword); - default: // Custom Swift type (record) – for now mapped to a custom TS type exported at the top of the file by `getMockedTypes`. - return typescript_1.default.factory.createTypeReferenceNode(type); - } -} -// Mocks require sample return values, so we generate them based on TS AST. -function getMockLiterals(tsReturnType) { - if (!tsReturnType) { - return undefined; - } - switch (tsReturnType.kind) { - case typescript_1.default.SyntaxKind.AnyKeyword: - case typescript_1.default.SyntaxKind.VoidKeyword: - return undefined; - case typescript_1.default.SyntaxKind.UnionType: - // we take the first element of our union for the mock – we know the cast is correct since we create the type ourselves - // the second is `undefined` for optionals. - return getMockLiterals(tsReturnType.types[0]); - case typescript_1.default.SyntaxKind.StringKeyword: - return typescript_1.default.factory.createStringLiteral(''); - case typescript_1.default.SyntaxKind.BooleanKeyword: - return typescript_1.default.factory.createFalse(); - case typescript_1.default.SyntaxKind.NumberKeyword: - return typescript_1.default.factory.createNumericLiteral('0'); - case typescript_1.default.SyntaxKind.ArrayType: - return typescript_1.default.factory.createArrayLiteralExpression(); - case typescript_1.default.SyntaxKind.TypeLiteral: - // handles a dictionary, could be improved by creating an object fitting the schema instead of an empty one - return typescript_1.default.factory.createObjectLiteralExpression([], false); - } - return undefined; -} -function wrapWithAsync(tsType) { - return typescript_1.default.factory.createTypeReferenceNode('Promise', [tsType]); -} -function maybeWrapWithReturnStatement(tsType) { - if (tsType.kind === typescript_1.default.SyntaxKind.AnyKeyword || tsType.kind === typescript_1.default.SyntaxKind.VoidKeyword) { - return []; - } - if (tsType.kind === typescript_1.default.SyntaxKind.TypeReference) { - // A fallback – we print a comment that these mocks are not fitting the custom type. Could be improved by expanding a set of default mocks. - return [ - typescript_1.default.addSyntheticTrailingComment(typescript_1.default.factory.createReturnStatement(typescript_1.default.factory.createNull()), typescript_1.default.SyntaxKind.SingleLineCommentTrivia, ` TODO: Replace with mock for value of type ${tsType?.typeName?.escapedText ?? ''}.`), - ]; - } - return [typescript_1.default.factory.createReturnStatement(getMockLiterals(tsType))]; -} -/* -We iterate over a list of functions and we create TS AST for each of them. -*/ -function getMockedFunctions(functions, { async = false, classMethod = false } = {}) { - return functions.map((fnStructure) => { - const name = typescript_1.default.factory.createIdentifier(fnStructure.name); - const returnType = mapSwiftTypeToTsType(fnStructure.types?.returnType); - const parameters = fnStructure?.types?.parameters.map((p) => typescript_1.default.factory.createParameterDeclaration(undefined, undefined, p.name ?? '_', undefined, mapSwiftTypeToTsType(p.typename), undefined)) ?? []; - const returnBlock = typescript_1.default.factory.createBlock(maybeWrapWithReturnStatement(returnType), true); - if (classMethod) { - return typescript_1.default.factory.createMethodDeclaration([async ? typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.AsyncKeyword) : undefined].flatMap((f) => f ? [f] : []), undefined, name, undefined, undefined, parameters, async ? wrapWithAsync(returnType) : returnType, returnBlock); - } - const func = typescript_1.default.factory.createFunctionDeclaration([ - typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword), - async ? typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.AsyncKeyword) : undefined, - ].flatMap((f) => (f ? [f] : [])), undefined, name, undefined, parameters, async ? wrapWithAsync(returnType) : returnType, returnBlock); - return func; - }); -} -/* -We iterate over a list of constants and create TS AST for each of them. -Constants are exported as `export const NAME = value;` -*/ -function getMockedConstants(constants) { - return constants.map((constant) => { - const name = typescript_1.default.factory.createIdentifier(constant.name); - const returnType = mapSwiftTypeToTsType(constant.types?.returnType ?? 'unknown'); - const initializer = getMockLiterals(returnType) ?? typescript_1.default.factory.createNumericLiteral('0'); - return typescript_1.default.factory.createVariableStatement([typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword)], typescript_1.default.factory.createVariableDeclarationList([typescript_1.default.factory.createVariableDeclaration(name, undefined, undefined, initializer)], typescript_1.default.NodeFlags.Const)); - }); -} -/** - * Collect all type references used in any of the AST types to generate type aliases - * e.g. type `[URL: string]?` will generate `type URL = any;` - */ -function getAllTypeReferences(node, accumulator) { - if (typescript_1.default.isTypeReferenceNode(node)) { - accumulator.push(node.typeName?.escapedText); - } - node.forEachChild((n) => getAllTypeReferences(n, accumulator)); -} -/** - * Iterates over types to collect the aliases. - */ -function getTypesToMock(module) { - const foundTypes = []; - Object.values(module) - .flatMap((t) => (Array.isArray(t) ? t.map((t2) => t2?.types) : [])) - .forEach((types) => { - types?.parameters.forEach(({ typename }) => { - getAllTypeReferences(mapSwiftTypeToTsType(typename), foundTypes); - }); - types?.returnType && - getAllTypeReferences(mapSwiftTypeToTsType(types?.returnType), foundTypes); - }); - return new Set(foundTypes); -} -/** - * Gets a mock for a custom type. - */ -function getMockedTypes(types) { - return Array.from(types).map((type) => { - const name = typescript_1.default.factory.createIdentifier(type); - const typeAlias = typescript_1.default.factory.createTypeAliasDeclaration([typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword)], name, undefined, typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword)); - return typeAlias; - }); -} -const prefix = `Automatically generated by expo-modules-test-core. - -This autogenerated file provides a mock for native Expo module, -and works out of the box with the expo jest preset. -`; -function getPrefix() { - return [typescript_1.default.factory.createJSDocComment(prefix)]; -} -function generatePropTypesForDefinition(definition) { - return typescript_1.default.factory.createTypeAliasDeclaration([typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword)], 'ViewProps', undefined, typescript_1.default.factory.createTypeLiteralNode([ - ...definition.props.map((p) => { - const propType = mapSwiftTypeToTsType(p.types.parameters[0]?.typename ?? ''); - return typescript_1.default.factory.createPropertySignature(undefined, p.name, undefined, propType); - }), - ...definition.events.map((e) => { - const eventType = typescript_1.default.factory.createFunctionTypeNode(undefined, [ - typescript_1.default.factory.createParameterDeclaration(undefined, undefined, 'event', undefined, typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword)), - ], typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.VoidKeyword)); - return typescript_1.default.factory.createPropertySignature(undefined, e.name, undefined, eventType); - }), - ])); -} -/* -Generate a mock for view props and functions. -*/ -function getMockedViews(viewDefinitions) { - return viewDefinitions.flatMap((definition) => { - if (!definition) { - return []; - } - const propsType = generatePropTypesForDefinition(definition); - const props = typescript_1.default.factory.createParameterDeclaration(undefined, undefined, 'props', undefined, typescript_1.default.factory.createTypeReferenceNode('ViewProps', undefined), undefined); - const viewFunction = typescript_1.default.factory.createFunctionDeclaration([typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword)], undefined, - // TODO: Handle this better once requireNativeViewManager accepts view name or a different solution for multiple views is built. - viewDefinitions.length === 1 ? 'View' : definition.name, undefined, [props], undefined, typescript_1.default.factory.createBlock([])); - return [propsType, viewFunction]; - }); -} -function getMockedClass(def) { - const classDecl = typescript_1.default.factory.createClassDeclaration([typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.ExportKeyword)], typescript_1.default.factory.createIdentifier(def.name), undefined, undefined, [ - ...getMockedFunctions(def.functions, { classMethod: true }), - ...getMockedFunctions(def.asyncFunctions, { async: true, classMethod: true }), - ]); - return classDecl; -} -function getMockedClasses(def) { - return def.map((d) => getMockedClass(d)); -} -const newlineIdentifier = typescript_1.default.factory.createIdentifier('\n\n'); -function separateWithNewlines(arr) { - return [arr, newlineIdentifier]; -} -function omitFromSet(set, toOmit) { - const newSet = new Set(set); - toOmit.forEach((item) => { - if (item) { - newSet.delete(item); - } - }); - return newSet; -} -function getMockForModule(module, includeTypes) { - return [] - .concat(getPrefix(), newlineIdentifier, includeTypes - ? getMockedTypes(omitFromSet(new Set([ - ...getTypesToMock(module), - ...new Set(...module.views.map((v) => getTypesToMock(v))), - ...new Set(...module.classes.map((c) => getTypesToMock(c))), - ]), - // Ignore all types that are actually native classes - [ - module.name, - ...module.views.map((c) => c.name), - ...module.classes.map((c) => c.name), - ])) - : [], newlineIdentifier, getMockedConstants(module.constants), newlineIdentifier, getMockedFunctions(module.functions), getMockedFunctions(module.asyncFunctions, { async: true }), newlineIdentifier, getMockedViews(module.views), getMockedClasses(module.classes)) - .flatMap(separateWithNewlines); -} -async function prettifyCode(text, parser = 'babel') { - return await prettier.format(text, { - parser, - tabWidth: 2, - printWidth: 100, - trailingComma: 'none', - singleQuote: true, - }); -} -async function generateMocks(modules, outputLanguage = 'javascript') { - const printer = typescript_1.default.createPrinter({ newLine: typescript_1.default.NewLineKind.LineFeed }); - for (const m of modules) { - const filename = m.name + (outputLanguage === 'javascript' ? '.js' : '.ts'); - const resultFile = typescript_1.default.createSourceFile(filename, '', typescript_1.default.ScriptTarget.Latest, false, typescript_1.default.ScriptKind.TSX); - fs_1.default.mkdirSync(path_1.default.join(directoryPath, 'mocks'), { recursive: true }); - const filePath = path_1.default.join(directoryPath, 'mocks', filename); - // get ts nodearray from getMockForModule(m) array - const mock = typescript_1.default.factory.createNodeArray(getMockForModule(m, outputLanguage === 'typescript')); - const printedTs = printer.printList(typescript_1.default.ListFormat.MultiLine + typescript_1.default.ListFormat.PreserveLines, mock, resultFile); - if (outputLanguage === 'javascript') { - const compiledJs = typescript_1.default.transpileModule(printedTs, { - compilerOptions: { - module: typescript_1.default.ModuleKind.ESNext, - target: typescript_1.default.ScriptTarget.ESNext, - }, - }).outputText; - const prettifiedJs = await prettifyCode(compiledJs); - fs_1.default.writeFileSync(filePath, prettifiedJs); - } - else { - const prettifiedTs = await prettifyCode(printedTs, 'typescript'); - fs_1.default.writeFileSync(filePath, prettifiedTs); - } - } -} -//# sourceMappingURL=mockgen.js.map \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/mockgen.js.map b/packages/expo-modules-test-core/build/mockgen.js.map deleted file mode 100644 index 46bd3c6953df1b..00000000000000 --- a/packages/expo-modules-test-core/build/mockgen.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mockgen.js","sourceRoot":"","sources":["../src/mockgen.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n'use strict';\n\nimport fs from 'fs';\nimport path from 'path';\nimport * as prettier from 'prettier';\nimport ts from 'typescript';\n\nimport {\n Closure,\n ClosureTypes,\n Constant,\n OutputModuleDefinition,\n OutputNestedClassDefinition,\n} from './types';\n\nconst directoryPath = process.cwd();\n\n/*\nWe receive types from SourceKitten and `getStructure` like so (examples):\n[AcceptedTypes]?, UIColor?, [String: Any]\n\nWe need to parse them first to TS nodes in `mapSwiftTypeToTsType` with the following helper functions.\n*/\n\nfunction isSwiftArray(type: string) {\n // This can also be an object, but we check that first, so if it's not an object and is wrapped with [] it's an array.\n return type.startsWith('[') && type.endsWith(']');\n}\nfunction maybeUnwrapSwiftArray(type: string) {\n const isArray = isSwiftArray(type);\n if (!isArray) {\n return type;\n }\n const innerType = type.substring(1, type.length - 1);\n return innerType;\n}\n\nfunction isSwiftOptional(type: string) {\n return type.endsWith('?');\n}\nfunction maybeUnwrapSwiftOptional(type: string) {\n const isOptional = isSwiftOptional(type);\n if (!isOptional) {\n return type;\n }\n const innerType = type.substring(0, type.length - 1);\n return innerType;\n}\n\nfunction isSwiftDictionary(type: string) {\n return (\n type.startsWith('[') &&\n type.endsWith(']') &&\n findRootColonInDictionary(type.substring(1, type.length - 1)) >= 0\n );\n}\n\nfunction isEither(type: string) {\n return type.startsWith('Either<');\n}\n// \"Either\" -> [\"TypeOne\", \"TypeTwo\"]\nfunction maybeUnwrapEither(type: string): string[] {\n if (!isEither(type)) {\n return [type];\n }\n const innerType = type.substring(7, type.length - 1);\n return innerType.split(',').map((t) => t.trim());\n}\n\n/*\nThe Swift object type can have nested objects as the type of it's values (or maybe even keys).\n[String: [String: Any]]\n\nWe can't use regex to find the root colon, so this is the safest way – by counting brackets.\n*/\nfunction findRootColonInDictionary(type: string) {\n let colonIndex = -1;\n let openBracketsCount = 0;\n for (let i = 0; i < type.length; i++) {\n if (type[i] === '[') {\n openBracketsCount++;\n } else if (type[i] === ']') {\n openBracketsCount--;\n } else if (type[i] === ':' && openBracketsCount === 0) {\n colonIndex = i;\n break;\n }\n }\n return colonIndex;\n}\nfunction unwrapSwiftDictionary(type: string) {\n const innerType = type.substring(1, type.length - 1);\n const colonPosition = findRootColonInDictionary(innerType);\n return {\n key: innerType.slice(0, colonPosition).trim(),\n value: innerType.slice(colonPosition + 1).trim(),\n };\n}\n\ntype TSNode =\n | ts.UnionTypeNode\n | ts.KeywordTypeNode\n | ts.TypeReferenceNode\n | ts.ArrayTypeNode\n | ts.OptionalTypeNode\n | ts.TypeLiteralNode;\n\n/*\nMain function that converts a string representation of a Swift type to a TypeScript compiler API node AST.\nWe can pass those types straight to a TypeScript printer (a function that converts AST to text).\n*/\nfunction mapSwiftTypeToTsType(type: string): TSNode {\n if (!type) {\n return ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword);\n }\n if (isSwiftOptional(type)) {\n return ts.factory.createUnionTypeNode([\n mapSwiftTypeToTsType(maybeUnwrapSwiftOptional(type)),\n ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),\n ]);\n }\n if (isSwiftDictionary(type)) {\n const { key, value } = unwrapSwiftDictionary(type);\n const keyType = mapSwiftTypeToTsType(key);\n const valueType = mapSwiftTypeToTsType(value);\n\n const indexSignature = ts.factory.createIndexSignature(\n undefined,\n [ts.factory.createParameterDeclaration(undefined, undefined, 'key', undefined, keyType)],\n valueType\n );\n\n const typeLiteralNode = ts.factory.createTypeLiteralNode([indexSignature]);\n return typeLiteralNode;\n }\n if (isSwiftArray(type)) {\n return ts.factory.createArrayTypeNode(mapSwiftTypeToTsType(maybeUnwrapSwiftArray(type)));\n }\n // Custom handling for the Either convertible\n if (isEither(type)) {\n return ts.factory.createUnionTypeNode(\n maybeUnwrapEither(type).map((t) => mapSwiftTypeToTsType(t))\n );\n }\n\n switch (type) {\n // Our custom representation for types that we have no type hints for. Not necessairly Swift any.\n case 'unknown':\n return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);\n case 'String':\n return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);\n case 'Bool':\n return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);\n case 'Int':\n case 'Float':\n case 'Double':\n return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);\n case 'Any': // Swift Any type\n return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);\n default: // Custom Swift type (record) – for now mapped to a custom TS type exported at the top of the file by `getMockedTypes`.\n return ts.factory.createTypeReferenceNode(type);\n }\n}\n\n// Mocks require sample return values, so we generate them based on TS AST.\nfunction getMockLiterals(tsReturnType: TSNode) {\n if (!tsReturnType) {\n return undefined;\n }\n switch (tsReturnType.kind) {\n case ts.SyntaxKind.AnyKeyword:\n case ts.SyntaxKind.VoidKeyword:\n return undefined;\n case ts.SyntaxKind.UnionType:\n // we take the first element of our union for the mock – we know the cast is correct since we create the type ourselves\n // the second is `undefined` for optionals.\n return getMockLiterals(tsReturnType.types[0] as TSNode);\n case ts.SyntaxKind.StringKeyword:\n return ts.factory.createStringLiteral('');\n case ts.SyntaxKind.BooleanKeyword:\n return ts.factory.createFalse();\n case ts.SyntaxKind.NumberKeyword:\n return ts.factory.createNumericLiteral('0');\n case ts.SyntaxKind.ArrayType:\n return ts.factory.createArrayLiteralExpression();\n case ts.SyntaxKind.TypeLiteral:\n // handles a dictionary, could be improved by creating an object fitting the schema instead of an empty one\n return ts.factory.createObjectLiteralExpression([], false);\n }\n return undefined;\n}\n\nfunction wrapWithAsync(tsType: ts.TypeNode) {\n return ts.factory.createTypeReferenceNode('Promise', [tsType]);\n}\n\nfunction maybeWrapWithReturnStatement(tsType: TSNode) {\n if (tsType.kind === ts.SyntaxKind.AnyKeyword || tsType.kind === ts.SyntaxKind.VoidKeyword) {\n return [];\n }\n if (tsType.kind === ts.SyntaxKind.TypeReference) {\n // A fallback – we print a comment that these mocks are not fitting the custom type. Could be improved by expanding a set of default mocks.\n return [\n ts.addSyntheticTrailingComment(\n ts.factory.createReturnStatement(ts.factory.createNull()),\n ts.SyntaxKind.SingleLineCommentTrivia,\n ` TODO: Replace with mock for value of type ${\n ((tsType as any)?.typeName as any)?.escapedText ?? ''\n }.`\n ),\n ];\n }\n return [ts.factory.createReturnStatement(getMockLiterals(tsType))];\n}\n\n/*\nWe iterate over a list of functions and we create TS AST for each of them.\n*/\nfunction getMockedFunctions(functions: Closure[], { async = false, classMethod = false } = {}) {\n return functions.map((fnStructure) => {\n const name = ts.factory.createIdentifier(fnStructure.name);\n const returnType = mapSwiftTypeToTsType(fnStructure.types?.returnType);\n const parameters =\n fnStructure?.types?.parameters.map((p) =>\n ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n p.name ?? '_',\n undefined,\n mapSwiftTypeToTsType(p.typename),\n undefined\n )\n ) ?? [];\n const returnBlock = ts.factory.createBlock(maybeWrapWithReturnStatement(returnType), true);\n\n if (classMethod) {\n return ts.factory.createMethodDeclaration(\n [async ? ts.factory.createToken(ts.SyntaxKind.AsyncKeyword) : undefined].flatMap((f) =>\n f ? [f] : []\n ),\n undefined,\n name,\n undefined,\n undefined,\n parameters,\n async ? wrapWithAsync(returnType) : returnType,\n returnBlock\n );\n }\n const func = ts.factory.createFunctionDeclaration(\n [\n ts.factory.createToken(ts.SyntaxKind.ExportKeyword),\n async ? ts.factory.createToken(ts.SyntaxKind.AsyncKeyword) : undefined,\n ].flatMap((f) => (f ? [f] : [])),\n undefined,\n name,\n undefined,\n parameters,\n async ? wrapWithAsync(returnType) : returnType,\n returnBlock\n );\n return func;\n });\n}\n\n/*\nWe iterate over a list of constants and create TS AST for each of them.\nConstants are exported as `export const NAME = value;`\n*/\nfunction getMockedConstants(constants: Constant[]) {\n return constants.map((constant) => {\n const name = ts.factory.createIdentifier(constant.name);\n const returnType = mapSwiftTypeToTsType(constant.types?.returnType ?? 'unknown');\n const initializer = getMockLiterals(returnType) ?? ts.factory.createNumericLiteral('0');\n\n return ts.factory.createVariableStatement(\n [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],\n ts.factory.createVariableDeclarationList(\n [ts.factory.createVariableDeclaration(name, undefined, undefined, initializer)],\n ts.NodeFlags.Const\n )\n );\n });\n}\n\n/**\n * Collect all type references used in any of the AST types to generate type aliases\n * e.g. type `[URL: string]?` will generate `type URL = any;`\n */\nfunction getAllTypeReferences(node: ts.Node, accumulator: string[]) {\n if (ts.isTypeReferenceNode(node)) {\n accumulator.push((node.typeName as any)?.escapedText);\n }\n node.forEachChild((n) => getAllTypeReferences(n, accumulator));\n}\n\n/**\n * Iterates over types to collect the aliases.\n */\nfunction getTypesToMock(module: OutputModuleDefinition | OutputNestedClassDefinition) {\n const foundTypes: string[] = [];\n\n Object.values(module)\n .flatMap((t) => (Array.isArray(t) ? t.map((t2) => (t2 as Closure)?.types) : []))\n .forEach((types: ClosureTypes | null) => {\n types?.parameters.forEach(({ typename }) => {\n getAllTypeReferences(mapSwiftTypeToTsType(typename), foundTypes);\n });\n types?.returnType &&\n getAllTypeReferences(mapSwiftTypeToTsType(types?.returnType), foundTypes);\n });\n return new Set(foundTypes);\n}\n\n/**\n * Gets a mock for a custom type.\n */\nfunction getMockedTypes(types: Set) {\n return Array.from(types).map((type) => {\n const name = ts.factory.createIdentifier(type);\n const typeAlias = ts.factory.createTypeAliasDeclaration(\n [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],\n name,\n undefined,\n ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)\n );\n return typeAlias;\n });\n}\n\nconst prefix = `Automatically generated by expo-modules-test-core.\n\nThis autogenerated file provides a mock for native Expo module,\nand works out of the box with the expo jest preset.\n`;\nfunction getPrefix() {\n return [ts.factory.createJSDocComment(prefix)];\n}\n\nfunction generatePropTypesForDefinition(definition: OutputNestedClassDefinition) {\n return ts.factory.createTypeAliasDeclaration(\n [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],\n 'ViewProps',\n undefined,\n ts.factory.createTypeLiteralNode([\n ...definition.props.map((p) => {\n const propType = mapSwiftTypeToTsType(p.types.parameters[0]?.typename ?? '');\n return ts.factory.createPropertySignature(undefined, p.name, undefined, propType);\n }),\n ...definition.events.map((e) => {\n const eventType = ts.factory.createFunctionTypeNode(\n undefined,\n [\n ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n 'event',\n undefined,\n ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)\n ),\n ],\n ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword)\n );\n return ts.factory.createPropertySignature(undefined, e.name, undefined, eventType);\n }),\n ])\n );\n}\n/*\nGenerate a mock for view props and functions.\n*/\nfunction getMockedViews(viewDefinitions: OutputNestedClassDefinition[]) {\n return viewDefinitions.flatMap((definition) => {\n if (!definition) {\n return [];\n }\n const propsType = generatePropTypesForDefinition(definition);\n const props = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n 'props',\n undefined,\n ts.factory.createTypeReferenceNode('ViewProps', undefined),\n undefined\n );\n const viewFunction = ts.factory.createFunctionDeclaration(\n [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],\n undefined,\n // TODO: Handle this better once requireNativeViewManager accepts view name or a different solution for multiple views is built.\n viewDefinitions.length === 1 ? 'View' : definition.name,\n undefined,\n [props],\n undefined,\n ts.factory.createBlock([])\n );\n return [propsType, viewFunction];\n });\n}\n\nfunction getMockedClass(def: OutputNestedClassDefinition) {\n const classDecl = ts.factory.createClassDeclaration(\n [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],\n ts.factory.createIdentifier(def.name),\n undefined,\n undefined,\n [\n ...getMockedFunctions(def.functions, { classMethod: true }),\n ...getMockedFunctions(def.asyncFunctions, { async: true, classMethod: true }),\n ] as ts.MethodDeclaration[]\n );\n return classDecl;\n}\n\nfunction getMockedClasses(def: OutputNestedClassDefinition[]) {\n return def.map((d) => getMockedClass(d));\n}\n\nconst newlineIdentifier = ts.factory.createIdentifier('\\n\\n') as any;\nfunction separateWithNewlines(arr: T) {\n return [arr, newlineIdentifier];\n}\n\nfunction omitFromSet(set: Set, toOmit: (string | undefined)[]) {\n const newSet = new Set(set);\n toOmit.forEach((item) => {\n if (item) {\n newSet.delete(item);\n }\n });\n return newSet;\n}\n\nfunction getMockForModule(module: OutputModuleDefinition, includeTypes: boolean) {\n return (\n [] as (\n | ts.TypeAliasDeclaration\n | ts.FunctionDeclaration\n | ts.JSDoc\n | ts.ClassDeclaration\n | ts.VariableStatement\n )[]\n )\n .concat(\n getPrefix(),\n newlineIdentifier,\n includeTypes\n ? getMockedTypes(\n omitFromSet(\n new Set([\n ...getTypesToMock(module),\n ...new Set(...module.views.map((v) => getTypesToMock(v))),\n ...new Set(...module.classes.map((c) => getTypesToMock(c))),\n ]),\n // Ignore all types that are actually native classes\n [\n module.name,\n ...module.views.map((c) => c.name),\n ...module.classes.map((c) => c.name),\n ]\n )\n )\n : [],\n newlineIdentifier,\n getMockedConstants(module.constants),\n newlineIdentifier,\n getMockedFunctions(module.functions) as ts.FunctionDeclaration[],\n getMockedFunctions(module.asyncFunctions, { async: true }) as ts.FunctionDeclaration[],\n newlineIdentifier,\n getMockedViews(module.views),\n getMockedClasses(module.classes)\n )\n .flatMap(separateWithNewlines);\n}\n\nasync function prettifyCode(text: string, parser: 'babel' | 'typescript' = 'babel') {\n return await prettier.format(text, {\n parser,\n tabWidth: 2,\n printWidth: 100,\n trailingComma: 'none',\n singleQuote: true,\n });\n}\n\nexport async function generateMocks(\n modules: OutputModuleDefinition[],\n outputLanguage: 'javascript' | 'typescript' = 'javascript'\n) {\n const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });\n\n for (const m of modules) {\n const filename = m.name + (outputLanguage === 'javascript' ? '.js' : '.ts');\n const resultFile = ts.createSourceFile(\n filename,\n '',\n ts.ScriptTarget.Latest,\n false,\n ts.ScriptKind.TSX\n );\n fs.mkdirSync(path.join(directoryPath, 'mocks'), { recursive: true });\n const filePath = path.join(directoryPath, 'mocks', filename);\n // get ts nodearray from getMockForModule(m) array\n const mock = ts.factory.createNodeArray(getMockForModule(m, outputLanguage === 'typescript'));\n const printedTs = printer.printList(\n ts.ListFormat.MultiLine + ts.ListFormat.PreserveLines,\n mock,\n resultFile\n );\n\n if (outputLanguage === 'javascript') {\n const compiledJs = ts.transpileModule(printedTs, {\n compilerOptions: {\n module: ts.ModuleKind.ESNext,\n target: ts.ScriptTarget.ESNext,\n },\n }).outputText;\n const prettifiedJs = await prettifyCode(compiledJs);\n fs.writeFileSync(filePath, prettifiedJs);\n } else {\n const prettifiedTs = await prettifyCode(printedTs, 'typescript');\n fs.writeFileSync(filePath, prettifiedTs);\n }\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/types.d.ts.map b/packages/expo-modules-test-core/build/types.d.ts.map deleted file mode 100644 index f575e9f052e10d..00000000000000 --- a/packages/expo-modules-test-core/build/types.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,kBAAkB,EAAE,SAAS,EAAE,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0BAA0B,EAAE,MAAM,CAAC;IACnC,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,oBAAoB,EAAE;QACpB,oBAAoB,EAAE;YACpB,mCAAmC,EAAE,MAAM,CAAC;YAC5C,yBAAyB,EAAE,MAAM,CAAC;SACnC,EAAE,CAAC;QACJ,0BAA0B,EAAE,MAAM,CAAC;KACpC,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE;QACV,IAAI,EAAE,GAAG,CAAC;QACV,QAAQ,EAAE,GAAG,CAAC;KACf,EAAE,CAAC;IACJ,UAAU,EAAE,GAAG,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,2BAA2B,EAAE,CAAC;IACrC,OAAO,EAAE,2BAA2B,EAAE,CAAC;IACvC,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;KACd,EAAE,CAAC;IACJ,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB,GAAG,MAAM,CAAC,gBAAgB,GAAG,WAAW,GAAG,YAAY,EAAE,OAAO,EAAE,CAAC,GAClE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAG1B,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/types.js.map b/packages/expo-modules-test-core/build/types.js.map deleted file mode 100644 index c554722ad61839..00000000000000 --- a/packages/expo-modules-test-core/build/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type FileType = {\n path: string;\n content: string;\n};\n\nexport type Structure = {\n 'key.substructure': Structure[];\n 'key.typename': string;\n 'key.name': string;\n 'key.kind': string;\n 'key.offset': number;\n 'key.length': number;\n};\n\nexport type CursorInfoOutput = {\n 'key.fully_annotated_decl': string;\n 'key.annotated_decl': string;\n};\n\nexport type FullyAnnotatedDecl = {\n 'decl.function.free': {\n 'decl.var.parameter': {\n 'decl.var.parameter.argument_label': string;\n 'decl.var.parameter.type': string;\n }[];\n 'decl.function.returntype': string;\n };\n};\n\nexport type ClosureTypes = {\n parameters: {\n name: any;\n typename: any;\n }[];\n returnType: any;\n};\n\nexport type Closure = {\n name: string;\n types: ClosureTypes | null;\n};\n\nexport type Prop = {\n name: string;\n types: Omit;\n};\n\nexport type Constant = {\n name: string;\n types: ClosureTypes | null;\n};\n\nexport type OutputModuleDefinition = {\n name: string;\n views: OutputNestedClassDefinition[];\n classes: OutputNestedClassDefinition[];\n events: {\n name: string;\n }[];\n constants: Constant[];\n} & Record<'asyncFunctions' | 'functions' | 'properties', Closure[]> &\n Record<'props', Prop[]>;\n\n// views and classes are a very similar structure, same as module but without more nesting levels\nexport type OutputNestedClassDefinition = Omit;\n"]} \ No newline at end of file diff --git a/packages/expo-modules-test-core/package.json b/packages/expo-modules-test-core/package.json index 89d7b40fd4fb01..e7822ac4c88542 100644 --- a/packages/expo-modules-test-core/package.json +++ b/packages/expo-modules-test-core/package.json @@ -11,7 +11,10 @@ "expo-modules-test-core" ], "scripts": { - "build": "tsc" + "build": "tsc", + "test": "expo-module test", + "lint": "expo-module lint", + "clean": "expo-module clean" }, "bin": { "expo-modules-test-core": "./bin/cli.js" @@ -32,6 +35,7 @@ "glob": "^13.0.0", "prettier": "^3.0.3", "xml-js": "^1.6.11", - "yaml": "^2.8.3" + "yaml": "^2.8.3", + "expo-type-information": "^0.0.1" } } diff --git a/packages/expo-modules-test-core/src/getStructure.ts b/packages/expo-modules-test-core/src/getStructure.ts deleted file mode 100644 index 5e3be63458d9d9..00000000000000 --- a/packages/expo-modules-test-core/src/getStructure.ts +++ /dev/null @@ -1,299 +0,0 @@ -// convert requires above to imports -import { execSync } from 'child_process'; -import fsNode from 'fs'; -import { globSync } from 'glob'; -import XML from 'xml-js'; -import YAML from 'yaml'; - -import type { - Closure, - CursorInfoOutput, - FileType, - FullyAnnotatedDecl, - OutputModuleDefinition, - Structure, -} from './types'; - -const rootDir = process.cwd(); -const pattern = `${rootDir}/**/*.swift`; - -function getStructureFromFile(file: FileType) { - const command = 'sourcekitten structure --file ' + file.path; - - try { - const output = execSync(command); - return JSON.parse(output.toString()); - } catch (error) { - console.error('An error occurred while executing the command:', error); - } -} -// find an object with "key.typename" : "ModuleDefinition" somewhere in the structure and return it -function findModuleDefinitionInStructure(structure: Structure): Structure[] | null { - if (!structure) { - return null; - } - if (structure?.['key.typename'] === 'ModuleDefinition') { - const root = structure?.['key.substructure']; - if (!root) { - console.warn('Found ModuleDefinition but it is malformed'); - } - return root; - } - const substructure = structure['key.substructure']; - if (Array.isArray(substructure) && substructure.length > 0) { - for (const child of substructure) { - let result = null; - result = findModuleDefinitionInStructure(child); - if (result) { - return result; - } - } - } - return null; -} - -// Read string straight from file – needed since we can't get cursorinfo for modulename -function getIdentifierFromOffsetObject(offsetObject: Structure, file: FileType) { - // adding 1 and removing 1 to get rid of quotes - return file.content - .substring(offsetObject['key.offset'], offsetObject['key.offset'] + offsetObject['key.length']) - .replaceAll('"', ''); -} - -function maybeUnwrapXMLStructs(type: string | Partial<{ _text: string; 'ref.struct': string }>) { - if (!type) { - return type; - } - if (typeof type === 'string') { - return type; - } - if (type['_text']) { - return type['_text']; - } - if (type['ref.struct']) { - return maybeUnwrapXMLStructs(type['ref.struct']); - } - return type; -} - -function maybeWrapArray(itemOrItems: T[] | T | null) { - if (!itemOrItems) { - return null; - } - if (Array.isArray(itemOrItems)) { - return itemOrItems; - } else { - return [itemOrItems]; - } -} - -function parseXMLAnnotatedDeclarations(cursorInfoOutput: CursorInfoOutput) { - const xml = cursorInfoOutput['key.fully_annotated_decl']; - if (!xml) { - return null; - } - const parsed = XML.xml2js(xml, { compact: true }) as FullyAnnotatedDecl; - - const parameters = - maybeWrapArray(parsed?.['decl.function.free']?.['decl.var.parameter'])?.map((p) => ({ - name: maybeUnwrapXMLStructs(p['decl.var.parameter.argument_label']), - typename: maybeUnwrapXMLStructs(p['decl.var.parameter.type']), - })) ?? []; - const returnType = maybeUnwrapXMLStructs( - parsed?.['decl.function.free']?.['decl.function.returntype'] - ); - return { parameters, returnType }; -} - -let cachedSDKPath: string | null = null; -function getSDKPath() { - if (cachedSDKPath) { - return cachedSDKPath; - } - const sdkPath = execSync('xcrun --sdk iphoneos --show-sdk-path').toString().trim(); - cachedSDKPath = sdkPath; - return cachedSDKPath; -} - -// Read type description with sourcekitten, works only for variables -function getTypeFromOffsetObject(offsetObject: Structure, file: FileType) { - if (!offsetObject) { - return null; - } - const request = { - 'key.request': 'source.request.cursorinfo', - 'key.sourcefile': file.path, - 'key.offset': offsetObject['key.offset'], - 'key.compilerargs': [file.path, '-target', 'arm64-apple-ios', '-sdk', getSDKPath()], - }; - const yamlRequest = YAML.stringify(request, { - defaultStringType: 'QUOTE_DOUBLE', - lineWidth: 0, - defaultKeyType: 'PLAIN', - // needed since behaviour of sourcekitten is not consistent - } as any).replace('"source.request.cursorinfo"', 'source.request.cursorinfo'); - - const command = 'sourcekitten request --yaml "' + yamlRequest.replaceAll('"', '\\"') + '"'; - try { - const output = execSync(command, { stdio: 'pipe' }); - return parseXMLAnnotatedDeclarations(JSON.parse(output.toString())); - } catch (error) { - console.error('An error occurred while executing the command:', error); - } - return null; -} - -function hasSubstructure(structureObject: Structure) { - return structureObject?.['key.substructure'] && structureObject['key.substructure'].length > 0; -} - -function parseClosureTypes(structureObject: Structure) { - const closure = structureObject['key.substructure']?.find( - (s) => s['key.kind'] === 'source.lang.swift.expr.closure' - ); - if (!closure) { - return null; - } - const parameters = closure['key.substructure'] - ?.filter((s) => s['key.kind'] === 'source.lang.swift.decl.var.parameter') - .map((p) => ({ name: p['key.name'], typename: p['key.typename'] })); - - const returnType = closure?.['key.typename'] ?? 'unknown'; - return { parameters, returnType }; -} - -// Used for functions,async functions, all of shape Identifier(name, closure or function) -function findNamedDefinitionsOfType(type: string, moduleDefinition: Structure[], file: FileType) { - const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type); - - return definitionsOfType.reduce< - { name: string; types: ReturnType }[] - >((acc, d) => { - const definitionParams = d['key.substructure']; - - if (definitionParams[0] == null) { - return acc; - } - - const name = getIdentifierFromOffsetObject(definitionParams[0], file); - let types = null; - - if (definitionParams[1] == null) { - acc.push({ name, types }); - return acc; - } - - if (hasSubstructure(definitionParams[1])) { - types = parseClosureTypes(definitionParams[1]); - } else { - types = getTypeFromOffsetObject(definitionParams[1], file); - } - - acc.push({ name, types }); - return acc; - }, []); -} - -// Used for events -function findGroupedDefinitionsOfType(type: string, moduleDefinition: Structure[], file: FileType) { - const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type); - return definitionsOfType.flatMap((d) => { - const definitionParams = d['key.substructure']; - return definitionParams.map((d) => ({ name: getIdentifierFromOffsetObject(d, file) })); - }); -} -function findAndParseNestedClassesOfType( - moduleDefinition: Structure[], - file: FileType, - type: string -) { - // we support reading definitions from closure only - const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type); - return definitionsOfType - .map((df) => { - const nestedModuleDefinition = - df['key.substructure']?.[1]?.['key.substructure']?.[0]?.['key.substructure']?.[0]?.[ - 'key.substructure' - ]; - const nameStructure = df['key.substructure']?.[0]; - if (!nestedModuleDefinition || !nameStructure) { - console.warn('Could not parse definition'); - return null; - } - const name = getIdentifierFromOffsetObject(nameStructure, file).replace('.self', ''); - // let's drop nested view field and classes (are null anyways) - const { - views: _, - classes: _2, - ...definition - } = parseModuleDefinition(nestedModuleDefinition, file); - return { ...definition, name }; - }) - .flatMap((f) => (f ? [f] : [])); -} - -function omitParamsFromClosureArguments( - definitions: T[], - paramsToOmit: string[] -) { - return definitions.map((d) => ({ - ...d, - types: { - ...d.types, - parameters: d.types?.parameters?.filter((t, idx) => !paramsToOmit.includes(t.name)) ?? [], - }, - })); -} - -// Some blocks have additional modifiers like runOnQueue – we may need to do additional traversing to get to the function definition -function parseBlockModifiers(structureObject: Structure) { - if (structureObject['key.name']?.includes('runOnQueue')) { - const structure = structureObject['key.substructure'][0]; - if (structure != null) { - return structure; - } - } - return structureObject; -} - -function parseModuleDefinition( - moduleDefinition: Structure[], - file: FileType -): OutputModuleDefinition { - const preparedModuleDefinition = moduleDefinition.map(parseBlockModifiers); - const parsedDefinition = { - name: findNamedDefinitionsOfType('Name', preparedModuleDefinition, file)[0]?.name ?? '', - functions: findNamedDefinitionsOfType('Function', preparedModuleDefinition, file), - asyncFunctions: omitParamsFromClosureArguments( - findNamedDefinitionsOfType('AsyncFunction', preparedModuleDefinition, file), - ['promise'] - ), - events: findGroupedDefinitionsOfType('Events', preparedModuleDefinition, file), - properties: findNamedDefinitionsOfType('Property', preparedModuleDefinition, file), - props: omitParamsFromClosureArguments( - findNamedDefinitionsOfType('Prop', preparedModuleDefinition, file), - ['view'] - ), - constants: findNamedDefinitionsOfType('Constant', preparedModuleDefinition, file), - views: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'View'), - classes: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'Class'), - }; - return parsedDefinition; -} - -function findModuleDefinitionsInFiles(files: string[]) { - const modules = []; - for (const path of files) { - const file = { path, content: fsNode.readFileSync(path, 'utf8') }; - const definition = findModuleDefinitionInStructure(getStructureFromFile(file)); - if (definition) { - modules.push(parseModuleDefinition(definition, file)); - } - } - return modules; -} - -export function getAllExpoModulesInWorkingDirectory() { - const files = globSync(pattern); - return findModuleDefinitionsInFiles(files); -} diff --git a/packages/expo-modules-test-core/src/index.ts b/packages/expo-modules-test-core/src/index.ts index 302d3858674060..4c15ac8aac6be7 100644 --- a/packages/expo-modules-test-core/src/index.ts +++ b/packages/expo-modules-test-core/src/index.ts @@ -1,19 +1,21 @@ -import { getAllExpoModulesInWorkingDirectory } from './getStructure'; -import { generateMocks } from './mockgen'; - +import { generateMocks, getAllExpoModulesInWorkingDirectory } from 'expo-type-information'; const command = process.argv[2]; -if (command === 'generate-js-mocks') { - const modules = getAllExpoModulesInWorkingDirectory(); - generateMocks(modules); -} else if (command === 'generate-ts-mocks') { - const modules = getAllExpoModulesInWorkingDirectory(); - generateMocks(modules, 'typescript'); -} else if (command === 'get-mocks-structure') { - const modules = getAllExpoModulesInWorkingDirectory(); - console.log(JSON.stringify(modules, null, 2)); -} else { - console.log( - 'Command not recognized\n\nAvailable commands are:\n- generate-js-mocks\n- generate-ts-mocks\n- get-mocks-structure' - ); +async function main(args: string[]) { + if (command === 'generate-js-mocks') { + const modules = await getAllExpoModulesInWorkingDirectory(); + generateMocks(modules); + } else if (command === 'generate-ts-mocks') { + const modules = await getAllExpoModulesInWorkingDirectory(); + generateMocks(modules, 'typescript'); + } else if (command === 'get-mocks-structure') { + const modules = await getAllExpoModulesInWorkingDirectory(); + console.log(JSON.stringify(modules, null, 2)); + } else { + console.log( + 'Command not recognized\n\nAvailable commands are:\n- generate-js-mocks\n- generate-ts-mocks\n- get-mocks-structure' + ); + } } + +main(process.argv.slice(2)); diff --git a/packages/expo-modules-test-core/src/mockgen.ts b/packages/expo-modules-test-core/src/mockgen.ts deleted file mode 100644 index e0401b15795883..00000000000000 --- a/packages/expo-modules-test-core/src/mockgen.ts +++ /dev/null @@ -1,525 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -import fs from 'fs'; -import path from 'path'; -import * as prettier from 'prettier'; -import ts from 'typescript'; - -import { - Closure, - ClosureTypes, - Constant, - OutputModuleDefinition, - OutputNestedClassDefinition, -} from './types'; - -const directoryPath = process.cwd(); - -/* -We receive types from SourceKitten and `getStructure` like so (examples): -[AcceptedTypes]?, UIColor?, [String: Any] - -We need to parse them first to TS nodes in `mapSwiftTypeToTsType` with the following helper functions. -*/ - -function isSwiftArray(type: string) { - // This can also be an object, but we check that first, so if it's not an object and is wrapped with [] it's an array. - return type.startsWith('[') && type.endsWith(']'); -} -function maybeUnwrapSwiftArray(type: string) { - const isArray = isSwiftArray(type); - if (!isArray) { - return type; - } - const innerType = type.substring(1, type.length - 1); - return innerType; -} - -function isSwiftOptional(type: string) { - return type.endsWith('?'); -} -function maybeUnwrapSwiftOptional(type: string) { - const isOptional = isSwiftOptional(type); - if (!isOptional) { - return type; - } - const innerType = type.substring(0, type.length - 1); - return innerType; -} - -function isSwiftDictionary(type: string) { - return ( - type.startsWith('[') && - type.endsWith(']') && - findRootColonInDictionary(type.substring(1, type.length - 1)) >= 0 - ); -} - -function isEither(type: string) { - return type.startsWith('Either<'); -} -// "Either" -> ["TypeOne", "TypeTwo"] -function maybeUnwrapEither(type: string): string[] { - if (!isEither(type)) { - return [type]; - } - const innerType = type.substring(7, type.length - 1); - return innerType.split(',').map((t) => t.trim()); -} - -/* -The Swift object type can have nested objects as the type of it's values (or maybe even keys). -[String: [String: Any]] - -We can't use regex to find the root colon, so this is the safest way – by counting brackets. -*/ -function findRootColonInDictionary(type: string) { - let colonIndex = -1; - let openBracketsCount = 0; - for (let i = 0; i < type.length; i++) { - if (type[i] === '[') { - openBracketsCount++; - } else if (type[i] === ']') { - openBracketsCount--; - } else if (type[i] === ':' && openBracketsCount === 0) { - colonIndex = i; - break; - } - } - return colonIndex; -} -function unwrapSwiftDictionary(type: string) { - const innerType = type.substring(1, type.length - 1); - const colonPosition = findRootColonInDictionary(innerType); - return { - key: innerType.slice(0, colonPosition).trim(), - value: innerType.slice(colonPosition + 1).trim(), - }; -} - -type TSNode = - | ts.UnionTypeNode - | ts.KeywordTypeNode - | ts.TypeReferenceNode - | ts.ArrayTypeNode - | ts.OptionalTypeNode - | ts.TypeLiteralNode; - -/* -Main function that converts a string representation of a Swift type to a TypeScript compiler API node AST. -We can pass those types straight to a TypeScript printer (a function that converts AST to text). -*/ -function mapSwiftTypeToTsType(type: string): TSNode { - if (!type) { - return ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword); - } - if (isSwiftOptional(type)) { - return ts.factory.createUnionTypeNode([ - mapSwiftTypeToTsType(maybeUnwrapSwiftOptional(type)), - ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword), - ]); - } - if (isSwiftDictionary(type)) { - const { key, value } = unwrapSwiftDictionary(type); - const keyType = mapSwiftTypeToTsType(key); - const valueType = mapSwiftTypeToTsType(value); - - const indexSignature = ts.factory.createIndexSignature( - undefined, - [ts.factory.createParameterDeclaration(undefined, undefined, 'key', undefined, keyType)], - valueType - ); - - const typeLiteralNode = ts.factory.createTypeLiteralNode([indexSignature]); - return typeLiteralNode; - } - if (isSwiftArray(type)) { - return ts.factory.createArrayTypeNode(mapSwiftTypeToTsType(maybeUnwrapSwiftArray(type))); - } - // Custom handling for the Either convertible - if (isEither(type)) { - return ts.factory.createUnionTypeNode( - maybeUnwrapEither(type).map((t) => mapSwiftTypeToTsType(t)) - ); - } - - switch (type) { - // Our custom representation for types that we have no type hints for. Not necessairly Swift any. - case 'unknown': - return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); - case 'String': - return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); - case 'Bool': - return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword); - case 'Int': - case 'Float': - case 'Double': - return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); - case 'Any': // Swift Any type - return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); - default: // Custom Swift type (record) – for now mapped to a custom TS type exported at the top of the file by `getMockedTypes`. - return ts.factory.createTypeReferenceNode(type); - } -} - -// Mocks require sample return values, so we generate them based on TS AST. -function getMockLiterals(tsReturnType: TSNode) { - if (!tsReturnType) { - return undefined; - } - switch (tsReturnType.kind) { - case ts.SyntaxKind.AnyKeyword: - case ts.SyntaxKind.VoidKeyword: - return undefined; - case ts.SyntaxKind.UnionType: - // we take the first element of our union for the mock – we know the cast is correct since we create the type ourselves - // the second is `undefined` for optionals. - return getMockLiterals(tsReturnType.types[0] as TSNode); - case ts.SyntaxKind.StringKeyword: - return ts.factory.createStringLiteral(''); - case ts.SyntaxKind.BooleanKeyword: - return ts.factory.createFalse(); - case ts.SyntaxKind.NumberKeyword: - return ts.factory.createNumericLiteral('0'); - case ts.SyntaxKind.ArrayType: - return ts.factory.createArrayLiteralExpression(); - case ts.SyntaxKind.TypeLiteral: - // handles a dictionary, could be improved by creating an object fitting the schema instead of an empty one - return ts.factory.createObjectLiteralExpression([], false); - } - return undefined; -} - -function wrapWithAsync(tsType: ts.TypeNode) { - return ts.factory.createTypeReferenceNode('Promise', [tsType]); -} - -function maybeWrapWithReturnStatement(tsType: TSNode) { - if (tsType.kind === ts.SyntaxKind.AnyKeyword || tsType.kind === ts.SyntaxKind.VoidKeyword) { - return []; - } - if (tsType.kind === ts.SyntaxKind.TypeReference) { - // A fallback – we print a comment that these mocks are not fitting the custom type. Could be improved by expanding a set of default mocks. - return [ - ts.addSyntheticTrailingComment( - ts.factory.createReturnStatement(ts.factory.createNull()), - ts.SyntaxKind.SingleLineCommentTrivia, - ` TODO: Replace with mock for value of type ${ - ((tsType as any)?.typeName as any)?.escapedText ?? '' - }.` - ), - ]; - } - return [ts.factory.createReturnStatement(getMockLiterals(tsType))]; -} - -/* -We iterate over a list of functions and we create TS AST for each of them. -*/ -function getMockedFunctions(functions: Closure[], { async = false, classMethod = false } = {}) { - return functions.map((fnStructure) => { - const name = ts.factory.createIdentifier(fnStructure.name); - const returnType = mapSwiftTypeToTsType(fnStructure.types?.returnType); - const parameters = - fnStructure?.types?.parameters.map((p) => - ts.factory.createParameterDeclaration( - undefined, - undefined, - p.name ?? '_', - undefined, - mapSwiftTypeToTsType(p.typename), - undefined - ) - ) ?? []; - const returnBlock = ts.factory.createBlock(maybeWrapWithReturnStatement(returnType), true); - - if (classMethod) { - return ts.factory.createMethodDeclaration( - [async ? ts.factory.createToken(ts.SyntaxKind.AsyncKeyword) : undefined].flatMap((f) => - f ? [f] : [] - ), - undefined, - name, - undefined, - undefined, - parameters, - async ? wrapWithAsync(returnType) : returnType, - returnBlock - ); - } - const func = ts.factory.createFunctionDeclaration( - [ - ts.factory.createToken(ts.SyntaxKind.ExportKeyword), - async ? ts.factory.createToken(ts.SyntaxKind.AsyncKeyword) : undefined, - ].flatMap((f) => (f ? [f] : [])), - undefined, - name, - undefined, - parameters, - async ? wrapWithAsync(returnType) : returnType, - returnBlock - ); - return func; - }); -} - -/* -We iterate over a list of constants and create TS AST for each of them. -Constants are exported as `export const NAME = value;` -*/ -function getMockedConstants(constants: Constant[]) { - return constants.map((constant) => { - const name = ts.factory.createIdentifier(constant.name); - const returnType = mapSwiftTypeToTsType(constant.types?.returnType ?? 'unknown'); - const initializer = getMockLiterals(returnType) ?? ts.factory.createNumericLiteral('0'); - - return ts.factory.createVariableStatement( - [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], - ts.factory.createVariableDeclarationList( - [ts.factory.createVariableDeclaration(name, undefined, undefined, initializer)], - ts.NodeFlags.Const - ) - ); - }); -} - -/** - * Collect all type references used in any of the AST types to generate type aliases - * e.g. type `[URL: string]?` will generate `type URL = any;` - */ -function getAllTypeReferences(node: ts.Node, accumulator: string[]) { - if (ts.isTypeReferenceNode(node)) { - accumulator.push((node.typeName as any)?.escapedText); - } - node.forEachChild((n) => getAllTypeReferences(n, accumulator)); -} - -/** - * Iterates over types to collect the aliases. - */ -function getTypesToMock(module: OutputModuleDefinition | OutputNestedClassDefinition) { - const foundTypes: string[] = []; - - Object.values(module) - .flatMap((t) => (Array.isArray(t) ? t.map((t2) => (t2 as Closure)?.types) : [])) - .forEach((types: ClosureTypes | null) => { - types?.parameters.forEach(({ typename }) => { - getAllTypeReferences(mapSwiftTypeToTsType(typename), foundTypes); - }); - types?.returnType && - getAllTypeReferences(mapSwiftTypeToTsType(types?.returnType), foundTypes); - }); - return new Set(foundTypes); -} - -/** - * Gets a mock for a custom type. - */ -function getMockedTypes(types: Set) { - return Array.from(types).map((type) => { - const name = ts.factory.createIdentifier(type); - const typeAlias = ts.factory.createTypeAliasDeclaration( - [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], - name, - undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ); - return typeAlias; - }); -} - -const prefix = `Automatically generated by expo-modules-test-core. - -This autogenerated file provides a mock for native Expo module, -and works out of the box with the expo jest preset. -`; -function getPrefix() { - return [ts.factory.createJSDocComment(prefix)]; -} - -function generatePropTypesForDefinition(definition: OutputNestedClassDefinition) { - return ts.factory.createTypeAliasDeclaration( - [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], - 'ViewProps', - undefined, - ts.factory.createTypeLiteralNode([ - ...definition.props.map((p) => { - const propType = mapSwiftTypeToTsType(p.types.parameters[0]?.typename ?? ''); - return ts.factory.createPropertySignature(undefined, p.name, undefined, propType); - }), - ...definition.events.map((e) => { - const eventType = ts.factory.createFunctionTypeNode( - undefined, - [ - ts.factory.createParameterDeclaration( - undefined, - undefined, - 'event', - undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ), - ], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword) - ); - return ts.factory.createPropertySignature(undefined, e.name, undefined, eventType); - }), - ]) - ); -} -/* -Generate a mock for view props and functions. -*/ -function getMockedViews(viewDefinitions: OutputNestedClassDefinition[]) { - return viewDefinitions.flatMap((definition) => { - if (!definition) { - return []; - } - const propsType = generatePropTypesForDefinition(definition); - const props = ts.factory.createParameterDeclaration( - undefined, - undefined, - 'props', - undefined, - ts.factory.createTypeReferenceNode('ViewProps', undefined), - undefined - ); - const viewFunction = ts.factory.createFunctionDeclaration( - [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], - undefined, - // TODO: Handle this better once requireNativeViewManager accepts view name or a different solution for multiple views is built. - viewDefinitions.length === 1 ? 'View' : definition.name, - undefined, - [props], - undefined, - ts.factory.createBlock([]) - ); - return [propsType, viewFunction]; - }); -} - -function getMockedClass(def: OutputNestedClassDefinition) { - const classDecl = ts.factory.createClassDeclaration( - [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], - ts.factory.createIdentifier(def.name), - undefined, - undefined, - [ - ...getMockedFunctions(def.functions, { classMethod: true }), - ...getMockedFunctions(def.asyncFunctions, { async: true, classMethod: true }), - ] as ts.MethodDeclaration[] - ); - return classDecl; -} - -function getMockedClasses(def: OutputNestedClassDefinition[]) { - return def.map((d) => getMockedClass(d)); -} - -const newlineIdentifier = ts.factory.createIdentifier('\n\n') as any; -function separateWithNewlines(arr: T) { - return [arr, newlineIdentifier]; -} - -function omitFromSet(set: Set, toOmit: (string | undefined)[]) { - const newSet = new Set(set); - toOmit.forEach((item) => { - if (item) { - newSet.delete(item); - } - }); - return newSet; -} - -function getMockForModule(module: OutputModuleDefinition, includeTypes: boolean) { - return ( - [] as ( - | ts.TypeAliasDeclaration - | ts.FunctionDeclaration - | ts.JSDoc - | ts.ClassDeclaration - | ts.VariableStatement - )[] - ) - .concat( - getPrefix(), - newlineIdentifier, - includeTypes - ? getMockedTypes( - omitFromSet( - new Set([ - ...getTypesToMock(module), - ...new Set(...module.views.map((v) => getTypesToMock(v))), - ...new Set(...module.classes.map((c) => getTypesToMock(c))), - ]), - // Ignore all types that are actually native classes - [ - module.name, - ...module.views.map((c) => c.name), - ...module.classes.map((c) => c.name), - ] - ) - ) - : [], - newlineIdentifier, - getMockedConstants(module.constants), - newlineIdentifier, - getMockedFunctions(module.functions) as ts.FunctionDeclaration[], - getMockedFunctions(module.asyncFunctions, { async: true }) as ts.FunctionDeclaration[], - newlineIdentifier, - getMockedViews(module.views), - getMockedClasses(module.classes) - ) - .flatMap(separateWithNewlines); -} - -async function prettifyCode(text: string, parser: 'babel' | 'typescript' = 'babel') { - return await prettier.format(text, { - parser, - tabWidth: 2, - printWidth: 100, - trailingComma: 'none', - singleQuote: true, - }); -} - -export async function generateMocks( - modules: OutputModuleDefinition[], - outputLanguage: 'javascript' | 'typescript' = 'javascript' -) { - const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); - - for (const m of modules) { - const filename = m.name + (outputLanguage === 'javascript' ? '.js' : '.ts'); - const resultFile = ts.createSourceFile( - filename, - '', - ts.ScriptTarget.Latest, - false, - ts.ScriptKind.TSX - ); - fs.mkdirSync(path.join(directoryPath, 'mocks'), { recursive: true }); - const filePath = path.join(directoryPath, 'mocks', filename); - // get ts nodearray from getMockForModule(m) array - const mock = ts.factory.createNodeArray(getMockForModule(m, outputLanguage === 'typescript')); - const printedTs = printer.printList( - ts.ListFormat.MultiLine + ts.ListFormat.PreserveLines, - mock, - resultFile - ); - - if (outputLanguage === 'javascript') { - const compiledJs = ts.transpileModule(printedTs, { - compilerOptions: { - module: ts.ModuleKind.ESNext, - target: ts.ScriptTarget.ESNext, - }, - }).outputText; - const prettifiedJs = await prettifyCode(compiledJs); - fs.writeFileSync(filePath, prettifiedJs); - } else { - const prettifiedTs = await prettifyCode(printedTs, 'typescript'); - fs.writeFileSync(filePath, prettifiedTs); - } - } -} diff --git a/packages/expo-type-information/README.md b/packages/expo-type-information/README.md new file mode 100644 index 00000000000000..a3f559f0664d1e --- /dev/null +++ b/packages/expo-type-information/README.md @@ -0,0 +1 @@ +# expo-type-information diff --git a/packages/expo-type-information/bin/cli.js b/packages/expo-type-information/bin/cli.js new file mode 100755 index 00000000000000..3e2b84f95ab0d5 --- /dev/null +++ b/packages/expo-type-information/bin/cli.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../build/cli.js') diff --git a/packages/expo-type-information/build/cli.d.ts b/packages/expo-type-information/build/cli.d.ts new file mode 100644 index 00000000000000..cb0ff5c3b541f6 --- /dev/null +++ b/packages/expo-type-information/build/cli.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/expo-type-information/build/cli.js b/packages/expo-type-information/build/cli.js new file mode 100644 index 00000000000000..7d9042d8a31d1e --- /dev/null +++ b/packages/expo-type-information/build/cli.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const commander_1 = require("commander"); +const commandUtils_1 = require("./commands/commandUtils"); +const generateJSXIntrinsicsCommand_1 = require("./commands/generateJSXIntrinsicsCommand"); +const generateMocksForFileCommand_1 = require("./commands/generateMocksForFileCommand"); +const generateModuleTypesCommand_1 = require("./commands/generateModuleTypesCommand"); +const generateViewTypesCommand_1 = require("./commands/generateViewTypesCommand"); +const inlineModulesInterfaceCommand_1 = require("./commands/inlineModulesInterfaceCommand"); +const moduleInterfaceCommand_1 = require("./commands/moduleInterfaceCommand"); +const shortModuleInterfaceCommand_1 = require("./commands/shortModuleInterfaceCommand"); +const typeInformationCommand_1 = require("./commands/typeInformationCommand"); +async function main(args) { + if (!(0, commandUtils_1.isSourceKittenInstalled)()) { + console.error('Sourcekitten not found! Install it like so: brew install sourcekitten'); + return; + } + const cli = new commander_1.Command(); + cli + .name('expo-type-information') + .version(require('../package.json').version) + .description('CLI commands for retrieving type information from native files.'); + (0, moduleInterfaceCommand_1.moduleInterfaceCommand)(cli); + (0, inlineModulesInterfaceCommand_1.inlineModulesInterfaceCommand)(cli); + (0, shortModuleInterfaceCommand_1.shortModuleInterfaceCommand)(cli); + (0, generateMocksForFileCommand_1.generateMocksForFileCommand)(cli); + const otherCommands = cli.command('other').description('internal or very specific commands'); + (0, typeInformationCommand_1.typeInformationCommand)(otherCommands); + (0, generateModuleTypesCommand_1.generateModuleTypesCommand)(otherCommands); + (0, generateViewTypesCommand_1.generateViewTypesCommand)(otherCommands); + (0, generateJSXIntrinsicsCommand_1.generateJsxIntrinsics)(otherCommands); + await cli.parseAsync(args, { from: 'user' }); +} +main(process.argv.slice(2)); +//# sourceMappingURL=cli.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/cli.js.map b/packages/expo-type-information/build/cli.js.map new file mode 100644 index 00000000000000..e17661d964aa89 --- /dev/null +++ b/packages/expo-type-information/build/cli.js.map @@ -0,0 +1 @@ +{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AAAA,yCAAoC;AAEpC,0DAAkE;AAClE,0FAAgF;AAChF,wFAAqF;AACrF,sFAAmF;AACnF,kFAA+E;AAC/E,4FAAyF;AACzF,8EAA2E;AAC3E,wFAAqF;AACrF,8EAA2E;AAE3E,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,IAAI,CAAC,IAAA,sCAAuB,GAAE,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;QACvF,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,mBAAO,EAAE,CAAC;IAC1B,GAAG;SACA,IAAI,CAAC,uBAAuB,CAAC;SAC7B,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC;SAC3C,WAAW,CAAC,iEAAiE,CAAC,CAAC;IAElF,IAAA,+CAAsB,EAAC,GAAG,CAAC,CAAC;IAC5B,IAAA,6DAA6B,EAAC,GAAG,CAAC,CAAC;IACnC,IAAA,yDAA2B,EAAC,GAAG,CAAC,CAAC;IACjC,IAAA,yDAA2B,EAAC,GAAG,CAAC,CAAC;IAEjC,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC;IAC7F,IAAA,+CAAsB,EAAC,aAAa,CAAC,CAAC;IACtC,IAAA,uDAA0B,EAAC,aAAa,CAAC,CAAC;IAC1C,IAAA,mDAAwB,EAAC,aAAa,CAAC,CAAC;IACxC,IAAA,oDAAqB,EAAC,aAAa,CAAC,CAAC;IAErC,MAAM,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/commandUtils.d.ts b/packages/expo-type-information/build/commands/commandUtils.d.ts new file mode 100644 index 00000000000000..5ea757ec56cfbe --- /dev/null +++ b/packages/expo-type-information/build/commands/commandUtils.d.ts @@ -0,0 +1,46 @@ +import commander from 'commander'; +import { FileTypeInformation, TypeInferenceOption } from '../typeInformation'; +export type TypeInformationCommandCommonAllArguments = { + inputPaths?: string[]; + modulePath?: string; + outputPath?: string; + typeInference?: 'NO_INFERENCE' | 'SIMPLE_INFERENCE' | 'PREPROCESS_AND_INFERENCE'; + watcher?: boolean; + appJson?: string; +}; +export declare function isSourceKittenInstalled(): boolean; +export interface ParsedArguments { + realInputPaths: string[]; + realOutputPath?: string; + typeInference: TypeInferenceOption; + watcher: boolean; + appJsonPath?: string; +} +export declare function addCommonOptions(command: commander.Command): commander.Command; +/** + * Debounce a function to only run once after a period of inactivity + * If called while waiting, it will reset the timer + */ +export declare function debounce any>(fn: T, timeout?: number): (...args: Parameters) => void; +export declare function runCommandOnWatch(parsedArgs: ParsedArguments, command: () => Promise): Promise; +export declare function getFilesForGlobPattern(globPattern: string): string[] | null; +export declare function sanitizeAndValidateOutputPath(rawPath: string, isFilePath?: boolean): string | null; +export declare function parseInferenceOption(option?: string): TypeInferenceOption | null; +export declare function getPodspecFilePath(modulePath: string): string | null; +export declare function getSourceFilesGlobFromPodspecFile(podspecPath: string): string | null; +export declare function getModuleFilePathsFromPodspec(modulePath: string): string[] | null; +export declare function uniqueStrings(strings: string[]): string[]; +export declare function parseCommandArguments(options: TypeInformationCommandCommonAllArguments, isOutputFile?: boolean): ParsedArguments | null; +export declare function getFileTypeInformationFromArgs({ realInputPaths, typeInference, }: { + realInputPaths: string[]; + typeInference: TypeInferenceOption; +}): Promise; +export declare function writeStringToFileOrPrintToConsole(text: string, realOutputPath: string | undefined): void; +export declare function getContentHash(content: string): string; +export declare function contentHasChanged(fileContent: string): boolean; +export declare function insertFileHashComment(fileContent: string): string; +export declare function writeToStableFile({ filePath, content, }: { + filePath: string; + content: string; +}): Promise; +export declare function generateConciseTsFiles(parsedArgs: ParsedArguments): Promise; diff --git a/packages/expo-type-information/build/commands/commandUtils.js b/packages/expo-type-information/build/commands/commandUtils.js new file mode 100644 index 00000000000000..5639bf419ed710 --- /dev/null +++ b/packages/expo-type-information/build/commands/commandUtils.js @@ -0,0 +1,274 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isSourceKittenInstalled = isSourceKittenInstalled; +exports.addCommonOptions = addCommonOptions; +exports.debounce = debounce; +exports.runCommandOnWatch = runCommandOnWatch; +exports.getFilesForGlobPattern = getFilesForGlobPattern; +exports.sanitizeAndValidateOutputPath = sanitizeAndValidateOutputPath; +exports.parseInferenceOption = parseInferenceOption; +exports.getPodspecFilePath = getPodspecFilePath; +exports.getSourceFilesGlobFromPodspecFile = getSourceFilesGlobFromPodspecFile; +exports.getModuleFilePathsFromPodspec = getModuleFilePathsFromPodspec; +exports.uniqueStrings = uniqueStrings; +exports.parseCommandArguments = parseCommandArguments; +exports.getFileTypeInformationFromArgs = getFileTypeInformationFromArgs; +exports.writeStringToFileOrPrintToConsole = writeStringToFileOrPrintToConsole; +exports.getContentHash = getContentHash; +exports.contentHasChanged = contentHasChanged; +exports.insertFileHashComment = insertFileHashComment; +exports.writeToStableFile = writeToStableFile; +exports.generateConciseTsFiles = generateConciseTsFiles; +const chalk_1 = __importDefault(require("chalk")); +const child_process_1 = require("child_process"); +const crypto_1 = require("crypto"); +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const typeInformation_1 = require("../typeInformation"); +const typescriptGeneration_1 = require("../typescriptGeneration"); +const utils_1 = require("../utils"); +let sourcekittenInstalled; +function isSourceKittenInstalled() { + if (sourcekittenInstalled !== undefined) { + return sourcekittenInstalled; + } + try { + (0, child_process_1.execSync)('which sourcekitten', { stdio: 'ignore' }); + sourcekittenInstalled = true; + } + catch { + sourcekittenInstalled = false; + } + return sourcekittenInstalled; +} +function addCommonOptions(command) { + return command + .option('-i, --input-paths ', 'Paths to Swift files for some module, glob patterns are allowed.') + .option('-m --module-path ', 'Path to expo module root directory.') + .option('-o, --output-path ', 'Path to save the generated output. If this option is not provided the generated output is printed to console.') + .option('-t, --type-inference ', + // TODO(@HubertBer) Fix the PREPROCESS_AND_INFERENCE option. + 'Level of type inference: NO_INFERENCE, SIMPLE_INFERENCE, or PREPROCESS_AND_INFERENCE. Note that the last option rarely fails for some modules, use the 2nd or 1st in that case.', 'SIMPLE_INFERENCE') + .option('-w --watcher', 'Starts a watcher that checks for changes in input-path file.'); +} +/** + * Debounce a function to only run once after a period of inactivity + * If called while waiting, it will reset the timer + */ +function debounce(fn, timeout = 500) { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => { + fn(...args); + }, timeout); + }; +} +async function runCommandOnWatch(parsedArgs, command) { + const debounced_command = debounce(command, 1000); + debounced_command(); + if (!parsedArgs.watcher) { + return; + } + await (0, utils_1.taskAll)(parsedArgs.realInputPaths, async (realInputPath) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for await (const _ of fs_1.default.promises.watch(realInputPath)) { + if (!fs_1.default.existsSync(realInputPath)) { + return; + } + debounced_command(); + } + }); +} +function getFilesForGlobPattern(globPattern) { + try { + const normalizedPattern = globPattern.replace(/\\/g, '/'); + const matches = fs_1.default.globSync(normalizedPattern, { + withFileTypes: true, + }); + const resolvedPaths = matches + .filter((entry) => entry.isFile()) + .map((entry) => path_1.default.resolve(entry.parentPath, entry.name)); + return resolvedPaths.length > 0 ? resolvedPaths : null; + } + catch { + return null; + } +} +function sanitizeAndValidateOutputPath(rawPath, isFilePath = true) { + try { + const resolvedPath = path_1.default.resolve(rawPath); + if (fs_1.default.existsSync(resolvedPath)) { + const pathStat = fs_1.default.statSync(resolvedPath); + const isValid = isFilePath ? pathStat.isFile() : pathStat.isDirectory(); + return isValid ? resolvedPath : null; + } + if (isFilePath && fs_1.default.existsSync(path_1.default.dirname(resolvedPath))) { + return resolvedPath; + } + } + catch { } + return null; +} +function parseInferenceOption(option) { + if (!option) + return typeInformation_1.TypeInferenceOption.PREPROCESS_AND_INFERENCE; + switch (option) { + case 'NO_INFERENCE': + return typeInformation_1.TypeInferenceOption.NO_INFERENCE; + case 'SIMPLE_INFERENCE': + return typeInformation_1.TypeInferenceOption.SIMPLE_INFERENCE; + case 'PREPROCESS_AND_INFERENCE': + return typeInformation_1.TypeInferenceOption.PREPROCESS_AND_INFERENCE; + } + return null; +} +function getPodspecFilePath(modulePath) { + const normalizedModulePath = fs_1.default.realpathSync(modulePath).replace(/\\/g, '/'); + const podspecFiles = [...fs_1.default.globSync(`${normalizedModulePath}/ios/*.podspec`)]; + const podspecFile = podspecFiles[0]; + return podspecFile ?? null; +} +function getSourceFilesGlobFromPodspecFile(podspecPath) { + const podspecContent = fs_1.default.readFileSync(podspecPath, 'utf8'); + const sourceFilesRegex = /\.source_files\s*=\s*(["'])(.*?)\1/; + const match = podspecContent.match(sourceFilesRegex); + return match?.[2] ?? null; +} +function getModuleFilePathsFromPodspec(modulePath) { + const podspecPath = getPodspecFilePath(modulePath); + if (!podspecPath) { + console.warn(`No .podspec found in ${modulePath}`); + return null; + } + const extractedGlob = getSourceFilesGlobFromPodspecFile(podspecPath); + if (!extractedGlob) { + console.warn(`Could not extract source_files glob from ${podspecPath}`); + return null; + } + const podspecDir = path_1.default.dirname(podspecPath); + const absoluteGlobPattern = path_1.default.posix.join(podspecDir.replace(/\\/g, '/'), extractedGlob); + return getFilesForGlobPattern(absoluteGlobPattern)?.filter((f) => f.endsWith('.swift')) ?? null; +} +function uniqueStrings(strings) { + return [...new Set(strings)]; +} +function parseCommandArguments(options, isOutputFile = true) { + const appJsonPath = options.appJson ?? undefined; + let realInputPaths = (options.inputPaths ?? []) + .flatMap(getFilesForGlobPattern) + .filter((p) => p != null); + if (options.modulePath) { + const modulePaths = getModuleFilePathsFromPodspec(options.modulePath) ?? []; + realInputPaths.push(...modulePaths); + } + realInputPaths = uniqueStrings(realInputPaths); + if ((!realInputPaths || realInputPaths.length === 0) && !appJsonPath) { + console.error(`Provide valid globs to existing files or a path to a module with valid podspec.`); + return null; + } + let realOutputPath = undefined; + if (options.outputPath) { + const validatedOutPath = sanitizeAndValidateOutputPath(options.outputPath, isOutputFile); + if (!validatedOutPath) { + console.error(`Output path ${options.outputPath} is not valid. ${isOutputFile ? 'Provide a path to an existing file, or to a file in an existing parent directory.' : 'Provide a path to an existing directory.'}`); + return null; + } + realOutputPath = validatedOutPath; + } + else if (options.modulePath) { + // if path to module directory is provided, we can generate ts types under src directory + realOutputPath = + sanitizeAndValidateOutputPath(path_1.default.join(options.modulePath, 'src'), false) ?? undefined; + } + const typeInference = parseInferenceOption(options.typeInference); + if (typeInference === null) { + console.error(`Invalid typeInference option. ${options.typeInference}`); + return null; + } + const watcher = options.watcher ?? false; + return { realInputPaths, realOutputPath, typeInference, watcher, appJsonPath }; +} +async function getFileTypeInformationFromArgs({ realInputPaths, typeInference, }) { + const typeInfo = await (0, typeInformation_1.getFileTypeInformation)({ + input: { type: 'file', inputFileAbsolutePaths: realInputPaths }, + typeInference, + }); + if (!typeInfo) { + console.error(chalk_1.default.red(`Provided files: ${realInputPaths} couldn't be parsed for type information!`)); + return null; + } + return typeInfo; +} +function writeStringToFileOrPrintToConsole(text, realOutputPath) { + if (realOutputPath) { + fs_1.default.writeFileSync(realOutputPath, text, { flag: 'w', encoding: 'utf-8' }); + return; + } + console.log(text); +} +function getContentHash(content) { + return (0, crypto_1.createHash)('sha256').update(content).digest('hex'); +} +function contentHasChanged(fileContent) { + const hashRegex = /^\/\/ File hash: ([a-f0-9]{64})\r?\n/; + const match = fileContent.match(hashRegex); + if (!match) { + return true; + } + const storedHash = match[1]; + const originalContent = fileContent.slice(match[0].length); + const calculatedHash = getContentHash(originalContent); + return storedHash !== calculatedHash; +} +function insertFileHashComment(fileContent) { + const hashString = getContentHash(fileContent); + return `// File hash: ${hashString} +${fileContent}`; +} +async function writeToStableFile({ filePath, content, }) { + let flag = 'wx'; + if (fs_1.default.existsSync(filePath) && + !contentHasChanged(await fs_1.default.promises.readFile(filePath, 'utf-8'))) { + // Overwrite the file if it wasn't changed since the last generation + flag = 'w'; + } + try { + await fs_1.default.promises.writeFile(filePath, insertFileHashComment(content), { + flag, + encoding: 'utf-8', + }); + } + catch (e) { + console.error('Error writing to a file.', e); + } +} +async function generateConciseTsFiles(parsedArgs) { + const { realInputPaths, realOutputPath } = parsedArgs; + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + const { volatileGeneratedFileContent, moduleTypescriptInterfaceFileContent } = await (0, typescriptGeneration_1.generateConciseTsInterface)(typeInfo); + const moduleName = typeInfo.moduleClasses[0]?.name ?? 'UnknownModuleName'; + const dirName = realOutputPath ?? path_1.default.dirname(realInputPaths[0]); + try { + await Promise.all([ + fs_1.default.promises.writeFile(path_1.default.resolve(dirName, `${moduleName}.generated.ts`), volatileGeneratedFileContent, { + flag: 'w', + encoding: 'utf-8', + }), + writeToStableFile({ + filePath: path_1.default.resolve(dirName, `${moduleName}.tsx`), + content: moduleTypescriptInterfaceFileContent, + }), + ]); + } + catch (e) { + console.error(`Error writing to a file.`, e); + } +} +//# sourceMappingURL=commandUtils.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/commandUtils.js.map b/packages/expo-type-information/build/commands/commandUtils.js.map new file mode 100644 index 00000000000000..caa3df40be71a2 --- /dev/null +++ b/packages/expo-type-information/build/commands/commandUtils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"commandUtils.js","sourceRoot":"","sources":["../../src/commands/commandUtils.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.d.ts b/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.d.ts new file mode 100644 index 00000000000000..93da5f2bfeacfa --- /dev/null +++ b/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function generateJsxIntrinsics(cli: commander.Command): commander.Command; diff --git a/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js b/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js new file mode 100644 index 00000000000000..ef4fd42770bc62 --- /dev/null +++ b/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateJsxIntrinsics = generateJsxIntrinsics; +const commandUtils_1 = require("./commandUtils"); +const typescriptGeneration_1 = require("../typescriptGeneration"); +function generateJsxIntrinsics(cli) { + return (0, commandUtils_1.addCommonOptions)(cli.command('generate-jsx-intrinsics')).action(async (options) => { + const parsedArgs = await (0, commandUtils_1.parseCommandArguments)(options); + if (!parsedArgs) { + return; + } + const { realOutputPath } = parsedArgs; + const command = async () => { + const typeInfo = await (0, commandUtils_1.getFileTypeInformationFromArgs)(parsedArgs); + if (!typeInfo) { + return; + } + const jsxIntrinsicViewFileContent = await (0, typescriptGeneration_1.generateJSXIntrinsicsFileContent)(typeInfo); + if (!jsxIntrinsicViewFileContent) { + console.error("Couldn't generate view types!"); + return; + } + (0, commandUtils_1.writeStringToFileOrPrintToConsole)(jsxIntrinsicViewFileContent, realOutputPath); + }; + (0, commandUtils_1.runCommandOnWatch)(parsedArgs, command); + }); +} +//# sourceMappingURL=generateJSXIntrinsicsCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js.map b/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js.map new file mode 100644 index 00000000000000..a82af2a86b09d5 --- /dev/null +++ b/packages/expo-type-information/build/commands/generateJSXIntrinsicsCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"generateJSXIntrinsicsCommand.js","sourceRoot":"","sources":["../../src/commands/generateJSXIntrinsicsCommand.ts"],"names":[],"mappings":";;AAYA,sDAyBC;AAnCD,iDAOwB;AACxB,kEAA2E;AAE3E,SAAgB,qBAAqB,CAAC,GAAsB;IAC1D,OAAO,IAAA,+BAAgB,EAAC,GAAG,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,MAAM,CACpE,KAAK,EAAE,OAAiD,EAAE,EAAE;QAC1D,MAAM,UAAU,GAAG,MAAM,IAAA,oCAAqB,EAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,cAAc,EAAE,GAAG,UAAU,CAAC;QAEtC,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,QAAQ,GAAG,MAAM,IAAA,6CAA8B,EAAC,UAAU,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YAED,MAAM,2BAA2B,GAAG,MAAM,IAAA,uDAAgC,EAAC,QAAQ,CAAC,CAAC;YACrF,IAAI,CAAC,2BAA2B,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;YACD,IAAA,gDAAiC,EAAC,2BAA2B,EAAE,cAAc,CAAC,CAAC;QACjF,CAAC,CAAC;QACF,IAAA,gCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateMocksForFileCommand.d.ts b/packages/expo-type-information/build/commands/generateMocksForFileCommand.d.ts new file mode 100644 index 00000000000000..68f7bd70f0d862 --- /dev/null +++ b/packages/expo-type-information/build/commands/generateMocksForFileCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function generateMocksForFileCommand(cli: commander.Command): commander.Command; diff --git a/packages/expo-type-information/build/commands/generateMocksForFileCommand.js b/packages/expo-type-information/build/commands/generateMocksForFileCommand.js new file mode 100644 index 00000000000000..6c5110c293eb3c --- /dev/null +++ b/packages/expo-type-information/build/commands/generateMocksForFileCommand.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateMocksForFileCommand = generateMocksForFileCommand; +const commandUtils_1 = require("./commandUtils"); +const mockgen_1 = require("../mockgen"); +function generateMocksForFileCommand(cli) { + return (0, commandUtils_1.addCommonOptions)(cli.command('generate-mocks-for-file')).action(async (options) => { + const parsedArgs = await (0, commandUtils_1.parseCommandArguments)(options); + if (!parsedArgs) { + return; + } + const command = async () => { + const typeInfo = await (0, commandUtils_1.getFileTypeInformationFromArgs)(parsedArgs); + if (!typeInfo) { + return; + } + (0, mockgen_1.generateMocks)([typeInfo], 'typescript'); + }; + (0, commandUtils_1.runCommandOnWatch)(parsedArgs, command); + }); +} +//# sourceMappingURL=generateMocksForFileCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateMocksForFileCommand.js.map b/packages/expo-type-information/build/commands/generateMocksForFileCommand.js.map new file mode 100644 index 00000000000000..ac7f842104ee01 --- /dev/null +++ b/packages/expo-type-information/build/commands/generateMocksForFileCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"generateMocksForFileCommand.js","sourceRoot":"","sources":["../../src/commands/generateMocksForFileCommand.ts"],"names":[],"mappings":";;AAWA,kEAkBC;AA3BD,iDAMwB;AACxB,wCAA2C;AAE3C,SAAgB,2BAA2B,CAAC,GAAsB;IAChE,OAAO,IAAA,+BAAgB,EAAC,GAAG,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,MAAM,CACpE,KAAK,EAAE,OAAiD,EAAE,EAAE;QAC1D,MAAM,UAAU,GAAG,MAAM,IAAA,oCAAqB,EAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,QAAQ,GAAG,MAAM,IAAA,6CAA8B,EAAC,UAAU,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YACD,IAAA,uBAAa,EAAC,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC;QAC1C,CAAC,CAAC;QACF,IAAA,gCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateModuleTypesCommand.d.ts b/packages/expo-type-information/build/commands/generateModuleTypesCommand.d.ts new file mode 100644 index 00000000000000..acbe7e40fee467 --- /dev/null +++ b/packages/expo-type-information/build/commands/generateModuleTypesCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function generateModuleTypesCommand(cli: commander.Command): commander.Command; diff --git a/packages/expo-type-information/build/commands/generateModuleTypesCommand.js b/packages/expo-type-information/build/commands/generateModuleTypesCommand.js new file mode 100644 index 00000000000000..e1102849dac7ab --- /dev/null +++ b/packages/expo-type-information/build/commands/generateModuleTypesCommand.js @@ -0,0 +1,32 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateModuleTypesCommand = generateModuleTypesCommand; +const chalk_1 = __importDefault(require("chalk")); +const commandUtils_1 = require("./commandUtils"); +const typescriptGeneration_1 = require("../typescriptGeneration"); +function generateModuleTypesCommand(cli) { + return (0, commandUtils_1.addCommonOptions)(cli.command('generate-module-types')).action(async (options) => { + const parsedArgs = await (0, commandUtils_1.parseCommandArguments)(options); + if (!parsedArgs) { + return; + } + const { realOutputPath } = parsedArgs; + const command = async () => { + const typeInfo = await (0, commandUtils_1.getFileTypeInformationFromArgs)(parsedArgs); + if (!typeInfo) { + return; + } + const moduleTypesFileContent = await (0, typescriptGeneration_1.generateModuleTypesFileContent)(typeInfo); + if (!moduleTypesFileContent) { + console.error(chalk_1.default.red(`Couldn't generate module types file content!`)); + return; + } + (0, commandUtils_1.writeStringToFileOrPrintToConsole)(moduleTypesFileContent, realOutputPath); + }; + (0, commandUtils_1.runCommandOnWatch)(parsedArgs, command); + }); +} +//# sourceMappingURL=generateModuleTypesCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateModuleTypesCommand.js.map b/packages/expo-type-information/build/commands/generateModuleTypesCommand.js.map new file mode 100644 index 00000000000000..7d232beaf54658 --- /dev/null +++ b/packages/expo-type-information/build/commands/generateModuleTypesCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"generateModuleTypesCommand.js","sourceRoot":"","sources":["../../src/commands/generateModuleTypesCommand.ts"],"names":[],"mappings":";;;;;AAaA,gEAyBC;AAtCD,kDAA0B;AAG1B,iDAOwB;AACxB,kEAAyE;AAEzE,SAAgB,0BAA0B,CAAC,GAAsB;IAC/D,OAAO,IAAA,+BAAgB,EAAC,GAAG,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAClE,KAAK,EAAE,OAAiD,EAAE,EAAE;QAC1D,MAAM,UAAU,GAAG,MAAM,IAAA,oCAAqB,EAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,cAAc,EAAE,GAAG,UAAU,CAAC;QAEtC,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,QAAQ,GAAG,MAAM,IAAA,6CAA8B,EAAC,UAAU,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YAED,MAAM,sBAAsB,GAAG,MAAM,IAAA,qDAA8B,EAAC,QAAQ,CAAC,CAAC;YAC9E,IAAI,CAAC,sBAAsB,EAAE,CAAC;gBAC5B,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC,CAAC;gBACzE,OAAO;YACT,CAAC;YACD,IAAA,gDAAiC,EAAC,sBAAsB,EAAE,cAAc,CAAC,CAAC;QAC5E,CAAC,CAAC;QACF,IAAA,gCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateViewTypesCommand.d.ts b/packages/expo-type-information/build/commands/generateViewTypesCommand.d.ts new file mode 100644 index 00000000000000..6a4350fcfc6e6e --- /dev/null +++ b/packages/expo-type-information/build/commands/generateViewTypesCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function generateViewTypesCommand(cli: commander.Command): commander.Command; diff --git a/packages/expo-type-information/build/commands/generateViewTypesCommand.js b/packages/expo-type-information/build/commands/generateViewTypesCommand.js new file mode 100644 index 00000000000000..710a739ea9353c --- /dev/null +++ b/packages/expo-type-information/build/commands/generateViewTypesCommand.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateViewTypesCommand = generateViewTypesCommand; +const commandUtils_1 = require("./commandUtils"); +const typescriptGeneration_1 = require("../typescriptGeneration"); +function generateViewTypesCommand(cli) { + return (0, commandUtils_1.addCommonOptions)(cli.command('generate-view-types')).action(async (options) => { + const parsedArgs = await (0, commandUtils_1.parseCommandArguments)(options); + if (!parsedArgs) { + return; + } + const { realOutputPath } = parsedArgs; + const command = async () => { + const typeInfo = await (0, commandUtils_1.getFileTypeInformationFromArgs)(parsedArgs); + if (!typeInfo) { + return; + } + const viewTypesFileContent = await (0, typescriptGeneration_1.generateViewTypesFileContent)(typeInfo); + if (!viewTypesFileContent) { + console.error("Couldn't generate view types!"); + return; + } + (0, commandUtils_1.writeStringToFileOrPrintToConsole)(viewTypesFileContent, realOutputPath); + }; + (0, commandUtils_1.runCommandOnWatch)(parsedArgs, command); + }); +} +//# sourceMappingURL=generateViewTypesCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/generateViewTypesCommand.js.map b/packages/expo-type-information/build/commands/generateViewTypesCommand.js.map new file mode 100644 index 00000000000000..b4972bf959b4b0 --- /dev/null +++ b/packages/expo-type-information/build/commands/generateViewTypesCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"generateViewTypesCommand.js","sourceRoot":"","sources":["../../src/commands/generateViewTypesCommand.ts"],"names":[],"mappings":";;AAYA,4DA0BC;AApCD,iDAOwB;AACxB,kEAAuE;AAEvE,SAAgB,wBAAwB,CAAC,GAAsB;IAC7D,OAAO,IAAA,+BAAgB,EAAC,GAAG,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAChE,KAAK,EAAE,OAAiD,EAAE,EAAE;QAC1D,MAAM,UAAU,GAAG,MAAM,IAAA,oCAAqB,EAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,cAAc,EAAE,GAAG,UAAU,CAAC;QAEtC,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,QAAQ,GAAG,MAAM,IAAA,6CAA8B,EAAC,UAAU,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YAED,MAAM,oBAAoB,GAAG,MAAM,IAAA,mDAA4B,EAAC,QAAQ,CAAC,CAAC;YAC1E,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBAC1B,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;YACD,IAAA,gDAAiC,EAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC;QAC1E,CAAC,CAAC;QAEF,IAAA,gCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.d.ts b/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.d.ts new file mode 100644 index 00000000000000..5e7d6a41b38dec --- /dev/null +++ b/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function inlineModulesInterfaceCommand(cli: commander.Command): Promise; diff --git a/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js b/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js new file mode 100644 index 00000000000000..b2c359faaf02bc --- /dev/null +++ b/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js @@ -0,0 +1,129 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.inlineModulesInterfaceCommand = inlineModulesInterfaceCommand; +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const commandUtils_1 = require("./commandUtils"); +const utils_1 = require("../utils"); +async function getResolvedWatchedDirectoriesFromAppJson(appJsonPath) { + try { + const appJson = JSON.parse(await fs_1.default.promises.readFile(appJsonPath, 'utf-8')); + const watchedDirectories = appJson?.expo?.experiments?.inlineModules?.watchedDirectories; + if (!Array.isArray(watchedDirectories)) { + console.error(`watchedDirectories are not defined!`); + return null; + } + const rootDir = path_1.default.dirname(path_1.default.resolve(appJsonPath)); + return watchedDirectories.map((relativePath) => path_1.default.resolve(rootDir, relativePath)); + } + catch (e) { + console.error(`Couldn't read ${appJsonPath}.`, e); + } + return null; +} +async function generateInlineModuleTSFiles({ filePath, dirPath, typeInference, }) { + return await (0, commandUtils_1.generateConciseTsFiles)({ + realInputPaths: [filePath], + realOutputPath: dirPath, + typeInference, + watcher: false, + }); +} +async function inlineModulesWatcher({ appJsonPath, typeInference }) { + const debouncedInlineModulesTsGeneration = (0, commandUtils_1.debounce)(generateInlineModuleTSFiles); + const watchedDirectoriesWatchers = new Map(); + const setupWatchedDirectoriesWatchers = async () => { + const watchedDirectories = await getResolvedWatchedDirectoriesFromAppJson(appJsonPath); + // Merge new watchers with old watchers. + // Let's first find and remove the obsolete ones. + const watchedDirsSet = new Set(watchedDirectories ?? []); + const obsoleteWatchersKeys = []; + for (const [key] of watchedDirectoriesWatchers) { + if (!watchedDirsSet.has(key)) { + obsoleteWatchersKeys.push(key); + } + } + for (const key of obsoleteWatchersKeys) { + const watcher = watchedDirectoriesWatchers.get(key); + watcher?.close(); + watchedDirectoriesWatchers.delete(key); + } + // Now let's create and add new watchers + const createWatcherForDir = (dir) => { + return fs_1.default.watch(dir, { recursive: true, encoding: 'utf-8' }, async (event, fileName) => { + if (!fileName) { + return; + } + const resolvedFilePath = path_1.default.resolve(dir, fileName); + if (fs_1.default.existsSync(resolvedFilePath)) { + debouncedInlineModulesTsGeneration({ + filePath: resolvedFilePath, + dirPath: path_1.default.dirname(resolvedFilePath), + typeInference, + }); + } + }); + }; + for (const dir of watchedDirectories ?? []) { + const watcher = watchedDirectoriesWatchers.get(dir); + if (!watcher) { + watchedDirectoriesWatchers.set(dir, createWatcherForDir(dir)); + } + } + }; + await setupWatchedDirectoriesWatchers(); + const appJsonWatcher = fs_1.default.watch(appJsonPath, 'utf-8', async (event) => { + if (event === 'rename' && !fs_1.default.existsSync(appJsonPath)) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for (const [_, watcher] of watchedDirectoriesWatchers) { + watcher.close(); + } + appJsonWatcher.close(); + return; + } + await setupWatchedDirectoriesWatchers(); + }); +} +async function inlineModulesInterfaceCommand(cli) { + return cli + .command('inline-modules-interface') + .summary('Creates ts interface for every Swift inline module in the project.') + .description('Creates ts interface for every Swift inline module in the project. The ts interface consists of two files Module.generated.ts and Module.tsx, the first one is regenerated with each run of the command and the second one will not be regenerated if user changes it.') + .requiredOption('-a --app-json ', 'A path to the `app.json` where the inline.modules.watchedDirectories are defined.') + .option('-w --watcher', 'Starts a watcher that checks for changes in inline modules files.') + .action(async (options) => { + const parsedArgs = (0, commandUtils_1.parseCommandArguments)(options); + if (!parsedArgs) { + return; + } + const { appJsonPath, watcher } = parsedArgs; + if (!appJsonPath) { + return; + } + const watchedDirectories = await getResolvedWatchedDirectoriesFromAppJson(appJsonPath); + if (!watchedDirectories) { + return; + } + const dirents = []; + for (const dir of watchedDirectories) { + for await (const dirent of (0, utils_1.scanFilesRecursively)(dir)) { + if (!dirent.name.endsWith('.swift')) { + continue; + } + dirents.push(dirent); + } + } + await (0, utils_1.taskAll)(dirents, async (dirent) => await generateInlineModuleTSFiles({ + filePath: dirent.path, + dirPath: dirent.parentPath, + typeInference: parsedArgs.typeInference, + })); + if (watcher) { + await inlineModulesWatcher({ appJsonPath, typeInference: parsedArgs.typeInference }); + } + }); +} +//# sourceMappingURL=inlineModulesInterfaceCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js.map b/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js.map new file mode 100644 index 00000000000000..4032ede9b6055f --- /dev/null +++ b/packages/expo-type-information/build/commands/inlineModulesInterfaceCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"inlineModulesInterfaceCommand.js","sourceRoot":"","sources":["../../src/commands/inlineModulesInterfaceCommand.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/moduleInterfaceCommand.d.ts b/packages/expo-type-information/build/commands/moduleInterfaceCommand.d.ts new file mode 100644 index 00000000000000..d58d66cb70f631 --- /dev/null +++ b/packages/expo-type-information/build/commands/moduleInterfaceCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function moduleInterfaceCommand(cli: commander.Command): commander.Command; diff --git a/packages/expo-type-information/build/commands/moduleInterfaceCommand.js b/packages/expo-type-information/build/commands/moduleInterfaceCommand.js new file mode 100644 index 00000000000000..8459ed4b002b15 --- /dev/null +++ b/packages/expo-type-information/build/commands/moduleInterfaceCommand.js @@ -0,0 +1,46 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.moduleInterfaceCommand = moduleInterfaceCommand; +const path_1 = __importDefault(require("path")); +const commandUtils_1 = require("./commandUtils"); +const typescriptGeneration_1 = require("../typescriptGeneration"); +function moduleInterfaceCommand(cli) { + return (0, commandUtils_1.addCommonOptions)(cli.command('module-interface')) + .summary('Generates a full ts interface for a Swift module.') + .description('Generates a full ts interface for a Swift module. It consists of types.ts file with all types defined in the module, module.ts with the native module definition, and view.tsx for each view defined in the module, and an index.ts file which reexports some functions.') + .action(async (options) => { + const parsedArgs = await (0, commandUtils_1.parseCommandArguments)(options, false); + if (!parsedArgs) { + return; + } + const { realInputPaths, realOutputPath } = parsedArgs; + const command = async () => { + const typeInfo = await (0, commandUtils_1.getFileTypeInformationFromArgs)(parsedArgs); + if (!typeInfo) { + return; + } + const generatedFiles = await (0, typescriptGeneration_1.generateFullTsInterface)(typeInfo); + if (!generatedFiles) { + return; + } + const { moduleTypesFile, moduleViewsFiles, moduleNativeFile, indexFile } = generatedFiles; + const dirName = realOutputPath ?? path_1.default.dirname(realInputPaths[0]); + const writeFilePromises = []; + for (const outputFile of [ + moduleTypesFile, + ...moduleViewsFiles, + moduleNativeFile, + indexFile, + ]) { + const outputFilePath = path_1.default.resolve(dirName, outputFile.name); + writeFilePromises.push((0, commandUtils_1.writeToStableFile)({ filePath: outputFilePath, content: outputFile.content })); + } + await Promise.all(writeFilePromises); + }; + (0, commandUtils_1.runCommandOnWatch)(parsedArgs, command); + }); +} +//# sourceMappingURL=moduleInterfaceCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/moduleInterfaceCommand.js.map b/packages/expo-type-information/build/commands/moduleInterfaceCommand.js.map new file mode 100644 index 00000000000000..7b9b210cd7f1ca --- /dev/null +++ b/packages/expo-type-information/build/commands/moduleInterfaceCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"moduleInterfaceCommand.js","sourceRoot":"","sources":["../../src/commands/moduleInterfaceCommand.ts"],"names":[],"mappings":";;;;;AAaA,wDA0CC;AAtDD,gDAAwB;AAExB,iDAOwB;AACxB,kEAAkE;AAElE,SAAgB,sBAAsB,CAAC,GAAsB;IAC3D,OAAO,IAAA,+BAAgB,EAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;SACrD,OAAO,CAAC,mDAAmD,CAAC;SAC5D,WAAW,CACV,0QAA0Q,CAC3Q;SACA,MAAM,CAAC,KAAK,EAAE,OAAiD,EAAE,EAAE;QAClE,MAAM,UAAU,GAAG,MAAM,IAAA,oCAAqB,EAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC/D,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,GAAG,UAAU,CAAC;QAEtD,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,QAAQ,GAAG,MAAM,IAAA,6CAA8B,EAAC,UAAU,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YACD,MAAM,cAAc,GAAG,MAAM,IAAA,8CAAuB,EAAC,QAAQ,CAAC,CAAC;YAC/D,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,OAAO;YACT,CAAC;YACD,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,cAAc,CAAC;YAE1F,MAAM,OAAO,GAAG,cAAc,IAAI,cAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAW,CAAC,CAAC;YAC5E,MAAM,iBAAiB,GAAG,EAAE,CAAC;YAC7B,KAAK,MAAM,UAAU,IAAI;gBACvB,eAAe;gBACf,GAAG,gBAAgB;gBACnB,gBAAgB;gBAChB,SAAS;aACV,EAAE,CAAC;gBACF,MAAM,cAAc,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC9D,iBAAiB,CAAC,IAAI,CACpB,IAAA,gCAAiB,EAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAC7E,CAAC;YACJ,CAAC;YACD,MAAM,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QACvC,CAAC,CAAC;QAEF,IAAA,gCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACP,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.d.ts b/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.d.ts new file mode 100644 index 00000000000000..93c1f515380a52 --- /dev/null +++ b/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function shortModuleInterfaceCommand(cli: commander.Command): void; diff --git a/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js b/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js new file mode 100644 index 00000000000000..67b04704a9d69d --- /dev/null +++ b/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.shortModuleInterfaceCommand = shortModuleInterfaceCommand; +const commandUtils_1 = require("./commandUtils"); +function shortModuleInterfaceCommand(cli) { + (0, commandUtils_1.addCommonOptions)(cli + .command('short-module-interface') + .summary('Creates a short ts interface, great with inline-modules.') + .description('Creates a short ts interface for an expo module. Overrites `ModuleName.generated.ts` and creates `ModuleName.ts` if not present. Can be used with inline-modules.')).action(async (options) => { + const parsedArgs = await (0, commandUtils_1.parseCommandArguments)(options, false); + if (!parsedArgs) + return; + const command = () => (0, commandUtils_1.generateConciseTsFiles)(parsedArgs); + (0, commandUtils_1.runCommandOnWatch)(parsedArgs, command); + }); +} +//# sourceMappingURL=shortModuleInterfaceCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js.map b/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js.map new file mode 100644 index 00000000000000..0b1afb6668c994 --- /dev/null +++ b/packages/expo-type-information/build/commands/shortModuleInterfaceCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"shortModuleInterfaceCommand.js","sourceRoot":"","sources":["../../src/commands/shortModuleInterfaceCommand.ts"],"names":[],"mappings":";;AAUA,kEAeC;AAvBD,iDAMwB;AAExB,SAAgB,2BAA2B,CAAC,GAAsB;IAChE,IAAA,+BAAgB,EACd,GAAG;SACA,OAAO,CAAC,wBAAwB,CAAC;SACjC,OAAO,CAAC,0DAA0D,CAAC;SACnE,WAAW,CACV,mKAAmK,CACpK,CACJ,CAAC,MAAM,CAAC,KAAK,EAAE,OAAiD,EAAE,EAAE;QACnE,MAAM,UAAU,GAAG,MAAM,IAAA,oCAAqB,EAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC/D,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAA,qCAAsB,EAAC,UAAU,CAAC,CAAC;QACzD,IAAA,gCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/typeInformationCommand.d.ts b/packages/expo-type-information/build/commands/typeInformationCommand.d.ts new file mode 100644 index 00000000000000..56a7b3892d648e --- /dev/null +++ b/packages/expo-type-information/build/commands/typeInformationCommand.d.ts @@ -0,0 +1,2 @@ +import commander from 'commander'; +export declare function typeInformationCommand(cli: commander.Command): commander.Command; diff --git a/packages/expo-type-information/build/commands/typeInformationCommand.js b/packages/expo-type-information/build/commands/typeInformationCommand.js new file mode 100644 index 00000000000000..68261f37a8694f --- /dev/null +++ b/packages/expo-type-information/build/commands/typeInformationCommand.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.typeInformationCommand = typeInformationCommand; +const commandUtils_1 = require("./commandUtils"); +const typeInformation_1 = require("../typeInformation"); +function typeInformationCommand(cli) { + return (0, commandUtils_1.addCommonOptions)(cli.command('type-information')).action(async (options) => { + const parsedArgs = await (0, commandUtils_1.parseCommandArguments)(options); + if (!parsedArgs) { + return; + } + const command = async () => { + const typeInfo = await (0, commandUtils_1.getFileTypeInformationFromArgs)(parsedArgs); + if (!typeInfo) { + return; + } + const typeInfoSerialized = (0, typeInformation_1.serializeTypeInformation)(typeInfo); + const typeInfoSerializedString = JSON.stringify(typeInfoSerialized, null, 2); + (0, commandUtils_1.writeStringToFileOrPrintToConsole)(typeInfoSerializedString, parsedArgs.realOutputPath); + }; + (0, commandUtils_1.runCommandOnWatch)(parsedArgs, command); + }); +} +//# sourceMappingURL=typeInformationCommand.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/commands/typeInformationCommand.js.map b/packages/expo-type-information/build/commands/typeInformationCommand.js.map new file mode 100644 index 00000000000000..f1d61706fa70f9 --- /dev/null +++ b/packages/expo-type-information/build/commands/typeInformationCommand.js.map @@ -0,0 +1 @@ +{"version":3,"file":"typeInformationCommand.js","sourceRoot":"","sources":["../../src/commands/typeInformationCommand.ts"],"names":[],"mappings":";;AAYA,wDAsBC;AAhCD,iDAOwB;AACxB,wDAA8D;AAE9D,SAAgB,sBAAsB,CAAC,GAAsB;IAC3D,OAAO,IAAA,+BAAgB,EAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAC7D,KAAK,EAAE,OAAiD,EAAE,EAAE;QAC1D,MAAM,UAAU,GAAG,MAAM,IAAA,oCAAqB,EAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,QAAQ,GAAG,MAAM,IAAA,6CAA8B,EAAC,UAAU,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YAED,MAAM,kBAAkB,GAAG,IAAA,0CAAwB,EAAC,QAAQ,CAAC,CAAC;YAC9D,MAAM,wBAAwB,GAAG,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC7E,IAAA,gDAAiC,EAAC,wBAAwB,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;QACzF,CAAC,CAAC;QAEF,IAAA,gCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/build/index.d.ts b/packages/expo-type-information/build/index.d.ts new file mode 100644 index 00000000000000..fe27744bacc387 --- /dev/null +++ b/packages/expo-type-information/build/index.d.ts @@ -0,0 +1,3 @@ +export * from './typeInformation'; +export { generateMocks, getAllExpoModulesInWorkingDirectory } from './mockgen'; +export { generateConciseTsInterface, generateFullTsInterface, generateModuleTypesFileContent, generateViewTypesFileContent, generateJSXIntrinsicsFileContent, } from './typescriptGeneration'; diff --git a/packages/expo-type-information/build/index.js b/packages/expo-type-information/build/index.js new file mode 100644 index 00000000000000..103ce087f3fc9a --- /dev/null +++ b/packages/expo-type-information/build/index.js @@ -0,0 +1,28 @@ +"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.generateJSXIntrinsicsFileContent = exports.generateViewTypesFileContent = exports.generateModuleTypesFileContent = exports.generateFullTsInterface = exports.generateConciseTsInterface = exports.getAllExpoModulesInWorkingDirectory = exports.generateMocks = void 0; +__exportStar(require("./typeInformation"), exports); +var mockgen_1 = require("./mockgen"); +Object.defineProperty(exports, "generateMocks", { enumerable: true, get: function () { return mockgen_1.generateMocks; } }); +Object.defineProperty(exports, "getAllExpoModulesInWorkingDirectory", { enumerable: true, get: function () { return mockgen_1.getAllExpoModulesInWorkingDirectory; } }); +var typescriptGeneration_1 = require("./typescriptGeneration"); +Object.defineProperty(exports, "generateConciseTsInterface", { enumerable: true, get: function () { return typescriptGeneration_1.generateConciseTsInterface; } }); +Object.defineProperty(exports, "generateFullTsInterface", { enumerable: true, get: function () { return typescriptGeneration_1.generateFullTsInterface; } }); +Object.defineProperty(exports, "generateModuleTypesFileContent", { enumerable: true, get: function () { return typescriptGeneration_1.generateModuleTypesFileContent; } }); +Object.defineProperty(exports, "generateViewTypesFileContent", { enumerable: true, get: function () { return typescriptGeneration_1.generateViewTypesFileContent; } }); +Object.defineProperty(exports, "generateJSXIntrinsicsFileContent", { enumerable: true, get: function () { return typescriptGeneration_1.generateJSXIntrinsicsFileContent; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/index.js.map b/packages/expo-type-information/build/index.js.map new file mode 100644 index 00000000000000..9541b58ad5318c --- /dev/null +++ b/packages/expo-type-information/build/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,qCAA+E;AAAtE,wGAAA,aAAa,OAAA;AAAE,8HAAA,mCAAmC,OAAA;AAC3D,+DAMgC;AAL9B,kIAAA,0BAA0B,OAAA;AAC1B,+HAAA,uBAAuB,OAAA;AACvB,sIAAA,8BAA8B,OAAA;AAC9B,oIAAA,4BAA4B,OAAA;AAC5B,wIAAA,gCAAgC,OAAA"} \ No newline at end of file diff --git a/packages/expo-type-information/build/mockgen.d.ts b/packages/expo-type-information/build/mockgen.d.ts new file mode 100644 index 00000000000000..3205f5074ddd3c --- /dev/null +++ b/packages/expo-type-information/build/mockgen.d.ts @@ -0,0 +1,4 @@ +import { FileTypeInformation, ModuleClassDeclaration } from './typeInformation'; +export declare function generateTSMockForModule(module: ModuleClassDeclaration, fileTypeInformation: FileTypeInformation, includeTypes: boolean): string; +export declare function generateMocks(files: FileTypeInformation[], outputLanguage?: 'javascript' | 'typescript'): Promise; +export declare function getAllExpoModulesInWorkingDirectory(): Promise; diff --git a/packages/expo-type-information/build/mockgen.js b/packages/expo-type-information/build/mockgen.js new file mode 100644 index 00000000000000..9e2dcbe5b848be --- /dev/null +++ b/packages/expo-type-information/build/mockgen.js @@ -0,0 +1,204 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateTSMockForModule = generateTSMockForModule; +exports.generateMocks = generateMocks; +exports.getAllExpoModulesInWorkingDirectory = getAllExpoModulesInWorkingDirectory; +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const typescript_1 = __importDefault(require("typescript")); +const typeInformation_1 = require("./typeInformation"); +const typescriptGeneration_1 = require("./typescriptGeneration"); +const utils_1 = require("./utils"); +const prefix = `Automatically generated by expo-type-information. + +This autogenerated file provides a mock for native Expo module, +and works out of the box with the expo jest preset. +`; +function getPrefix() { + return [typescript_1.default.factory.createJSDocComment(prefix)]; +} +let freeId = 0; +function getNextFreeId() { + freeId += 1; + return freeId; +} +function maybeWrapWithReturnStatement(type, fileTypeInformation) { + if (type.kind === typeInformation_1.TypeKind.BASIC) { + const basicType = type.type; + if (basicType === typeInformation_1.BasicType.VOID || basicType === typeInformation_1.BasicType.ANY) { + return []; + } + } + // TODO(@HubertBer): maybe add a comment when we couldn't create a mock for the return type + const returnExpression = getMockedValueForType(type, fileTypeInformation); + if (returnExpression || type.kind !== typeInformation_1.TypeKind.BASIC || type.type === typeInformation_1.BasicType.UNRESOLVED) { + return [typescript_1.default.factory.createReturnStatement(returnExpression)]; + } + return []; +} +function getBasicTypeMockLiteral(type) { + switch (type) { + case typeInformation_1.BasicType.STRING: + return typescript_1.default.factory.createStringLiteral(''); + case typeInformation_1.BasicType.BOOLEAN: + return typescript_1.default.factory.createFalse(); + case typeInformation_1.BasicType.NUMBER: + return typescript_1.default.factory.createNumericLiteral(0); + case typeInformation_1.BasicType.VOID: + case typeInformation_1.BasicType.UNDEFINED: + case typeInformation_1.BasicType.ANY: + default: + return undefined; + } +} +function getBasicTypeFromString(basicType) { + switch (basicType) { + case 'any': + return typeInformation_1.BasicType.ANY; + case 'number': + return typeInformation_1.BasicType.NUMBER; + case 'string': + return typeInformation_1.BasicType.STRING; + case 'boolean': + return typeInformation_1.BasicType.BOOLEAN; + } + return undefined; +} +function getMockedEnumInstance(enumType) { + const firstCase = enumType.cases[0]; + if (!firstCase) { + return undefined; + } + return typescript_1.default.factory.createPropertyAccessExpression(typescript_1.default.factory.createRegularExpressionLiteral(enumType.name), firstCase); +} +function getMockedRecordInstance(recordType, fileTypeInformation) { + return typescript_1.default.factory.createObjectLiteralExpression(recordType.fields.map((f) => typescript_1.default.factory.createPropertyAssignment(f.name ?? '_' + getNextFreeId(), getMockedValueForType(f.type, fileTypeInformation) ?? typescript_1.default.factory.createNull()))); +} +function getMockValueForIdentifier(identifier, fileTypeInformation) { + if (!fileTypeInformation.typeIdentifierDefinitionMap.has(identifier)) { + return undefined; + } + const typeDefinition = fileTypeInformation.typeIdentifierDefinitionMap.get(identifier); + switch (typeDefinition?.kind) { + case typeInformation_1.IdentifierKind.BASIC: { + const basicType = getBasicTypeFromString(typeDefinition.definition); + if (basicType) { + return getBasicTypeMockLiteral(basicType); + } + return undefined; + } + case typeInformation_1.IdentifierKind.ENUM: + return getMockedEnumInstance(typeDefinition.definition); + case typeInformation_1.IdentifierKind.RECORD: + return getMockedRecordInstance(typeDefinition.definition, fileTypeInformation); + } + return undefined; +} +function getMockedValueForType(type, fileTypeInformation) { + switch (type.kind) { + case typeInformation_1.TypeKind.BASIC: + return getBasicTypeMockLiteral(type.type); + case typeInformation_1.TypeKind.IDENTIFIER: + return getMockValueForIdentifier(type.type, fileTypeInformation); + case typeInformation_1.TypeKind.SUM: { + const firstType = type.type.types[0]; + return getMockedValueForType(firstType ?? { kind: typeInformation_1.TypeKind.BASIC, type: typeInformation_1.BasicType.UNDEFINED }, fileTypeInformation); + } + case typeInformation_1.TypeKind.PARAMETRIZED: + return typescript_1.default.factory.createNull(); + case typeInformation_1.TypeKind.OPTIONAL: + return getMockedValueForType(type.type, fileTypeInformation); + case typeInformation_1.TypeKind.ARRAY: + return typescript_1.default.factory.createArrayLiteralExpression(); + case typeInformation_1.TypeKind.DICTIONARY: + return typescript_1.default.factory.createObjectLiteralExpression(); + } +} +function getFunctionReturnBlock(functionDeclaration, fileTypeInformation) { + return maybeWrapWithReturnStatement(functionDeclaration.returnType, fileTypeInformation); +} +function getMockedFunctionDeclaration(functionDeclaration, fileTypeInformation, async, exported) { + return (0, typescriptGeneration_1.buildFunction)({ + functionDeclaration, + async, + method: false, + exported, + declaration: false, + returnStatement: maybeWrapWithReturnStatement(functionDeclaration.returnType, fileTypeInformation), + }); +} +function getMockedClass(classDeclaration, fileInfo) { + return (0, typescriptGeneration_1.buildClass)({ + classDeclaration, + exported: true, + getFunctionReturnBlock: (func) => getFunctionReturnBlock(func, fileInfo), + }); +} +function getMockedView(viewDeclaration) { + const propsTypeName = (0, typescriptGeneration_1.getViewPropsTypeName)(viewDeclaration); + const propsType = (0, typescriptGeneration_1.buildViewPropsInterface)(viewDeclaration, { exported: true }); + const propsParameter = typescript_1.default.factory.createParameterDeclaration(undefined, undefined, 'props', undefined, typescript_1.default.factory.createTypeReferenceNode(propsTypeName, undefined), undefined); + const viewFunction = typescript_1.default.factory.createFunctionDeclaration([typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.ExportKeyword)], undefined, (viewDeclaration.name?.length ?? 0) > 0 ? viewDeclaration.name : 'View', undefined, [propsParameter], undefined, typescript_1.default.factory.createBlock([])); + return [...propsType, viewFunction]; +} +function getMockForModule(module, typeInfo) { + const { usedTypeIdentifiers, declaredTypeIdentifiers, inferredTypeParametersCount, records, enums, } = typeInfo; + const undeclaredTypes = usedTypeIdentifiers + .difference(declaredTypeIdentifiers) + .difference((0, typescriptGeneration_1.getBasicTypesIdentifiers)()); + const sections = [ + getPrefix(), + [...undeclaredTypes].map((identifier) => (0, typescriptGeneration_1.buildUnknownTypeAlias)(identifier, true, inferredTypeParametersCount)), + records.flatMap((record) => (0, typescriptGeneration_1.buildRecordTypeAlias)(record, true)), + enums.flatMap((e) => (0, typescriptGeneration_1.buildEnumTypeDeclaration)(e, true, false)), + module.functions.map((f) => getMockedFunctionDeclaration(f, typeInfo, false, true)), + module.asyncFunctions.map((f) => getMockedFunctionDeclaration(f, typeInfo, true, true)), + module.classes.map((c) => getMockedClass(c, typeInfo)), + module.views.flatMap((v) => getMockedView(v)), + ]; + return (0, typescriptGeneration_1.joinTSNodesWithNewlines)(sections).flat(); +} +function generateTSMockForModule(module, fileTypeInformation, includeTypes) { + const mockFileName = module.name + (includeTypes ? '.ts' : '.js'); + const mock = typescript_1.default.factory.createNodeArray(getMockForModule(module, fileTypeInformation)); + const printer = typescript_1.default.createPrinter({ newLine: typescript_1.default.NewLineKind.LineFeed }); + // get ts nodearray from getMockForModule(m) array + const resultFile = typescript_1.default.createSourceFile(mockFileName, '', typescript_1.default.ScriptTarget.Latest, false, typescript_1.default.ScriptKind.TSX); + const printedTs = printer.printList(typescript_1.default.ListFormat.MultiLine + typescript_1.default.ListFormat.PreserveLines, mock, resultFile); + if (includeTypes) { + return printedTs; + } + return typescript_1.default.transpileModule(printedTs, { + compilerOptions: { + module: typescript_1.default.ModuleKind.ESNext, + target: typescript_1.default.ScriptTarget.ESNext, + }, + }).outputText; +} +const directoryPath = process.cwd(); +const swiftFilesGlob = `${directoryPath}/**/*.swift`; +async function generateMocks(files, outputLanguage = 'javascript') { + const modules = files.flatMap((file) => file.moduleClasses.map((module) => ({ module, file }))); + if (modules.length === 0) { + return; + } + const isTypeScript = outputLanguage === 'typescript'; + const extension = isTypeScript ? '.ts' : '.js'; + const mocksDir = path_1.default.join(directoryPath, 'mocks'); + await fs_1.default.promises.mkdir(mocksDir, { recursive: true }); + (0, utils_1.taskAll)(modules, async ({ module, file }) => { + const code = generateTSMockForModule(module, file, isTypeScript); + const prettified = await (0, typescriptGeneration_1.prettifyCode)(code, isTypeScript ? 'typescript' : undefined); + await fs_1.default.promises.writeFile(path_1.default.join(mocksDir, module.name + extension), prettified); + }); +} +async function getAllExpoModulesInWorkingDirectory() { + const files = fs_1.default.globSync(swiftFilesGlob); + return (await Promise.all(files.map((file) => (0, typeInformation_1.getFileTypeInformation)({ + input: { type: 'file', inputFileAbsolutePaths: [fs_1.default.realpathSync(file)] }, + })))).filter((f) => f); +} +//# sourceMappingURL=mockgen.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/mockgen.js.map b/packages/expo-type-information/build/mockgen.js.map new file mode 100644 index 00000000000000..a4be22f424f6d7 --- /dev/null +++ b/packages/expo-type-information/build/mockgen.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mockgen.js","sourceRoot":"","sources":["../src/mockgen.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-type-information/build/swift/sourcekittenTypeInformation.d.ts b/packages/expo-type-information/build/swift/sourcekittenTypeInformation.d.ts new file mode 100644 index 00000000000000..5e461ebb4ff94f --- /dev/null +++ b/packages/expo-type-information/build/swift/sourcekittenTypeInformation.d.ts @@ -0,0 +1,6 @@ +import { FileTypeInformation } from '../typeInformation'; +export type SwiftFileTypeInformationOptions = { + typeInference: boolean; +}; +export declare function getSwiftFileTypeInformation(filePath: string, options: SwiftFileTypeInformationOptions): Promise; +export declare function preprocessSwiftFile(originalFileContent: string): string; diff --git a/packages/expo-type-information/build/swift/sourcekittenTypeInformation.js b/packages/expo-type-information/build/swift/sourcekittenTypeInformation.js new file mode 100644 index 00000000000000..f5f4dcbb5050e9 --- /dev/null +++ b/packages/expo-type-information/build/swift/sourcekittenTypeInformation.js @@ -0,0 +1,875 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getSwiftFileTypeInformation = getSwiftFileTypeInformation; +exports.preprocessSwiftFile = preprocessSwiftFile; +const child_process_1 = require("child_process"); +const fs_1 = __importDefault(require("fs")); +const util_1 = require("util"); +const yaml_1 = __importDefault(require("yaml")); +const typeInformation_1 = require("../typeInformation"); +const utils_1 = require("../utils"); +const execAsync = (0, util_1.promisify)(child_process_1.exec); +const swiftDeclarationKind = { + enum: 'source.lang.swift.decl.enum', + struct: 'source.lang.swift.decl.struct', + class: 'source.lang.swift.decl.class', + varLocal: 'source.lang.swift.decl.var.local', + varInstance: 'source.lang.swift.decl.var.instance', + varParameter: 'source.lang.swift.decl.var.parameter', + closure: 'source.lang.swift.expr.closure', + enumcase: 'source.lang.swift.decl.enumcase', +}; +function isSwiftDictionary(type) { + return (type.startsWith('[') && + type.endsWith(']') && + findRootColonInDictionary(type.substring(1, type.length - 1)) >= 0); +} +function isSwiftArray(type) { + // This can also be an object, but we check that first, so if it's not an object and is wrapped with [] it's an array. + return type.startsWith('[') && type.endsWith(']'); +} +function isSwiftOptional(type) { + return type.endsWith('?'); +} +function isParametrizedType(type) { + return type.endsWith('>'); +} +function isEitherTypeIdentifier(typeIdentifier) { + return (typeIdentifier === 'Either' || + typeIdentifier === 'EitherOfThree' || + typeIdentifier === 'EitherOfFour'); +} +function isEnumStructure(structure) { + return structure['key.kind'] === swiftDeclarationKind.enum; +} +function isRecordStructure(structure) { + const isRecordOrClass = structure['key.kind'] === swiftDeclarationKind.struct || + structure['key.kind'] === swiftDeclarationKind.class; + const inheritsFromRecord = structure['key.inheritedtypes']?.find((type) => { + return type['key.name'] === 'Record'; + }) !== undefined; + return isRecordOrClass && inheritsFromRecord; +} +function isModuleStructure(structure) { + return structure['key.typename'] === 'ModuleDefinition'; +} +function unwrapSwiftArray(type) { + const innerType = type.substring(1, type.length - 1); + return mapSwiftTypeToTsType(innerType.trim()); +} +function unwrapParametrizedType(type) { + let openBracketCount = 0; + let start = 0; + const innerTypes = []; + let name = ''; + for (let i = 0; i < type.length; i += 1) { + if (type[i] === '<') { + openBracketCount += 1; + if (openBracketCount === 1) { + name = type.substring(0, i); + start = i + 1; + } + } + else if (type[i] === '>') { + openBracketCount -= 1; + if (openBracketCount === 0) { + innerTypes.push(mapSwiftTypeToTsType(type.substring(start, i).trim())); + start = i + 1; + } + } + else if (type[i] === ',' && openBracketCount === 1) { + innerTypes.push(mapSwiftTypeToTsType(type.substring(start, i).trim())); + start = i + 1; + } + } + return { name, types: innerTypes }; +} +function unwrapSwiftDictionary(type) { + const innerType = type.substring(1, type.length - 1); + const colonPosition = findRootColonInDictionary(innerType); + return { + key: innerType.slice(0, colonPosition).trim(), + value: innerType.slice(colonPosition + 1).trim(), + }; +} +/* +The Swift object type can have nested objects as the type of it's values (or maybe even keys). +[String: [String: Any]] + +We can't use regex to find the root colon, so this is the safest way – by counting brackets. +*/ +function findRootColonInDictionary(type) { + let colonIndex = -1; + let openBracketsCount = 0; + for (let i = 0; i < type.length; i++) { + if (type[i] === '[') { + openBracketsCount++; + } + else if (type[i] === ']') { + openBracketsCount--; + } + else if (type[i] === ':' && openBracketsCount === 0) { + colonIndex = i; + break; + } + } + return colonIndex; +} +function mapSwiftTypeToTsType(type) { + if (!type) { + return { kind: typeInformation_1.TypeKind.BASIC, type: typeInformation_1.BasicType.UNRESOLVED }; + } + if (isSwiftOptional(type)) { + return { kind: typeInformation_1.TypeKind.OPTIONAL, type: mapSwiftTypeToTsType(type.slice(0, -1).trim()) }; + } + if (isSwiftDictionary(type)) { + const { key, value } = unwrapSwiftDictionary(type); + const keyType = mapSwiftTypeToTsType(key); + const valueType = mapSwiftTypeToTsType(value); + return { + kind: typeInformation_1.TypeKind.DICTIONARY, + type: { + key: keyType, + value: valueType, + }, + }; + } + if (isSwiftArray(type)) { + return { + kind: typeInformation_1.TypeKind.ARRAY, + type: unwrapSwiftArray(type), + }; + } + if (isParametrizedType(type)) { + const parametrizedType = unwrapParametrizedType(type); + if (isEitherTypeIdentifier(parametrizedType.name)) { + return { + kind: typeInformation_1.TypeKind.SUM, + type: parametrizedType, + }; + } + return { + kind: typeInformation_1.TypeKind.PARAMETRIZED, + type: parametrizedType, + }; + } + const returnType = { + kind: typeInformation_1.TypeKind.BASIC, + type: typeInformation_1.BasicType.ANY, + }; + switch (type) { + case 'unknown': + case 'Any': + returnType.type = typeInformation_1.BasicType.ANY; + break; + case 'String': + returnType.type = typeInformation_1.BasicType.STRING; + break; + case 'Bool': + returnType.type = typeInformation_1.BasicType.BOOLEAN; + break; + case 'Int': + case 'Float': + case 'Double': + returnType.type = typeInformation_1.BasicType.NUMBER; + break; + case 'Void': + returnType.type = typeInformation_1.BasicType.VOID; + break; + default: + returnType.kind = typeInformation_1.TypeKind.IDENTIFIER; + returnType.type = type; + } + return returnType; +} +function getStructureFromFile(file) { + const command = 'sourcekitten structure --file ' + file.path; + try { + const output = (0, child_process_1.execSync)(command, { maxBuffer: 10 * 1024 * 1024 }); + return JSON.parse(output.toString()); + } + catch (error) { + console.error('An error occurred while executing the command:', error); + } +} +// Read string straight from file – needed since we can't get cursorinfo for modulename +function getIdentifierFromOffsetObject(offsetObject, file) { + const startIndex = offsetObject['key.offset']; + const endIndex = offsetObject['key.offset'] + offsetObject['key.length']; + return file.content.substring(startIndex, endIndex).replaceAll('"', ''); +} +function hasSubstructure(structure) { + return structure?.['key.substructure'] && structure['key.substructure'].length > 0; +} +async function findReturnType(structure, file, options) { + if (structure['key.kind'] === swiftDeclarationKind.varLocal && + structure['key.name'].startsWith('returnValueDeclaration_') && + options.typeInference) { + // TODO(@HubertBer): this return type inference is really costly + return getTypeOfByteOffsetVariable(structure['key.nameoffset'], file); + } + if (hasSubstructure(structure)) { + for (const substructure of structure['key.substructure']) { + const returnType = findReturnType(substructure, file, options); + if (returnType) { + return returnType; + } + } + } + return null; +} +let cachedSDKPath = null; +function getSDKPath() { + if (cachedSDKPath) { + return cachedSDKPath; + } + cachedSDKPath = (0, child_process_1.execSync)('xcrun --sdk iphoneos --show-sdk-path')?.toString()?.trim(); + if (!cachedSDKPath) { + console.error(`Couldn't find xcode sdk path!`); + return null; + } + return cachedSDKPath; +} +function getUnresolvedType() { + return { kind: typeInformation_1.TypeKind.BASIC, type: typeInformation_1.BasicType.UNRESOLVED }; +} +async function extractDeclarationType(structure, file, options) { + if (structure['key.typename']) { + return mapSwiftTypeToTsType(structure['key.typename']); + } + // TODO(@HubertBer): this type inference is really costly + if (options.typeInference) { + const inferReturn = await getTypeOfByteOffsetVariable(structure['key.nameoffset'], file); + return inferReturn ? mapSwiftTypeToTsType(inferReturn) : getUnresolvedType(); + } + return getUnresolvedType(); +} +function constructSourcekiitenCursorInfoRequest({ filePath, byteOffset, sdkPath, }) { + const request = { + 'key.request': 'source.request.cursorinfo', + 'key.sourcefile': filePath, + 'key.offset': byteOffset, + 'key.compilerargs': [filePath, '-target', 'arm64-apple-ios7', '-sdk', sdkPath], + }; + const yamlRequest = yaml_1.default.stringify(request, { + defaultStringType: 'QUOTE_DOUBLE', + lineWidth: 0, + defaultKeyType: 'PLAIN', + }) + .replace('"source.request.cursorinfo"', 'source.request.cursorinfo') + .replaceAll('"', '\\"'); + return yamlRequest; +} +// Read type description with sourcekitten, works only for variables +// TODO(@HubertBer): This function is extremely slow and inefficient +// consider other options +async function getTypeOfByteOffsetVariable(byteOffset, file) { + const sdkPath = getSDKPath(); + if (!sdkPath) { + return null; + } + const yamlRequest = constructSourcekiitenCursorInfoRequest({ + filePath: file.path, + byteOffset, + sdkPath, + }); + const command = 'sourcekitten request --yaml "' + yamlRequest + '"'; + try { + const { stdout } = await execAsync(command); + const output = JSON.parse(stdout.toString()); + const inferredType = output['key.typename']; + if (inferredType === '<>') { + return null; + } + return inferredType; + } + catch (error) { + console.error('An error occurred while executing the command:', error); + } + return null; +} +function mapSourcekittenParameterToType(parameter) { + return { + name: parameter.name ?? undefined, + type: mapSwiftTypeToTsType(parameter.typename), + }; +} +const parseModulePropertyStructure = parseModuleConstantStructure; +async function parseClosureTypes(structure, file, options) { + const closure = structure['key.substructure']?.find((s) => s['key.kind'] === swiftDeclarationKind.closure); + if (!closure) { + // Try finding the preprocessed return value, if not found we don't know the return type + const returnType = await findReturnType(structure, file, options); + return { parameters: [], returnType }; + } + const parameters = closure['key.substructure'] + ?.filter((s) => s['key.kind'] === swiftDeclarationKind.varParameter) + .map((p) => ({ + name: p['key.name'] ?? undefined, + typename: p['key.typename'], + })); + const returnType = closure?.['key.typename'] ?? (await findReturnType(structure, file, options)); + return { parameters, returnType }; +} +async function parseModuleConstructorDeclaration(substructure, file, options) { + const definitionParams = substructure['key.substructure']; + let types = null; + // TODO(@HubertBer): rethink this maybe split based on what closure is expected + // Maybe this should be the last substructure + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } + else if (definitionParams[0] && hasSubstructure(definitionParams[0])) { + types = await parseClosureTypes(definitionParams[0], file, options); + } + else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + return { + arguments: types?.parameters.map(mapSourcekittenParameterToType) ?? [], + definitionOffset: substructure['key.offset'], + }; +} +async function parseModuleConstantStructure(substructure, file, options) { + const definitionParams = substructure['key.substructure']; + if (!definitionParams[0]) { + return null; + } + const name = getIdentifierFromOffsetObject(definitionParams[0], file); + let types = null; + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } + else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + return { + name, + type: mapSwiftTypeToTsType(types?.returnType ?? undefined), + definitionOffset: substructure['key.offset'], + }; +} +function getClosureBodyStructure(structure) { + // Let's look at an example DSL class declaration + // + // Class(Blob.self) { + // Constructor { // ... + // // ... + //. } + // } + // + // The strucutre for a ClassDeclaration (from SourceKitten) looks like this: + // { + // "key.name": "Class", + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.expr.argument", // 1st argument: `Blob.self` + // // ... + // }, + // { + // "key.kind": "source.lang.swift.expr.argument", // 2nd argument: the closure + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.expr.closure", // the closure + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.stmt.brace", // the closure body + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.expr.call", // DSL functions in the body + // "key.name": "Constructor", + // }, // ... + // ] + // } + // ] + // } + // ] + // } + // // ... + // } + // + // So to get to the closure body we need to take 1st argument, go in the closure definition and go in the closure body. + const classDeclarationClosureArgument = structure['key.substructure']?.[1]; + const classDeclarationClosure = classDeclarationClosureArgument?.['key.substructure']?.[0]; + const classDeclarationClosureBody = classDeclarationClosure?.['key.substructure']?.[0]; + return classDeclarationClosureBody ?? null; +} +async function parseModuleClassStructure(structure, file, options) { + const nestedModuleSubstructure = getClosureBodyStructure(structure)?.['key.substructure']; + const nameSubstrucutre = structure['key.substructure']?.[0]; + const name = nameSubstrucutre + ? getIdentifierFromOffsetObject(nameSubstrucutre, file).replace('.self', '') + : 'UnnamedClass'; + if (!nestedModuleSubstructure) { + console.warn(name + " class is empty or couldn't parse its definition!"); + return { + name, + constructor: null, + methods: [], + asyncMethods: [], + properties: [], + definitionOffset: structure['key.offset'], + }; + } + // `parseModuleStructure` returns `ModuleClassDeclaration` with a found name or with the provided 'UNUSED_NAME', we don't need it here. + const classTypeInfo = await parseModuleStructure(nestedModuleSubstructure, file, 'UNUSED_NAME', structure['key.offset'], options); + return { + name, + methods: classTypeInfo.functions, + asyncMethods: classTypeInfo.asyncFunctions, + properties: classTypeInfo.properties, + constructor: classTypeInfo.constructor, + definitionOffset: structure['key.offset'], + }; +} +async function parseModuleFunctionSubstructure(substructure, file, options) { + const definitionParams = substructure['key.substructure']; + const nameSubstrucutre = definitionParams[0]; + const name = nameSubstrucutre + ? getIdentifierFromOffsetObject(nameSubstrucutre, file) + : 'UnnamedFunction'; + let types = null; + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } + else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + return { + name, + returnType: mapSwiftTypeToTsType(types?.returnType ?? undefined), // any or void ? Probably any + parameters: [], // TODO(@HubertBer): Module function is not generic. I think so. Check it + arguments: types?.parameters?.map(mapSourcekittenParameterToType) ?? [], + definitionOffset: substructure['key.offset'], + }; +} +async function parseModulePropDeclaration(substructure, file, options) { + const definitionParams = substructure['key.substructure']; + const nameSubstrucutre = definitionParams[0]; + const name = nameSubstrucutre + ? getIdentifierFromOffsetObject(nameSubstrucutre, file) + : 'UnkownProp'; + let types = null; + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } + else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + return { + name, + arguments: types?.parameters?.map(mapSourcekittenParameterToType) ?? [], + definitionOffset: substructure['key.offset'], + }; +} +async function parseModuleViewDeclaration(substructure, file, options) { + // The View arguments is a.self for some class a we want. + const suffixLength = 5; + const nameSubstrucutre = substructure['key.substructure']?.[0]; + if (!nameSubstrucutre) { + return null; + } + const name = getIdentifierFromOffsetObject(nameSubstrucutre, file).slice(0, -suffixLength); + const viewStructure = getClosureBodyStructure(substructure); + const viewSubstructure = viewStructure?.['key.substructure']; + if (!viewSubstructure) { + return null; + } + return await parseModuleStructure(viewSubstructure, file, name, viewStructure['key.offset'], options); +} +function parseModuleEventDeclaration(structure, file, events) { + structure['key.substructure'].forEach((substructure) => events.push(getIdentifierFromOffsetObject(substructure, file))); +} +function hasFieldAttribute(attributes, file) { + if (!attributes) { + return false; + } + return attributes.some((attribute) => { + const startIndex = attribute['key.offset']; + const length = attribute['key.length']; + return (length === '@Field'.length && + file.content.substring(startIndex, startIndex + length) === '@Field'); + }); +} +async function parseRecordStructure(recordStructure, usedTypeIdentifiers, inferredTypeParametersCount, file, options) { + const recordSubstrucutres = recordStructure['key.substructure'].filter((substructure) => substructure['key.kind'] === swiftDeclarationKind.varInstance && + hasFieldAttribute(substructure['key.attributes'], file)); + const fields = await (0, utils_1.taskAll)(recordSubstrucutres, async (substructure) => { + const type = await extractDeclarationType(substructure, file, options); + return { type, name: substructure['key.name'] }; + }); + fields.forEach(({ type }) => { + collectTypeIdentifiers(type, usedTypeIdentifiers, inferredTypeParametersCount); + }); + return { + name: recordStructure['key.name'], + fields, + }; +} +function parseEnumStructure(enumStructure) { + const enumcases = enumStructure['key.substructure'] + .filter((sub) => sub['key.kind'] === swiftDeclarationKind.enumcase) + .flatMap((sub) => sub['key.substructure']) + .map((sub) => sub['key.name'].split('(', 1)[0]) + .filter((enumcase) => enumcase !== undefined); + return { + name: enumStructure['key.name'], + cases: enumcases, + }; +} +function sortModuleClassDeclaration(moduleClassDeclaration) { + const cmp = (obj0, obj1) => obj0.definitionOffset - obj1.definitionOffset; + moduleClassDeclaration.asyncFunctions.sort(cmp); + moduleClassDeclaration.classes.sort(cmp); + moduleClassDeclaration.constants.sort(cmp); + moduleClassDeclaration.events.sort(); + moduleClassDeclaration.functions.sort(cmp); + moduleClassDeclaration.properties.sort(cmp); + moduleClassDeclaration.props.sort(cmp); + moduleClassDeclaration.views.sort(cmp); +} +function parsePropertyString(property, definitionOffset) { + const propertyRegex = /Property\(\.\s*"([^"]*)"\s*\)/; + const matches = property.match(propertyRegex); + const propertyName = matches?.[1]; + if (!matches || !propertyName) { + return null; + } + return { + name: propertyName, + type: { + kind: typeInformation_1.TypeKind.BASIC, + type: typeInformation_1.BasicType.UNRESOLVED, + }, + definitionOffset, + }; +} +async function parseModuleStructure(moduleStructure, file, name, definitionOffset, options) { + const moduleClassDeclaration = { + name, + constants: [], + constructor: null, + functions: [], + asyncFunctions: [], + classes: [], + properties: [], + props: [], + views: [], + events: [], + definitionOffset, + }; + await (0, utils_1.taskAll)(moduleStructure, async (structure) => { + // TODO(@HubertBer): Some special cases when the sourcekitten parses the structure differently, for now only Property as it is common + if (structure['key.name'].startsWith('Property(')) { + const propertyDeclaration = parsePropertyString(structure['key.name'], structure['key.nameoffset']); + if (propertyDeclaration) { + moduleClassDeclaration.properties.push(propertyDeclaration); + } + return; + } + switch (structure['key.name']) { + case 'Name': { + const nameSubstrucutre = structure['key.substructure']?.[0]; + if (nameSubstrucutre) { + moduleClassDeclaration.name = getIdentifierFromOffsetObject(nameSubstrucutre, file); + } + break; + } + case 'Function': { + moduleClassDeclaration.functions.push(await parseModuleFunctionSubstructure(structure, file, options)); + break; + } + case 'Constant': { + const constantDeclaration = await parseModuleConstantStructure(structure, file, options); + if (constantDeclaration) { + moduleClassDeclaration.constants.push(constantDeclaration); + } + break; + } + case 'Class': + moduleClassDeclaration.classes.push(await parseModuleClassStructure(structure, file, options)); + break; + case 'Property': { + const propertyDeclaration = await parseModulePropertyStructure(structure, file, options); + if (propertyDeclaration) { + moduleClassDeclaration.properties.push(propertyDeclaration); + } + break; + } + case 'AsyncFunction': + moduleClassDeclaration.asyncFunctions.push(await parseModuleFunctionSubstructure(structure, file, options)); + break; + case 'Constructor': + moduleClassDeclaration.constructor = await parseModuleConstructorDeclaration(structure, file, options); + break; + case 'Prop': + moduleClassDeclaration.props.push(await parseModulePropDeclaration(structure, file, options)); + break; + case 'View': { + const viewDeclaration = await parseModuleViewDeclaration(structure, file, options); + if (viewDeclaration) { + moduleClassDeclaration.views.push(viewDeclaration); + } + break; + } + case 'Events': + parseModuleEventDeclaration(structure, file, moduleClassDeclaration.events); + break; + default: + console.warn(`Module substructure not supported. ${structure['key.name']}`); + } + }); + // As we parse the module structure concurrently the order of for example functions is nondeterministic. + // We want to make it deterministic -- better for testing and usage. + // + // To make it deterministic a `definitionOffset` was added to each declaration. + // We sort declaration by this `definitionOffset` which additionally preserves the in file ordering. + // + // This may not be as useful if we get to merging type informations from multiple files as the `definitionOffset` will not be comparable. + sortModuleClassDeclaration(moduleClassDeclaration); + return moduleClassDeclaration; +} +function parseStructure(structure, name, modulesStructures, recordsStructures, enumsStructures) { + // TODO(@HubertBer): Find out why sometimes the structure is undefined (for example when parsing expo-audio) + if (!structure || !structure['key.substructure']) { + return; + } + const substructure = structure['key.substructure']; + if (isModuleStructure(structure)) { + modulesStructures.push({ structure, name }); + } + else if (isRecordStructure(structure)) { + recordsStructures.push(structure); + } + else if (isEnumStructure(structure)) { + enumsStructures.push(structure); + } + else if (Array.isArray(substructure) && substructure.length > 0) { + for (const substructure of structure['key.substructure']) { + parseStructure(substructure, structure['key.name'] ?? name, modulesStructures, recordsStructures, enumsStructures); + } + } +} +function getTypeIdentifierDefinitionMap(fileTypeInformation) { + const typeIdentifierDefinitionMap = new Map([]); + fileTypeInformation.records.forEach((r) => typeIdentifierDefinitionMap.set(r.name, { kind: typeInformation_1.IdentifierKind.RECORD, definition: r })); + fileTypeInformation.enums.forEach((e) => typeIdentifierDefinitionMap.set(e.name, { kind: typeInformation_1.IdentifierKind.ENUM, definition: e })); + return typeIdentifierDefinitionMap; +} +function collectTypeIdentifiers(type, typeIdentiers, inferredTypeParametersCount) { + switch (type.kind) { + case typeInformation_1.TypeKind.ARRAY: + case typeInformation_1.TypeKind.OPTIONAL: + collectTypeIdentifiers(type.type, typeIdentiers, inferredTypeParametersCount); + break; + case typeInformation_1.TypeKind.DICTIONARY: + collectTypeIdentifiers(type.type.key, typeIdentiers, inferredTypeParametersCount); + collectTypeIdentifiers(type.type.value, typeIdentiers, inferredTypeParametersCount); + break; + case typeInformation_1.TypeKind.SUM: + for (const t of type.type.types) { + collectTypeIdentifiers(t, typeIdentiers, inferredTypeParametersCount); + } + break; + case typeInformation_1.TypeKind.BASIC: + break; + case typeInformation_1.TypeKind.IDENTIFIER: + typeIdentiers.add(type.type); + break; + case typeInformation_1.TypeKind.PARAMETRIZED: { + const parametrizedType = type.type; + const typename = parametrizedType.name; + typeIdentiers.add(typename); + inferredTypeParametersCount.set(typename, Math.max(inferredTypeParametersCount.get(typename) ?? 0, parametrizedType.types.length)); + for (const t of type.type.types) { + collectTypeIdentifiers(t, typeIdentiers, inferredTypeParametersCount); + } + break; + } + } +} +function collectModuleTypeIdentifiers(moduleClassDeclaration, fileTypeInformation) { + const collect = (type) => { + collectTypeIdentifiers(type, fileTypeInformation.usedTypeIdentifiers, fileTypeInformation.inferredTypeParametersCount); + }; + const collectArg = (arg) => { + collect(arg.type); + }; + const collectFunction = (functionDeclaration) => { + collect(functionDeclaration.returnType); + functionDeclaration.arguments.forEach(collectArg); + functionDeclaration.parameters.forEach(collect); + }; + moduleClassDeclaration.asyncFunctions.forEach(collectFunction); + moduleClassDeclaration.functions.forEach(collectFunction); + moduleClassDeclaration.constants.forEach(collectArg); + moduleClassDeclaration.properties.forEach(collectArg); + moduleClassDeclaration.constructor?.arguments.forEach(collectArg); + moduleClassDeclaration.views.forEach((v) => collectModuleTypeIdentifiers(v, fileTypeInformation)); + moduleClassDeclaration.props.forEach((p) => p.arguments.forEach(collectArg)); + moduleClassDeclaration.classes.forEach((c) => { + fileTypeInformation.declaredTypeIdentifiers.add(c.name); + c.asyncMethods.forEach(collectFunction); + c.methods.forEach(collectFunction); + c.constructor?.arguments.forEach(collectArg); + c.properties.forEach(collectArg); + }); +} +async function getSwiftFileTypeInformation(filePath, options) { + const file = { path: filePath, content: fs_1.default.readFileSync(filePath, 'utf8') }; + const modulesStructures = []; + const recordsStructures = []; + const enumsStructures = []; + parseStructure(getStructureFromFile(file), '', modulesStructures, recordsStructures, enumsStructures); + const inferredTypeParametersCount = new Map(); + const moduleClasses = []; + const moduleTypeIdentifiers = new Set(); + const declaredTypeIdentifiers = new Set(); + const recordTypeIdentifiers = new Set(); + const typeIdentifierDefinitionMap = new Map(); + const enums = enumsStructures.map(parseEnumStructure); + const recordMap = (rd) => { + return parseRecordStructure(rd, recordTypeIdentifiers, inferredTypeParametersCount, file, options); + }; + const recordsPromise = (0, utils_1.taskAll)(recordsStructures, recordMap); + const moduleClassDeclarationsPromise = (0, utils_1.taskAll)(modulesStructures.filter(({ structure }) => hasSubstructure(structure)), ({ structure, name }) => parseModuleStructure(structure['key.substructure'], file, name, structure['key.offset'], options)); + const [records, moduleClassDeclarations] = await Promise.all([ + recordsPromise, + moduleClassDeclarationsPromise, + ]); + enums.forEach(({ name }) => { + declaredTypeIdentifiers.add(name); + }); + records.forEach(({ name }) => { + declaredTypeIdentifiers.add(name); + }); + const fileTypeInformation = { + moduleClasses, + records, + enums, + functions: [], + usedTypeIdentifiers: moduleTypeIdentifiers.union(recordTypeIdentifiers), + declaredTypeIdentifiers, + inferredTypeParametersCount, + typeIdentifierDefinitionMap, + }; + for (const moduleClassDeclaration of moduleClassDeclarations) { + moduleClasses.push(moduleClassDeclaration); + collectModuleTypeIdentifiers(moduleClassDeclaration, fileTypeInformation); + } + fileTypeInformation.typeIdentifierDefinitionMap = + getTypeIdentifierDefinitionMap(fileTypeInformation); + return fileTypeInformation; +} +function removeComments(fileContent) { + // This regex matches doubly quoted strings ("string"), and comments (`// comment` and `/* comment */`). + // + // It is in a form A|B where: + // A = ("(?:[^"\\]|\\.)*") + // Matches and captures doubly quoted strings ("string") + // + // B = (\/\/.*|\/\*[\s\S]*?\*\/) + // Matches and captures comments (`// comment` and `/* comment */`) + // By first matching strings we ensure that we don't match comments which happen to be inside a string literal. + // This regex doesn't handle: + // - multline strings literals """ multiline """ + // - nested comments /* comment /* nested comment */ */ + const commentRegex = /("(?:[^"\\]|\\.)*")|(\/\/.*|\/\*[\s\S]*?\*\/)/g; + return fileContent.replace(commentRegex, (match, doubleQuoted) => { + if (doubleQuoted) { + return match; + } + return ''; + }); +} +function returnExpressionEnd(fileContent, returnIndex) { + let inString = false; + let escaped = false; + let parenCount = 0; + let braceCount = 0; + // TODO(@HubertBer): figure out what also changes the typical end of expression + let i = returnIndex; + while (i < fileContent.length) { + const char = fileContent[i]; + let escapedNow = false; + switch (char) { + case '(': + parenCount += 1; + break; + case ')': + parenCount -= 1; + break; + case '{': + braceCount += 1; + break; + case '}': + if (braceCount === 0) { + return i; + } + braceCount -= 1; + break; + case '"': + if (!escaped) { + inString = !inString; + } + break; + case ';': + return i; + case '\n': + case '\r': + if (!inString && parenCount === 0 && braceCount === 0) { + return i; + } + break; + case '\\': + escapedNow = true; + } + escaped = escapedNow; + i += 1; + } + return i; +} +// Preprocessing to help sourcekitten functions +// For now we create a new variable for each return statement, +// we can find it's type easily with sourcekitten +// TODO(@HubertBer): This has many problems which need fixing: +// - return can be inside a string +// - return Expression end parses incorrectly in case of some strings (check how it parses expo-video) +function preprocessSwiftFile(originalFileContent) { + const newFileContent = []; + const fileContent = removeComments(originalFileContent); + const returnPositions = []; + let startPos = 0; + while (startPos < fileContent.length) { + const returnIndex = fileContent.indexOf('return ', startPos); + if (returnIndex < 0 || returnIndex >= fileContent.length) { + break; + } + returnPositions.push({ + start: returnIndex, + end: returnExpressionEnd(fileContent, returnIndex), + }); + startPos = returnIndex + 1; + } + let prevEnd = 0; + for (const { start, end } of returnPositions) { + newFileContent.push(fileContent.substring(prevEnd, start)); + newFileContent.push(`\nlet returnValueDeclaration_${start}_${end} = ${fileContent.substring(start + 6, end)}\n`); + newFileContent.push(`return returnValueDeclaration_${start}_${end}\n`); + prevEnd = end; + } + newFileContent.push(fileContent.substring(prevEnd, fileContent.length)); + return newFileContent.join(''); +} +//# sourceMappingURL=sourcekittenTypeInformation.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/swift/sourcekittenTypeInformation.js.map b/packages/expo-type-information/build/swift/sourcekittenTypeInformation.js.map new file mode 100644 index 00000000000000..a0064aa3f26465 --- /dev/null +++ b/packages/expo-type-information/build/swift/sourcekittenTypeInformation.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sourcekittenTypeInformation.js","sourceRoot":"","sources":["../../src/swift/sourcekittenTypeInformation.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-type-information/build/typeInformation.d.ts b/packages/expo-type-information/build/typeInformation.d.ts new file mode 100644 index 00000000000000..33a034d2e6148c --- /dev/null +++ b/packages/expo-type-information/build/typeInformation.d.ts @@ -0,0 +1,209 @@ +export declare enum IdentifierKind { + BASIC = 0, + ENUM = 1, + RECORD = 2, + CLASS = 3 +} +export type ParametrizedType = { + name: TypeIdentifier; + types: Type[]; +}; +export type Argument = { + name: string | undefined; + type: Type; +}; +export type Field = Argument; +export type RecordType = { + name: string; + fields: Field[]; +}; +export type EnumCase = string; +export type EnumType = { + name: string; + cases: EnumCase[]; +}; +export type SumType = { + types: Type[]; +}; +export type DictionaryType = { + key: Type; + value: Type; +}; +export type OptionalType = Type; +export type ArrayType = Type; +export type TypeIdentifier = string; +export type AnonymousType = ParametrizedType | SumType | OptionalType | DictionaryType | ArrayType; +export declare enum TypeKind { + BASIC = 0, + IDENTIFIER = 1, + SUM = 2, + PARAMETRIZED = 3, + OPTIONAL = 4, + ARRAY = 5, + DICTIONARY = 6 +} +export declare enum BasicType { + ANY = 0, + STRING = 1, + NUMBER = 2, + BOOLEAN = 3, + VOID = 4, + UNDEFINED = 5, + UNRESOLVED = 6 +} +export type Type = { + kind: TypeKind; + type: BasicType | TypeIdentifier | AnonymousType; +}; +export type PropertyDeclaration = ConstantDeclaration; +export type ViewDeclaration = ModuleClassDeclaration; +export type EventDeclaration = string; +/** + * Retain information of where the thing was defined in the file. + * As collecting type information is written in asynchronous way it is non-deterministic. + * To make it deterministic we just sort the declaration by the definitionOffset, maintianing the same ordering as in original file. + */ +export type DefinitionOffset = { + definitionOffset: number; +}; +export type ConstantDeclaration = { + name: string; + type: Type; +} & DefinitionOffset; +export type FunctionDeclaration = { + name: string; + returnType: Type; + arguments: Argument[]; + parameters: Type[]; +} & DefinitionOffset; +export type PropDeclaration = { + name: string; + arguments: Argument[]; +} & DefinitionOffset; +export type ConstructorDeclaration = { + arguments: Argument[]; +} & DefinitionOffset; +export type ClassDeclaration = { + name: string; + constructor: ConstructorDeclaration | null; + methods: FunctionDeclaration[]; + asyncMethods: FunctionDeclaration[]; + properties: PropertyDeclaration[]; +} & DefinitionOffset; +export type ModuleClassDeclaration = { + name: string; + constructor: ConstructorDeclaration | null; + constants: ConstantDeclaration[]; + classes: ClassDeclaration[]; + functions: FunctionDeclaration[]; + asyncFunctions: FunctionDeclaration[]; + properties: PropertyDeclaration[]; + props: PropDeclaration[]; + views: ViewDeclaration[]; + events: EventDeclaration[]; +} & DefinitionOffset; +export type IdentifierDefinition = { + kind: IdentifierKind; + definition: string | RecordType | EnumType | ClassDeclaration; +}; +export type TypeIdentifierDefinitionMap = Map; +export type TypeIdentifierDefinitionList = [string, IdentifierDefinition][]; +export type FileTypeInformationSerialized = { + usedTypeIdentifiersList: string[]; + declaredTypeIdentifiersList: string[]; + inferredTypeParametersCountList: [string, number][]; + typeIdentifierDefinitionList: TypeIdentifierDefinitionList; + moduleClasses: ModuleClassDeclaration[]; + records: RecordType[]; + enums: EnumType[]; +}; +/** + * FileTypeInformation object abstracts over type related information in a file. + * The abstraction is closely related to Typescript and expo NativeModules (both to be independent of the actual native side + * and to give accurate information about what and how we can use the given module). + */ +export type FileTypeInformation = { + /** + * @field Set of all type identifiers declared and used in the file. + */ + usedTypeIdentifiers: Set; + /** + * @field Set of all type identifiers declared in the file. + */ + declaredTypeIdentifiers: Set; + /** + * @field For parametrized types it is the maximum number of parameters this type is used with. + * This map is useful if we want to infer how many parameters a type declared in other file has. + * + * For example if `Set` exists in a file then inferredTypeParametersCount['Set'] == 1. + * If `Map` exists then inferredTypeParametersCount['Map'] == 2. + * If you use both `SomeParametrizedType` and `SomeParametrizedType` then inferredTypeParametersCount['SomeParametrizedType'] == 2. + */ + inferredTypeParametersCount: Map; + /** + * @field Maps string identifier to the appropriate declaration object. For now only enum and records identifiers are mapped. + */ + typeIdentifierDefinitionMap: TypeIdentifierDefinitionMap; + /** + * @field Array of all module classes declared in the given file. + */ + moduleClasses: ModuleClassDeclaration[]; + /** + * @field Array of all record classes declared in the given file. + */ + records: RecordType[]; + /** + * @field Array of all enums declared in the given file. + */ + enums: EnumType[]; +}; +/** + * Used for testing purposes, maps Sets and Maps to Arrays and returns FileTypeInformationSerialized object which can be written to a JSON. + * @param param0 FileTypeInformation object to serialize. + * @returns FileTypeInformationSerialized object. + */ +export declare function serializeTypeInformation({ usedTypeIdentifiers, declaredTypeIdentifiers, inferredTypeParametersCount, typeIdentifierDefinitionMap, moduleClasses, records, enums, }: FileTypeInformation): FileTypeInformationSerialized; +/** + * Used for testing purposes, maps Arrays to Sets and Maps depending on the field and returns FileTypeInformation object. + * @param param0 FileTypeInformationSerialized object to deserialize. + * @returns FileTypeInformation object. + */ +export declare function deserializeTypeInformation({ usedTypeIdentifiersList, declaredTypeIdentifiersList, inferredTypeParametersCountList, typeIdentifierDefinitionList, moduleClasses, records, enums, }: FileTypeInformationSerialized): FileTypeInformation; +/** + * Defines the level of type inference to apply when extracting type information. + * Note: In case where type inference is on, it may take more then twice the time to compute the type information. + */ +export declare enum TypeInferenceOption { + /** No type inference will be performed. */ + NO_INFERENCE = 0, + /** Basic type inference will be applied. */ + SIMPLE_INFERENCE = 1, + /** Preprocesses the file by injecting returns to extract more type info from sourcekitten. */ + PREPROCESS_AND_INFERENCE = 2 +} +export type StringInputOption = { + type: 'string'; + fileContent: string; + language: 'Swift'; +}; +export type FileInputOption = { + type: 'file'; + inputFileAbsolutePaths: string[]; +}; +/** + * Options specifying the input source and inference level for retrieving type information. + */ +export type GetFileTypeInformationOptions = { + /** The input source, provided either as a direct string or a file path. */ + input: StringInputOption | FileInputOption; + /** The desired level of type inference. Defaults to PREPROCESS_AND_INFERENCE if omitted. */ + typeInference?: TypeInferenceOption; +}; +/** + * Reads and extracts `FileTypeInformation` from either a provided file path or a raw string of source code. + * If a raw string is provided, or if the `PREPROCESS_AND_INFERENCE` inference option is selected, + * the function will create a temporary file with the (optionally preprocessed) content to facilitate parsing. + * @param options - Configuration object containing the input source (file or string) and the desired level of type inference. + * @returns A promise that resolves to a `FileTypeInformation` object if the input was parsed successfully. Otherwise, it returns `null`. + */ +export declare function getFileTypeInformation({ input, typeInference, }: GetFileTypeInformationOptions): Promise; diff --git a/packages/expo-type-information/build/typeInformation.js b/packages/expo-type-information/build/typeInformation.js new file mode 100644 index 00000000000000..16bbb2a3e5d44b --- /dev/null +++ b/packages/expo-type-information/build/typeInformation.js @@ -0,0 +1,157 @@ +"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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TypeInferenceOption = exports.BasicType = exports.TypeKind = exports.IdentifierKind = void 0; +exports.serializeTypeInformation = serializeTypeInformation; +exports.deserializeTypeInformation = deserializeTypeInformation; +exports.getFileTypeInformation = getFileTypeInformation; +const fs = __importStar(require("fs")); +const os = __importStar(require("os")); +const path = __importStar(require("path")); +const sourcekittenTypeInformation_1 = require("./swift/sourcekittenTypeInformation"); +const utils_1 = require("./utils"); +var IdentifierKind; +(function (IdentifierKind) { + IdentifierKind[IdentifierKind["BASIC"] = 0] = "BASIC"; + IdentifierKind[IdentifierKind["ENUM"] = 1] = "ENUM"; + IdentifierKind[IdentifierKind["RECORD"] = 2] = "RECORD"; + IdentifierKind[IdentifierKind["CLASS"] = 3] = "CLASS"; +})(IdentifierKind || (exports.IdentifierKind = IdentifierKind = {})); +var TypeKind; +(function (TypeKind) { + TypeKind[TypeKind["BASIC"] = 0] = "BASIC"; + TypeKind[TypeKind["IDENTIFIER"] = 1] = "IDENTIFIER"; + TypeKind[TypeKind["SUM"] = 2] = "SUM"; + TypeKind[TypeKind["PARAMETRIZED"] = 3] = "PARAMETRIZED"; + TypeKind[TypeKind["OPTIONAL"] = 4] = "OPTIONAL"; + TypeKind[TypeKind["ARRAY"] = 5] = "ARRAY"; + TypeKind[TypeKind["DICTIONARY"] = 6] = "DICTIONARY"; +})(TypeKind || (exports.TypeKind = TypeKind = {})); +var BasicType; +(function (BasicType) { + BasicType[BasicType["ANY"] = 0] = "ANY"; + BasicType[BasicType["STRING"] = 1] = "STRING"; + BasicType[BasicType["NUMBER"] = 2] = "NUMBER"; + BasicType[BasicType["BOOLEAN"] = 3] = "BOOLEAN"; + BasicType[BasicType["VOID"] = 4] = "VOID"; + BasicType[BasicType["UNDEFINED"] = 5] = "UNDEFINED"; + BasicType[BasicType["UNRESOLVED"] = 6] = "UNRESOLVED"; +})(BasicType || (exports.BasicType = BasicType = {})); +/** + * Used for testing purposes, maps Sets and Maps to Arrays and returns FileTypeInformationSerialized object which can be written to a JSON. + * @param param0 FileTypeInformation object to serialize. + * @returns FileTypeInformationSerialized object. + */ +function serializeTypeInformation({ usedTypeIdentifiers, declaredTypeIdentifiers, inferredTypeParametersCount, typeIdentifierDefinitionMap, moduleClasses, records, enums, }) { + return { + usedTypeIdentifiersList: [...usedTypeIdentifiers.keys()].sort(), + declaredTypeIdentifiersList: [...declaredTypeIdentifiers.keys()].sort(), + inferredTypeParametersCountList: [...inferredTypeParametersCount.entries()].sort(), + typeIdentifierDefinitionList: [...typeIdentifierDefinitionMap.entries()].sort(), + moduleClasses, + records, + enums, + }; +} +/** + * Used for testing purposes, maps Arrays to Sets and Maps depending on the field and returns FileTypeInformation object. + * @param param0 FileTypeInformationSerialized object to deserialize. + * @returns FileTypeInformation object. + */ +function deserializeTypeInformation({ usedTypeIdentifiersList, declaredTypeIdentifiersList, inferredTypeParametersCountList, typeIdentifierDefinitionList, moduleClasses, records, enums, }) { + return { + usedTypeIdentifiers: new Set(usedTypeIdentifiersList), + declaredTypeIdentifiers: new Set(declaredTypeIdentifiersList), + inferredTypeParametersCount: new Map(inferredTypeParametersCountList), + typeIdentifierDefinitionMap: new Map(typeIdentifierDefinitionList), + moduleClasses, + records, + enums, + }; +} +/** + * Defines the level of type inference to apply when extracting type information. + * Note: In case where type inference is on, it may take more then twice the time to compute the type information. + */ +var TypeInferenceOption; +(function (TypeInferenceOption) { + /** No type inference will be performed. */ + TypeInferenceOption[TypeInferenceOption["NO_INFERENCE"] = 0] = "NO_INFERENCE"; + /** Basic type inference will be applied. */ + TypeInferenceOption[TypeInferenceOption["SIMPLE_INFERENCE"] = 1] = "SIMPLE_INFERENCE"; + /** Preprocesses the file by injecting returns to extract more type info from sourcekitten. */ + TypeInferenceOption[TypeInferenceOption["PREPROCESS_AND_INFERENCE"] = 2] = "PREPROCESS_AND_INFERENCE"; +})(TypeInferenceOption || (exports.TypeInferenceOption = TypeInferenceOption = {})); +async function mergeFileContents(absoluteFilePaths) { + const filesContents = await (0, utils_1.taskAll)(absoluteFilePaths, (filePath) => fs.promises.readFile(filePath, 'utf-8')); + return filesContents.join(''); +} +async function withTempFile(content, fn) { + const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'type-gen-')); + const filePath = path.join(tempDir, 'TypeInformationTemporaryFile.swift'); + try { + await fs.promises.writeFile(filePath, content, 'utf8'); + return await fn(filePath); + } + finally { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + } +} +/** + * Reads and extracts `FileTypeInformation` from either a provided file path or a raw string of source code. + * If a raw string is provided, or if the `PREPROCESS_AND_INFERENCE` inference option is selected, + * the function will create a temporary file with the (optionally preprocessed) content to facilitate parsing. + * @param options - Configuration object containing the input source (file or string) and the desired level of type inference. + * @returns A promise that resolves to a `FileTypeInformation` object if the input was parsed successfully. Otherwise, it returns `null`. + */ +async function getFileTypeInformation({ input, typeInference, }) { + const shouldPreprocessFile = typeInference === TypeInferenceOption.PREPROCESS_AND_INFERENCE; + const typeInferenceOn = typeInference !== TypeInferenceOption.NO_INFERENCE; + if (!shouldPreprocessFile && input.type === 'file' && input.inputFileAbsolutePaths.length === 0) { + return (0, sourcekittenTypeInformation_1.getSwiftFileTypeInformation)(input.inputFileAbsolutePaths[0], { + typeInference: typeInferenceOn, + }); + } + const fileContent = input.type === 'file' + ? await mergeFileContents(input.inputFileAbsolutePaths) + : input.fileContent; + const preprocessedContent = shouldPreprocessFile ? (0, sourcekittenTypeInformation_1.preprocessSwiftFile)(fileContent) : fileContent; + return withTempFile(preprocessedContent, async (tempFilePath) => { + return (0, sourcekittenTypeInformation_1.getSwiftFileTypeInformation)(tempFilePath, { + typeInference: typeInferenceOn, + }); + }); +} +//# sourceMappingURL=typeInformation.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/typeInformation.js.map b/packages/expo-type-information/build/typeInformation.js.map new file mode 100644 index 00000000000000..a74e29c503874d --- /dev/null +++ b/packages/expo-type-information/build/typeInformation.js.map @@ -0,0 +1 @@ +{"version":3,"file":"typeInformation.js","sourceRoot":"","sources":["../src/typeInformation.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoMA,4DAkBC;AAOD,gEAkBC;AA8DD,wDAwBC;AArUD,uCAAyB;AACzB,uCAAyB;AACzB,2CAA6B;AAE7B,qFAG6C;AAC7C,mCAAkC;AAElC,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,qDAAK,CAAA;IACL,mDAAI,CAAA;IACJ,uDAAM,CAAA;IACN,qDAAK,CAAA;AACP,CAAC,EALW,cAAc,8BAAd,cAAc,QAKzB;AAoCD,IAAY,QAQX;AARD,WAAY,QAAQ;IAClB,yCAAK,CAAA;IACL,mDAAU,CAAA;IACV,qCAAG,CAAA;IACH,uDAAY,CAAA;IACZ,+CAAQ,CAAA;IACR,yCAAK,CAAA;IACL,mDAAU,CAAA;AACZ,CAAC,EARW,QAAQ,wBAAR,QAAQ,QAQnB;AAED,IAAY,SAQX;AARD,WAAY,SAAS;IACnB,uCAAG,CAAA;IACH,6CAAM,CAAA;IACN,6CAAM,CAAA;IACN,+CAAO,CAAA;IACP,yCAAI,CAAA;IACJ,mDAAS,CAAA;IACT,qDAAU,CAAA;AACZ,CAAC,EARW,SAAS,yBAAT,SAAS,QAQpB;AA0HD;;;;GAIG;AACH,SAAgB,wBAAwB,CAAC,EACvC,mBAAmB,EACnB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,aAAa,EACb,OAAO,EACP,KAAK,GACe;IACpB,OAAO;QACL,uBAAuB,EAAE,CAAC,GAAG,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QAC/D,2BAA2B,EAAE,CAAC,GAAG,uBAAuB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QACvE,+BAA+B,EAAE,CAAC,GAAG,2BAA2B,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;QAClF,4BAA4B,EAAE,CAAC,GAAG,2BAA2B,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;QAC/E,aAAa;QACb,OAAO;QACP,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,0BAA0B,CAAC,EACzC,uBAAuB,EACvB,2BAA2B,EAC3B,+BAA+B,EAC/B,4BAA4B,EAC5B,aAAa,EACb,OAAO,EACP,KAAK,GACyB;IAC9B,OAAO;QACL,mBAAmB,EAAE,IAAI,GAAG,CAAS,uBAAuB,CAAC;QAC7D,uBAAuB,EAAE,IAAI,GAAG,CAAS,2BAA2B,CAAC;QACrE,2BAA2B,EAAE,IAAI,GAAG,CAAiB,+BAA+B,CAAC;QACrF,2BAA2B,EAAE,IAAI,GAAG,CAAC,4BAA4B,CAAC;QAClE,aAAa;QACb,OAAO;QACP,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,IAAY,mBAOX;AAPD,WAAY,mBAAmB;IAC7B,2CAA2C;IAC3C,6EAAY,CAAA;IACZ,4CAA4C;IAC5C,qFAAgB,CAAA;IAChB,8FAA8F;IAC9F,qGAAwB,CAAA;AAC1B,CAAC,EAPW,mBAAmB,mCAAnB,mBAAmB,QAO9B;AAuBD,KAAK,UAAU,iBAAiB,CAAC,iBAA2B;IAC1D,MAAM,aAAa,GAAG,MAAM,IAAA,eAAO,EAAC,iBAAiB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAClE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CACxC,CAAC;IACF,OAAO,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,YAAY,CAAI,OAAe,EAAE,EAAoC;IAClF,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,oCAAoC,CAAC,CAAC;IAE1E,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACvD,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,sBAAsB,CAAC,EAC3C,KAAK,EACL,aAAa,GACiB;IAC9B,MAAM,oBAAoB,GAAG,aAAa,KAAK,mBAAmB,CAAC,wBAAwB,CAAC;IAC5F,MAAM,eAAe,GAAG,aAAa,KAAK,mBAAmB,CAAC,YAAY,CAAC;IAC3E,IAAI,CAAC,oBAAoB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChG,OAAO,IAAA,yDAA2B,EAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAW,EAAE;YAC5E,aAAa,EAAE,eAAe;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,WAAW,GACf,KAAK,CAAC,IAAI,KAAK,MAAM;QACnB,CAAC,CAAC,MAAM,iBAAiB,CAAC,KAAK,CAAC,sBAAsB,CAAC;QACvD,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;IAExB,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,CAAC,CAAC,IAAA,iDAAmB,EAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAElG,OAAO,YAAY,CAAC,mBAAmB,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE;QAC9D,OAAO,IAAA,yDAA2B,EAAC,YAAY,EAAE;YAC/C,aAAa,EAAE,eAAe;SAC/B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/types.d.ts b/packages/expo-type-information/build/types.d.ts similarity index 84% rename from packages/expo-modules-test-core/build/types.d.ts rename to packages/expo-type-information/build/types.d.ts index 9149b0ec9b569d..b5f1dda879bbb9 100644 --- a/packages/expo-modules-test-core/build/types.d.ts +++ b/packages/expo-type-information/build/types.d.ts @@ -2,6 +2,11 @@ export type FileType = { path: string; content: string; }; +export type Attribute = { + 'key.attribute': string; + 'key.length': number; + 'key.offset': number; +}; export type Structure = { 'key.substructure': Structure[]; 'key.typename': string; @@ -9,6 +14,11 @@ export type Structure = { 'key.kind': string; 'key.offset': number; 'key.length': number; + 'key.nameoffset': number; + 'key.inheritedtypes': { + 'key.name': string; + }[]; + 'key.attributes': Attribute[]; }; export type CursorInfoOutput = { 'key.fully_annotated_decl': string; @@ -38,10 +48,6 @@ export type Prop = { name: string; types: Omit; }; -export type Constant = { - name: string; - types: ClosureTypes | null; -}; export type OutputModuleDefinition = { name: string; views: OutputNestedClassDefinition[]; @@ -49,7 +55,5 @@ export type OutputModuleDefinition = { events: { name: string; }[]; - constants: Constant[]; } & Record<'asyncFunctions' | 'functions' | 'properties', Closure[]> & Record<'props', Prop[]>; export type OutputNestedClassDefinition = Omit; -//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/packages/expo-modules-test-core/build/types.js b/packages/expo-type-information/build/types.js similarity index 100% rename from packages/expo-modules-test-core/build/types.js rename to packages/expo-type-information/build/types.js diff --git a/packages/expo-type-information/build/types.js.map b/packages/expo-type-information/build/types.js.map new file mode 100644 index 00000000000000..c768b79002615c --- /dev/null +++ b/packages/expo-type-information/build/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/packages/expo-type-information/build/typescriptGeneration.d.ts b/packages/expo-type-information/build/typescriptGeneration.d.ts new file mode 100644 index 00000000000000..2dd4f3d1398479 --- /dev/null +++ b/packages/expo-type-information/build/typescriptGeneration.d.ts @@ -0,0 +1,61 @@ +import ts from 'typescript'; +import { ClassDeclaration, ConstructorDeclaration, EnumType, FileTypeInformation, FunctionDeclaration, ModuleClassDeclaration, RecordType, Type, ViewDeclaration } from './typeInformation'; +export type OutputFile = { + content: string; + name: string; +}; +export interface GenerationContext { + fileInfo: FileTypeInformation; + module: ModuleClassDeclaration; + view: ViewDeclaration | null; + missingTypes: Set; +} +export declare function createDefaultGenerationContext(fileInfo: FileTypeInformation): GenerationContext | null; +export declare function getBasicTypesIdentifiers(): Set; +export declare function joinTSNodesWithNewlines(nodes: ts.Node[][]): ts.Node[]; +export declare function mapTypeToTsTypeNode(type: Type): ts.TypeNode; +export declare function buildViewPropsInterface(view: ViewDeclaration | null, options: { + exported?: boolean; +}): ts.Node[]; +export type buildFunctionOptions = { + functionDeclaration: FunctionDeclaration; + async?: boolean; + method?: boolean; + exported?: boolean; + declaration?: boolean; + returnStatement?: null | ts.ReturnStatement[]; + overrideArgumentDeclarations?: ts.ParameterDeclaration[]; + omitReturnType?: boolean; +}; +export declare function buildFunction({ functionDeclaration, async, method, exported, declaration, returnStatement, overrideArgumentDeclarations, omitReturnType, }: buildFunctionOptions): ts.FunctionDeclaration | ts.MethodDeclaration; +export declare function buildConstructor(constructor: ConstructorDeclaration, declaration: boolean): ts.ClassElement; +type BuildClassOptions = { + classDeclaration: ClassDeclaration; + exported?: boolean; + declaration?: boolean; + getFunctionReturnBlock?: (functionDeclaration: FunctionDeclaration) => ts.ReturnStatement[]; +}; +export declare function buildClass({ classDeclaration, exported, declaration, getFunctionReturnBlock, }: BuildClassOptions): ts.ClassDeclaration; +export declare function buildUnknownTypeAlias(identifier: string, exported: boolean, inferredTypeParametersCount: Map): ts.Statement; +export declare function buildRecordTypeAlias(recordType: RecordType, exported: boolean): ts.Node; +export declare function buildEnumTypeDeclaration(enumType: EnumType, exported: boolean, declared: boolean): ts.Node; +export declare function buildExposedTypesDeclarations(ctx: GenerationContext, options: { + exported?: boolean; + declare?: boolean; +}): ts.Node[]; +export declare function getViewPropsTypeName(view: ViewDeclaration): string; +export declare function prettifyCode(text: string, parser?: 'babel' | 'typescript'): Promise; +export declare function generateViewTypesFileContent(fileTypeInformation: FileTypeInformation): Promise; +export declare function generateJSXIntrinsicsFileContent(fileTypeInformation: FileTypeInformation): Promise; +export declare function generateModuleTypesFileContent(fileTypeInformation: FileTypeInformation): Promise; +export declare function generateConciseTsInterface(fileTypeInformation: FileTypeInformation): Promise<{ + volatileGeneratedFileContent: string; + moduleTypescriptInterfaceFileContent: string; +}>; +export declare function generateFullTsInterface(fileTypeInformation: FileTypeInformation): Promise<{ + moduleTypesFile: OutputFile; + moduleViewsFiles: OutputFile[]; + moduleNativeFile: OutputFile; + indexFile: OutputFile; +} | null>; +export {}; diff --git a/packages/expo-type-information/build/typescriptGeneration.js b/packages/expo-type-information/build/typescriptGeneration.js new file mode 100644 index 00000000000000..20aa6074dadf18 --- /dev/null +++ b/packages/expo-type-information/build/typescriptGeneration.js @@ -0,0 +1,696 @@ +'use strict'; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createDefaultGenerationContext = createDefaultGenerationContext; +exports.getBasicTypesIdentifiers = getBasicTypesIdentifiers; +exports.joinTSNodesWithNewlines = joinTSNodesWithNewlines; +exports.mapTypeToTsTypeNode = mapTypeToTsTypeNode; +exports.buildViewPropsInterface = buildViewPropsInterface; +exports.buildFunction = buildFunction; +exports.buildConstructor = buildConstructor; +exports.buildClass = buildClass; +exports.buildUnknownTypeAlias = buildUnknownTypeAlias; +exports.buildRecordTypeAlias = buildRecordTypeAlias; +exports.buildEnumTypeDeclaration = buildEnumTypeDeclaration; +exports.buildExposedTypesDeclarations = buildExposedTypesDeclarations; +exports.getViewPropsTypeName = getViewPropsTypeName; +exports.prettifyCode = prettifyCode; +exports.generateViewTypesFileContent = generateViewTypesFileContent; +exports.generateJSXIntrinsicsFileContent = generateJSXIntrinsicsFileContent; +exports.generateModuleTypesFileContent = generateModuleTypesFileContent; +exports.generateConciseTsInterface = generateConciseTsInterface; +exports.generateFullTsInterface = generateFullTsInterface; +const prettier_1 = __importDefault(require("prettier")); +const typescript_1 = __importDefault(require("typescript")); +const typeInformation_1 = require("./typeInformation"); +const prefix = `Automatically generated by expo-type-information.`; +const exportModifier = () => typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.ExportKeyword); +const declareModifier = () => typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.DeclareKeyword); +const asyncModifier = () => typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.AsyncKeyword); +const readonlyModifier = () => typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.ReadonlyKeyword); +const constModifier = () => typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.ConstKeyword); +const defaultModifier = () => typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.DefaultKeyword); +const unknownKeywordType = () => typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.UnknownKeyword); +const anyKeywordType = () => typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword); +const voidKeywordType = () => typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.VoidKeyword); +const newlineIdentifier = () => typescript_1.default.factory.createIdentifier('\n\n'); +let freeId = 0; +function getNextFreeId() { + freeId += 1; + return freeId; +} +function createDefaultGenerationContext(fileInfo) { + const module = fileInfo.moduleClasses[0]; + if (!module) { + return null; + } + const view = module.views[0] ?? null; + return { + fileInfo, + module, + view, + missingTypes: getMissingTypeIdentifiers(fileInfo), + }; +} +function getBasicTypesIdentifiers() { + return new Set(['any', 'number', 'string', 'undefined', 'null', 'Map', 'Set', 'Promise']); +} +function getAllNonBasicTypes(fileInfo) { + return fileInfo.declaredTypeIdentifiers + .union(fileInfo.usedTypeIdentifiers) + .difference(getBasicTypesIdentifiers()); +} +function createGeneratedPrefix() { + return [ + typescript_1.default.addSyntheticLeadingComment(typescript_1.default.factory.createIdentifier(''), typescript_1.default.SyntaxKind.MultiLineCommentTrivia, prefix), + ]; +} +function constructModifiersArray(modifiers) { + const modifiersArray = []; + if (modifiers.exported) + modifiersArray.push(exportModifier()); + if (modifiers.declare) + modifiersArray.push(declareModifier()); + if (modifiers.async) + modifiersArray.push(asyncModifier()); + if (modifiers.readonly) + modifiersArray.push(readonlyModifier()); + return modifiersArray; +} +function joinTSNodesWithNewlines(nodes) { + const new_nodes = []; + for (const node of nodes) { + if (node.length > 0) { + new_nodes.push(...node); + new_nodes.push(newlineIdentifier()); + } + } + return new_nodes; +} +function mapBasicTypeToTypeNode(basicType) { + if (basicType === typeInformation_1.BasicType.UNRESOLVED) { + return typescript_1.default.addSyntheticTrailingComment(unknownKeywordType(), typescript_1.default.SyntaxKind.MultiLineCommentTrivia, "The type couldn't be resolved automatically."); + } + const BASIC_TYPE_MAP = { + [typeInformation_1.BasicType.ANY]: typescript_1.default.SyntaxKind.AnyKeyword, + [typeInformation_1.BasicType.BOOLEAN]: typescript_1.default.SyntaxKind.BooleanKeyword, + [typeInformation_1.BasicType.NUMBER]: typescript_1.default.SyntaxKind.NumberKeyword, + [typeInformation_1.BasicType.STRING]: typescript_1.default.SyntaxKind.StringKeyword, + [typeInformation_1.BasicType.VOID]: typescript_1.default.SyntaxKind.VoidKeyword, + [typeInformation_1.BasicType.UNDEFINED]: typescript_1.default.SyntaxKind.UndefinedKeyword, + [typeInformation_1.BasicType.UNRESOLVED]: typescript_1.default.SyntaxKind.UndefinedKeyword, // This is handled earlier + }; + return typescript_1.default.factory.createKeywordTypeNode(BASIC_TYPE_MAP[basicType]); +} +function mapTypeToTsTypeNode(type) { + switch (type.kind) { + case typeInformation_1.TypeKind.BASIC: + return mapBasicTypeToTypeNode(type.type); + case typeInformation_1.TypeKind.IDENTIFIER: + return typescript_1.default.factory.createTypeReferenceNode(type.type); + case typeInformation_1.TypeKind.SUM: + return typescript_1.default.factory.createUnionTypeNode(type.type.types.map(mapTypeToTsTypeNode)); + case typeInformation_1.TypeKind.ARRAY: + return typescript_1.default.factory.createArrayTypeNode(mapTypeToTsTypeNode(type.type)); + case typeInformation_1.TypeKind.DICTIONARY: { + const dictionaryType = type.type; + const name = 'key'; + const typeNode = mapTypeToTsTypeNode(dictionaryType.key); + const valueType = mapTypeToTsTypeNode(dictionaryType.value); + return typescript_1.default.factory.createTypeLiteralNode([ + typescript_1.default.factory.createIndexSignature(undefined, [createParameter({ name, type: typeNode })], valueType), + ]); + } + // Technically this one should only be the top one and it should be handled somewhere else + // for example when creating arguemnt adding the '?' token. + // + // However we can just make it (type | undefined) in here. + // TODO(@HubertBer): Maybe also need null? + case typeInformation_1.TypeKind.OPTIONAL: + return typescript_1.default.factory.createUnionTypeNode([ + mapTypeToTsTypeNode(type.type), + mapBasicTypeToTypeNode(typeInformation_1.BasicType.UNDEFINED), + ]); + case typeInformation_1.TypeKind.PARAMETRIZED: + return typescript_1.default.factory.createTypeReferenceNode(type.type.name, type.type.types.map(mapTypeToTsTypeNode)); + } + return mapBasicTypeToTypeNode(typeInformation_1.BasicType.UNRESOLVED); +} +// +// ts.factory wrapper functions +// +function createImportDeclaration({ defaultImportName, namedImportsNames, importFromName, }) { + const hasDefault = !!defaultImportName; + const hasNamed = namedImportsNames && namedImportsNames.length > 0; + if (!hasDefault && !hasNamed) { + return []; + } + const defaultImport = hasDefault ? typescript_1.default.factory.createIdentifier(defaultImportName) : undefined; + const namedImports = hasNamed + ? typescript_1.default.factory.createNamedImports(namedImportsNames.map((name) => typescript_1.default.factory.createImportSpecifier(false, undefined, typescript_1.default.factory.createIdentifier(name)))) + : undefined; + return [ + typescript_1.default.factory.createImportDeclaration(undefined, typescript_1.default.factory.createImportClause(undefined, defaultImport, namedImports), typescript_1.default.factory.createStringLiteral(importFromName)), + ]; +} +function createParameter({ modifiers, name, type, questionToken, dotDotDotToken, initializer, }) { + return typescript_1.default.factory.createParameterDeclaration(modifiers, dotDotDotToken, name, questionToken, type, initializer); +} +function createProperty({ modifiers, name, typeNode, initializer, optional, }) { + return typescript_1.default.factory.createPropertyDeclaration(modifiers, name, optional ? typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionToken) : undefined, typeNode, initializer); +} +function createPropertySignature({ name, typeNode, optional, modifiers, }) { + return typescript_1.default.factory.createPropertySignature(modifiers, name, optional ? typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionToken) : undefined, typeNode); +} +function createCall({ expression, args, typeArgs, }) { + return typescript_1.default.factory.createCallExpression(typeof expression === 'string' ? typescript_1.default.factory.createIdentifier(expression) : expression, typeArgs, args); +} +function createRequireNativeModuleExpression({ moduleType, moduleName, }) { + return typescript_1.default.factory.createCallExpression(typescript_1.default.factory.createIdentifier('requireNativeModule'), moduleType ? [typescript_1.default.factory.createTypeReferenceNode(moduleType)] : undefined, [typescript_1.default.factory.createStringLiteral(moduleName)]); +} +function createExportDefaultAsDeclaration({ exportAsName, importFromName, }) { + return [ + typescript_1.default.factory.createExportDeclaration(undefined, false, typescript_1.default.factory.createNamedExports([ + typescript_1.default.factory.createExportSpecifier(false, typescript_1.default.factory.createIdentifier('default'), typescript_1.default.factory.createIdentifier(exportAsName)), + ]), typescript_1.default.factory.createStringLiteral(importFromName)), + ]; +} +function createTypeAlias({ exported, alias, typeParams, type, }) { + return typescript_1.default.factory.createTypeAliasDeclaration(constructModifiersArray({ exported }), alias, typeParams, type); +} +function createRequireNativeViewDeclaration(module, view) { + return [ + createParameter({ + modifiers: [constModifier()], + name: view.name, + initializer: createCall({ + expression: 'requireNativeView', + typeArgs: [typescript_1.default.factory.createTypeReferenceNode(getViewPropsTypeName(view))], + args: [ + typescript_1.default.factory.createStringLiteral(module.name), + typescript_1.default.factory.createStringLiteral(view.name), + ], + }), + }), + ]; +} +function createExportAllDeclaration({ importFromName, justTypes, }) { + return [ + typescript_1.default.factory.createExportDeclaration(undefined, justTypes ?? false, undefined, typescript_1.default.factory.createStringLiteral(importFromName)), + ]; +} +function createExportDefault(name = '_default') { + return [typescript_1.default.factory.createExportDefault(typescript_1.default.factory.createIdentifier(name))]; +} +function createComponentType(propsTypeName) { + return typescript_1.default.factory.createTypeReferenceNode('React.JSXElementConstructor', [ + typescript_1.default.factory.createTypeReferenceNode(propsTypeName), + ]); +} +function getMissingTypeIdentifiers(fileTypeInformation) { + return fileTypeInformation.usedTypeIdentifiers + .difference(fileTypeInformation.declaredTypeIdentifiers) + .difference(getBasicTypesIdentifiers()); +} +function buildPropsMembers({ props, events }) { + const buildEventPropertySignature = (eventDeclaration) => { + const name = eventDeclaration; + const typeNode = typescript_1.default.factory.createFunctionTypeNode(undefined, [createParameter({ name: 'event', type: anyKeywordType() })], voidKeywordType()); + // TODO(@HubertBer) check whether we have ways of making events not optional + return createPropertySignature({ name, typeNode, optional: true }); + }; + const buildPropPropertySignature = (propDeclaration) => { + const propTypeArgument = propDeclaration.arguments[1]?.type; + if (!propDeclaration || !propDeclaration.arguments || !propTypeArgument) { + return undefined; + } + const name = propDeclaration.name; + const typeNode = mapTypeToTsTypeNode(propTypeArgument); + return createPropertySignature({ name, typeNode }); + }; + return [ + ...props.map(buildPropPropertySignature).filter((p) => p), + ...events.map(buildEventPropertySignature), + ]; +} +function buildViewPropsInterface(view, options) { + if (!view) { + return []; + } + return [ + typescript_1.default.factory.createInterfaceDeclaration(constructModifiersArray(options), getViewPropsTypeName(view), undefined, [ + typescript_1.default.factory.createHeritageClause(typescript_1.default.SyntaxKind.ExtendsKeyword, [ + typescript_1.default.factory.createExpressionWithTypeArguments(typescript_1.default.factory.createIdentifier('ViewProps'), undefined), + ]), + ], buildPropsMembers(view)), + ]; +} +function buildClassProperty(declaration) { + return createProperty({ + modifiers: [readonlyModifier()], + name: declaration.name, + typeNode: mapTypeToTsTypeNode(declaration.type), + }); +} +function buildNativeModuleClassDeclaration({ moduleClassDeclaration, exportedModuleName, }) { + const buildClassTypeProperty = (classDeclaration) => createProperty({ + // TODO(@HubertBer): that's a hack, but I couldn't find a proper way to do this + // The problem is that declare class semantics seem somewhat different than class semantics. + name: classDeclaration.name, + typeNode: typescript_1.default.factory.createTypeQueryNode(typescript_1.default.factory.createIdentifier(classDeclaration.name)), + }); + const buildSyncMethod = (functionDeclaration) => buildFunction({ + functionDeclaration, + method: true, + declaration: true, + }); + const buildAsyncMethod = (functionDeclaration) => buildFunction({ + functionDeclaration, + async: true, + method: true, + declaration: true, + }); + return [ + typescript_1.default.factory.createClassDeclaration([exportModifier(), declareModifier()], exportedModuleName ?? `${moduleClassDeclaration.name}NativeModuleType`, undefined, [ + typescript_1.default.factory.createHeritageClause(typescript_1.default.SyntaxKind.ExtendsKeyword, [ + typescript_1.default.factory.createExpressionWithTypeArguments(typescript_1.default.factory.createIdentifier('NativeModule'), undefined), + ]), + ], [ + ...moduleClassDeclaration.constants.map(buildClassProperty), + ...moduleClassDeclaration.properties.map(buildClassProperty), + ...moduleClassDeclaration.functions.map(buildSyncMethod), + ...moduleClassDeclaration.asyncFunctions.map(buildAsyncMethod), + ...moduleClassDeclaration.classes.map(buildClassTypeProperty), + ]), + ]; +} +function buildArgumentDeclarationAndName(arg) { + const argName = arg.name ?? '_' + getNextFreeId(); + const argDeclaration = createParameter({ + name: argName, + type: mapTypeToTsTypeNode(arg.type), + }); + return { argDeclaration, argName }; +} +function buildArgumentDeclaration(arg) { + return buildArgumentDeclarationAndName(arg).argDeclaration; +} +function buildFunction({ functionDeclaration, async, method, exported, declaration, returnStatement, overrideArgumentDeclarations, omitReturnType, }) { + const functionModifiers = constructModifiersArray({ exported, async: async && !declaration }); + const customReturn = !!returnStatement; + const bareReturnTypeNode = mapTypeToTsTypeNode(functionDeclaration.returnType); + const wrapWithPromiseType = (typeNode) => typescript_1.default.factory.createTypeReferenceNode('Promise', [typeNode]); + let returnTypeNode = async + ? wrapWithPromiseType(bareReturnTypeNode) + : bareReturnTypeNode; + if (omitReturnType) { + returnTypeNode = undefined; + } + const argumentDeclarations = overrideArgumentDeclarations ?? functionDeclaration.arguments.map(buildArgumentDeclaration); + if (method) { + return typescript_1.default.factory.createMethodDeclaration(functionModifiers, undefined, functionDeclaration.name, undefined, undefined, argumentDeclarations, returnTypeNode, declaration ? undefined : typescript_1.default.factory.createBlock(customReturn ? returnStatement : [])); + } + return typescript_1.default.factory.createFunctionDeclaration(functionModifiers, undefined, functionDeclaration.name, undefined, argumentDeclarations, returnTypeNode, declaration ? undefined : typescript_1.default.factory.createBlock(customReturn ? returnStatement : [])); +} +function buildConstructor(constructor, declaration) { + return typescript_1.default.factory.createConstructorDeclaration(undefined, constructor.arguments.map(buildArgumentDeclaration), declaration ? undefined : typescript_1.default.factory.createBlock([])); +} +// TODO(@HubertBer): figure out what about inheritance, should or should not inherit SharedObject +function buildClass({ classDeclaration, exported, declaration, getFunctionReturnBlock, }) { + const getReturnStatement = (method) => !declaration && getFunctionReturnBlock ? getFunctionReturnBlock(method) : null; + const buildMethod = (method, async) => buildFunction({ + functionDeclaration: method, + method: true, + async, + declaration, + returnStatement: getReturnStatement(method), + }); + const classMembers = [ + ...classDeclaration.methods.map((m) => buildMethod(m)), + ...classDeclaration.asyncMethods.map((m) => buildMethod(m, true)), + ...(declaration ? classDeclaration.properties.map(buildClassProperty) : []), + classDeclaration.constructor + ? buildConstructor(classDeclaration.constructor, declaration ?? false) + : undefined, + ].filter((x) => x !== undefined); + return typescript_1.default.factory.createClassDeclaration(constructModifiersArray({ exported, declare: declaration }), typescript_1.default.factory.createIdentifier(classDeclaration.name), undefined, [], classMembers); +} +function buildModuleDefaultExport({ moduleName, moduleType, declaration, }) { + const name = '_default'; + const type = moduleType ? typescript_1.default.factory.createTypeReferenceNode(moduleType) : undefined; + return [ + createParameter({ + modifiers: [constModifier()], + name, + type, + initializer: declaration + ? undefined + : createRequireNativeModuleExpression({ moduleName, moduleType }), + }), + typescript_1.default.factory.createExportDefault(typescript_1.default.factory.createIdentifier('_default')), + ]; +} +function buildUnknownTypeAlias(identifier, exported, inferredTypeParametersCount) { + const paramCount = inferredTypeParametersCount.get(identifier); + const typeParamsList = []; + for (let i = 0; i < (paramCount ?? 0); i += 1) { + typeParamsList.push(typescript_1.default.factory.createTypeParameterDeclaration(undefined, 'T' + i)); + } + const typeParams = (paramCount ?? 0) === 0 ? undefined : typeParamsList; + return createTypeAlias({ exported, alias: identifier, type: unknownKeywordType(), typeParams }); +} +function buildRecordTypeAlias(recordType, exported) { + return createTypeAlias({ + exported, + alias: recordType.name, + type: typescript_1.default.factory.createTypeLiteralNode(recordType.fields.map((field) => { + const optional = field.type.kind === typeInformation_1.TypeKind.OPTIONAL; + const typeNode = mapTypeToTsTypeNode(optional ? field.type.type : field.type); + const name = field.name ?? '_' + getNextFreeId(); + return createPropertySignature({ name, optional, typeNode }); + })), + }); +} +function buildEnumTypeDeclaration(enumType, exported, declared) { + return typescript_1.default.factory.createEnumDeclaration(constructModifiersArray({ exported, declare: declared }), enumType.name, enumType.cases.map((enumcase) => typescript_1.default.factory.createEnumMember(enumcase))); +} +function buildMissingTypesDeclarations(ctx) { + if (ctx.missingTypes.size === 0) { + return []; + } + const header = typescript_1.default.addSyntheticLeadingComment(typescript_1.default.factory.createIdentifier(''), typescript_1.default.SyntaxKind.SingleLineCommentTrivia, ` These types haven't been defined in provided file(s).`, true); + const aliases = [...ctx.missingTypes].map((identifier) => buildUnknownTypeAlias(identifier, true, ctx.fileInfo.inferredTypeParametersCount)); + return [header, ...aliases]; +} +function buildDefaultViewComponent({ componentName, propsTypeAlias, }) { + const jsxElement = typescript_1.default.factory.createJsxSelfClosingElement(typescript_1.default.factory.createIdentifier(componentName), undefined, typescript_1.default.factory.createJsxAttributes([ + typescript_1.default.factory.createJsxSpreadAttribute(typescript_1.default.factory.createIdentifier('props')), + ])); + const functionBody = typescript_1.default.factory.createBlock([typescript_1.default.factory.createReturnStatement(jsxElement)]); + return [ + typescript_1.default.factory.createFunctionExpression([exportModifier(), defaultModifier()], undefined, componentName + 'Component', undefined, [ + createParameter({ + name: 'props', + type: typescript_1.default.factory.createTypeReferenceNode(propsTypeAlias), + }), + ], undefined, functionBody), + ]; +} +function buildExposedTypesDeclarations(ctx, options) { + const recordDeclarationMap = (recordType) => buildRecordTypeAlias(recordType, options.exported ?? false); + const enumDeclarationMap = (enumType) => buildEnumTypeDeclaration(enumType, options.exported ?? false, options.declare ?? false); + const classDeclarationMap = (classDeclaration) => buildClass({ classDeclaration, exported: true, declaration: true }); + return joinTSNodesWithNewlines([ + createImportDeclaration({ namedImportsNames: ['NativeModule'], importFromName: 'expo' }), + buildMissingTypesDeclarations(ctx), + ctx.fileInfo.records.flatMap(recordDeclarationMap), + ctx.fileInfo.enums.flatMap(enumDeclarationMap), + ctx.module.classes.map(classDeclarationMap), + ]); +} +function buildModuleDeclarationNodes(ctx) { + return joinTSNodesWithNewlines([ + createGeneratedPrefix(), + buildExposedTypesDeclarations(ctx, { exported: true }), + buildNativeModuleClassDeclaration({ moduleClassDeclaration: ctx.module }), + buildModuleDefaultExport({ + moduleName: ctx.module.name, + moduleType: ctx.module.name, + declaration: true, + }), + ]); +} +function getViewPropsTypeName(view) { + return view.name + (view.name.endsWith('View') ? 'Props' : 'ViewProps'); +} +function buildViewDeclarationNodes(ctx) { + if (!ctx.view) { + return []; + } + const viewComponentType = createComponentType(getViewPropsTypeName(ctx.view)); + const modifiers = [declareModifier(), constModifier()]; + return joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ namedImportsNames: ['ViewProps'], importFromName: 'react-native' }), + buildMissingTypesDeclarations(ctx), + buildViewPropsInterface(ctx.view, {}), + [createParameter({ modifiers, name: '_default', type: viewComponentType })], + createExportDefault(), + ]); +} +function buildJSXIntrinsicsViewNodes(ctx) { + const name = ctx.module.name; + const propsTypeNode = ctx.view + ? typescript_1.default.factory.createTypeLiteralNode(buildPropsMembers(ctx.view)) + : undefined; + const jsxIntrinsicElementsNodes = []; + if (ctx.view) { + const globalIdentifier = typescript_1.default.factory.createIdentifier('global'); + const jsxIdentifier = typescript_1.default.factory.createIdentifier('JSX'); + const intrinsicElementsIdentifier = typescript_1.default.factory.createIdentifier('IntrinsicElements'); + jsxIntrinsicElementsNodes.push(typescript_1.default.factory.createModuleDeclaration([declareModifier()], globalIdentifier, typescript_1.default.factory.createModuleBlock([ + typescript_1.default.factory.createModuleDeclaration(undefined, jsxIdentifier, typescript_1.default.factory.createModuleBlock([ + typescript_1.default.factory.createInterfaceDeclaration(undefined, intrinsicElementsIdentifier, undefined, undefined, [createPropertySignature({ name, typeNode: propsTypeNode })]), + ]), typescript_1.default.NodeFlags.Namespace), + ]), typescript_1.default.NodeFlags.GlobalAugmentation)); + } + return joinTSNodesWithNewlines([ + buildExposedTypesDeclarations(ctx, { declare: true }), + jsxIntrinsicElementsNodes, + ]); +} +function buildNativeModuleGeneratedNodes(ctx) { + return joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ namedImportsNames: ['ViewProps'], importFromName: 'react-native' }), + buildExposedTypesDeclarations(ctx, { exported: true }), + buildViewPropsInterface(ctx.view, { exported: true }), + buildNativeModuleClassDeclaration({ moduleClassDeclaration: ctx.module }), + ]); +} +function buildStableNativeModuleInterface(ctx) { + const generatedModuleAlias = ctx.module.name; + const generatedModuleTypeAlias = `${ctx.module.name}NativeModuleType`; + const generatedFilePath = `./${ctx.module.name}.generated`; + const exportedFunctionReturnStatement = (functionDeclaration, overrideArguments) => { + const expression = `${generatedModuleAlias}.${functionDeclaration.name}`; + const args = overrideArguments ?? + functionDeclaration.arguments.map((arg) => typescript_1.default.factory.createIdentifier(arg.name ?? 'unnamedArgument')); + return typescript_1.default.factory.createReturnStatement(createCall({ + expression, + args, + })); + }; + const mapFunctionDeclarationTemplate = (isAsync) => (functionDeclaration) => { + const argumentDeclarations = []; + const argumentNames = []; + for (const arg of functionDeclaration.arguments) { + const { argDeclaration, argName } = buildArgumentDeclarationAndName(arg); + argumentDeclarations.push(argDeclaration); + argumentNames.push(argName); + } + return [ + buildFunction({ + functionDeclaration, + async: isAsync, + exported: true, + returnStatement: [ + exportedFunctionReturnStatement(functionDeclaration, argumentNames.map(typescript_1.default.factory.createIdentifier)), + ], + overrideArgumentDeclarations: argumentDeclarations, + omitReturnType: true, + }), + ]; + }; + const mapSyncFunctionDeclaration = mapFunctionDeclarationTemplate(false); + const mapAsyncFunctionDeclaration = mapFunctionDeclarationTemplate(true); + const buildConstantExportProperty = (constant) => { + const typeNode = mapTypeToTsTypeNode(constant.type); + const modifiers = [exportModifier(), constModifier()]; + const initializer = typescript_1.default.factory.createIdentifier(`${generatedModuleAlias}.${constant.name}`); + return createProperty({ modifiers, name: constant.name, typeNode, initializer }); + }; + return joinTSNodesWithNewlines([ + ctx.view + ? createImportDeclaration({ importFromName: 'react', defaultImportName: 'React' }) + : [], + createImportDeclaration({ + namedImportsNames: [ + ...ctx.fileInfo.usedTypeIdentifiers.difference(getBasicTypesIdentifiers()), + ...[generatedModuleTypeAlias, ctx.view ? getViewPropsTypeName(ctx.view) : null].filter((v) => v !== null), + ], + importFromName: generatedFilePath, + }), + createImportDeclaration({ + namedImportsNames: ['requireNativeModule', 'requireNativeView'], + importFromName: 'expo', + }), + [ + createParameter({ + modifiers: [constModifier()], + name: ctx.module.name, + type: typescript_1.default.factory.createTypeReferenceNode(generatedModuleTypeAlias), + initializer: createRequireNativeModuleExpression({ + moduleName: ctx.module.name, + moduleType: generatedModuleTypeAlias, + }), + }), + ], + ctx.view ? createRequireNativeViewDeclaration(ctx.module, ctx.view) : [], + ctx.module.constants.map(buildConstantExportProperty), + ctx.module.functions.flatMap(mapSyncFunctionDeclaration), + ctx.module.asyncFunctions.flatMap(mapAsyncFunctionDeclaration), + ctx.view + ? buildDefaultViewComponent({ + componentName: ctx.view.name, + propsTypeAlias: getViewPropsTypeName(ctx.view), + }) + : [], + ]); +} +async function tsNodesToString(elements) { + const printer = typescript_1.default.createPrinter({ newLine: typescript_1.default.NewLineKind.LineFeed }); + const resultFile = typescript_1.default.createSourceFile('', '', typescript_1.default.ScriptTarget.Latest, false, typescript_1.default.ScriptKind.TSX); + const viewTypes = typescript_1.default.factory.createNodeArray(elements); + const printedTs = printer.printList(typescript_1.default.ListFormat.MultiLine | typescript_1.default.ListFormat.PreserveLines, viewTypes, resultFile); + return await prettifyCode(printedTs, 'typescript'); +} +async function prettifyCode(text, parser = 'babel') { + return await prettier_1.default.format(text, { + parser, + tabWidth: 2, + printWidth: 100, + trailingComma: 'none', + singleQuote: true, + }); +} +async function generateViewTypesFileContent(fileTypeInformation) { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + return tsNodesToString(buildViewDeclarationNodes(ctx)); +} +async function generateJSXIntrinsicsFileContent(fileTypeInformation) { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + return tsNodesToString(buildJSXIntrinsicsViewNodes(ctx)); +} +async function generateModuleTypesFileContent(fileTypeInformation) { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + return tsNodesToString(buildModuleDeclarationNodes(ctx)); +} +async function generateConciseTsInterface(fileTypeInformation) { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return { volatileGeneratedFileContent: '', moduleTypescriptInterfaceFileContent: '' }; + } + const volatileGeneratedFileContent = await tsNodesToString(buildNativeModuleGeneratedNodes(ctx)); + const moduleTypescriptInterfaceFileContent = await tsNodesToString(buildStableNativeModuleInterface(ctx)); + return { + volatileGeneratedFileContent, + moduleTypescriptInterfaceFileContent, + }; +} +async function generateFullTsInterface(fileTypeInformation) { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + const moduleNativeFileImportName = `${ctx?.module.name}Module`; + const moduleTypesFileImportName = `${ctx?.module.name}.types`; + const moduleViewsFilesImportNames = []; + const moduleTypesFileNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ namedImportsNames: ['ViewProps'], importFromName: 'react-native' }), + buildExposedTypesDeclarations(ctx, { exported: true }), + ...ctx.module.views.map((view) => buildViewPropsInterface(view, { exported: true })), + ]); + const moduleViewFilesNodes = []; + for (const view of ctx.module.views) { + const moduleViewFileNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ + namedImportsNames: ['requireNativeView'], + importFromName: 'expo', + }), + createImportDeclaration({ + namedImportsNames: [getViewPropsTypeName(view)], + importFromName: `./${moduleTypesFileImportName}`, + }), + createRequireNativeViewDeclaration(ctx.module, view), + buildDefaultViewComponent({ + componentName: view.name, + propsTypeAlias: getViewPropsTypeName(view), + }), + ]); + moduleViewFilesNodes.push(moduleViewFileNodes); + moduleViewsFilesImportNames.push(`${view.name}View`); + } + const moduleNativeModuleNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ + namedImportsNames: ['requireNativeModule', 'NativeModule'], + importFromName: 'expo', + }), + createImportDeclaration({ + namedImportsNames: [...getAllNonBasicTypes(ctx.fileInfo)], + importFromName: `./${moduleTypesFileImportName}`, + }), + buildNativeModuleClassDeclaration({ + moduleClassDeclaration: ctx.module, + exportedModuleName: ctx.module.name, + }), + buildModuleDefaultExport({ moduleName: ctx.module.name, moduleType: ctx.module.name }), + ]); + const indexFileNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createExportAllDeclaration({ + importFromName: `./${moduleTypesFileImportName}`, + justTypes: true, + }), + createExportDefaultAsDeclaration({ + exportAsName: ctx.module.name, + importFromName: `./${moduleNativeFileImportName}`, + }), + ...ctx.module.views.map((view, idx) => createExportDefaultAsDeclaration({ + exportAsName: view.name, + importFromName: `./${moduleViewsFilesImportNames[idx]}`, + })), + ]); + const [moduleTypesFileContent, moduleViewFilesContents, moduleNativeFileContent, indexFileContent,] = await Promise.all([ + tsNodesToString(moduleTypesFileNodes), + Promise.all(moduleViewFilesNodes.map(tsNodesToString)), + tsNodesToString(moduleNativeModuleNodes), + tsNodesToString(indexFileNodes), + ]); + const moduleTypesFile = { + content: moduleTypesFileContent, + name: `${moduleTypesFileImportName}.ts`, + }; + const moduleViewsFiles = moduleViewFilesContents.map((moduleViewFileContent, idx) => { + return { + content: moduleViewFileContent, + name: `${moduleViewsFilesImportNames[idx]}.tsx`, + }; + }); + const moduleNativeFile = { + content: moduleNativeFileContent, + name: `${moduleNativeFileImportName}.ts`, + }; + const indexFile = { content: indexFileContent, name: `index.ts` }; + return { + moduleTypesFile, + moduleViewsFiles, + moduleNativeFile, + indexFile, + }; +} +//# sourceMappingURL=typescriptGeneration.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/typescriptGeneration.js.map b/packages/expo-type-information/build/typescriptGeneration.js.map new file mode 100644 index 00000000000000..37180c28ee2de5 --- /dev/null +++ b/packages/expo-type-information/build/typescriptGeneration.js.map @@ -0,0 +1 @@ +{"version":3,"file":"typescriptGeneration.js","sourceRoot":"","sources":["../src/typescriptGeneration.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-type-information/build/utils.d.ts b/packages/expo-type-information/build/utils.d.ts new file mode 100644 index 00000000000000..504d6f50e29c6b --- /dev/null +++ b/packages/expo-type-information/build/utils.d.ts @@ -0,0 +1,6 @@ +export declare const taskAll: (inputs: T[], map: (input: T, index: number) => Promise) => Promise; +export declare function scanFilesRecursively(parentPath: string, includeDirectory?: (parentPath: string, name: string) => boolean, sort?: boolean): AsyncGenerator<{ + readonly path: string; + readonly parentPath: string; + readonly name: string; +}, void, unknown>; diff --git a/packages/expo-type-information/build/utils.js b/packages/expo-type-information/build/utils.js new file mode 100644 index 00000000000000..82c1a054ee212f --- /dev/null +++ b/packages/expo-type-information/build/utils.js @@ -0,0 +1,44 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.taskAll = void 0; +exports.scanFilesRecursively = scanFilesRecursively; +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +// TODO(@HubertBer): Also exists in expo-modules-autolinking, but with a limiter, maybe take it or depend on it? +const taskAll = (inputs, map) => { + return Promise.all(inputs.map(map)); +}; +exports.taskAll = taskAll; +// TODO(@HubertBer): Taken from expo-modules-autolinking, maybe import it instead? +async function* scanFilesRecursively(parentPath, includeDirectory, sort = !fs_1.default.promises.opendir) { + const queue = [parentPath]; + let targetPath; + while (queue.length > 0 && (targetPath = queue.shift()) != null) { + try { + const entries = sort + ? (await fs_1.default.promises.readdir(targetPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name)) + : await fs_1.default.promises.opendir(targetPath); + for await (const entry of entries) { + if (entry.isDirectory() && entry.name !== 'node_modules') { + if (!includeDirectory || includeDirectory(targetPath, entry.name)) { + queue.push(path_1.default.join(targetPath, entry.name)); + } + } + else if (entry.isFile()) { + yield { + path: path_1.default.join(targetPath, entry.name), + parentPath: targetPath, + name: entry.name, + }; + } + } + } + catch { + continue; + } + } +} +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/packages/expo-type-information/build/utils.js.map b/packages/expo-type-information/build/utils.js.map new file mode 100644 index 00000000000000..9f9aa80474977d --- /dev/null +++ b/packages/expo-type-information/build/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;AAYA,oDA+BC;AA3CD,4CAAoB;AACpB,gDAAwB;AAExB,gHAAgH;AACzG,MAAM,OAAO,GAAG,CACrB,MAAW,EACX,GAA4C,EAC9B,EAAE;IAChB,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACtC,CAAC,CAAC;AALW,QAAA,OAAO,WAKlB;AAEF,kFAAkF;AAC3E,KAAK,SAAS,CAAC,CAAC,oBAAoB,CACzC,UAAkB,EAClB,gBAAgE,EAChE,IAAI,GAAG,CAAC,YAAE,CAAC,QAAQ,CAAC,OAAO;IAE3B,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC;IAC3B,IAAI,UAA8B,CAAC;IACnC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAChE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI;gBAClB,CAAC,CAAC,CAAC,MAAM,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC7E,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAC7B;gBACH,CAAC,CAAC,MAAM,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC1C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAClC,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;oBACzD,IAAI,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBAClE,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;oBAChD,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;oBAC1B,MAAM;wBACJ,IAAI,EAAE,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC;wBACvC,UAAU,EAAE,UAAU;wBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;qBACR,CAAC;gBACb,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/packages/expo-type-information/jest.config.js b/packages/expo-type-information/jest.config.js new file mode 100644 index 00000000000000..d34908ad4fac25 --- /dev/null +++ b/packages/expo-type-information/jest.config.js @@ -0,0 +1,6 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + clearMocks: true, +}; diff --git a/packages/expo-type-information/package.json b/packages/expo-type-information/package.json new file mode 100644 index 00000000000000..8781e6162301c6 --- /dev/null +++ b/packages/expo-type-information/package.json @@ -0,0 +1,47 @@ +{ + "name": "expo-type-information", + "version": "0.0.1", + "keywords": [ + "react-native", + "expo", + "expo-modules" + ], + "main": "build/index.js", + "types": "build/index.d.ts", + "scripts": { + "build": "expo-module build", + "clean": "expo-module clean", + "lint": "expo-module lint", + "test": "echo \"Tests can only be run on MacOS with sourceKitten installed. Run tests locally instead using local-test script.\"", + "local-test": "NODE_OPTIONS=\"--experimental-vm-modules\" expo-module test", + "expo-module": "expo-module" + }, + "bin": { + "expo-type-information": "./bin/cli.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/expo/expo.git", + "directory": "packages/expo-type-information" + }, + "bugs": { + "url": "https://github.com/expo/expo/issues" + }, + "author": "650 Industries, Inc.", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "commander": "^12.1.0", + "prettier": "^3.0.3", + "yaml": "^2.3.2", + "typescript": "~6.0.3" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "@types/jest": "^29.2.1", + "@types/node": "^22.14.0", + "expo-module-scripts": "workspace:*", + "jest": "^29.3.1", + "ts-jest": "^29.1.2" + } +} diff --git a/packages/expo-type-information/src/cli.ts b/packages/expo-type-information/src/cli.ts new file mode 100644 index 00000000000000..bd4053df965771 --- /dev/null +++ b/packages/expo-type-information/src/cli.ts @@ -0,0 +1,38 @@ +import { Command } from 'commander'; + +import { isSourceKittenInstalled } from './commands/commandUtils'; +import { generateJsxIntrinsics } from './commands/generateJSXIntrinsicsCommand'; +import { generateMocksForFileCommand } from './commands/generateMocksForFileCommand'; +import { generateModuleTypesCommand } from './commands/generateModuleTypesCommand'; +import { generateViewTypesCommand } from './commands/generateViewTypesCommand'; +import { inlineModulesInterfaceCommand } from './commands/inlineModulesInterfaceCommand'; +import { moduleInterfaceCommand } from './commands/moduleInterfaceCommand'; +import { shortModuleInterfaceCommand } from './commands/shortModuleInterfaceCommand'; +import { typeInformationCommand } from './commands/typeInformationCommand'; + +async function main(args: string[]) { + if (!isSourceKittenInstalled()) { + console.error('Sourcekitten not found! Install it like so: brew install sourcekitten'); + return; + } + const cli = new Command(); + cli + .name('expo-type-information') + .version(require('../package.json').version) + .description('CLI commands for retrieving type information from native files.'); + + moduleInterfaceCommand(cli); + inlineModulesInterfaceCommand(cli); + shortModuleInterfaceCommand(cli); + generateMocksForFileCommand(cli); + + const otherCommands = cli.command('other').description('internal or very specific commands'); + typeInformationCommand(otherCommands); + generateModuleTypesCommand(otherCommands); + generateViewTypesCommand(otherCommands); + generateJsxIntrinsics(otherCommands); + + await cli.parseAsync(args, { from: 'user' }); +} + +main(process.argv.slice(2)); diff --git a/packages/expo-type-information/src/commands/commandUtils.ts b/packages/expo-type-information/src/commands/commandUtils.ts new file mode 100644 index 00000000000000..a9c4bda40d0e23 --- /dev/null +++ b/packages/expo-type-information/src/commands/commandUtils.ts @@ -0,0 +1,352 @@ +import chalk from 'chalk'; +import { execSync } from 'child_process'; +import commander from 'commander'; +import { createHash } from 'crypto'; +import fs from 'fs'; +import path from 'path'; + +import { + FileTypeInformation, + getFileTypeInformation, + TypeInferenceOption, +} from '../typeInformation'; +import { generateConciseTsInterface } from '../typescriptGeneration'; +import { taskAll } from '../utils'; + +export type TypeInformationCommandCommonAllArguments = { + inputPaths?: string[]; + modulePath?: string; + outputPath?: string; + typeInference?: 'NO_INFERENCE' | 'SIMPLE_INFERENCE' | 'PREPROCESS_AND_INFERENCE'; + watcher?: boolean; + appJson?: string; +}; + +let sourcekittenInstalled: boolean; +export function isSourceKittenInstalled(): boolean { + if (sourcekittenInstalled !== undefined) { + return sourcekittenInstalled; + } + try { + execSync('which sourcekitten', { stdio: 'ignore' }); + sourcekittenInstalled = true; + } catch { + sourcekittenInstalled = false; + } + return sourcekittenInstalled; +} + +export interface ParsedArguments { + realInputPaths: string[]; + realOutputPath?: string; + typeInference: TypeInferenceOption; + watcher: boolean; + appJsonPath?: string; +} + +export function addCommonOptions(command: commander.Command): commander.Command { + return command + .option( + '-i, --input-paths ', + 'Paths to Swift files for some module, glob patterns are allowed.' + ) + .option('-m --module-path ', 'Path to expo module root directory.') + .option( + '-o, --output-path ', + 'Path to save the generated output. If this option is not provided the generated output is printed to console.' + ) + .option( + '-t, --type-inference ', + // TODO(@HubertBer) Fix the PREPROCESS_AND_INFERENCE option. + 'Level of type inference: NO_INFERENCE, SIMPLE_INFERENCE, or PREPROCESS_AND_INFERENCE. Note that the last option rarely fails for some modules, use the 2nd or 1st in that case.', + 'SIMPLE_INFERENCE' + ) + .option('-w --watcher', 'Starts a watcher that checks for changes in input-path file.'); +} + +/** + * Debounce a function to only run once after a period of inactivity + * If called while waiting, it will reset the timer + */ +export function debounce any>( + fn: T, + timeout: number = 500 +): (...args: Parameters) => void { + let timer: ReturnType; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => { + fn(...args); + }, timeout); + }; +} + +export async function runCommandOnWatch(parsedArgs: ParsedArguments, command: () => Promise) { + const debounced_command = debounce(command, 1000); + debounced_command(); + if (!parsedArgs.watcher) { + return; + } + + await taskAll(parsedArgs.realInputPaths, async (realInputPath) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for await (const _ of fs.promises.watch(realInputPath)) { + if (!fs.existsSync(realInputPath)) { + return; + } + debounced_command(); + } + }); +} + +export function getFilesForGlobPattern(globPattern: string): string[] | null { + try { + const normalizedPattern = globPattern.replace(/\\/g, '/'); + + const matches = fs.globSync(normalizedPattern, { + withFileTypes: true, + }); + + const resolvedPaths = matches + .filter((entry) => entry.isFile()) + .map((entry) => path.resolve(entry.parentPath, entry.name)); + + return resolvedPaths.length > 0 ? resolvedPaths : null; + } catch { + return null; + } +} + +export function sanitizeAndValidateOutputPath( + rawPath: string, + isFilePath: boolean = true +): string | null { + try { + const resolvedPath = path.resolve(rawPath); + + if (fs.existsSync(resolvedPath)) { + const pathStat = fs.statSync(resolvedPath); + const isValid = isFilePath ? pathStat.isFile() : pathStat.isDirectory(); + return isValid ? resolvedPath : null; + } + + if (isFilePath && fs.existsSync(path.dirname(resolvedPath))) { + return resolvedPath; + } + } catch {} + + return null; +} + +export function parseInferenceOption(option?: string): TypeInferenceOption | null { + if (!option) return TypeInferenceOption.PREPROCESS_AND_INFERENCE; + switch (option) { + case 'NO_INFERENCE': + return TypeInferenceOption.NO_INFERENCE; + case 'SIMPLE_INFERENCE': + return TypeInferenceOption.SIMPLE_INFERENCE; + case 'PREPROCESS_AND_INFERENCE': + return TypeInferenceOption.PREPROCESS_AND_INFERENCE; + } + return null; +} + +export function getPodspecFilePath(modulePath: string): string | null { + const normalizedModulePath = fs.realpathSync(modulePath).replace(/\\/g, '/'); + + const podspecFiles = [...fs.globSync(`${normalizedModulePath}/ios/*.podspec`)]; + const podspecFile = podspecFiles[0]; + return podspecFile ?? null; +} + +export function getSourceFilesGlobFromPodspecFile(podspecPath: string): string | null { + const podspecContent = fs.readFileSync(podspecPath, 'utf8'); + const sourceFilesRegex = /\.source_files\s*=\s*(["'])(.*?)\1/; + const match = podspecContent.match(sourceFilesRegex); + return match?.[2] ?? null; +} + +export function getModuleFilePathsFromPodspec(modulePath: string): string[] | null { + const podspecPath = getPodspecFilePath(modulePath); + if (!podspecPath) { + console.warn(`No .podspec found in ${modulePath}`); + return null; + } + + const extractedGlob = getSourceFilesGlobFromPodspecFile(podspecPath); + if (!extractedGlob) { + console.warn(`Could not extract source_files glob from ${podspecPath}`); + return null; + } + + const podspecDir = path.dirname(podspecPath); + const absoluteGlobPattern = path.posix.join(podspecDir.replace(/\\/g, '/'), extractedGlob); + + return getFilesForGlobPattern(absoluteGlobPattern)?.filter((f) => f.endsWith('.swift')) ?? null; +} + +export function uniqueStrings(strings: string[]): string[] { + return [...new Set(strings)]; +} + +export function parseCommandArguments( + options: TypeInformationCommandCommonAllArguments, + isOutputFile: boolean = true +): ParsedArguments | null { + const appJsonPath = options.appJson ?? undefined; + let realInputPaths: string[] = (options.inputPaths ?? []) + .flatMap(getFilesForGlobPattern) + .filter((p) => p != null); + + if (options.modulePath) { + const modulePaths = getModuleFilePathsFromPodspec(options.modulePath) ?? []; + realInputPaths.push(...modulePaths); + } + realInputPaths = uniqueStrings(realInputPaths); + + if ((!realInputPaths || realInputPaths.length === 0) && !appJsonPath) { + console.error( + `Provide valid globs to existing files or a path to a module with valid podspec.` + ); + return null; + } + + let realOutputPath: string | undefined = undefined; + if (options.outputPath) { + const validatedOutPath = sanitizeAndValidateOutputPath(options.outputPath, isOutputFile); + if (!validatedOutPath) { + console.error( + `Output path ${options.outputPath} is not valid. ${isOutputFile ? 'Provide a path to an existing file, or to a file in an existing parent directory.' : 'Provide a path to an existing directory.'}` + ); + return null; + } + realOutputPath = validatedOutPath; + } else if (options.modulePath) { + // if path to module directory is provided, we can generate ts types under src directory + realOutputPath = + sanitizeAndValidateOutputPath(path.join(options.modulePath, 'src'), false) ?? undefined; + } + + const typeInference = parseInferenceOption(options.typeInference); + if (typeInference === null) { + console.error(`Invalid typeInference option. ${options.typeInference}`); + return null; + } + + const watcher = options.watcher ?? false; + return { realInputPaths, realOutputPath, typeInference, watcher, appJsonPath }; +} + +export async function getFileTypeInformationFromArgs({ + realInputPaths, + typeInference, +}: { + realInputPaths: string[]; + typeInference: TypeInferenceOption; +}): Promise { + const typeInfo = await getFileTypeInformation({ + input: { type: 'file', inputFileAbsolutePaths: realInputPaths }, + typeInference, + }); + + if (!typeInfo) { + console.error( + chalk.red(`Provided files: ${realInputPaths} couldn't be parsed for type information!`) + ); + return null; + } + return typeInfo; +} + +export function writeStringToFileOrPrintToConsole( + text: string, + realOutputPath: string | undefined +) { + if (realOutputPath) { + fs.writeFileSync(realOutputPath, text, { flag: 'w', encoding: 'utf-8' }); + return; + } + console.log(text); +} + +export function getContentHash(content: string): string { + return createHash('sha256').update(content).digest('hex'); +} + +export function contentHasChanged(fileContent: string): boolean { + const hashRegex = /^\/\/ File hash: ([a-f0-9]{64})\r?\n/; + const match = fileContent.match(hashRegex); + + if (!match) { + return true; + } + + const storedHash = match[1]; + const originalContent = fileContent.slice(match[0].length); + const calculatedHash = getContentHash(originalContent); + return storedHash !== calculatedHash; +} + +export function insertFileHashComment(fileContent: string): string { + const hashString = getContentHash(fileContent); + return `// File hash: ${hashString} +${fileContent}`; +} + +export async function writeToStableFile({ + filePath, + content, +}: { + filePath: string; + content: string; +}) { + let flag = 'wx'; + if ( + fs.existsSync(filePath) && + !contentHasChanged(await fs.promises.readFile(filePath, 'utf-8')) + ) { + // Overwrite the file if it wasn't changed since the last generation + flag = 'w'; + } + try { + await fs.promises.writeFile(filePath, insertFileHashComment(content), { + flag, + encoding: 'utf-8', + }); + } catch (e) { + console.error('Error writing to a file.', e); + } +} + +export async function generateConciseTsFiles(parsedArgs: ParsedArguments) { + const { realInputPaths, realOutputPath } = parsedArgs; + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + + const { volatileGeneratedFileContent, moduleTypescriptInterfaceFileContent } = + await generateConciseTsInterface(typeInfo); + + const moduleName = typeInfo.moduleClasses[0]?.name ?? 'UnknownModuleName'; + const dirName = realOutputPath ?? path.dirname(realInputPaths[0] as string); + + try { + await Promise.all([ + fs.promises.writeFile( + path.resolve(dirName, `${moduleName}.generated.ts`), + volatileGeneratedFileContent, + { + flag: 'w', + encoding: 'utf-8', + } + ), + writeToStableFile({ + filePath: path.resolve(dirName, `${moduleName}.tsx`), + content: moduleTypescriptInterfaceFileContent, + }), + ]); + } catch (e) { + console.error(`Error writing to a file.`, e); + } +} diff --git a/packages/expo-type-information/src/commands/generateJSXIntrinsicsCommand.ts b/packages/expo-type-information/src/commands/generateJSXIntrinsicsCommand.ts new file mode 100644 index 00000000000000..dfdb3115f9b441 --- /dev/null +++ b/packages/expo-type-information/src/commands/generateJSXIntrinsicsCommand.ts @@ -0,0 +1,38 @@ +import commander from 'commander'; + +import { + addCommonOptions, + getFileTypeInformationFromArgs, + parseCommandArguments, + runCommandOnWatch, + TypeInformationCommandCommonAllArguments, + writeStringToFileOrPrintToConsole, +} from './commandUtils'; +import { generateJSXIntrinsicsFileContent } from '../typescriptGeneration'; + +export function generateJsxIntrinsics(cli: commander.Command) { + return addCommonOptions(cli.command('generate-jsx-intrinsics')).action( + async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = await parseCommandArguments(options); + if (!parsedArgs) { + return; + } + const { realOutputPath } = parsedArgs; + + const command = async () => { + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + + const jsxIntrinsicViewFileContent = await generateJSXIntrinsicsFileContent(typeInfo); + if (!jsxIntrinsicViewFileContent) { + console.error("Couldn't generate view types!"); + return; + } + writeStringToFileOrPrintToConsole(jsxIntrinsicViewFileContent, realOutputPath); + }; + runCommandOnWatch(parsedArgs, command); + } + ); +} diff --git a/packages/expo-type-information/src/commands/generateMocksForFileCommand.ts b/packages/expo-type-information/src/commands/generateMocksForFileCommand.ts new file mode 100644 index 00000000000000..efe189b2662fb4 --- /dev/null +++ b/packages/expo-type-information/src/commands/generateMocksForFileCommand.ts @@ -0,0 +1,30 @@ +import commander from 'commander'; + +import { + addCommonOptions, + getFileTypeInformationFromArgs, + parseCommandArguments, + runCommandOnWatch, + TypeInformationCommandCommonAllArguments, +} from './commandUtils'; +import { generateMocks } from '../mockgen'; + +export function generateMocksForFileCommand(cli: commander.Command) { + return addCommonOptions(cli.command('generate-mocks-for-file')).action( + async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = await parseCommandArguments(options); + if (!parsedArgs) { + return; + } + + const command = async () => { + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + generateMocks([typeInfo], 'typescript'); + }; + runCommandOnWatch(parsedArgs, command); + } + ); +} diff --git a/packages/expo-type-information/src/commands/generateModuleTypesCommand.ts b/packages/expo-type-information/src/commands/generateModuleTypesCommand.ts new file mode 100644 index 00000000000000..5b30feca312543 --- /dev/null +++ b/packages/expo-type-information/src/commands/generateModuleTypesCommand.ts @@ -0,0 +1,39 @@ +import chalk from 'chalk'; +import commander from 'commander'; + +import { + addCommonOptions, + getFileTypeInformationFromArgs, + parseCommandArguments, + runCommandOnWatch, + TypeInformationCommandCommonAllArguments, + writeStringToFileOrPrintToConsole, +} from './commandUtils'; +import { generateModuleTypesFileContent } from '../typescriptGeneration'; + +export function generateModuleTypesCommand(cli: commander.Command) { + return addCommonOptions(cli.command('generate-module-types')).action( + async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = await parseCommandArguments(options); + if (!parsedArgs) { + return; + } + const { realOutputPath } = parsedArgs; + + const command = async () => { + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + + const moduleTypesFileContent = await generateModuleTypesFileContent(typeInfo); + if (!moduleTypesFileContent) { + console.error(chalk.red(`Couldn't generate module types file content!`)); + return; + } + writeStringToFileOrPrintToConsole(moduleTypesFileContent, realOutputPath); + }; + runCommandOnWatch(parsedArgs, command); + } + ); +} diff --git a/packages/expo-type-information/src/commands/generateViewTypesCommand.ts b/packages/expo-type-information/src/commands/generateViewTypesCommand.ts new file mode 100644 index 00000000000000..225bccf23e279e --- /dev/null +++ b/packages/expo-type-information/src/commands/generateViewTypesCommand.ts @@ -0,0 +1,39 @@ +import commander from 'commander'; + +import { + addCommonOptions, + getFileTypeInformationFromArgs, + parseCommandArguments, + runCommandOnWatch, + TypeInformationCommandCommonAllArguments, + writeStringToFileOrPrintToConsole, +} from './commandUtils'; +import { generateViewTypesFileContent } from '../typescriptGeneration'; + +export function generateViewTypesCommand(cli: commander.Command) { + return addCommonOptions(cli.command('generate-view-types')).action( + async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = await parseCommandArguments(options); + if (!parsedArgs) { + return; + } + const { realOutputPath } = parsedArgs; + + const command = async () => { + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + + const viewTypesFileContent = await generateViewTypesFileContent(typeInfo); + if (!viewTypesFileContent) { + console.error("Couldn't generate view types!"); + return; + } + writeStringToFileOrPrintToConsole(viewTypesFileContent, realOutputPath); + }; + + runCommandOnWatch(parsedArgs, command); + } + ); +} diff --git a/packages/expo-type-information/src/commands/inlineModulesInterfaceCommand.ts b/packages/expo-type-information/src/commands/inlineModulesInterfaceCommand.ts new file mode 100644 index 00000000000000..af260d7b1a83c6 --- /dev/null +++ b/packages/expo-type-information/src/commands/inlineModulesInterfaceCommand.ts @@ -0,0 +1,175 @@ +import commander from 'commander'; +import fs from 'fs'; +import path from 'path'; + +import { + debounce, + generateConciseTsFiles, + parseCommandArguments, + TypeInformationCommandCommonAllArguments, +} from './commandUtils'; +import { TypeInferenceOption } from '../typeInformation'; +import { scanFilesRecursively, taskAll } from '../utils'; + +async function getResolvedWatchedDirectoriesFromAppJson( + appJsonPath: string +): Promise { + try { + const appJson = JSON.parse(await fs.promises.readFile(appJsonPath, 'utf-8')); + const watchedDirectories = appJson?.expo?.experiments?.inlineModules?.watchedDirectories; + + if (!Array.isArray(watchedDirectories)) { + console.error(`watchedDirectories are not defined!`); + return null; + } + + const rootDir = path.dirname(path.resolve(appJsonPath)); + return watchedDirectories.map((relativePath) => path.resolve(rootDir, relativePath)); + } catch (e) { + console.error(`Couldn't read ${appJsonPath}.`, e); + } + return null; +} + +type GenerateInlineModulesTSFilesOptions = { + filePath: string; + dirPath: string; + typeInference: TypeInferenceOption; +}; + +async function generateInlineModuleTSFiles({ + filePath, + dirPath, + typeInference, +}: GenerateInlineModulesTSFilesOptions) { + return await generateConciseTsFiles({ + realInputPaths: [filePath], + realOutputPath: dirPath, + typeInference, + watcher: false, + }); +} + +type InlineModulesWatcherOptions = { + appJsonPath: string; + typeInference: TypeInferenceOption; +}; + +async function inlineModulesWatcher({ appJsonPath, typeInference }: InlineModulesWatcherOptions) { + const debouncedInlineModulesTsGeneration = debounce(generateInlineModuleTSFiles); + const watchedDirectoriesWatchers: Map = new Map(); + + const setupWatchedDirectoriesWatchers = async () => { + const watchedDirectories = await getResolvedWatchedDirectoriesFromAppJson(appJsonPath); + + // Merge new watchers with old watchers. + // Let's first find and remove the obsolete ones. + const watchedDirsSet = new Set(watchedDirectories ?? []); + const obsoleteWatchersKeys = []; + for (const [key] of watchedDirectoriesWatchers) { + if (!watchedDirsSet.has(key)) { + obsoleteWatchersKeys.push(key); + } + } + + for (const key of obsoleteWatchersKeys) { + const watcher = watchedDirectoriesWatchers.get(key); + watcher?.close(); + watchedDirectoriesWatchers.delete(key); + } + + // Now let's create and add new watchers + const createWatcherForDir = (dir: string) => { + return fs.watch(dir, { recursive: true, encoding: 'utf-8' }, async (event, fileName) => { + if (!fileName) { + return; + } + + const resolvedFilePath = path.resolve(dir, fileName); + if (fs.existsSync(resolvedFilePath)) { + debouncedInlineModulesTsGeneration({ + filePath: resolvedFilePath, + dirPath: path.dirname(resolvedFilePath), + typeInference, + }); + } + }); + }; + + for (const dir of watchedDirectories ?? []) { + const watcher = watchedDirectoriesWatchers.get(dir); + if (!watcher) { + watchedDirectoriesWatchers.set(dir, createWatcherForDir(dir)); + } + } + }; + await setupWatchedDirectoriesWatchers(); + + const appJsonWatcher = fs.watch(appJsonPath, 'utf-8', async (event) => { + if (event === 'rename' && !fs.existsSync(appJsonPath)) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for (const [_, watcher] of watchedDirectoriesWatchers) { + watcher.close(); + } + appJsonWatcher.close(); + return; + } + + await setupWatchedDirectoriesWatchers(); + }); +} + +export async function inlineModulesInterfaceCommand(cli: commander.Command) { + return cli + .command('inline-modules-interface') + .summary('Creates ts interface for every Swift inline module in the project.') + .description( + 'Creates ts interface for every Swift inline module in the project. The ts interface consists of two files Module.generated.ts and Module.tsx, the first one is regenerated with each run of the command and the second one will not be regenerated if user changes it.' + ) + .requiredOption( + '-a --app-json ', + 'A path to the `app.json` where the inline.modules.watchedDirectories are defined.' + ) + .option('-w --watcher', 'Starts a watcher that checks for changes in inline modules files.') + .action(async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = parseCommandArguments(options); + if (!parsedArgs) { + return; + } + + const { appJsonPath, watcher } = parsedArgs; + if (!appJsonPath) { + return; + } + + const watchedDirectories = await getResolvedWatchedDirectoriesFromAppJson(appJsonPath); + if (!watchedDirectories) { + return; + } + + const dirents = []; + for (const dir of watchedDirectories) { + for await (const dirent of scanFilesRecursively(dir)) { + if (!dirent.name.endsWith('.swift')) { + continue; + } + + dirents.push(dirent); + } + } + + await taskAll( + dirents, + async (dirent) => + await generateInlineModuleTSFiles({ + filePath: dirent.path, + dirPath: dirent.parentPath, + typeInference: parsedArgs.typeInference, + }) + ); + + if (watcher) { + await inlineModulesWatcher({ appJsonPath, typeInference: parsedArgs.typeInference }); + } + }); +} diff --git a/packages/expo-type-information/src/commands/moduleInterfaceCommand.ts b/packages/expo-type-information/src/commands/moduleInterfaceCommand.ts new file mode 100644 index 00000000000000..f71f78ef5c837b --- /dev/null +++ b/packages/expo-type-information/src/commands/moduleInterfaceCommand.ts @@ -0,0 +1,56 @@ +import commander from 'commander'; +import path from 'path'; + +import { + addCommonOptions, + getFileTypeInformationFromArgs, + parseCommandArguments, + runCommandOnWatch, + TypeInformationCommandCommonAllArguments, + writeToStableFile, +} from './commandUtils'; +import { generateFullTsInterface } from '../typescriptGeneration'; + +export function moduleInterfaceCommand(cli: commander.Command) { + return addCommonOptions(cli.command('module-interface')) + .summary('Generates a full ts interface for a Swift module.') + .description( + 'Generates a full ts interface for a Swift module. It consists of types.ts file with all types defined in the module, module.ts with the native module definition, and view.tsx for each view defined in the module, and an index.ts file which reexports some functions.' + ) + .action(async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = await parseCommandArguments(options, false); + if (!parsedArgs) { + return; + } + const { realInputPaths, realOutputPath } = parsedArgs; + + const command = async () => { + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + const generatedFiles = await generateFullTsInterface(typeInfo); + if (!generatedFiles) { + return; + } + const { moduleTypesFile, moduleViewsFiles, moduleNativeFile, indexFile } = generatedFiles; + + const dirName = realOutputPath ?? path.dirname(realInputPaths[0] as string); + const writeFilePromises = []; + for (const outputFile of [ + moduleTypesFile, + ...moduleViewsFiles, + moduleNativeFile, + indexFile, + ]) { + const outputFilePath = path.resolve(dirName, outputFile.name); + writeFilePromises.push( + writeToStableFile({ filePath: outputFilePath, content: outputFile.content }) + ); + } + await Promise.all(writeFilePromises); + }; + + runCommandOnWatch(parsedArgs, command); + }); +} diff --git a/packages/expo-type-information/src/commands/shortModuleInterfaceCommand.ts b/packages/expo-type-information/src/commands/shortModuleInterfaceCommand.ts new file mode 100644 index 00000000000000..8a231dad893f57 --- /dev/null +++ b/packages/expo-type-information/src/commands/shortModuleInterfaceCommand.ts @@ -0,0 +1,26 @@ +import commander from 'commander'; + +import { + addCommonOptions, + generateConciseTsFiles, + parseCommandArguments, + runCommandOnWatch, + TypeInformationCommandCommonAllArguments, +} from './commandUtils'; + +export function shortModuleInterfaceCommand(cli: commander.Command) { + addCommonOptions( + cli + .command('short-module-interface') + .summary('Creates a short ts interface, great with inline-modules.') + .description( + 'Creates a short ts interface for an expo module. Overrites `ModuleName.generated.ts` and creates `ModuleName.ts` if not present. Can be used with inline-modules.' + ) + ).action(async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = await parseCommandArguments(options, false); + if (!parsedArgs) return; + + const command = () => generateConciseTsFiles(parsedArgs); + runCommandOnWatch(parsedArgs, command); + }); +} diff --git a/packages/expo-type-information/src/commands/typeInformationCommand.ts b/packages/expo-type-information/src/commands/typeInformationCommand.ts new file mode 100644 index 00000000000000..fdf3e2e027f7a4 --- /dev/null +++ b/packages/expo-type-information/src/commands/typeInformationCommand.ts @@ -0,0 +1,35 @@ +import commander from 'commander'; + +import { + addCommonOptions, + getFileTypeInformationFromArgs, + parseCommandArguments, + runCommandOnWatch, + TypeInformationCommandCommonAllArguments, + writeStringToFileOrPrintToConsole, +} from './commandUtils'; +import { serializeTypeInformation } from '../typeInformation'; + +export function typeInformationCommand(cli: commander.Command) { + return addCommonOptions(cli.command('type-information')).action( + async (options: TypeInformationCommandCommonAllArguments) => { + const parsedArgs = await parseCommandArguments(options); + if (!parsedArgs) { + return; + } + + const command = async () => { + const typeInfo = await getFileTypeInformationFromArgs(parsedArgs); + if (!typeInfo) { + return; + } + + const typeInfoSerialized = serializeTypeInformation(typeInfo); + const typeInfoSerializedString = JSON.stringify(typeInfoSerialized, null, 2); + writeStringToFileOrPrintToConsole(typeInfoSerializedString, parsedArgs.realOutputPath); + }; + + runCommandOnWatch(parsedArgs, command); + } + ); +} diff --git a/packages/expo-type-information/src/index.ts b/packages/expo-type-information/src/index.ts new file mode 100644 index 00000000000000..d54b8b2b33acd4 --- /dev/null +++ b/packages/expo-type-information/src/index.ts @@ -0,0 +1,9 @@ +export * from './typeInformation'; +export { generateMocks, getAllExpoModulesInWorkingDirectory } from './mockgen'; +export { + generateConciseTsInterface, + generateFullTsInterface, + generateModuleTypesFileContent, + generateViewTypesFileContent, + generateJSXIntrinsicsFileContent, +} from './typescriptGeneration'; diff --git a/packages/expo-type-information/src/mockgen.ts b/packages/expo-type-information/src/mockgen.ts new file mode 100644 index 00000000000000..5ca50b4c9573de --- /dev/null +++ b/packages/expo-type-information/src/mockgen.ts @@ -0,0 +1,338 @@ +import fs from 'fs'; +import path from 'path'; +import ts from 'typescript'; + +import { + BasicType, + ClassDeclaration, + EnumType, + FileTypeInformation, + FunctionDeclaration, + getFileTypeInformation, + IdentifierKind, + ModuleClassDeclaration, + OptionalType, + RecordType, + SumType, + Type, + TypeKind, + ViewDeclaration, +} from './typeInformation'; +import { + getBasicTypesIdentifiers, + buildEnumTypeDeclaration, + buildViewPropsInterface, + buildRecordTypeAlias, + buildClass, + buildFunction, + getViewPropsTypeName, + joinTSNodesWithNewlines, + prettifyCode, + buildUnknownTypeAlias, +} from './typescriptGeneration'; +import { taskAll } from './utils'; + +const prefix = `Automatically generated by expo-type-information. + +This autogenerated file provides a mock for native Expo module, +and works out of the box with the expo jest preset. +`; + +function getPrefix() { + return [ts.factory.createJSDocComment(prefix)]; +} + +let freeId = 0; + +function getNextFreeId() { + freeId += 1; + return freeId; +} + +function maybeWrapWithReturnStatement( + type: Type, + fileTypeInformation: FileTypeInformation +): ts.ReturnStatement[] { + if (type.kind === TypeKind.BASIC) { + const basicType = type.type as BasicType; + if (basicType === BasicType.VOID || basicType === BasicType.ANY) { + return []; + } + } + + // TODO(@HubertBer): maybe add a comment when we couldn't create a mock for the return type + const returnExpression = getMockedValueForType(type, fileTypeInformation); + if (returnExpression || type.kind !== TypeKind.BASIC || type.type === BasicType.UNRESOLVED) { + return [ts.factory.createReturnStatement(returnExpression)]; + } + return []; +} + +function getBasicTypeMockLiteral(type: BasicType): ts.PrimaryExpression | undefined { + switch (type) { + case BasicType.STRING: + return ts.factory.createStringLiteral(''); + case BasicType.BOOLEAN: + return ts.factory.createFalse(); + case BasicType.NUMBER: + return ts.factory.createNumericLiteral(0); + case BasicType.VOID: + case BasicType.UNDEFINED: + case BasicType.ANY: + default: + return undefined; + } +} + +function getBasicTypeFromString(basicType: string): BasicType | undefined { + switch (basicType) { + case 'any': + return BasicType.ANY; + case 'number': + return BasicType.NUMBER; + case 'string': + return BasicType.STRING; + case 'boolean': + return BasicType.BOOLEAN; + } + return undefined; +} + +function getMockedEnumInstance(enumType: EnumType): ts.Expression | undefined { + const firstCase = enumType.cases[0]; + if (!firstCase) { + return undefined; + } + + return ts.factory.createPropertyAccessExpression( + ts.factory.createRegularExpressionLiteral(enumType.name), + firstCase + ); +} + +function getMockedRecordInstance(recordType: RecordType, fileTypeInformation: FileTypeInformation) { + return ts.factory.createObjectLiteralExpression( + recordType.fields.map((f) => + ts.factory.createPropertyAssignment( + f.name ?? '_' + getNextFreeId(), + getMockedValueForType(f.type, fileTypeInformation) ?? ts.factory.createNull() + ) + ) + ); +} + +function getMockValueForIdentifier( + identifier: string, + fileTypeInformation: FileTypeInformation +): ts.Expression | undefined { + if (!fileTypeInformation.typeIdentifierDefinitionMap.has(identifier)) { + return undefined; + } + + const typeDefinition = fileTypeInformation.typeIdentifierDefinitionMap.get(identifier); + switch (typeDefinition?.kind) { + case IdentifierKind.BASIC: { + const basicType = getBasicTypeFromString(typeDefinition.definition as string); + if (basicType) { + return getBasicTypeMockLiteral(basicType); + } + return undefined; + } + case IdentifierKind.ENUM: + return getMockedEnumInstance(typeDefinition.definition as EnumType); + case IdentifierKind.RECORD: + return getMockedRecordInstance(typeDefinition.definition as RecordType, fileTypeInformation); + } + return undefined; +} + +function getMockedValueForType( + type: Type, + fileTypeInformation: FileTypeInformation +): ts.Expression | undefined { + switch (type.kind) { + case TypeKind.BASIC: + return getBasicTypeMockLiteral(type.type as BasicType); + case TypeKind.IDENTIFIER: + return getMockValueForIdentifier(type.type as string, fileTypeInformation); + case TypeKind.SUM: { + const firstType = (type.type as SumType).types[0]; + return getMockedValueForType( + firstType ?? { kind: TypeKind.BASIC, type: BasicType.UNDEFINED }, + fileTypeInformation + ); + } + case TypeKind.PARAMETRIZED: + return ts.factory.createNull(); + case TypeKind.OPTIONAL: + return getMockedValueForType(type.type as OptionalType, fileTypeInformation); + case TypeKind.ARRAY: + return ts.factory.createArrayLiteralExpression(); + case TypeKind.DICTIONARY: + return ts.factory.createObjectLiteralExpression(); + } +} + +function getFunctionReturnBlock( + functionDeclaration: FunctionDeclaration, + fileTypeInformation: FileTypeInformation +): ts.ReturnStatement[] { + return maybeWrapWithReturnStatement(functionDeclaration.returnType, fileTypeInformation); +} + +function getMockedFunctionDeclaration( + functionDeclaration: FunctionDeclaration, + fileTypeInformation: FileTypeInformation, + async: boolean, + exported: boolean +): ts.FunctionDeclaration { + return buildFunction({ + functionDeclaration, + async, + method: false, + exported, + declaration: false, + returnStatement: maybeWrapWithReturnStatement( + functionDeclaration.returnType, + fileTypeInformation + ), + }) as ts.FunctionDeclaration; +} + +function getMockedClass( + classDeclaration: ClassDeclaration, + fileInfo: FileTypeInformation +): ts.ClassDeclaration { + return buildClass({ + classDeclaration, + exported: true, + getFunctionReturnBlock: (func) => getFunctionReturnBlock(func, fileInfo), + }); +} + +function getMockedView(viewDeclaration: ViewDeclaration): ts.Node[] { + const propsTypeName = getViewPropsTypeName(viewDeclaration); + const propsType = buildViewPropsInterface(viewDeclaration, { exported: true }); + const propsParameter = ts.factory.createParameterDeclaration( + undefined, + undefined, + 'props', + undefined, + ts.factory.createTypeReferenceNode(propsTypeName, undefined), + undefined + ); + const viewFunction = ts.factory.createFunctionDeclaration( + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], + undefined, + (viewDeclaration.name?.length ?? 0) > 0 ? viewDeclaration.name : 'View', + undefined, + [propsParameter], + undefined, + ts.factory.createBlock([]) + ); + return [...propsType, viewFunction]; +} + +function getMockForModule( + module: ModuleClassDeclaration, + typeInfo: FileTypeInformation +): ts.Node[] { + const { + usedTypeIdentifiers, + declaredTypeIdentifiers, + inferredTypeParametersCount, + records, + enums, + } = typeInfo; + + const undeclaredTypes: Set = usedTypeIdentifiers + .difference(declaredTypeIdentifiers) + .difference(getBasicTypesIdentifiers()); + + const sections = [ + getPrefix(), + [...undeclaredTypes].map((identifier) => + buildUnknownTypeAlias(identifier, true, inferredTypeParametersCount) + ), + records.flatMap((record: RecordType) => buildRecordTypeAlias(record, true)), + enums.flatMap((e: EnumType) => buildEnumTypeDeclaration(e, true, false)), + module.functions.map((f) => getMockedFunctionDeclaration(f, typeInfo, false, true)), + module.asyncFunctions.map((f) => getMockedFunctionDeclaration(f, typeInfo, true, true)), + module.classes.map((c) => getMockedClass(c, typeInfo)), + module.views.flatMap((v) => getMockedView(v)), + ]; + + return joinTSNodesWithNewlines(sections).flat(); +} + +export function generateTSMockForModule( + module: ModuleClassDeclaration, + fileTypeInformation: FileTypeInformation, + includeTypes: boolean +): string { + const mockFileName = module.name + (includeTypes ? '.ts' : '.js'); + const mock = ts.factory.createNodeArray(getMockForModule(module, fileTypeInformation)); + + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); + // get ts nodearray from getMockForModule(m) array + const resultFile = ts.createSourceFile( + mockFileName, + '', + ts.ScriptTarget.Latest, + false, + ts.ScriptKind.TSX + ); + const printedTs = printer.printList( + ts.ListFormat.MultiLine + ts.ListFormat.PreserveLines, + mock, + resultFile + ); + + if (includeTypes) { + return printedTs; + } + return ts.transpileModule(printedTs, { + compilerOptions: { + module: ts.ModuleKind.ESNext, + target: ts.ScriptTarget.ESNext, + }, + }).outputText; +} + +const directoryPath = process.cwd(); +const swiftFilesGlob = `${directoryPath}/**/*.swift`; + +export async function generateMocks( + files: FileTypeInformation[], + outputLanguage: 'javascript' | 'typescript' = 'javascript' +) { + const modules = files.flatMap((file) => file.moduleClasses.map((module) => ({ module, file }))); + + if (modules.length === 0) { + return; + } + + const isTypeScript = outputLanguage === 'typescript'; + const extension = isTypeScript ? '.ts' : '.js'; + const mocksDir = path.join(directoryPath, 'mocks'); + await fs.promises.mkdir(mocksDir, { recursive: true }); + + taskAll(modules, async ({ module, file }) => { + const code = generateTSMockForModule(module, file, isTypeScript); + const prettified = await prettifyCode(code, isTypeScript ? 'typescript' : undefined); + await fs.promises.writeFile(path.join(mocksDir, module.name + extension), prettified); + }); +} + +export async function getAllExpoModulesInWorkingDirectory(): Promise { + const files = fs.globSync(swiftFilesGlob); + return ( + await Promise.all( + files.map((file) => + getFileTypeInformation({ + input: { type: 'file', inputFileAbsolutePaths: [fs.realpathSync(file)] }, + }) + ) + ) + ).filter((f) => f) as FileTypeInformation[]; +} diff --git a/packages/expo-type-information/src/swift/sourcekittenTypeInformation.ts b/packages/expo-type-information/src/swift/sourcekittenTypeInformation.ts new file mode 100644 index 00000000000000..0098bca73d8cae --- /dev/null +++ b/packages/expo-type-information/src/swift/sourcekittenTypeInformation.ts @@ -0,0 +1,1173 @@ +import { execSync, exec } from 'child_process'; +import fs from 'fs'; +import { promisify } from 'util'; +import YAML from 'yaml'; + +import { + Argument, + BasicType, + ClassDeclaration, + ConstantDeclaration, + ConstructorDeclaration, + DefinitionOffset, + DictionaryType, + EnumType, + FileTypeInformation, + FunctionDeclaration, + IdentifierDefinition, + IdentifierKind, + ModuleClassDeclaration, + ParametrizedType, + PropDeclaration, + PropertyDeclaration, + RecordType, + SumType, + Type, + TypeIdentifier, + TypeIdentifierDefinitionMap, + TypeKind, + ViewDeclaration, +} from '../typeInformation'; +import { Attribute, FileType, Structure } from '../types'; +import { taskAll } from '../utils'; + +const execAsync = promisify(exec); + +type SourcekittenClosure = { + parameters: { name: string; typename: string }[]; + returnType: string | null; +}; + +const swiftDeclarationKind = { + enum: 'source.lang.swift.decl.enum', + struct: 'source.lang.swift.decl.struct', + class: 'source.lang.swift.decl.class', + varLocal: 'source.lang.swift.decl.var.local', + varInstance: 'source.lang.swift.decl.var.instance', + varParameter: 'source.lang.swift.decl.var.parameter', + closure: 'source.lang.swift.expr.closure', + enumcase: 'source.lang.swift.decl.enumcase', +}; + +function isSwiftDictionary(type: string): boolean { + return ( + type.startsWith('[') && + type.endsWith(']') && + findRootColonInDictionary(type.substring(1, type.length - 1)) >= 0 + ); +} + +function isSwiftArray(type: string) { + // This can also be an object, but we check that first, so if it's not an object and is wrapped with [] it's an array. + return type.startsWith('[') && type.endsWith(']'); +} + +function isSwiftOptional(type: string): boolean { + return type.endsWith('?'); +} + +function isParametrizedType(type: string): boolean { + return type.endsWith('>'); +} + +function isEitherTypeIdentifier(typeIdentifier: string): boolean { + return ( + typeIdentifier === 'Either' || + typeIdentifier === 'EitherOfThree' || + typeIdentifier === 'EitherOfFour' + ); +} + +function isEnumStructure(structure: Structure): boolean { + return structure['key.kind'] === swiftDeclarationKind.enum; +} + +function isRecordStructure(structure: Structure): boolean { + const isRecordOrClass = + structure['key.kind'] === swiftDeclarationKind.struct || + structure['key.kind'] === swiftDeclarationKind.class; + + const inheritsFromRecord = + structure['key.inheritedtypes']?.find((type) => { + return type['key.name'] === 'Record'; + }) !== undefined; + + return isRecordOrClass && inheritsFromRecord; +} + +function isModuleStructure(structure: Structure): boolean { + return structure['key.typename'] === 'ModuleDefinition'; +} + +function unwrapSwiftArray(type: string): Type { + const innerType = type.substring(1, type.length - 1); + return mapSwiftTypeToTsType(innerType.trim()); +} + +function unwrapParametrizedType(type: string): ParametrizedType { + let openBracketCount = 0; + let start = 0; + const innerTypes: Type[] = []; + let name: string = ''; + for (let i = 0; i < type.length; i += 1) { + if (type[i] === '<') { + openBracketCount += 1; + if (openBracketCount === 1) { + name = type.substring(0, i); + start = i + 1; + } + } else if (type[i] === '>') { + openBracketCount -= 1; + if (openBracketCount === 0) { + innerTypes.push(mapSwiftTypeToTsType(type.substring(start, i).trim())); + start = i + 1; + } + } else if (type[i] === ',' && openBracketCount === 1) { + innerTypes.push(mapSwiftTypeToTsType(type.substring(start, i).trim())); + start = i + 1; + } + } + return { name, types: innerTypes }; +} + +function unwrapSwiftDictionary(type: string) { + const innerType = type.substring(1, type.length - 1); + const colonPosition = findRootColonInDictionary(innerType); + return { + key: innerType.slice(0, colonPosition).trim(), + value: innerType.slice(colonPosition + 1).trim(), + }; +} + +/* +The Swift object type can have nested objects as the type of it's values (or maybe even keys). +[String: [String: Any]] + +We can't use regex to find the root colon, so this is the safest way – by counting brackets. +*/ +function findRootColonInDictionary(type: string) { + let colonIndex = -1; + let openBracketsCount = 0; + for (let i = 0; i < type.length; i++) { + if (type[i] === '[') { + openBracketsCount++; + } else if (type[i] === ']') { + openBracketsCount--; + } else if (type[i] === ':' && openBracketsCount === 0) { + colonIndex = i; + break; + } + } + return colonIndex; +} + +function mapSwiftTypeToTsType(type?: string): Type { + if (!type) { + return { kind: TypeKind.BASIC, type: BasicType.UNRESOLVED }; + } + + if (isSwiftOptional(type)) { + return { kind: TypeKind.OPTIONAL, type: mapSwiftTypeToTsType(type.slice(0, -1).trim()) }; + } + + if (isSwiftDictionary(type)) { + const { key, value } = unwrapSwiftDictionary(type); + const keyType = mapSwiftTypeToTsType(key); + const valueType = mapSwiftTypeToTsType(value); + + return { + kind: TypeKind.DICTIONARY, + type: { + key: keyType, + value: valueType, + }, + }; + } + + if (isSwiftArray(type)) { + return { + kind: TypeKind.ARRAY, + type: unwrapSwiftArray(type), + }; + } + + if (isParametrizedType(type)) { + const parametrizedType = unwrapParametrizedType(type); + if (isEitherTypeIdentifier(parametrizedType.name)) { + return { + kind: TypeKind.SUM, + type: parametrizedType as SumType, + }; + } + + return { + kind: TypeKind.PARAMETRIZED, + type: parametrizedType, + }; + } + + const returnType: Type = { + kind: TypeKind.BASIC, + type: BasicType.ANY, + }; + + switch (type) { + case 'unknown': + case 'Any': + returnType.type = BasicType.ANY; + break; + case 'String': + returnType.type = BasicType.STRING; + break; + case 'Bool': + returnType.type = BasicType.BOOLEAN; + break; + case 'Int': + case 'Float': + case 'Double': + returnType.type = BasicType.NUMBER; + break; + case 'Void': + returnType.type = BasicType.VOID; + break; + default: + returnType.kind = TypeKind.IDENTIFIER; + returnType.type = type; + } + return returnType; +} + +function getStructureFromFile(file: FileType) { + const command = 'sourcekitten structure --file ' + file.path; + + try { + const output = execSync(command, { maxBuffer: 10 * 1024 * 1024 }); + return JSON.parse(output.toString()); + } catch (error) { + console.error('An error occurred while executing the command:', error); + } +} + +// Read string straight from file – needed since we can't get cursorinfo for modulename +function getIdentifierFromOffsetObject(offsetObject: Structure, file: FileType) { + const startIndex = offsetObject['key.offset']; + const endIndex = offsetObject['key.offset'] + offsetObject['key.length']; + return file.content.substring(startIndex, endIndex).replaceAll('"', ''); +} + +function hasSubstructure(structure: Structure) { + return structure?.['key.substructure'] && structure['key.substructure'].length > 0; +} + +async function findReturnType( + structure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + if ( + structure['key.kind'] === swiftDeclarationKind.varLocal && + structure['key.name'].startsWith('returnValueDeclaration_') && + options.typeInference + ) { + // TODO(@HubertBer): this return type inference is really costly + return getTypeOfByteOffsetVariable(structure['key.nameoffset'], file); + } + + if (hasSubstructure(structure)) { + for (const substructure of structure['key.substructure']) { + const returnType = findReturnType(substructure, file, options); + if (returnType) { + return returnType; + } + } + } + return null; +} + +let cachedSDKPath: string | null = null; +function getSDKPath(): string | null { + if (cachedSDKPath) { + return cachedSDKPath; + } + + cachedSDKPath = execSync('xcrun --sdk iphoneos --show-sdk-path')?.toString()?.trim(); + if (!cachedSDKPath) { + console.error(`Couldn't find xcode sdk path!`); + return null; + } + + return cachedSDKPath; +} + +function getUnresolvedType(): Type { + return { kind: TypeKind.BASIC, type: BasicType.UNRESOLVED }; +} + +async function extractDeclarationType( + structure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + if (structure['key.typename']) { + return mapSwiftTypeToTsType(structure['key.typename'] as string); + } + + // TODO(@HubertBer): this type inference is really costly + if (options.typeInference) { + const inferReturn = await getTypeOfByteOffsetVariable(structure['key.nameoffset'], file); + return inferReturn ? mapSwiftTypeToTsType(inferReturn) : getUnresolvedType(); + } + + return getUnresolvedType(); +} + +function constructSourcekiitenCursorInfoRequest({ + filePath, + byteOffset, + sdkPath, +}: { + filePath: string; + byteOffset: number; + sdkPath: string; +}): string { + const request = { + 'key.request': 'source.request.cursorinfo', + 'key.sourcefile': filePath, + 'key.offset': byteOffset, + 'key.compilerargs': [filePath, '-target', 'arm64-apple-ios7', '-sdk', sdkPath], + }; + + const yamlRequest = YAML.stringify(request, { + defaultStringType: 'QUOTE_DOUBLE', + lineWidth: 0, + defaultKeyType: 'PLAIN', + }) + .replace('"source.request.cursorinfo"', 'source.request.cursorinfo') + .replaceAll('"', '\\"'); + + return yamlRequest; +} + +// Read type description with sourcekitten, works only for variables +// TODO(@HubertBer): This function is extremely slow and inefficient +// consider other options +async function getTypeOfByteOffsetVariable( + byteOffset: number, + file: FileType +): Promise { + const sdkPath = getSDKPath(); + if (!sdkPath) { + return null; + } + const yamlRequest = constructSourcekiitenCursorInfoRequest({ + filePath: file.path, + byteOffset, + sdkPath, + }); + const command = 'sourcekitten request --yaml "' + yamlRequest + '"'; + try { + const { stdout } = await execAsync(command); + const output = JSON.parse(stdout.toString()); + const inferredType = output['key.typename']; + if (inferredType === '<>') { + return null; + } + return inferredType; + } catch (error) { + console.error('An error occurred while executing the command:', error); + } + return null; +} + +function mapSourcekittenParameterToType(parameter: { + name: string | undefined; + typename: string; +}): Argument { + return { + name: parameter.name ?? undefined, + type: mapSwiftTypeToTsType(parameter.typename), + }; +} + +const parseModulePropertyStructure = parseModuleConstantStructure; + +async function parseClosureTypes( + structure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + const closure = structure['key.substructure']?.find( + (s) => s['key.kind'] === swiftDeclarationKind.closure + ); + if (!closure) { + // Try finding the preprocessed return value, if not found we don't know the return type + const returnType = await findReturnType(structure, file, options); + return { parameters: [], returnType }; + } + + const parameters = closure['key.substructure'] + ?.filter((s) => s['key.kind'] === swiftDeclarationKind.varParameter) + .map((p) => ({ + name: p['key.name'] ?? undefined, + typename: p['key.typename'], + })); + + const returnType = closure?.['key.typename'] ?? (await findReturnType(structure, file, options)); + return { parameters, returnType }; +} + +async function parseModuleConstructorDeclaration( + substructure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + const definitionParams = substructure['key.substructure']; + let types = null; + + // TODO(@HubertBer): rethink this maybe split based on what closure is expected + // Maybe this should be the last substructure + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } else if (definitionParams[0] && hasSubstructure(definitionParams[0])) { + types = await parseClosureTypes(definitionParams[0], file, options); + } else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + + return { + arguments: types?.parameters.map(mapSourcekittenParameterToType) ?? [], + definitionOffset: substructure['key.offset'], + }; +} + +async function parseModuleConstantStructure( + substructure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + const definitionParams = substructure['key.substructure']; + if (!definitionParams[0]) { + return null; + } + + const name = getIdentifierFromOffsetObject(definitionParams[0], file); + let types = null; + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + + return { + name, + type: mapSwiftTypeToTsType(types?.returnType ?? undefined), + definitionOffset: substructure['key.offset'], + }; +} + +function getClosureBodyStructure(structure: Structure): Structure | null { + // Let's look at an example DSL class declaration + // + // Class(Blob.self) { + // Constructor { // ... + // // ... + //. } + // } + // + // The strucutre for a ClassDeclaration (from SourceKitten) looks like this: + // { + // "key.name": "Class", + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.expr.argument", // 1st argument: `Blob.self` + // // ... + // }, + // { + // "key.kind": "source.lang.swift.expr.argument", // 2nd argument: the closure + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.expr.closure", // the closure + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.stmt.brace", // the closure body + // "key.substructure": [ + // { + // "key.kind": "source.lang.swift.expr.call", // DSL functions in the body + // "key.name": "Constructor", + // }, // ... + // ] + // } + // ] + // } + // ] + // } + // // ... + // } + // + // So to get to the closure body we need to take 1st argument, go in the closure definition and go in the closure body. + const classDeclarationClosureArgument = structure['key.substructure']?.[1]; + const classDeclarationClosure = classDeclarationClosureArgument?.['key.substructure']?.[0]; + const classDeclarationClosureBody = classDeclarationClosure?.['key.substructure']?.[0]; + return classDeclarationClosureBody ?? null; +} + +async function parseModuleClassStructure( + structure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + const nestedModuleSubstructure = getClosureBodyStructure(structure)?.['key.substructure']; + const nameSubstrucutre = structure['key.substructure']?.[0]; + const name = nameSubstrucutre + ? getIdentifierFromOffsetObject(nameSubstrucutre, file).replace('.self', '') + : 'UnnamedClass'; + + if (!nestedModuleSubstructure) { + console.warn(name + " class is empty or couldn't parse its definition!"); + return { + name, + constructor: null, + methods: [], + asyncMethods: [], + properties: [], + definitionOffset: structure['key.offset'], + }; + } + + // `parseModuleStructure` returns `ModuleClassDeclaration` with a found name or with the provided 'UNUSED_NAME', we don't need it here. + const classTypeInfo = await parseModuleStructure( + nestedModuleSubstructure, + file, + 'UNUSED_NAME', + structure['key.offset'], + options + ); + return { + name, + methods: classTypeInfo.functions, + asyncMethods: classTypeInfo.asyncFunctions, + properties: classTypeInfo.properties, + constructor: classTypeInfo.constructor, + definitionOffset: structure['key.offset'], + }; +} + +async function parseModuleFunctionSubstructure( + substructure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + const definitionParams = substructure['key.substructure']; + const nameSubstrucutre = definitionParams[0]; + const name = nameSubstrucutre + ? getIdentifierFromOffsetObject(nameSubstrucutre, file) + : 'UnnamedFunction'; + let types = null; + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + + return { + name, + returnType: mapSwiftTypeToTsType(types?.returnType ?? undefined), // any or void ? Probably any + parameters: [], // TODO(@HubertBer): Module function is not generic. I think so. Check it + arguments: types?.parameters?.map(mapSourcekittenParameterToType) ?? [], + definitionOffset: substructure['key.offset'], + }; +} + +async function parseModulePropDeclaration( + substructure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + const definitionParams = substructure['key.substructure']; + const nameSubstrucutre = definitionParams[0]; + const name = nameSubstrucutre + ? getIdentifierFromOffsetObject(nameSubstrucutre, file) + : 'UnkownProp'; + let types = null; + if (definitionParams[1] && hasSubstructure(definitionParams[1])) { + types = await parseClosureTypes(definitionParams[1], file, options); + } else { + // TODO(@HubertBer): There sometimes might be another case which needs to be handled. + console.warn(`The type couldn't be resolved, this case is not yet implemented`); + // types = getTypeOfByteOffsetVariable(definitionParams[1]['key.offset'], file); + } + + return { + name, + arguments: types?.parameters?.map(mapSourcekittenParameterToType) ?? [], + definitionOffset: substructure['key.offset'], + }; +} + +async function parseModuleViewDeclaration( + substructure: Structure, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + // The View arguments is a.self for some class a we want. + const suffixLength = 5; + const nameSubstrucutre = substructure['key.substructure']?.[0]; + if (!nameSubstrucutre) { + return null; + } + + const name = getIdentifierFromOffsetObject(nameSubstrucutre, file).slice(0, -suffixLength); + const viewStructure = getClosureBodyStructure(substructure); + const viewSubstructure = viewStructure?.['key.substructure']; + if (!viewSubstructure) { + return null; + } + + return await parseModuleStructure( + viewSubstructure, + file, + name, + viewStructure['key.offset'], + options + ); +} + +function parseModuleEventDeclaration(structure: Structure, file: FileType, events: string[]) { + structure['key.substructure'].forEach((substructure) => + events.push(getIdentifierFromOffsetObject(substructure, file)) + ); +} + +function hasFieldAttribute(attributes: Attribute[] | null, file: FileType): boolean { + if (!attributes) { + return false; + } + + return attributes.some((attribute) => { + const startIndex = attribute['key.offset']; + const length = attribute['key.length']; + return ( + length === '@Field'.length && + file.content.substring(startIndex, startIndex + length) === '@Field' + ); + }); +} + +async function parseRecordStructure( + recordStructure: Structure, + usedTypeIdentifiers: Set, + inferredTypeParametersCount: Map, + file: FileType, + options: SwiftFileTypeInformationOptions +): Promise { + const recordSubstrucutres = recordStructure['key.substructure'].filter( + (substructure) => + substructure['key.kind'] === swiftDeclarationKind.varInstance && + hasFieldAttribute(substructure['key.attributes'], file) + ); + + const fields = await taskAll(recordSubstrucutres, async (substructure) => { + const type = await extractDeclarationType(substructure, file, options); + return { type, name: substructure['key.name'] }; + }); + + fields.forEach(({ type }) => { + collectTypeIdentifiers(type, usedTypeIdentifiers, inferredTypeParametersCount); + }); + + return { + name: recordStructure['key.name'], + fields, + }; +} + +function parseEnumStructure(enumStructure: Structure): EnumType { + const enumcases: string[] = enumStructure['key.substructure'] + .filter((sub) => sub['key.kind'] === swiftDeclarationKind.enumcase) + .flatMap((sub) => sub['key.substructure']) + .map((sub) => sub['key.name'].split('(', 1)[0]) + .filter((enumcase) => enumcase !== undefined); + + return { + name: enumStructure['key.name'], + cases: enumcases, + }; +} + +function sortModuleClassDeclaration(moduleClassDeclaration: ModuleClassDeclaration) { + const cmp = (obj0: DefinitionOffset, obj1: DefinitionOffset): number => + obj0.definitionOffset - obj1.definitionOffset; + + moduleClassDeclaration.asyncFunctions.sort(cmp); + moduleClassDeclaration.classes.sort(cmp); + moduleClassDeclaration.constants.sort(cmp); + moduleClassDeclaration.events.sort(); + moduleClassDeclaration.functions.sort(cmp); + moduleClassDeclaration.properties.sort(cmp); + moduleClassDeclaration.props.sort(cmp); + moduleClassDeclaration.views.sort(cmp); +} + +function parsePropertyString( + property: string, + definitionOffset: number +): PropertyDeclaration | null { + const propertyRegex = /Property\(\.\s*"([^"]*)"\s*\)/; + const matches = property.match(propertyRegex); + const propertyName = matches?.[1]; + if (!matches || !propertyName) { + return null; + } + + return { + name: propertyName, + type: { + kind: TypeKind.BASIC, + type: BasicType.UNRESOLVED, + }, + definitionOffset, + }; +} + +async function parseModuleStructure( + moduleStructure: Structure[], + file: FileType, + name: string, + definitionOffset: number, + options: SwiftFileTypeInformationOptions +): Promise { + const moduleClassDeclaration: ModuleClassDeclaration = { + name, + constants: [], + constructor: null, + functions: [], + asyncFunctions: [], + classes: [], + properties: [], + props: [], + views: [], + events: [], + definitionOffset, + }; + + await taskAll(moduleStructure, async (structure) => { + // TODO(@HubertBer): Some special cases when the sourcekitten parses the structure differently, for now only Property as it is common + if (structure['key.name'].startsWith('Property(')) { + const propertyDeclaration = parsePropertyString( + structure['key.name'], + structure['key.nameoffset'] + ); + if (propertyDeclaration) { + moduleClassDeclaration.properties.push(propertyDeclaration); + } + return; + } + + switch (structure['key.name']) { + case 'Name': { + const nameSubstrucutre = structure['key.substructure']?.[0]; + if (nameSubstrucutre) { + moduleClassDeclaration.name = getIdentifierFromOffsetObject(nameSubstrucutre, file); + } + break; + } + case 'Function': { + moduleClassDeclaration.functions.push( + await parseModuleFunctionSubstructure(structure, file, options) + ); + break; + } + case 'Constant': { + const constantDeclaration = await parseModuleConstantStructure(structure, file, options); + if (constantDeclaration) { + moduleClassDeclaration.constants.push(constantDeclaration); + } + break; + } + case 'Class': + moduleClassDeclaration.classes.push( + await parseModuleClassStructure(structure, file, options) + ); + break; + case 'Property': { + const propertyDeclaration = await parseModulePropertyStructure(structure, file, options); + if (propertyDeclaration) { + moduleClassDeclaration.properties.push(propertyDeclaration); + } + break; + } + case 'AsyncFunction': + moduleClassDeclaration.asyncFunctions.push( + await parseModuleFunctionSubstructure(structure, file, options) + ); + break; + case 'Constructor': + moduleClassDeclaration.constructor = await parseModuleConstructorDeclaration( + structure, + file, + options + ); + break; + case 'Prop': + moduleClassDeclaration.props.push( + await parseModulePropDeclaration(structure, file, options) + ); + break; + case 'View': { + const viewDeclaration = await parseModuleViewDeclaration(structure, file, options); + if (viewDeclaration) { + moduleClassDeclaration.views.push(viewDeclaration); + } + break; + } + case 'Events': + parseModuleEventDeclaration(structure, file, moduleClassDeclaration.events); + break; + default: + console.warn(`Module substructure not supported. ${structure['key.name']}`); + } + }); + + // As we parse the module structure concurrently the order of for example functions is nondeterministic. + // We want to make it deterministic -- better for testing and usage. + // + // To make it deterministic a `definitionOffset` was added to each declaration. + // We sort declaration by this `definitionOffset` which additionally preserves the in file ordering. + // + // This may not be as useful if we get to merging type informations from multiple files as the `definitionOffset` will not be comparable. + sortModuleClassDeclaration(moduleClassDeclaration); + return moduleClassDeclaration; +} + +function parseStructure( + structure: Structure, + name: string, + modulesStructures: { structure: Structure; name: string }[], + recordsStructures: Structure[], + enumsStructures: Structure[] +) { + // TODO(@HubertBer): Find out why sometimes the structure is undefined (for example when parsing expo-audio) + if (!structure || !structure['key.substructure']) { + return; + } + const substructure = structure['key.substructure']; + + if (isModuleStructure(structure)) { + modulesStructures.push({ structure, name }); + } else if (isRecordStructure(structure)) { + recordsStructures.push(structure); + } else if (isEnumStructure(structure)) { + enumsStructures.push(structure); + } else if (Array.isArray(substructure) && substructure.length > 0) { + for (const substructure of structure['key.substructure']) { + parseStructure( + substructure, + structure['key.name'] ?? name, + modulesStructures, + recordsStructures, + enumsStructures + ); + } + } +} + +function getTypeIdentifierDefinitionMap( + fileTypeInformation: FileTypeInformation +): Map { + const typeIdentifierDefinitionMap = new Map< + string, + { kind: IdentifierKind; definition: string | RecordType | EnumType | ClassDeclaration } + >([]); + + fileTypeInformation.records.forEach((r) => + typeIdentifierDefinitionMap.set(r.name, { kind: IdentifierKind.RECORD, definition: r }) + ); + fileTypeInformation.enums.forEach((e) => + typeIdentifierDefinitionMap.set(e.name, { kind: IdentifierKind.ENUM, definition: e }) + ); + + return typeIdentifierDefinitionMap; +} + +function collectTypeIdentifiers( + type: Type, + typeIdentiers: Set, + inferredTypeParametersCount: Map +) { + switch (type.kind) { + case TypeKind.ARRAY: + case TypeKind.OPTIONAL: + collectTypeIdentifiers(type.type as Type, typeIdentiers, inferredTypeParametersCount); + break; + case TypeKind.DICTIONARY: + collectTypeIdentifiers( + (type.type as DictionaryType).key, + typeIdentiers, + inferredTypeParametersCount + ); + collectTypeIdentifiers( + (type.type as DictionaryType).value, + typeIdentiers, + inferredTypeParametersCount + ); + break; + case TypeKind.SUM: + for (const t of (type.type as SumType).types) { + collectTypeIdentifiers(t, typeIdentiers, inferredTypeParametersCount); + } + break; + case TypeKind.BASIC: + break; + case TypeKind.IDENTIFIER: + typeIdentiers.add(type.type as TypeIdentifier); + break; + case TypeKind.PARAMETRIZED: { + const parametrizedType: ParametrizedType = type.type as ParametrizedType; + const typename = parametrizedType.name; + typeIdentiers.add(typename); + inferredTypeParametersCount.set( + typename, + Math.max(inferredTypeParametersCount.get(typename) ?? 0, parametrizedType.types.length) + ); + for (const t of (type.type as ParametrizedType).types) { + collectTypeIdentifiers(t, typeIdentiers, inferredTypeParametersCount); + } + break; + } + } +} + +function collectModuleTypeIdentifiers( + moduleClassDeclaration: ModuleClassDeclaration, + fileTypeInformation: FileTypeInformation +) { + const collect = (type: Type) => { + collectTypeIdentifiers( + type, + fileTypeInformation.usedTypeIdentifiers, + fileTypeInformation.inferredTypeParametersCount + ); + }; + const collectArg = (arg: Argument) => { + collect(arg.type); + }; + const collectFunction = (functionDeclaration: FunctionDeclaration) => { + collect(functionDeclaration.returnType); + functionDeclaration.arguments.forEach(collectArg); + functionDeclaration.parameters.forEach(collect); + }; + moduleClassDeclaration.asyncFunctions.forEach(collectFunction); + moduleClassDeclaration.functions.forEach(collectFunction); + moduleClassDeclaration.constants.forEach(collectArg); + moduleClassDeclaration.properties.forEach(collectArg); + moduleClassDeclaration.constructor?.arguments.forEach(collectArg); + moduleClassDeclaration.views.forEach((v) => collectModuleTypeIdentifiers(v, fileTypeInformation)); + moduleClassDeclaration.props.forEach((p) => p.arguments.forEach(collectArg)); + moduleClassDeclaration.classes.forEach((c) => { + fileTypeInformation.declaredTypeIdentifiers.add(c.name); + c.asyncMethods.forEach(collectFunction); + c.methods.forEach(collectFunction); + c.constructor?.arguments.forEach(collectArg); + c.properties.forEach(collectArg); + }); +} + +export type SwiftFileTypeInformationOptions = { + typeInference: boolean; +}; + +export async function getSwiftFileTypeInformation( + filePath: string, + options: SwiftFileTypeInformationOptions +): Promise { + const file = { path: filePath, content: fs.readFileSync(filePath, 'utf8') }; + + const modulesStructures: { name: string; structure: Structure }[] = []; + const recordsStructures: Structure[] = []; + const enumsStructures: Structure[] = []; + parseStructure( + getStructureFromFile(file), + '', + modulesStructures, + recordsStructures, + enumsStructures + ); + + const inferredTypeParametersCount = new Map(); + const moduleClasses: ModuleClassDeclaration[] = []; + const moduleTypeIdentifiers = new Set(); + const declaredTypeIdentifiers = new Set(); + const recordTypeIdentifiers = new Set(); + const typeIdentifierDefinitionMap: TypeIdentifierDefinitionMap = new Map(); + const enums: EnumType[] = enumsStructures.map(parseEnumStructure); + const recordMap = (rd: Structure) => { + return parseRecordStructure( + rd, + recordTypeIdentifiers, + inferredTypeParametersCount, + file, + options + ); + }; + + const recordsPromise = taskAll(recordsStructures, recordMap); + const moduleClassDeclarationsPromise = taskAll( + modulesStructures.filter(({ structure }) => hasSubstructure(structure)), + ({ structure, name }) => + parseModuleStructure( + structure['key.substructure'], + file, + name, + structure['key.offset'], + options + ) + ); + + const [records, moduleClassDeclarations] = await Promise.all([ + recordsPromise, + moduleClassDeclarationsPromise, + ]); + + enums.forEach(({ name }) => { + declaredTypeIdentifiers.add(name); + }); + records.forEach(({ name }) => { + declaredTypeIdentifiers.add(name); + }); + + const fileTypeInformation = { + moduleClasses, + records, + enums, + functions: [], + usedTypeIdentifiers: moduleTypeIdentifiers.union(recordTypeIdentifiers), + declaredTypeIdentifiers, + inferredTypeParametersCount, + typeIdentifierDefinitionMap, + }; + + for (const moduleClassDeclaration of moduleClassDeclarations) { + moduleClasses.push(moduleClassDeclaration); + collectModuleTypeIdentifiers(moduleClassDeclaration, fileTypeInformation); + } + + fileTypeInformation.typeIdentifierDefinitionMap = + getTypeIdentifierDefinitionMap(fileTypeInformation); + + return fileTypeInformation; +} + +function removeComments(fileContent: string): string { + // This regex matches doubly quoted strings ("string"), and comments (`// comment` and `/* comment */`). + // + // It is in a form A|B where: + // A = ("(?:[^"\\]|\\.)*") + // Matches and captures doubly quoted strings ("string") + // + // B = (\/\/.*|\/\*[\s\S]*?\*\/) + // Matches and captures comments (`// comment` and `/* comment */`) + + // By first matching strings we ensure that we don't match comments which happen to be inside a string literal. + // This regex doesn't handle: + // - multline strings literals """ multiline """ + // - nested comments /* comment /* nested comment */ */ + const commentRegex = /("(?:[^"\\]|\\.)*")|(\/\/.*|\/\*[\s\S]*?\*\/)/g; + return fileContent.replace(commentRegex, (match, doubleQuoted) => { + if (doubleQuoted) { + return match; + } + return ''; + }); +} + +function returnExpressionEnd(fileContent: string, returnIndex: number): number { + let inString = false; + let escaped = false; + let parenCount = 0; + let braceCount = 0; + // TODO(@HubertBer): figure out what also changes the typical end of expression + + let i = returnIndex; + while (i < fileContent.length) { + const char = fileContent[i]; + let escapedNow = false; + switch (char) { + case '(': + parenCount += 1; + break; + case ')': + parenCount -= 1; + break; + case '{': + braceCount += 1; + break; + case '}': + if (braceCount === 0) { + return i; + } + braceCount -= 1; + break; + case '"': + if (!escaped) { + inString = !inString; + } + break; + case ';': + return i; + case '\n': + case '\r': + if (!inString && parenCount === 0 && braceCount === 0) { + return i; + } + break; + case '\\': + escapedNow = true; + } + escaped = escapedNow; + i += 1; + } + return i; +} + +// Preprocessing to help sourcekitten functions +// For now we create a new variable for each return statement, +// we can find it's type easily with sourcekitten +// TODO(@HubertBer): This has many problems which need fixing: +// - return can be inside a string +// - return Expression end parses incorrectly in case of some strings (check how it parses expo-video) +export function preprocessSwiftFile(originalFileContent: string): string { + const newFileContent: string[] = []; + const fileContent = removeComments(originalFileContent); + const returnPositions: { start: number; end: number }[] = []; + let startPos = 0; + while (startPos < fileContent.length) { + const returnIndex = fileContent.indexOf('return ', startPos); + if (returnIndex < 0 || returnIndex >= fileContent.length) { + break; + } + returnPositions.push({ + start: returnIndex, + end: returnExpressionEnd(fileContent, returnIndex), + }); + startPos = returnIndex + 1; + } + + let prevEnd = 0; + + for (const { start, end } of returnPositions) { + newFileContent.push(fileContent.substring(prevEnd, start)); + newFileContent.push( + `\nlet returnValueDeclaration_${start}_${end} = ${fileContent.substring(start + 6, end)}\n` + ); + newFileContent.push(`return returnValueDeclaration_${start}_${end}\n`); + prevEnd = end; + } + newFileContent.push(fileContent.substring(prevEnd, fileContent.length)); + return newFileContent.join(''); +} diff --git a/packages/expo-type-information/src/typeInformation.ts b/packages/expo-type-information/src/typeInformation.ts new file mode 100644 index 00000000000000..da27b4dd454cbb --- /dev/null +++ b/packages/expo-type-information/src/typeInformation.ts @@ -0,0 +1,326 @@ +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; + +import { + getSwiftFileTypeInformation, + preprocessSwiftFile, +} from './swift/sourcekittenTypeInformation'; +import { taskAll } from './utils'; + +export enum IdentifierKind { + BASIC, + ENUM, + RECORD, + CLASS, +} + +export type ParametrizedType = { + name: TypeIdentifier; + types: Type[]; +}; + +export type Argument = { name: string | undefined; type: Type }; +export type Field = Argument; + +export type RecordType = { + name: string; + fields: Field[]; +}; + +export type EnumCase = string; + +export type EnumType = { + name: string; + cases: EnumCase[]; +}; + +export type SumType = { + types: Type[]; +}; + +export type DictionaryType = { + key: Type; + value: Type; +}; + +export type OptionalType = Type; +export type ArrayType = Type; +export type TypeIdentifier = string; +export type AnonymousType = ParametrizedType | SumType | OptionalType | DictionaryType | ArrayType; + +export enum TypeKind { + BASIC, + IDENTIFIER, + SUM, + PARAMETRIZED, + OPTIONAL, + ARRAY, + DICTIONARY, +} + +export enum BasicType { + ANY, + STRING, + NUMBER, + BOOLEAN, + VOID, + UNDEFINED, + UNRESOLVED, +} + +export type Type = { + kind: TypeKind; + type: BasicType | TypeIdentifier | AnonymousType; +}; + +export type PropertyDeclaration = ConstantDeclaration; +export type ViewDeclaration = ModuleClassDeclaration; +export type EventDeclaration = string; + +/** + * Retain information of where the thing was defined in the file. + * As collecting type information is written in asynchronous way it is non-deterministic. + * To make it deterministic we just sort the declaration by the definitionOffset, maintianing the same ordering as in original file. + */ +export type DefinitionOffset = { + definitionOffset: number; +}; + +export type ConstantDeclaration = { + name: string; + type: Type; +} & DefinitionOffset; + +export type FunctionDeclaration = { + name: string; + returnType: Type; + arguments: Argument[]; + parameters: Type[]; +} & DefinitionOffset; + +export type PropDeclaration = { + name: string; + arguments: Argument[]; +} & DefinitionOffset; + +export type ConstructorDeclaration = { + arguments: Argument[]; +} & DefinitionOffset; + +export type ClassDeclaration = { + name: string; + constructor: ConstructorDeclaration | null; + methods: FunctionDeclaration[]; + asyncMethods: FunctionDeclaration[]; + properties: PropertyDeclaration[]; +} & DefinitionOffset; + +export type ModuleClassDeclaration = { + name: string; + constructor: ConstructorDeclaration | null; + constants: ConstantDeclaration[]; + classes: ClassDeclaration[]; + functions: FunctionDeclaration[]; + asyncFunctions: FunctionDeclaration[]; + properties: PropertyDeclaration[]; + props: PropDeclaration[]; + views: ViewDeclaration[]; + events: EventDeclaration[]; +} & DefinitionOffset; + +export type IdentifierDefinition = { + kind: IdentifierKind; + definition: string | RecordType | EnumType | ClassDeclaration; +}; + +export type TypeIdentifierDefinitionMap = Map; + +export type TypeIdentifierDefinitionList = [string, IdentifierDefinition][]; + +export type FileTypeInformationSerialized = { + usedTypeIdentifiersList: string[]; + declaredTypeIdentifiersList: string[]; + inferredTypeParametersCountList: [string, number][]; + typeIdentifierDefinitionList: TypeIdentifierDefinitionList; + moduleClasses: ModuleClassDeclaration[]; + records: RecordType[]; + enums: EnumType[]; +}; + +/** + * FileTypeInformation object abstracts over type related information in a file. + * The abstraction is closely related to Typescript and expo NativeModules (both to be independent of the actual native side + * and to give accurate information about what and how we can use the given module). + */ +export type FileTypeInformation = { + /** + * @field Set of all type identifiers declared and used in the file. + */ + usedTypeIdentifiers: Set; + /** + * @field Set of all type identifiers declared in the file. + */ + declaredTypeIdentifiers: Set; + /** + * @field For parametrized types it is the maximum number of parameters this type is used with. + * This map is useful if we want to infer how many parameters a type declared in other file has. + * + * For example if `Set` exists in a file then inferredTypeParametersCount['Set'] == 1. + * If `Map` exists then inferredTypeParametersCount['Map'] == 2. + * If you use both `SomeParametrizedType` and `SomeParametrizedType` then inferredTypeParametersCount['SomeParametrizedType'] == 2. + */ + inferredTypeParametersCount: Map; + /** + * @field Maps string identifier to the appropriate declaration object. For now only enum and records identifiers are mapped. + */ + typeIdentifierDefinitionMap: TypeIdentifierDefinitionMap; + /** + * @field Array of all module classes declared in the given file. + */ + moduleClasses: ModuleClassDeclaration[]; + /** + * @field Array of all record classes declared in the given file. + */ + records: RecordType[]; + /** + * @field Array of all enums declared in the given file. + */ + enums: EnumType[]; +}; + +/** + * Used for testing purposes, maps Sets and Maps to Arrays and returns FileTypeInformationSerialized object which can be written to a JSON. + * @param param0 FileTypeInformation object to serialize. + * @returns FileTypeInformationSerialized object. + */ +export function serializeTypeInformation({ + usedTypeIdentifiers, + declaredTypeIdentifiers, + inferredTypeParametersCount, + typeIdentifierDefinitionMap, + moduleClasses, + records, + enums, +}: FileTypeInformation): FileTypeInformationSerialized { + return { + usedTypeIdentifiersList: [...usedTypeIdentifiers.keys()].sort(), + declaredTypeIdentifiersList: [...declaredTypeIdentifiers.keys()].sort(), + inferredTypeParametersCountList: [...inferredTypeParametersCount.entries()].sort(), + typeIdentifierDefinitionList: [...typeIdentifierDefinitionMap.entries()].sort(), + moduleClasses, + records, + enums, + }; +} + +/** + * Used for testing purposes, maps Arrays to Sets and Maps depending on the field and returns FileTypeInformation object. + * @param param0 FileTypeInformationSerialized object to deserialize. + * @returns FileTypeInformation object. + */ +export function deserializeTypeInformation({ + usedTypeIdentifiersList, + declaredTypeIdentifiersList, + inferredTypeParametersCountList, + typeIdentifierDefinitionList, + moduleClasses, + records, + enums, +}: FileTypeInformationSerialized): FileTypeInformation { + return { + usedTypeIdentifiers: new Set(usedTypeIdentifiersList), + declaredTypeIdentifiers: new Set(declaredTypeIdentifiersList), + inferredTypeParametersCount: new Map(inferredTypeParametersCountList), + typeIdentifierDefinitionMap: new Map(typeIdentifierDefinitionList), + moduleClasses, + records, + enums, + }; +} + +/** + * Defines the level of type inference to apply when extracting type information. + * Note: In case where type inference is on, it may take more then twice the time to compute the type information. + */ +export enum TypeInferenceOption { + /** No type inference will be performed. */ + NO_INFERENCE, + /** Basic type inference will be applied. */ + SIMPLE_INFERENCE, + /** Preprocesses the file by injecting returns to extract more type info from sourcekitten. */ + PREPROCESS_AND_INFERENCE, +} + +export type StringInputOption = { + type: 'string'; + fileContent: string; + language: 'Swift'; +}; + +export type FileInputOption = { + type: 'file'; + inputFileAbsolutePaths: string[]; +}; + +/** + * Options specifying the input source and inference level for retrieving type information. + */ +export type GetFileTypeInformationOptions = { + /** The input source, provided either as a direct string or a file path. */ + input: StringInputOption | FileInputOption; + /** The desired level of type inference. Defaults to PREPROCESS_AND_INFERENCE if omitted. */ + typeInference?: TypeInferenceOption; +}; + +async function mergeFileContents(absoluteFilePaths: string[]): Promise { + const filesContents = await taskAll(absoluteFilePaths, (filePath) => + fs.promises.readFile(filePath, 'utf-8') + ); + return filesContents.join(''); +} + +async function withTempFile(content: string, fn: (filePath: string) => Promise): Promise { + const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'type-gen-')); + const filePath = path.join(tempDir, 'TypeInformationTemporaryFile.swift'); + + try { + await fs.promises.writeFile(filePath, content, 'utf8'); + return await fn(filePath); + } finally { + await fs.promises.rm(tempDir, { recursive: true, force: true }); + } +} + +/** + * Reads and extracts `FileTypeInformation` from either a provided file path or a raw string of source code. + * If a raw string is provided, or if the `PREPROCESS_AND_INFERENCE` inference option is selected, + * the function will create a temporary file with the (optionally preprocessed) content to facilitate parsing. + * @param options - Configuration object containing the input source (file or string) and the desired level of type inference. + * @returns A promise that resolves to a `FileTypeInformation` object if the input was parsed successfully. Otherwise, it returns `null`. + */ +export async function getFileTypeInformation({ + input, + typeInference, +}: GetFileTypeInformationOptions): Promise { + const shouldPreprocessFile = typeInference === TypeInferenceOption.PREPROCESS_AND_INFERENCE; + const typeInferenceOn = typeInference !== TypeInferenceOption.NO_INFERENCE; + if (!shouldPreprocessFile && input.type === 'file' && input.inputFileAbsolutePaths.length === 0) { + return getSwiftFileTypeInformation(input.inputFileAbsolutePaths[0] as string, { + typeInference: typeInferenceOn, + }); + } + + const fileContent = + input.type === 'file' + ? await mergeFileContents(input.inputFileAbsolutePaths) + : input.fileContent; + + const preprocessedContent = shouldPreprocessFile ? preprocessSwiftFile(fileContent) : fileContent; + + return withTempFile(preprocessedContent, async (tempFilePath) => { + return getSwiftFileTypeInformation(tempFilePath, { + typeInference: typeInferenceOn, + }); + }); +} diff --git a/packages/expo-modules-test-core/src/types.ts b/packages/expo-type-information/src/types.ts similarity index 86% rename from packages/expo-modules-test-core/src/types.ts rename to packages/expo-type-information/src/types.ts index 9f17da84632f1d..43ca0224ea0ea3 100644 --- a/packages/expo-modules-test-core/src/types.ts +++ b/packages/expo-type-information/src/types.ts @@ -3,6 +3,12 @@ export type FileType = { content: string; }; +export type Attribute = { + 'key.attribute': string; + 'key.length': number; + 'key.offset': number; +}; + export type Structure = { 'key.substructure': Structure[]; 'key.typename': string; @@ -10,6 +16,9 @@ export type Structure = { 'key.kind': string; 'key.offset': number; 'key.length': number; + 'key.nameoffset': number; + 'key.inheritedtypes': { 'key.name': string }[]; + 'key.attributes': Attribute[]; }; export type CursorInfoOutput = { @@ -45,11 +54,6 @@ export type Prop = { types: Omit; }; -export type Constant = { - name: string; - types: ClosureTypes | null; -}; - export type OutputModuleDefinition = { name: string; views: OutputNestedClassDefinition[]; @@ -57,7 +61,6 @@ export type OutputModuleDefinition = { events: { name: string; }[]; - constants: Constant[]; } & Record<'asyncFunctions' | 'functions' | 'properties', Closure[]> & Record<'props', Prop[]>; diff --git a/packages/expo-type-information/src/typescriptGeneration.ts b/packages/expo-type-information/src/typescriptGeneration.ts new file mode 100644 index 00000000000000..a2a671ccec9b0f --- /dev/null +++ b/packages/expo-type-information/src/typescriptGeneration.ts @@ -0,0 +1,1179 @@ +'use strict'; +import prettier from 'prettier'; +import ts from 'typescript'; + +import { + Argument, + ArrayType, + BasicType, + ClassDeclaration, + ConstantDeclaration, + ConstructorDeclaration, + DictionaryType, + EnumType, + EventDeclaration, + FileTypeInformation, + FunctionDeclaration, + ModuleClassDeclaration, + ParametrizedType, + PropDeclaration, + PropertyDeclaration, + RecordType, + SumType, + Type, + TypeKind, + ViewDeclaration, +} from './typeInformation'; + +const prefix = `Automatically generated by expo-type-information.`; + +const exportModifier = () => ts.factory.createModifier(ts.SyntaxKind.ExportKeyword); +const declareModifier = () => ts.factory.createModifier(ts.SyntaxKind.DeclareKeyword); +const asyncModifier = () => ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword); +const readonlyModifier = () => ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword); +const constModifier = () => ts.factory.createModifier(ts.SyntaxKind.ConstKeyword); +const defaultModifier = () => ts.factory.createModifier(ts.SyntaxKind.DefaultKeyword); + +const unknownKeywordType = () => ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword); +const anyKeywordType = () => ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); +const voidKeywordType = () => ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword); + +const newlineIdentifier = () => ts.factory.createIdentifier('\n\n'); + +export type OutputFile = { + content: string; + name: string; +}; + +export interface GenerationContext { + fileInfo: FileTypeInformation; + module: ModuleClassDeclaration; + view: ViewDeclaration | null; + missingTypes: Set; +} + +let freeId = 0; +function getNextFreeId() { + freeId += 1; + return freeId; +} + +export function createDefaultGenerationContext( + fileInfo: FileTypeInformation +): GenerationContext | null { + const module = fileInfo.moduleClasses[0]; + if (!module) { + return null; + } + const view = module.views[0] ?? null; + return { + fileInfo, + module, + view, + missingTypes: getMissingTypeIdentifiers(fileInfo), + }; +} + +export function getBasicTypesIdentifiers(): Set { + return new Set(['any', 'number', 'string', 'undefined', 'null', 'Map', 'Set', 'Promise']); +} + +function getAllNonBasicTypes(fileInfo: FileTypeInformation): Set { + return fileInfo.declaredTypeIdentifiers + .union(fileInfo.usedTypeIdentifiers) + .difference(getBasicTypesIdentifiers()); +} + +function createGeneratedPrefix(): ts.Node[] { + return [ + ts.addSyntheticLeadingComment( + ts.factory.createIdentifier(''), + ts.SyntaxKind.MultiLineCommentTrivia, + prefix + ), + ]; +} + +function constructModifiersArray(modifiers: { + exported?: boolean; + declare?: boolean; + async?: boolean; + readonly?: boolean; +}): ts.Modifier[] { + const modifiersArray: ts.Modifier[] = []; + if (modifiers.exported) modifiersArray.push(exportModifier()); + if (modifiers.declare) modifiersArray.push(declareModifier()); + if (modifiers.async) modifiersArray.push(asyncModifier()); + if (modifiers.readonly) modifiersArray.push(readonlyModifier()); + return modifiersArray; +} + +export function joinTSNodesWithNewlines(nodes: ts.Node[][]): ts.Node[] { + const new_nodes: ts.Node[] = []; + for (const node of nodes) { + if (node.length > 0) { + new_nodes.push(...node); + new_nodes.push(newlineIdentifier()); + } + } + return new_nodes; +} + +function mapBasicTypeToTypeNode(basicType: BasicType): ts.TypeNode { + if (basicType === BasicType.UNRESOLVED) { + return ts.addSyntheticTrailingComment( + unknownKeywordType(), + ts.SyntaxKind.MultiLineCommentTrivia, + "The type couldn't be resolved automatically." + ); + } + + const BASIC_TYPE_MAP: Record = { + [BasicType.ANY]: ts.SyntaxKind.AnyKeyword, + [BasicType.BOOLEAN]: ts.SyntaxKind.BooleanKeyword, + [BasicType.NUMBER]: ts.SyntaxKind.NumberKeyword, + [BasicType.STRING]: ts.SyntaxKind.StringKeyword, + [BasicType.VOID]: ts.SyntaxKind.VoidKeyword, + [BasicType.UNDEFINED]: ts.SyntaxKind.UndefinedKeyword, + [BasicType.UNRESOLVED]: ts.SyntaxKind.UndefinedKeyword, // This is handled earlier + }; + + return ts.factory.createKeywordTypeNode(BASIC_TYPE_MAP[basicType]); +} + +export function mapTypeToTsTypeNode(type: Type): ts.TypeNode { + switch (type.kind) { + case TypeKind.BASIC: + return mapBasicTypeToTypeNode(type.type as BasicType); + case TypeKind.IDENTIFIER: + return ts.factory.createTypeReferenceNode(type.type as string); + case TypeKind.SUM: + return ts.factory.createUnionTypeNode((type.type as SumType).types.map(mapTypeToTsTypeNode)); + case TypeKind.ARRAY: + return ts.factory.createArrayTypeNode(mapTypeToTsTypeNode(type.type as ArrayType)); + case TypeKind.DICTIONARY: { + const dictionaryType = type.type as DictionaryType; + const name = 'key'; + const typeNode = mapTypeToTsTypeNode(dictionaryType.key); + const valueType = mapTypeToTsTypeNode(dictionaryType.value); + return ts.factory.createTypeLiteralNode([ + ts.factory.createIndexSignature( + undefined, + [createParameter({ name, type: typeNode })], + valueType + ), + ]); + } + // Technically this one should only be the top one and it should be handled somewhere else + // for example when creating arguemnt adding the '?' token. + // + // However we can just make it (type | undefined) in here. + // TODO(@HubertBer): Maybe also need null? + case TypeKind.OPTIONAL: + return ts.factory.createUnionTypeNode([ + mapTypeToTsTypeNode(type.type as Type), + mapBasicTypeToTypeNode(BasicType.UNDEFINED), + ]); + case TypeKind.PARAMETRIZED: + return ts.factory.createTypeReferenceNode( + (type.type as ParametrizedType).name, + (type.type as ParametrizedType).types.map(mapTypeToTsTypeNode) + ); + } + return mapBasicTypeToTypeNode(BasicType.UNRESOLVED); +} + +// +// ts.factory wrapper functions +// + +function createImportDeclaration({ + defaultImportName, + namedImportsNames, + importFromName, +}: { + defaultImportName?: string; + namedImportsNames?: string[]; + importFromName: string; +}): ts.Node[] { + const hasDefault = !!defaultImportName; + const hasNamed = namedImportsNames && namedImportsNames.length > 0; + + if (!hasDefault && !hasNamed) { + return []; + } + + const defaultImport = hasDefault ? ts.factory.createIdentifier(defaultImportName) : undefined; + + const namedImports = hasNamed + ? ts.factory.createNamedImports( + namedImportsNames.map((name) => + ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(name)) + ) + ) + : undefined; + + return [ + ts.factory.createImportDeclaration( + undefined, + ts.factory.createImportClause(undefined, defaultImport, namedImports), + ts.factory.createStringLiteral(importFromName) + ), + ]; +} + +function createParameter({ + modifiers, + name, + type, + questionToken, + dotDotDotToken, + initializer, +}: { + modifiers?: ts.Modifier[]; + name: string | ts.BindingName; + type?: ts.TypeNode; + questionToken?: ts.QuestionToken; + dotDotDotToken?: ts.DotDotDotToken; + initializer?: ts.Expression; +}): ts.ParameterDeclaration { + return ts.factory.createParameterDeclaration( + modifiers, + dotDotDotToken, + name, + questionToken, + type, + initializer + ); +} + +function createProperty({ + modifiers, + name, + typeNode, + initializer, + optional, +}: { + modifiers?: ts.Modifier[]; + name: string | ts.PropertyName; + typeNode?: ts.TypeNode; + initializer?: ts.Expression; + optional?: boolean; +}): ts.PropertyDeclaration { + return ts.factory.createPropertyDeclaration( + modifiers, + name, + optional ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, + typeNode, + initializer + ); +} + +function createPropertySignature({ + name, + typeNode, + optional, + modifiers, +}: { + name: string | ts.PropertyName; + typeNode?: ts.TypeNode; + optional?: boolean; + modifiers?: ts.Modifier[]; +}): ts.PropertySignature { + return ts.factory.createPropertySignature( + modifiers, + name, + optional ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, + typeNode + ); +} + +function createCall({ + expression, + args, + typeArgs, +}: { + expression: string | ts.Expression; + args?: ts.Expression[]; + typeArgs?: ts.TypeNode[]; +}): ts.CallExpression { + return ts.factory.createCallExpression( + typeof expression === 'string' ? ts.factory.createIdentifier(expression) : expression, + typeArgs, + args + ); +} + +function createRequireNativeModuleExpression({ + moduleType, + moduleName, +}: { + moduleType?: string; + moduleName: string; +}) { + return ts.factory.createCallExpression( + ts.factory.createIdentifier('requireNativeModule'), + moduleType ? [ts.factory.createTypeReferenceNode(moduleType)] : undefined, + [ts.factory.createStringLiteral(moduleName)] + ); +} + +function createExportDefaultAsDeclaration({ + exportAsName, + importFromName, +}: { + exportAsName: string; + importFromName: string; +}): ts.Node[] { + return [ + ts.factory.createExportDeclaration( + undefined, + false, + ts.factory.createNamedExports([ + ts.factory.createExportSpecifier( + false, + ts.factory.createIdentifier('default'), + ts.factory.createIdentifier(exportAsName) + ), + ]), + ts.factory.createStringLiteral(importFromName) + ), + ]; +} + +function createTypeAlias({ + exported, + alias, + typeParams, + type, +}: { + exported?: boolean; + alias: string; + typeParams?: ts.TypeParameterDeclaration[]; + type: ts.TypeNode; +}) { + return ts.factory.createTypeAliasDeclaration( + constructModifiersArray({ exported }), + alias, + typeParams, + type + ); +} + +function createRequireNativeViewDeclaration(module: ModuleClassDeclaration, view: ViewDeclaration) { + return [ + createParameter({ + modifiers: [constModifier()], + name: view.name, + initializer: createCall({ + expression: 'requireNativeView', + typeArgs: [ts.factory.createTypeReferenceNode(getViewPropsTypeName(view))], + args: [ + ts.factory.createStringLiteral(module.name), + ts.factory.createStringLiteral(view.name), + ], + }), + }), + ]; +} + +function createExportAllDeclaration({ + importFromName, + justTypes, +}: { + importFromName: string; + justTypes?: boolean; +}): ts.Node[] { + return [ + ts.factory.createExportDeclaration( + undefined, + justTypes ?? false, + undefined, + ts.factory.createStringLiteral(importFromName) + ), + ]; +} + +function createExportDefault(name: string = '_default'): ts.Node[] { + return [ts.factory.createExportDefault(ts.factory.createIdentifier(name))]; +} + +function createComponentType(propsTypeName: string) { + return ts.factory.createTypeReferenceNode('React.JSXElementConstructor', [ + ts.factory.createTypeReferenceNode(propsTypeName), + ]); +} + +function getMissingTypeIdentifiers(fileTypeInformation: FileTypeInformation): Set { + return fileTypeInformation.usedTypeIdentifiers + .difference(fileTypeInformation.declaredTypeIdentifiers) + .difference(getBasicTypesIdentifiers()); +} + +function buildPropsMembers({ props, events }: ViewDeclaration): ts.TypeElement[] { + const buildEventPropertySignature = (eventDeclaration: EventDeclaration) => { + const name = eventDeclaration; + const typeNode = ts.factory.createFunctionTypeNode( + undefined, + [createParameter({ name: 'event', type: anyKeywordType() })], + voidKeywordType() + ); + // TODO(@HubertBer) check whether we have ways of making events not optional + return createPropertySignature({ name, typeNode, optional: true }); + }; + + const buildPropPropertySignature = (propDeclaration: PropDeclaration) => { + const propTypeArgument = propDeclaration.arguments[1]?.type; + if (!propDeclaration || !propDeclaration.arguments || !propTypeArgument) { + return undefined; + } + const name = propDeclaration.name; + const typeNode = mapTypeToTsTypeNode(propTypeArgument); + return createPropertySignature({ name, typeNode }); + }; + + return [ + ...(props.map(buildPropPropertySignature).filter((p) => p) as ts.PropertySignature[]), + ...events.map(buildEventPropertySignature), + ]; +} + +export function buildViewPropsInterface( + view: ViewDeclaration | null, + options: { exported?: boolean } +): ts.Node[] { + if (!view) { + return []; + } + return [ + ts.factory.createInterfaceDeclaration( + constructModifiersArray(options), + getViewPropsTypeName(view), + undefined, + [ + ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + ts.factory.createExpressionWithTypeArguments( + ts.factory.createIdentifier('ViewProps'), + undefined + ), + ]), + ], + buildPropsMembers(view) + ), + ]; +} + +function buildClassProperty(declaration: PropertyDeclaration): ts.PropertyDeclaration { + return createProperty({ + modifiers: [readonlyModifier()], + name: declaration.name, + typeNode: mapTypeToTsTypeNode(declaration.type), + }); +} + +function buildNativeModuleClassDeclaration({ + moduleClassDeclaration, + exportedModuleName, +}: { + moduleClassDeclaration: ModuleClassDeclaration; + exportedModuleName?: string; +}): ts.Node[] { + const buildClassTypeProperty = (classDeclaration: ClassDeclaration) => + createProperty({ + // TODO(@HubertBer): that's a hack, but I couldn't find a proper way to do this + // The problem is that declare class semantics seem somewhat different than class semantics. + name: classDeclaration.name, + typeNode: ts.factory.createTypeQueryNode(ts.factory.createIdentifier(classDeclaration.name)), + }); + + const buildSyncMethod = (functionDeclaration: FunctionDeclaration): ts.MethodDeclaration => + buildFunction({ + functionDeclaration, + method: true, + declaration: true, + }) as ts.MethodDeclaration; + + const buildAsyncMethod = (functionDeclaration: FunctionDeclaration): ts.MethodDeclaration => + buildFunction({ + functionDeclaration, + async: true, + method: true, + declaration: true, + }) as ts.MethodDeclaration; + + return [ + ts.factory.createClassDeclaration( + [exportModifier(), declareModifier()], + exportedModuleName ?? `${moduleClassDeclaration.name}NativeModuleType`, + undefined, + [ + ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + ts.factory.createExpressionWithTypeArguments( + ts.factory.createIdentifier('NativeModule'), + undefined + ), + ]), + ], + [ + ...moduleClassDeclaration.constants.map(buildClassProperty), + ...moduleClassDeclaration.properties.map(buildClassProperty), + ...moduleClassDeclaration.functions.map(buildSyncMethod), + ...moduleClassDeclaration.asyncFunctions.map(buildAsyncMethod), + ...moduleClassDeclaration.classes.map(buildClassTypeProperty), + ] + ), + ]; +} + +function buildArgumentDeclarationAndName(arg: Argument): { + argDeclaration: ts.ParameterDeclaration; + argName: string; +} { + const argName = arg.name ?? '_' + getNextFreeId(); + const argDeclaration = createParameter({ + name: argName, + type: mapTypeToTsTypeNode(arg.type), + }); + return { argDeclaration, argName }; +} + +function buildArgumentDeclaration(arg: Argument): ts.ParameterDeclaration { + return buildArgumentDeclarationAndName(arg).argDeclaration; +} + +export type buildFunctionOptions = { + functionDeclaration: FunctionDeclaration; + async?: boolean; + method?: boolean; + exported?: boolean; + declaration?: boolean; + returnStatement?: null | ts.ReturnStatement[]; + overrideArgumentDeclarations?: ts.ParameterDeclaration[]; + omitReturnType?: boolean; +}; + +export function buildFunction({ + functionDeclaration, + async, + method, + exported, + declaration, + returnStatement, + overrideArgumentDeclarations, + omitReturnType, +}: buildFunctionOptions): ts.FunctionDeclaration | ts.MethodDeclaration { + const functionModifiers = constructModifiersArray({ exported, async: async && !declaration }); + const customReturn = !!returnStatement; + const bareReturnTypeNode = mapTypeToTsTypeNode(functionDeclaration.returnType); + + const wrapWithPromiseType = (typeNode: ts.TypeNode): ts.TypeNode => + ts.factory.createTypeReferenceNode('Promise', [typeNode]); + + let returnTypeNode: ts.TypeNode | undefined = async + ? wrapWithPromiseType(bareReturnTypeNode) + : bareReturnTypeNode; + if (omitReturnType) { + returnTypeNode = undefined; + } + const argumentDeclarations = + overrideArgumentDeclarations ?? functionDeclaration.arguments.map(buildArgumentDeclaration); + + if (method) { + return ts.factory.createMethodDeclaration( + functionModifiers, + undefined, + functionDeclaration.name, + undefined, + undefined, + argumentDeclarations, + returnTypeNode, + declaration ? undefined : ts.factory.createBlock(customReturn ? returnStatement : []) + ); + } + return ts.factory.createFunctionDeclaration( + functionModifiers, + undefined, + functionDeclaration.name, + undefined, + argumentDeclarations, + returnTypeNode, + declaration ? undefined : ts.factory.createBlock(customReturn ? returnStatement : []) + ); +} + +export function buildConstructor( + constructor: ConstructorDeclaration, + declaration: boolean +): ts.ClassElement { + return ts.factory.createConstructorDeclaration( + undefined, + constructor.arguments.map(buildArgumentDeclaration), + declaration ? undefined : ts.factory.createBlock([]) + ); +} + +type BuildClassOptions = { + classDeclaration: ClassDeclaration; + exported?: boolean; + declaration?: boolean; + getFunctionReturnBlock?: (functionDeclaration: FunctionDeclaration) => ts.ReturnStatement[]; +}; + +// TODO(@HubertBer): figure out what about inheritance, should or should not inherit SharedObject +export function buildClass({ + classDeclaration, + exported, + declaration, + getFunctionReturnBlock, +}: BuildClassOptions): ts.ClassDeclaration { + const getReturnStatement = (method: FunctionDeclaration) => + !declaration && getFunctionReturnBlock ? getFunctionReturnBlock(method) : null; + + const buildMethod = (method: FunctionDeclaration, async?: boolean) => + buildFunction({ + functionDeclaration: method, + method: true, + async, + declaration, + returnStatement: getReturnStatement(method), + }) as ts.MethodDeclaration; + + const classMembers = [ + ...classDeclaration.methods.map((m) => buildMethod(m)), + ...classDeclaration.asyncMethods.map((m) => buildMethod(m, true)), + ...(declaration ? classDeclaration.properties.map(buildClassProperty) : []), + classDeclaration.constructor + ? buildConstructor(classDeclaration.constructor, declaration ?? false) + : undefined, + ].filter((x) => x !== undefined); + + return ts.factory.createClassDeclaration( + constructModifiersArray({ exported, declare: declaration }), + ts.factory.createIdentifier(classDeclaration.name), + undefined, + [], + classMembers + ); +} + +function buildModuleDefaultExport({ + moduleName, + moduleType, + declaration, +}: { + moduleName: string; + moduleType?: string; + declaration?: boolean; +}): ts.Node[] { + const name = '_default'; + const type = moduleType ? ts.factory.createTypeReferenceNode(moduleType) : undefined; + return [ + createParameter({ + modifiers: [constModifier()], + name, + type, + initializer: declaration + ? undefined + : createRequireNativeModuleExpression({ moduleName, moduleType }), + }), + ts.factory.createExportDefault(ts.factory.createIdentifier('_default')), + ]; +} + +export function buildUnknownTypeAlias( + identifier: string, + exported: boolean, + inferredTypeParametersCount: Map +): ts.Statement { + const paramCount = inferredTypeParametersCount.get(identifier); + const typeParamsList = []; + for (let i = 0; i < (paramCount ?? 0); i += 1) { + typeParamsList.push(ts.factory.createTypeParameterDeclaration(undefined, 'T' + i)); + } + const typeParams = (paramCount ?? 0) === 0 ? undefined : typeParamsList; + return createTypeAlias({ exported, alias: identifier, type: unknownKeywordType(), typeParams }); +} + +export function buildRecordTypeAlias(recordType: RecordType, exported: boolean): ts.Node { + return createTypeAlias({ + exported, + alias: recordType.name, + type: ts.factory.createTypeLiteralNode( + recordType.fields.map((field) => { + const optional = field.type.kind === TypeKind.OPTIONAL; + const typeNode = mapTypeToTsTypeNode(optional ? (field.type.type as Type) : field.type); + const name = field.name ?? '_' + getNextFreeId(); + return createPropertySignature({ name, optional, typeNode }); + }) + ), + }); +} + +export function buildEnumTypeDeclaration( + enumType: EnumType, + exported: boolean, + declared: boolean +): ts.Node { + return ts.factory.createEnumDeclaration( + constructModifiersArray({ exported, declare: declared }), + enumType.name, + enumType.cases.map((enumcase) => ts.factory.createEnumMember(enumcase)) + ); +} + +function buildMissingTypesDeclarations(ctx: GenerationContext): ts.Node[] { + if (ctx.missingTypes.size === 0) { + return []; + } + + const header = ts.addSyntheticLeadingComment( + ts.factory.createIdentifier(''), + ts.SyntaxKind.SingleLineCommentTrivia, + ` These types haven't been defined in provided file(s).`, + true + ); + + const aliases = [...ctx.missingTypes].map((identifier) => + buildUnknownTypeAlias(identifier, true, ctx.fileInfo.inferredTypeParametersCount) + ); + + return [header, ...aliases]; +} + +function buildDefaultViewComponent({ + componentName, + propsTypeAlias, +}: { + componentName: string; + propsTypeAlias: string; +}) { + const jsxElement = ts.factory.createJsxSelfClosingElement( + ts.factory.createIdentifier(componentName), + undefined, + ts.factory.createJsxAttributes([ + ts.factory.createJsxSpreadAttribute(ts.factory.createIdentifier('props')), + ]) + ); + + const functionBody = ts.factory.createBlock([ts.factory.createReturnStatement(jsxElement)]); + + return [ + ts.factory.createFunctionExpression( + [exportModifier(), defaultModifier()], + undefined, + componentName + 'Component', + undefined, + [ + createParameter({ + name: 'props', + type: ts.factory.createTypeReferenceNode(propsTypeAlias), + }), + ], + undefined, + functionBody + ), + ]; +} + +export function buildExposedTypesDeclarations( + ctx: GenerationContext, + options: { exported?: boolean; declare?: boolean } +): ts.Node[] { + const recordDeclarationMap = (recordType: RecordType) => + buildRecordTypeAlias(recordType, options.exported ?? false); + const enumDeclarationMap = (enumType: EnumType) => + buildEnumTypeDeclaration(enumType, options.exported ?? false, options.declare ?? false); + const classDeclarationMap = (classDeclaration: ClassDeclaration) => + buildClass({ classDeclaration, exported: true, declaration: true }); + + return joinTSNodesWithNewlines([ + createImportDeclaration({ namedImportsNames: ['NativeModule'], importFromName: 'expo' }), + buildMissingTypesDeclarations(ctx), + ctx.fileInfo.records.flatMap(recordDeclarationMap), + ctx.fileInfo.enums.flatMap(enumDeclarationMap), + ctx.module.classes.map(classDeclarationMap), + ]); +} + +function buildModuleDeclarationNodes(ctx: GenerationContext): ts.Node[] { + return joinTSNodesWithNewlines([ + createGeneratedPrefix(), + buildExposedTypesDeclarations(ctx, { exported: true }), + buildNativeModuleClassDeclaration({ moduleClassDeclaration: ctx.module }), + buildModuleDefaultExport({ + moduleName: ctx.module.name, + moduleType: ctx.module.name, + declaration: true, + }), + ] as ts.Node[][]); +} + +export function getViewPropsTypeName(view: ViewDeclaration): string { + return view.name + (view.name.endsWith('View') ? 'Props' : 'ViewProps'); +} + +function buildViewDeclarationNodes(ctx: GenerationContext): ts.Node[] { + if (!ctx.view) { + return []; + } + const viewComponentType = createComponentType(getViewPropsTypeName(ctx.view)); + const modifiers = [declareModifier(), constModifier()]; + return joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ namedImportsNames: ['ViewProps'], importFromName: 'react-native' }), + buildMissingTypesDeclarations(ctx), + buildViewPropsInterface(ctx.view, {}), + [createParameter({ modifiers, name: '_default', type: viewComponentType })], + createExportDefault(), + ]); +} + +function buildJSXIntrinsicsViewNodes(ctx: GenerationContext): ts.Node[] { + const name = ctx.module.name; + const propsTypeNode = ctx.view + ? ts.factory.createTypeLiteralNode(buildPropsMembers(ctx.view)) + : undefined; + + const jsxIntrinsicElementsNodes = []; + if (ctx.view) { + const globalIdentifier = ts.factory.createIdentifier('global'); + const jsxIdentifier = ts.factory.createIdentifier('JSX'); + const intrinsicElementsIdentifier = ts.factory.createIdentifier('IntrinsicElements'); + jsxIntrinsicElementsNodes.push( + ts.factory.createModuleDeclaration( + [declareModifier()], + globalIdentifier, + ts.factory.createModuleBlock([ + ts.factory.createModuleDeclaration( + undefined, + jsxIdentifier, + ts.factory.createModuleBlock([ + ts.factory.createInterfaceDeclaration( + undefined, + intrinsicElementsIdentifier, + undefined, + undefined, + [createPropertySignature({ name, typeNode: propsTypeNode })] + ), + ]), + ts.NodeFlags.Namespace + ), + ]), + ts.NodeFlags.GlobalAugmentation + ) + ); + } + + return joinTSNodesWithNewlines([ + buildExposedTypesDeclarations(ctx, { declare: true }), + jsxIntrinsicElementsNodes, + ]); +} + +function buildNativeModuleGeneratedNodes(ctx: GenerationContext): ts.Node[] { + return joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ namedImportsNames: ['ViewProps'], importFromName: 'react-native' }), + buildExposedTypesDeclarations(ctx, { exported: true }), + buildViewPropsInterface(ctx.view, { exported: true }), + buildNativeModuleClassDeclaration({ moduleClassDeclaration: ctx.module }), + ]); +} + +function buildStableNativeModuleInterface(ctx: GenerationContext): ts.Node[] { + const generatedModuleAlias = ctx.module.name; + const generatedModuleTypeAlias = `${ctx.module.name}NativeModuleType`; + const generatedFilePath = `./${ctx.module.name}.generated`; + + const exportedFunctionReturnStatement = ( + functionDeclaration: FunctionDeclaration, + overrideArguments?: ts.Identifier[] + ) => { + const expression = `${generatedModuleAlias}.${functionDeclaration.name}`; + const args = + overrideArguments ?? + functionDeclaration.arguments.map((arg) => + ts.factory.createIdentifier(arg.name ?? 'unnamedArgument') + ); + + return ts.factory.createReturnStatement( + createCall({ + expression, + args, + }) + ); + }; + + const mapFunctionDeclarationTemplate = + (isAsync: boolean) => (functionDeclaration: FunctionDeclaration) => { + const argumentDeclarations = []; + const argumentNames = []; + for (const arg of functionDeclaration.arguments) { + const { argDeclaration, argName } = buildArgumentDeclarationAndName(arg); + argumentDeclarations.push(argDeclaration); + argumentNames.push(argName); + } + return [ + buildFunction({ + functionDeclaration, + async: isAsync, + exported: true, + returnStatement: [ + exportedFunctionReturnStatement( + functionDeclaration, + argumentNames.map(ts.factory.createIdentifier) + ), + ], + overrideArgumentDeclarations: argumentDeclarations, + omitReturnType: true, + }), + ]; + }; + + const mapSyncFunctionDeclaration = mapFunctionDeclarationTemplate(false); + const mapAsyncFunctionDeclaration = mapFunctionDeclarationTemplate(true); + const buildConstantExportProperty = (constant: ConstantDeclaration): ts.Node => { + const typeNode = mapTypeToTsTypeNode(constant.type); + const modifiers = [exportModifier(), constModifier()]; + const initializer = ts.factory.createIdentifier(`${generatedModuleAlias}.${constant.name}`); + return createProperty({ modifiers, name: constant.name, typeNode, initializer }); + }; + + return joinTSNodesWithNewlines([ + ctx.view + ? createImportDeclaration({ importFromName: 'react', defaultImportName: 'React' }) + : [], + + createImportDeclaration({ + namedImportsNames: [ + ...ctx.fileInfo.usedTypeIdentifiers.difference(getBasicTypesIdentifiers()), + ...[generatedModuleTypeAlias, ctx.view ? getViewPropsTypeName(ctx.view) : null].filter( + (v) => v !== null + ), + ], + importFromName: generatedFilePath, + }), + + createImportDeclaration({ + namedImportsNames: ['requireNativeModule', 'requireNativeView'], + importFromName: 'expo', + }), + + [ + createParameter({ + modifiers: [constModifier()], + name: ctx.module.name, + type: ts.factory.createTypeReferenceNode(generatedModuleTypeAlias), + initializer: createRequireNativeModuleExpression({ + moduleName: ctx.module.name, + moduleType: generatedModuleTypeAlias, + }), + }), + ], + + ctx.view ? createRequireNativeViewDeclaration(ctx.module, ctx.view) : [], + + ctx.module.constants.map(buildConstantExportProperty), + + ctx.module.functions.flatMap(mapSyncFunctionDeclaration), + ctx.module.asyncFunctions.flatMap(mapAsyncFunctionDeclaration), + + ctx.view + ? buildDefaultViewComponent({ + componentName: ctx.view.name, + propsTypeAlias: getViewPropsTypeName(ctx.view), + }) + : [], + ]); +} + +async function tsNodesToString(elements: ts.Node[]): Promise { + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); + const resultFile = ts.createSourceFile('', '', ts.ScriptTarget.Latest, false, ts.ScriptKind.TSX); + const viewTypes = ts.factory.createNodeArray(elements); + const printedTs = printer.printList( + ts.ListFormat.MultiLine | ts.ListFormat.PreserveLines, + viewTypes, + resultFile + ); + return await prettifyCode(printedTs, 'typescript'); +} + +export async function prettifyCode(text: string, parser: 'babel' | 'typescript' = 'babel') { + return await prettier.format(text, { + parser, + tabWidth: 2, + printWidth: 100, + trailingComma: 'none', + singleQuote: true, + }); +} + +export async function generateViewTypesFileContent( + fileTypeInformation: FileTypeInformation +): Promise { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + return tsNodesToString(buildViewDeclarationNodes(ctx)); +} + +export async function generateJSXIntrinsicsFileContent( + fileTypeInformation: FileTypeInformation +): Promise { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + return tsNodesToString(buildJSXIntrinsicsViewNodes(ctx)); +} + +export async function generateModuleTypesFileContent( + fileTypeInformation: FileTypeInformation +): Promise { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + return tsNodesToString(buildModuleDeclarationNodes(ctx)); +} + +export async function generateConciseTsInterface( + fileTypeInformation: FileTypeInformation +): Promise<{ + volatileGeneratedFileContent: string; + moduleTypescriptInterfaceFileContent: string; +}> { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return { volatileGeneratedFileContent: '', moduleTypescriptInterfaceFileContent: '' }; + } + + const volatileGeneratedFileContent = await tsNodesToString(buildNativeModuleGeneratedNodes(ctx)); + + const moduleTypescriptInterfaceFileContent = await tsNodesToString( + buildStableNativeModuleInterface(ctx) + ); + + return { + volatileGeneratedFileContent, + moduleTypescriptInterfaceFileContent, + }; +} + +export async function generateFullTsInterface(fileTypeInformation: FileTypeInformation): Promise<{ + moduleTypesFile: OutputFile; + moduleViewsFiles: OutputFile[]; + moduleNativeFile: OutputFile; + indexFile: OutputFile; +} | null> { + const ctx = createDefaultGenerationContext(fileTypeInformation); + if (!ctx) { + return null; + } + + const moduleNativeFileImportName = `${ctx?.module.name}Module`; + const moduleTypesFileImportName = `${ctx?.module.name}.types`; + const moduleViewsFilesImportNames: string[] = []; + const moduleTypesFileNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ namedImportsNames: ['ViewProps'], importFromName: 'react-native' }), + buildExposedTypesDeclarations(ctx, { exported: true }), + ...ctx.module.views.map((view) => buildViewPropsInterface(view, { exported: true })), + ]); + + const moduleViewFilesNodes = []; + for (const view of ctx.module.views) { + const moduleViewFileNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ + namedImportsNames: ['requireNativeView'], + importFromName: 'expo', + }), + createImportDeclaration({ + namedImportsNames: [getViewPropsTypeName(view)], + importFromName: `./${moduleTypesFileImportName}`, + }), + createRequireNativeViewDeclaration(ctx.module, view), + + buildDefaultViewComponent({ + componentName: view.name, + propsTypeAlias: getViewPropsTypeName(view), + }), + ]); + moduleViewFilesNodes.push(moduleViewFileNodes); + moduleViewsFilesImportNames.push(`${view.name}View`); + } + + const moduleNativeModuleNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createImportDeclaration({ + namedImportsNames: ['requireNativeModule', 'NativeModule'], + importFromName: 'expo', + }), + createImportDeclaration({ + namedImportsNames: [...getAllNonBasicTypes(ctx.fileInfo)], + importFromName: `./${moduleTypesFileImportName}`, + }), + buildNativeModuleClassDeclaration({ + moduleClassDeclaration: ctx.module, + exportedModuleName: ctx.module.name, + }), + buildModuleDefaultExport({ moduleName: ctx.module.name, moduleType: ctx.module.name }), + ]); + + const indexFileNodes = joinTSNodesWithNewlines([ + createGeneratedPrefix(), + createExportAllDeclaration({ + importFromName: `./${moduleTypesFileImportName}`, + justTypes: true, + }), + createExportDefaultAsDeclaration({ + exportAsName: ctx.module.name, + importFromName: `./${moduleNativeFileImportName}`, + }), + + ...ctx.module.views.map((view, idx) => + createExportDefaultAsDeclaration({ + exportAsName: view.name, + importFromName: `./${moduleViewsFilesImportNames[idx]}`, + }) + ), + ]); + + const [ + moduleTypesFileContent, + moduleViewFilesContents, + moduleNativeFileContent, + indexFileContent, + ] = await Promise.all([ + tsNodesToString(moduleTypesFileNodes), + Promise.all(moduleViewFilesNodes.map(tsNodesToString)), + tsNodesToString(moduleNativeModuleNodes), + tsNodesToString(indexFileNodes), + ]); + + const moduleTypesFile = { + content: moduleTypesFileContent, + name: `${moduleTypesFileImportName}.ts`, + }; + const moduleViewsFiles = moduleViewFilesContents.map((moduleViewFileContent, idx) => { + return { + content: moduleViewFileContent, + name: `${moduleViewsFilesImportNames[idx]}.tsx`, + }; + }); + const moduleNativeFile = { + content: moduleNativeFileContent, + name: `${moduleNativeFileImportName}.ts`, + }; + const indexFile = { content: indexFileContent, name: `index.ts` }; + + return { + moduleTypesFile, + moduleViewsFiles, + moduleNativeFile, + indexFile, + }; +} diff --git a/packages/expo-type-information/src/utils.ts b/packages/expo-type-information/src/utils.ts new file mode 100644 index 00000000000000..a9b11f82f21f99 --- /dev/null +++ b/packages/expo-type-information/src/utils.ts @@ -0,0 +1,44 @@ +import fs from 'fs'; +import path from 'path'; + +// TODO(@HubertBer): Also exists in expo-modules-autolinking, but with a limiter, maybe take it or depend on it? +export const taskAll = ( + inputs: T[], + map: (input: T, index: number) => Promise +): Promise => { + return Promise.all(inputs.map(map)); +}; + +// TODO(@HubertBer): Taken from expo-modules-autolinking, maybe import it instead? +export async function* scanFilesRecursively( + parentPath: string, + includeDirectory?: (parentPath: string, name: string) => boolean, + sort = !fs.promises.opendir +) { + const queue = [parentPath]; + let targetPath: string | undefined; + while (queue.length > 0 && (targetPath = queue.shift()) != null) { + try { + const entries = sort + ? (await fs.promises.readdir(targetPath, { withFileTypes: true })).sort((a, b) => + a.name.localeCompare(b.name) + ) + : await fs.promises.opendir(targetPath); + for await (const entry of entries) { + if (entry.isDirectory() && entry.name !== 'node_modules') { + if (!includeDirectory || includeDirectory(targetPath, entry.name)) { + queue.push(path.join(targetPath, entry.name)); + } + } else if (entry.isFile()) { + yield { + path: path.join(targetPath, entry.name), + parentPath: targetPath, + name: entry.name, + } as const; + } + } + } catch { + continue; + } + } +} diff --git a/packages/expo-type-information/tests/TestModule.swift b/packages/expo-type-information/tests/TestModule.swift new file mode 100644 index 00000000000000..fc54368af68e28 --- /dev/null +++ b/packages/expo-type-information/tests/TestModule.swift @@ -0,0 +1,175 @@ +import ExpoModulesCore +import WebKit + +public class TestModule: Module { + public func definition() -> ModuleDefinition { + Constant("StringConstant") { () -> Int in + return "Swift constant 1283" + } + + Constant("IntConstant") { () -> Int in + return 37; + } + + Constant("UntypedConstant") { () in 98} // Comment 1 + + Function("SimpleFunction") { (a: Double, b: Int) -> Double in + return a + b // Comment 2 + } + + Function("TestUntypedFunction") { () in + return "string" + } + + Function("TestUntypedFunction2") { /* Comment 3 */ () in + // Comment 4 + return TestEnum.simpleCase + } + + Function("TestUntypedFunction3" /* Comment 5 */) { + return TestRecord2(field1: /* Comment 6 */ 10, "field2") + } + + Function("TestArrays") { (a: [Int]) -> /* Comment 7 */ [[String]] in + return ["test"] + } + + Function("TestDictionaries") { (a: [Int: String] /* Comment 8 */, b: [Int : [Float : String]]) -> Any in + return "test" + } + + Function("TestParametrizedTypes") { (a: SomeParametrizedType, Map, Either, Set>>>) -> String in + return "" + } + + Function("TestTypeCombinations") { (a: [[[Int]]]) -> [[Either]] in + return [["test"]] + } + + Function("TestFunctionReturningRecord") { () -> TestRecord in /* Comment 10 + multiple + lines + comment + body + */ + return "" + } + + Function("TestFunctionReturningEnum") { () -> TestEnum in + return TestEnum.simpleCase + } + + AsyncFunction("TestSimpleAsyncFunction") { (a: String, b: String) async -> String in + return a + b + } + + AsyncFunction("TestUnderscore") { (url: URL, _ /* Comment 10 */: [BarcodeType]) in + } + + + Class(TestClassWithConstructor.self) { + Constructor { (a: Int) in + TestClass(a) + } + } + + Class(TestBasicClass.self) { + Constructor { (a: Int, b: String, c: Either) in + TestClass(a) + } + + Property("TestIntProperty") { () -> Int in + 1 + } + + Property("TestEitherProperty") { () -> Either in + 1 + } + + Property("TestEnumProperty") { () -> TestEnum in + .simpleCase + } + + Property("TestRecordProperty") { () -> TestRecord2 in + TestRecord2(1, "2") + } + + AsyncFunction("TestAsyncFunction") { (a: Int) async -> String in + "string" + } + } + + Class(TestEmptyClass.self) { + } + + View(ExpoWebView.self) { + Events("onEvent1", "onEvent2") + + Prop("url") { (view, url: URL) in + if view.webView.url != url { + let urlRequest = URLRequest(url: url) + view.webView.load(urlRequest) + } + } + + Prop("testRecord") { (view, testRecord: TestRecord) in + } + + Prop("testRecord2") { (view, testRecord2: TestRecord2) in + } + + Prop("testRecordClass") { (view, testRecordClass: TestRecordClass) in + } + + Prop("testEnum") { (view, testEnum: TestEnum) in + } + } + } +} + +struct TestRecord: Record { + @Field + var basicString: String + @Field + var basicStringInitialized: String = "utf8" + @Field + var basicIntInferred = 0 + @Field + var basicDoubleInferred = 0.1 + @Field + var basicStringInferred = "string" + @Field + var enumInferred = TestEnum.simpleCase + @Field + var complexEnumInferred = TestEnum.caseWithArgs1(2, 0.1, "Test") + + @Field + var recordInferred = TestRecord2(field1: 21, field2: "testing") + + @Field + var optionalInt: Int? + @Field + let letDoubleBinding: Double = 0.1 + + var fieldWithoutAnnotation: Int = 1 +} + +struct TestRecord2: Record { + @Field + var field1: Int + @Field + var field2: String +} + +class TestRecordClass: Record { + @Field + var field1: Int + @Field + var field2: String +} + +enum TestEnum { + case simpleCase + case multipleCases1, multipleCases2 + case caseWithArgs1(Int, Double, String), caseWithArgs2(Double, String, Either) +} diff --git a/packages/expo-type-information/tests/__snapshots__/typeInformation.test.ts.snap b/packages/expo-type-information/tests/__snapshots__/typeInformation.test.ts.snap new file mode 100644 index 00000000000000..92a173cdacfd49 --- /dev/null +++ b/packages/expo-type-information/tests/__snapshots__/typeInformation.test.ts.snap @@ -0,0 +1,1578 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Same generated concise ts interface 1`] = ` +"/*Automatically generated by expo-type-information.*/ + +import { ViewProps } from 'react-native'; + +import { NativeModule } from 'expo'; + +// These types haven't been defined in provided file(s). +export type URL = unknown; +export type BarcodeType = unknown; +export type SomeParametrizedType = unknown; + +export type TestRecord = { + basicString: string; + basicStringInitialized: string; + basicIntInferred: number; + basicDoubleInferred: number; + basicStringInferred: string; + enumInferred: TestEnum; + complexEnumInferred: TestEnum; + recordInferred: TestRecord2; + optionalInt?: number; + letDoubleBinding: number; +}; +export type TestRecord2 = { + field1: number; + field2: string; +}; +export type TestRecordClass = { + field1: number; + field2: string; +}; + +export enum TestEnum { + simpleCase, + multipleCases1, + multipleCases2, + caseWithArgs1, + caseWithArgs2 +} + +export declare class TestClassWithConstructor { + constructor(a: number); +} +export declare class TestBasicClass { + TestAsyncFunction(a: number): Promise; + readonly TestIntProperty: number; + readonly TestEitherProperty: number | string; + readonly TestEnumProperty: TestEnum; + readonly TestRecordProperty: TestRecord2; + constructor(a: number, b: string, c: string | TestRecord); +} +export declare class TestEmptyClass {} + +export interface ExpoWebViewProps extends ViewProps { + url: URL; + testRecord: TestRecord; + testRecord2: TestRecord2; + testRecordClass: TestRecordClass; + testEnum: TestEnum; + onEvent1?: (event: any) => void; + onEvent2?: (event: any) => void; +} + +export declare class TestModuleNativeModuleType extends NativeModule { + readonly StringConstant: number; + readonly IntConstant: number; + readonly UntypedConstant: unknown /*The type couldn't be resolved automatically.*/; + SimpleFunction(a: number, b: number): number; + TestUntypedFunction(): string; + TestUntypedFunction2(): TestEnum; + TestUntypedFunction3(): TestRecord2; + TestArrays(a: number[]): string[][]; + TestDictionaries( + a: { + [key: number]: string; + }, + b: { + [key: number]: { + [key: number]: string; + }; + } + ): any; + TestParametrizedTypes( + a: SomeParametrizedType, Set | Set>> + ): string; + TestTypeCombinations(a: number[][][]): ( + | string + | { + [key: number]: string; + } + )[][]; + TestFunctionReturningRecord(): TestRecord; + TestFunctionReturningEnum(): TestEnum; + TestSimpleAsyncFunction(a: string, b: string): Promise; + TestUnderscore( + url: URL, + _4: BarcodeType[] + ): Promise; + TestClassWithConstructor: typeof TestClassWithConstructor; + TestBasicClass: typeof TestBasicClass; + TestEmptyClass: typeof TestEmptyClass; +} +" +`; + +exports[`Same generated concise ts interface 2`] = ` +"import React from 'react'; + +import { + TestEnum, + TestRecord2, + URL, + BarcodeType, + SomeParametrizedType, + TestRecord, + TestRecordClass, + TestModuleNativeModuleType, + ExpoWebViewProps +} from './TestModule.generated'; + +import { requireNativeModule, requireNativeView } from 'expo'; + +const TestModule: TestModuleNativeModuleType = + requireNativeModule('TestModule'); + +const ExpoWebView = requireNativeView('TestModule', 'ExpoWebView'); + +export const StringConstant: number = TestModule.StringConstant; +export const IntConstant: number = TestModule.IntConstant; +export const UntypedConstant: unknown /*The type couldn't be resolved automatically.*/ = + TestModule.UntypedConstant; + +export function SimpleFunction(a: number, b: number) { + return TestModule.SimpleFunction(a, b); +} +export function TestUntypedFunction() { + return TestModule.TestUntypedFunction(); +} +export function TestUntypedFunction2() { + return TestModule.TestUntypedFunction2(); +} +export function TestUntypedFunction3() { + return TestModule.TestUntypedFunction3(); +} +export function TestArrays(a: number[]) { + return TestModule.TestArrays(a); +} +export function TestDictionaries( + a: { + [key: number]: string; + }, + b: { + [key: number]: { + [key: number]: string; + }; + } +) { + return TestModule.TestDictionaries(a, b); +} +export function TestParametrizedTypes( + a: SomeParametrizedType, Set | Set>> +) { + return TestModule.TestParametrizedTypes(a); +} +export function TestTypeCombinations(a: number[][][]) { + return TestModule.TestTypeCombinations(a); +} +export function TestFunctionReturningRecord() { + return TestModule.TestFunctionReturningRecord(); +} +export function TestFunctionReturningEnum() { + return TestModule.TestFunctionReturningEnum(); +} + +export async function TestSimpleAsyncFunction(a: string, b: string) { + return TestModule.TestSimpleAsyncFunction(a, b); +} +export async function TestUnderscore(url: URL, _5: BarcodeType[]) { + return TestModule.TestUnderscore(url, _5); +} + +export default function ExpoWebViewComponent(props: ExpoWebViewProps) { + return ; +} +" +`; + +exports[`Same generated full ts interface 1`] = ` +{ + "indexFile": { + "content": "/*Automatically generated by expo-type-information.*/ + +export type * from './TestModule.types'; + +export { default as TestModule } from './TestModuleModule'; + +export { default as ExpoWebView } from './ExpoWebViewView'; +", + "name": "index.ts", + }, + "moduleNativeFile": { + "content": "/*Automatically generated by expo-type-information.*/ + +import { requireNativeModule, NativeModule } from 'expo'; + +import { + TestEnum, + TestRecord, + TestRecord2, + TestRecordClass, + TestClassWithConstructor, + TestBasicClass, + TestEmptyClass, + URL, + BarcodeType, + SomeParametrizedType +} from './TestModule.types'; + +export declare class TestModule extends NativeModule { + readonly StringConstant: number; + readonly IntConstant: number; + readonly UntypedConstant: unknown /*The type couldn't be resolved automatically.*/; + SimpleFunction(a: number, b: number): number; + TestUntypedFunction(): string; + TestUntypedFunction2(): TestEnum; + TestUntypedFunction3(): TestRecord2; + TestArrays(a: number[]): string[][]; + TestDictionaries( + a: { + [key: number]: string; + }, + b: { + [key: number]: { + [key: number]: string; + }; + } + ): any; + TestParametrizedTypes( + a: SomeParametrizedType, Set | Set>> + ): string; + TestTypeCombinations(a: number[][][]): ( + | string + | { + [key: number]: string; + } + )[][]; + TestFunctionReturningRecord(): TestRecord; + TestFunctionReturningEnum(): TestEnum; + TestSimpleAsyncFunction(a: string, b: string): Promise; + TestUnderscore( + url: URL, + _6: BarcodeType[] + ): Promise; + TestClassWithConstructor: typeof TestClassWithConstructor; + TestBasicClass: typeof TestBasicClass; + TestEmptyClass: typeof TestEmptyClass; +} + +const _default: TestModule = requireNativeModule('TestModule'); +export default _default; +", + "name": "TestModuleModule.ts", + }, + "moduleTypesFile": { + "content": "/*Automatically generated by expo-type-information.*/ + +import { ViewProps } from 'react-native'; + +import { NativeModule } from 'expo'; + +// These types haven't been defined in provided file(s). +export type URL = unknown; +export type BarcodeType = unknown; +export type SomeParametrizedType = unknown; + +export type TestRecord = { + basicString: string; + basicStringInitialized: string; + basicIntInferred: number; + basicDoubleInferred: number; + basicStringInferred: string; + enumInferred: TestEnum; + complexEnumInferred: TestEnum; + recordInferred: TestRecord2; + optionalInt?: number; + letDoubleBinding: number; +}; +export type TestRecord2 = { + field1: number; + field2: string; +}; +export type TestRecordClass = { + field1: number; + field2: string; +}; + +export enum TestEnum { + simpleCase, + multipleCases1, + multipleCases2, + caseWithArgs1, + caseWithArgs2 +} + +export declare class TestClassWithConstructor { + constructor(a: number); +} +export declare class TestBasicClass { + TestAsyncFunction(a: number): Promise; + readonly TestIntProperty: number; + readonly TestEitherProperty: number | string; + readonly TestEnumProperty: TestEnum; + readonly TestRecordProperty: TestRecord2; + constructor(a: number, b: string, c: string | TestRecord); +} +export declare class TestEmptyClass {} + +export interface ExpoWebViewProps extends ViewProps { + url: URL; + testRecord: TestRecord; + testRecord2: TestRecord2; + testRecordClass: TestRecordClass; + testEnum: TestEnum; + onEvent1?: (event: any) => void; + onEvent2?: (event: any) => void; +} +", + "name": "TestModule.types.ts", + }, + "moduleViewsFiles": [ + { + "content": "/*Automatically generated by expo-type-information.*/ + +import { requireNativeView } from 'expo'; + +import { ExpoWebViewProps } from './TestModule.types'; + +const ExpoWebView = requireNativeView('TestModule', 'ExpoWebView'); + +export default function ExpoWebViewComponent(props: ExpoWebViewProps) { + return ; +} +", + "name": "ExpoWebViewView.tsx", + }, + ], +} +`; + +exports[`Same generated mock file 1`] = ` +"/** + * Automatically generated by expo-type-information. + * + * This autogenerated file provides a mock for native Expo module, + * and works out of the box with the expo jest preset. + * */ + + +export type URL = unknown; +export type BarcodeType = unknown; +export type SomeParametrizedType = unknown; + + +export type TestRecord = { + basicString: string; + basicStringInitialized: string; + basicIntInferred: number; + basicDoubleInferred: number; + basicStringInferred: string; + enumInferred: TestEnum; + complexEnumInferred: TestEnum; + recordInferred: TestRecord2; + optionalInt?: number; + letDoubleBinding: number; +}; +export type TestRecord2 = { + field1: number; + field2: string; +}; +export type TestRecordClass = { + field1: number; + field2: string; +}; + + +export enum TestEnum { + simpleCase, + multipleCases1, + multipleCases2, + caseWithArgs1, + caseWithArgs2 +} + + +export function SimpleFunction(a: number, b: number): number { return 0; } +export function TestUntypedFunction(): string { return ""; } +export function TestUntypedFunction2(): TestEnum { return TestEnum.simpleCase; } +export function TestUntypedFunction3(): TestRecord2 { return { field1: 0, field2: "" }; } +export function TestArrays(a: number[]): string[][] { return []; } +export function TestDictionaries(a: { + [key: number]: string; +}, b: { + [key: number]: { + [key: number]: string; + }; +}): any { } +export function TestParametrizedTypes(a: SomeParametrizedType, Set | Set>>): string { return ""; } +export function TestTypeCombinations(a: number[][][]): (string | { + [key: number]: string; +})[][] { return []; } +export function TestFunctionReturningRecord(): TestRecord { return { basicString: "", basicStringInitialized: "", basicIntInferred: 0, basicDoubleInferred: 0, basicStringInferred: "", enumInferred: TestEnum.simpleCase, complexEnumInferred: TestEnum.simpleCase, recordInferred: { field1: 0, field2: "" }, optionalInt: 0, letDoubleBinding: 0 }; } +export function TestFunctionReturningEnum(): TestEnum { return TestEnum.simpleCase; } + + +export async function TestSimpleAsyncFunction(a: string, b: string): Promise { return ""; } +export async function TestUnderscore(url: URL, _2: BarcodeType[]): Promise { return; } + + +export class TestClassWithConstructor { + constructor(a: number) { } +} +export class TestBasicClass { + async TestAsyncFunction(a: number): Promise { return ""; } + constructor(a: number, b: string, c: string | TestRecord) { } +} +export class TestEmptyClass { +} + + +export interface ExpoWebViewProps extends ViewProps { + url: URL; + testRecord: TestRecord; + testRecord2: TestRecord2; + testRecordClass: TestRecordClass; + testEnum: TestEnum; + onEvent1?: (event: any) => void; + onEvent2?: (event: any) => void; +} +export function ExpoWebView(props: ExpoWebViewProps) { } + + +" +`; + +exports[`Same generated mock file JS 1`] = ` +"/** + * Automatically generated by expo-type-information. + * + * This autogenerated file provides a mock for native Expo module, + * and works out of the box with the expo jest preset. + * */ +export var TestEnum; +(function (TestEnum) { + TestEnum[TestEnum["simpleCase"] = 0] = "simpleCase"; + TestEnum[TestEnum["multipleCases1"] = 1] = "multipleCases1"; + TestEnum[TestEnum["multipleCases2"] = 2] = "multipleCases2"; + TestEnum[TestEnum["caseWithArgs1"] = 3] = "caseWithArgs1"; + TestEnum[TestEnum["caseWithArgs2"] = 4] = "caseWithArgs2"; +})(TestEnum || (TestEnum = {})); +export function SimpleFunction(a, b) { return 0; } +export function TestUntypedFunction() { return ""; } +export function TestUntypedFunction2() { return TestEnum.simpleCase; } +export function TestUntypedFunction3() { return { field1: 0, field2: "" }; } +export function TestArrays(a) { return []; } +export function TestDictionaries(a, b) { } +export function TestParametrizedTypes(a) { return ""; } +export function TestTypeCombinations(a) { return []; } +export function TestFunctionReturningRecord() { return { basicString: "", basicStringInitialized: "", basicIntInferred: 0, basicDoubleInferred: 0, basicStringInferred: "", enumInferred: TestEnum.simpleCase, complexEnumInferred: TestEnum.simpleCase, recordInferred: { field1: 0, field2: "" }, optionalInt: 0, letDoubleBinding: 0 }; } +export function TestFunctionReturningEnum() { return TestEnum.simpleCase; } +export async function TestSimpleAsyncFunction(a, b) { return ""; } +export async function TestUnderscore(url, _3) { return; } +export class TestClassWithConstructor { + constructor(a) { } +} +export class TestBasicClass { + async TestAsyncFunction(a) { return ""; } + constructor(a, b, c) { } +} +export class TestEmptyClass { +} +export function ExpoWebView(props) { } +" +`; + +exports[`Same generated module file 1`] = ` +"/*Automatically generated by expo-type-information.*/ + +import { NativeModule } from 'expo'; + +// These types haven't been defined in provided file(s). +export type URL = unknown; +export type BarcodeType = unknown; +export type SomeParametrizedType = unknown; + +export type TestRecord = { + basicString: string; + basicStringInitialized: string; + basicIntInferred: number; + basicDoubleInferred: number; + basicStringInferred: string; + enumInferred: TestEnum; + complexEnumInferred: TestEnum; + recordInferred: TestRecord2; + optionalInt?: number; + letDoubleBinding: number; +}; +export type TestRecord2 = { + field1: number; + field2: string; +}; +export type TestRecordClass = { + field1: number; + field2: string; +}; + +export enum TestEnum { + simpleCase, + multipleCases1, + multipleCases2, + caseWithArgs1, + caseWithArgs2 +} + +export declare class TestClassWithConstructor { + constructor(a: number); +} +export declare class TestBasicClass { + TestAsyncFunction(a: number): Promise; + readonly TestIntProperty: number; + readonly TestEitherProperty: number | string; + readonly TestEnumProperty: TestEnum; + readonly TestRecordProperty: TestRecord2; + constructor(a: number, b: string, c: string | TestRecord); +} +export declare class TestEmptyClass {} + +export declare class TestModuleNativeModuleType extends NativeModule { + readonly StringConstant: number; + readonly IntConstant: number; + readonly UntypedConstant: unknown /*The type couldn't be resolved automatically.*/; + SimpleFunction(a: number, b: number): number; + TestUntypedFunction(): string; + TestUntypedFunction2(): TestEnum; + TestUntypedFunction3(): TestRecord2; + TestArrays(a: number[]): string[][]; + TestDictionaries( + a: { + [key: number]: string; + }, + b: { + [key: number]: { + [key: number]: string; + }; + } + ): any; + TestParametrizedTypes( + a: SomeParametrizedType, Set | Set>> + ): string; + TestTypeCombinations(a: number[][][]): ( + | string + | { + [key: number]: string; + } + )[][]; + TestFunctionReturningRecord(): TestRecord; + TestFunctionReturningEnum(): TestEnum; + TestSimpleAsyncFunction(a: string, b: string): Promise; + TestUnderscore( + url: URL, + _1: BarcodeType[] + ): Promise; + TestClassWithConstructor: typeof TestClassWithConstructor; + TestBasicClass: typeof TestBasicClass; + TestEmptyClass: typeof TestEmptyClass; +} + +const _default: TestModule; +export default _default; +" +`; + +exports[`Same generated view file 1`] = ` +"/*Automatically generated by expo-type-information.*/ + +import { ViewProps } from 'react-native'; + +// These types haven't been defined in provided file(s). +export type URL = unknown; +export type BarcodeType = unknown; +export type SomeParametrizedType = unknown; + +interface ExpoWebViewProps extends ViewProps { + url: URL; + testRecord: TestRecord; + testRecord2: TestRecord2; + testRecordClass: TestRecordClass; + testEnum: TestEnum; + onEvent1?: (event: any) => void; + onEvent2?: (event: any) => void; +} + +declare const _default: React.JSXElementConstructor; + +export default _default; +" +`; + +exports[`Same type information 1`] = ` +{ + "declaredTypeIdentifiersList": [ + "TestBasicClass", + "TestClassWithConstructor", + "TestEmptyClass", + "TestEnum", + "TestRecord", + "TestRecord2", + "TestRecordClass", + ], + "enums": [ + { + "cases": [ + "simpleCase", + "multipleCases1", + "multipleCases2", + "caseWithArgs1", + "caseWithArgs2", + ], + "name": "TestEnum", + }, + ], + "inferredTypeParametersCountList": [ + [ + "Map", + 2, + ], + [ + "Set", + 1, + ], + [ + "SomeParametrizedType", + 2, + ], + ], + "moduleClasses": [ + { + "asyncFunctions": [ + { + "arguments": [ + { + "name": "a", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "b", + "type": { + "kind": 0, + "type": 1, + }, + }, + ], + "definitionOffset": 2253, + "name": "TestSimpleAsyncFunction", + "parameters": [], + "returnType": { + "kind": 0, + "type": 1, + }, + }, + { + "arguments": [ + { + "name": "url", + "type": { + "kind": 1, + "type": "URL", + }, + }, + { + "name": undefined, + "type": { + "kind": 5, + "type": { + "kind": 1, + "type": "BarcodeType", + }, + }, + }, + ], + "definitionOffset": 2444, + "name": "TestUnderscore", + "parameters": [], + "returnType": { + "kind": 0, + "type": 6, + }, + }, + ], + "classes": [ + { + "asyncMethods": [], + "constructor": { + "arguments": [ + { + "name": "a", + "type": { + "kind": 0, + "type": 2, + }, + }, + ], + "definitionOffset": 2570, + }, + "definitionOffset": 2524, + "methods": [], + "name": "TestClassWithConstructor", + "properties": [], + }, + { + "asyncMethods": [ + { + "arguments": [ + { + "name": "a", + "type": { + "kind": 0, + "type": 2, + }, + }, + ], + "definitionOffset": 3112, + "name": "TestAsyncFunction", + "parameters": [], + "returnType": { + "kind": 0, + "type": 1, + }, + }, + ], + "constructor": { + "arguments": [ + { + "name": "a", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "b", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "c", + "type": { + "kind": 2, + "type": { + "name": "Either", + "types": [ + { + "kind": 0, + "type": 1, + }, + { + "kind": 1, + "type": "TestRecord", + }, + ], + }, + }, + }, + ], + "definitionOffset": 2672, + }, + "definitionOffset": 2636, + "methods": [], + "name": "TestBasicClass", + "properties": [ + { + "definitionOffset": 2776, + "name": "TestIntProperty", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "definitionOffset": 2844, + "name": "TestEitherProperty", + "type": { + "kind": 2, + "type": { + "name": "Either", + "types": [ + { + "kind": 0, + "type": 2, + }, + { + "kind": 0, + "type": 1, + }, + ], + }, + }, + }, + { + "definitionOffset": 2931, + "name": "TestEnumProperty", + "type": { + "kind": 1, + "type": "TestEnum", + }, + }, + { + "definitionOffset": 3015, + "name": "TestRecordProperty", + "type": { + "kind": 1, + "type": "TestRecord2", + }, + }, + ], + }, + { + "asyncMethods": [], + "constructor": null, + "definitionOffset": 3214, + "methods": [], + "name": "TestEmptyClass", + "properties": [], + }, + ], + "constants": [ + { + "definitionOffset": 125, + "name": "StringConstant", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "definitionOffset": 288, + "name": "IntConstant", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "definitionOffset": 426, + "name": "UntypedConstant", + "type": { + "kind": 0, + "type": 6, + }, + }, + ], + "constructor": null, + "definitionOffset": 81, + "events": [], + "functions": [ + { + "arguments": [ + { + "name": "a", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "b", + "type": { + "kind": 0, + "type": 2, + }, + }, + ], + "definitionOffset": 472, + "name": "SimpleFunction", + "parameters": [], + "returnType": { + "kind": 0, + "type": 2, + }, + }, + { + "arguments": [], + "definitionOffset": 636, + "name": "TestUntypedFunction", + "parameters": [], + "returnType": { + "kind": 0, + "type": 1, + }, + }, + { + "arguments": [], + "definitionOffset": 780, + "name": "TestUntypedFunction2", + "parameters": [], + "returnType": { + "kind": 1, + "type": "TestEnum", + }, + }, + { + "arguments": [], + "definitionOffset": 948, + "name": "TestUntypedFunction3", + "parameters": [], + "returnType": { + "kind": 1, + "type": "TestRecord2", + }, + }, + { + "arguments": [ + { + "name": "a", + "type": { + "kind": 5, + "type": { + "kind": 0, + "type": 2, + }, + }, + }, + ], + "definitionOffset": 1114, + "name": "TestArrays", + "parameters": [], + "returnType": { + "kind": 5, + "type": { + "kind": 5, + "type": { + "kind": 0, + "type": 1, + }, + }, + }, + }, + { + "arguments": [ + { + "name": "a", + "type": { + "kind": 6, + "type": { + "key": { + "kind": 0, + "type": 2, + }, + "value": { + "kind": 0, + "type": 1, + }, + }, + }, + }, + { + "name": "b", + "type": { + "kind": 6, + "type": { + "key": { + "kind": 0, + "type": 2, + }, + "value": { + "kind": 6, + "type": { + "key": { + "kind": 0, + "type": 2, + }, + "value": { + "kind": 0, + "type": 1, + }, + }, + }, + }, + }, + }, + ], + "definitionOffset": 1273, + "name": "TestDictionaries", + "parameters": [], + "returnType": { + "kind": 0, + "type": 0, + }, + }, + { + "arguments": [ + { + "name": "a", + "type": { + "kind": 3, + "type": { + "name": "SomeParametrizedType", + "types": [ + { + "kind": 2, + "type": { + "name": "Either", + "types": [ + { + "kind": 0, + "type": 2, + }, + { + "kind": 0, + "type": 1, + }, + ], + }, + }, + { + "kind": 3, + "type": { + "name": "Map", + "types": [ + { + "kind": 3, + "type": { + "name": "Set", + "types": [ + { + "kind": 0, + "type": 2, + }, + ], + }, + }, + { + "kind": 2, + "type": { + "name": "Either", + "types": [ + { + "kind": 3, + "type": { + "name": "Set", + "types": [ + { + "kind": 0, + "type": 2, + }, + ], + }, + }, + { + "kind": 3, + "type": { + "name": "Set", + "types": [ + { + "kind": 0, + "type": 1, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + }, + ], + "definitionOffset": 1466, + "name": "TestParametrizedTypes", + "parameters": [], + "returnType": { + "kind": 0, + "type": 1, + }, + }, + { + "arguments": [ + { + "name": "a", + "type": { + "kind": 5, + "type": { + "kind": 5, + "type": { + "kind": 5, + "type": { + "kind": 0, + "type": 2, + }, + }, + }, + }, + }, + ], + "definitionOffset": 1710, + "name": "TestTypeCombinations", + "parameters": [], + "returnType": { + "kind": 5, + "type": { + "kind": 5, + "type": { + "kind": 2, + "type": { + "name": "Either", + "types": [ + { + "kind": 0, + "type": 1, + }, + { + "kind": 6, + "type": { + "key": { + "kind": 0, + "type": 2, + }, + "value": { + "kind": 0, + "type": 1, + }, + }, + }, + ], + }, + }, + }, + }, + }, + { + "arguments": [], + "definitionOffset": 1911, + "name": "TestFunctionReturningRecord", + "parameters": [], + "returnType": { + "kind": 1, + "type": "TestRecord", + }, + }, + { + "arguments": [], + "definitionOffset": 2076, + "name": "TestFunctionReturningEnum", + "parameters": [], + "returnType": { + "kind": 1, + "type": "TestEnum", + }, + }, + ], + "name": "TestModule", + "properties": [], + "props": [], + "views": [ + { + "asyncFunctions": [], + "classes": [], + "constants": [], + "constructor": null, + "definitionOffset": 3277, + "events": [ + "onEvent1", + "onEvent2", + ], + "functions": [], + "name": "ExpoWebView", + "properties": [], + "props": [ + { + "arguments": [ + { + "name": "view", + "type": { + "kind": 0, + "type": 6, + }, + }, + { + "name": "url", + "type": { + "kind": 1, + "type": "URL", + }, + }, + ], + "definitionOffset": 3323, + "name": "url", + }, + { + "arguments": [ + { + "name": "view", + "type": { + "kind": 0, + "type": 6, + }, + }, + { + "name": "testRecord", + "type": { + "kind": 1, + "type": "TestRecord", + }, + }, + ], + "definitionOffset": 3507, + "name": "testRecord", + }, + { + "arguments": [ + { + "name": "view", + "type": { + "kind": 0, + "type": 6, + }, + }, + { + "name": "testRecord2", + "type": { + "kind": 1, + "type": "TestRecord2", + }, + }, + ], + "definitionOffset": 3578, + "name": "testRecord2", + }, + { + "arguments": [ + { + "name": "view", + "type": { + "kind": 0, + "type": 6, + }, + }, + { + "name": "testRecordClass", + "type": { + "kind": 1, + "type": "TestRecordClass", + }, + }, + ], + "definitionOffset": 3652, + "name": "testRecordClass", + }, + { + "arguments": [ + { + "name": "view", + "type": { + "kind": 0, + "type": 6, + }, + }, + { + "name": "testEnum", + "type": { + "kind": 1, + "type": "TestEnum", + }, + }, + ], + "definitionOffset": 3738, + "name": "testEnum", + }, + ], + "views": [], + }, + ], + }, + ], + "records": [ + { + "fields": [ + { + "name": "basicString", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "basicStringInitialized", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "basicIntInferred", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "basicDoubleInferred", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "basicStringInferred", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "enumInferred", + "type": { + "kind": 1, + "type": "TestEnum", + }, + }, + { + "name": "complexEnumInferred", + "type": { + "kind": 1, + "type": "TestEnum", + }, + }, + { + "name": "recordInferred", + "type": { + "kind": 1, + "type": "TestRecord2", + }, + }, + { + "name": "optionalInt", + "type": { + "kind": 4, + "type": { + "kind": 0, + "type": 2, + }, + }, + }, + { + "name": "letDoubleBinding", + "type": { + "kind": 0, + "type": 2, + }, + }, + ], + "name": "TestRecord", + }, + { + "fields": [ + { + "name": "field1", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "field2", + "type": { + "kind": 0, + "type": 1, + }, + }, + ], + "name": "TestRecord2", + }, + { + "fields": [ + { + "name": "field1", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "field2", + "type": { + "kind": 0, + "type": 1, + }, + }, + ], + "name": "TestRecordClass", + }, + ], + "typeIdentifierDefinitionList": [ + [ + "TestEnum", + { + "definition": { + "cases": [ + "simpleCase", + "multipleCases1", + "multipleCases2", + "caseWithArgs1", + "caseWithArgs2", + ], + "name": "TestEnum", + }, + "kind": 1, + }, + ], + [ + "TestRecord", + { + "definition": { + "fields": [ + { + "name": "basicString", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "basicStringInitialized", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "basicIntInferred", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "basicDoubleInferred", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "basicStringInferred", + "type": { + "kind": 0, + "type": 1, + }, + }, + { + "name": "enumInferred", + "type": { + "kind": 1, + "type": "TestEnum", + }, + }, + { + "name": "complexEnumInferred", + "type": { + "kind": 1, + "type": "TestEnum", + }, + }, + { + "name": "recordInferred", + "type": { + "kind": 1, + "type": "TestRecord2", + }, + }, + { + "name": "optionalInt", + "type": { + "kind": 4, + "type": { + "kind": 0, + "type": 2, + }, + }, + }, + { + "name": "letDoubleBinding", + "type": { + "kind": 0, + "type": 2, + }, + }, + ], + "name": "TestRecord", + }, + "kind": 2, + }, + ], + [ + "TestRecord2", + { + "definition": { + "fields": [ + { + "name": "field1", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "field2", + "type": { + "kind": 0, + "type": 1, + }, + }, + ], + "name": "TestRecord2", + }, + "kind": 2, + }, + ], + [ + "TestRecordClass", + { + "definition": { + "fields": [ + { + "name": "field1", + "type": { + "kind": 0, + "type": 2, + }, + }, + { + "name": "field2", + "type": { + "kind": 0, + "type": 1, + }, + }, + ], + "name": "TestRecordClass", + }, + "kind": 2, + }, + ], + ], + "usedTypeIdentifiersList": [ + "BarcodeType", + "Map", + "Set", + "SomeParametrizedType", + "TestEnum", + "TestRecord", + "TestRecord2", + "TestRecordClass", + "URL", + ], +} +`; diff --git a/packages/expo-type-information/tests/typeInformation.test.ts b/packages/expo-type-information/tests/typeInformation.test.ts new file mode 100644 index 00000000000000..4c18212662d2ce --- /dev/null +++ b/packages/expo-type-information/tests/typeInformation.test.ts @@ -0,0 +1,134 @@ +import { it, expect } from '@jest/globals'; +import * as fs from 'fs'; + +import { generateTSMockForModule } from '../src/mockgen'; +import { + FileTypeInformation, + getFileTypeInformation, + ModuleClassDeclaration, + serializeTypeInformation, + TypeInferenceOption, +} from '../src/typeInformation'; +import { + generateFullTsInterface, + generateConciseTsInterface, + generateModuleTypesFileContent, + generateViewTypesFileContent, +} from '../src/typescriptGeneration'; +import { GetFileTypeInformationOptions } from '../build'; + +const swiftFile = fs.realpathSync('./tests/TestModule.swift'); +const defaultArgs: GetFileTypeInformationOptions = { + input: { inputFileAbsolutePaths: [swiftFile], type: 'file' }, + typeInference: TypeInferenceOption.PREPROCESS_AND_INFERENCE, +}; + +let defaultArgsFileInfo: FileTypeInformation | null = null; +beforeAll(async () => { + defaultArgsFileInfo = await getFileTypeInformation(defaultArgs); +}); + +it('Same type information', async () => { + expect( + serializeTypeInformation( + (await getFileTypeInformation(defaultArgs)) ?? { + usedTypeIdentifiers: new Set(), + declaredTypeIdentifiers: new Set(), + inferredTypeParametersCount: new Map(), + typeIdentifierDefinitionMap: new Map(), + moduleClasses: [], + records: [], + enums: [], + } + ) + ).toMatchSnapshot(); +}); + +it('Same generated view file', async () => { + const fileInfo = defaultArgsFileInfo; + expect(fileInfo).toBeTruthy(); + if (fileInfo) { + expect(await generateViewTypesFileContent(fileInfo)).toMatchSnapshot(); + } +}); + +it('Same generated module file', async () => { + const fileInfo = defaultArgsFileInfo; + expect(fileInfo).toBeTruthy(); + if (fileInfo) { + expect(await generateModuleTypesFileContent(fileInfo)).toMatchSnapshot(); + } +}); + +it('Same generated mock file', async () => { + const fileInfo = defaultArgsFileInfo; + expect(fileInfo).toBeTruthy(); + if (fileInfo) { + expect( + generateTSMockForModule(fileInfo.moduleClasses[0] as ModuleClassDeclaration, fileInfo, true) + ).toMatchSnapshot(); + } +}); + +it('Same generated mock file JS', async () => { + const fileInfo = defaultArgsFileInfo; + expect(fileInfo).toBeTruthy(); + if (fileInfo) { + expect( + generateTSMockForModule(fileInfo.moduleClasses[0] as ModuleClassDeclaration, fileInfo, false) + ).toMatchSnapshot(); + } +}); + +it('Same generated concise ts interface', async () => { + const fileInfo = defaultArgsFileInfo; + expect(fileInfo).toBeTruthy(); + if (fileInfo) { + const { volatileGeneratedFileContent, moduleTypescriptInterfaceFileContent } = + await generateConciseTsInterface(fileInfo); + expect(volatileGeneratedFileContent).toMatchSnapshot(); + expect(moduleTypescriptInterfaceFileContent).toMatchSnapshot(); + } +}); + +it('Same generated full ts interface', async () => { + const fileInfo = defaultArgsFileInfo; + expect(fileInfo).toBeTruthy(); + if (fileInfo) { + const result = await generateFullTsInterface(fileInfo); + expect(result).toMatchSnapshot(); + } +}); + +it('Generation from string is the same as generation from file. Preprocessing.', async () => { + const fileInfo = defaultArgsFileInfo; + const fileInfoForString = await getFileTypeInformation({ + input: { type: 'string', fileContent: fs.readFileSync(swiftFile, 'utf8'), language: 'Swift' }, + typeInference: TypeInferenceOption.PREPROCESS_AND_INFERENCE, + }); + expect(fileInfo).toEqual(fileInfoForString); +}); + +it('Generation from string is the same as generation from file. Simple type inference.', async () => { + const fileInfo = await getFileTypeInformation({ + input: { type: 'file', inputFileAbsolutePaths: [swiftFile] }, + typeInference: TypeInferenceOption.NO_INFERENCE, + }); + const fileInfoForString = await getFileTypeInformation({ + input: { type: 'string', fileContent: fs.readFileSync(swiftFile, 'utf8'), language: 'Swift' }, + typeInference: TypeInferenceOption.NO_INFERENCE, + }); + expect(fileInfo).toEqual(fileInfoForString); +}); + +it('Generation from string is the same as generation from file. No type inference.', async () => { + const fileInfo = await getFileTypeInformation({ + input: { type: 'file', inputFileAbsolutePaths: [swiftFile] }, + typeInference: TypeInferenceOption.SIMPLE_INFERENCE, + }); + const fileInfoForString = await getFileTypeInformation({ + input: { type: 'string', fileContent: fs.readFileSync(swiftFile, 'utf8'), language: 'Swift' }, + typeInference: TypeInferenceOption.SIMPLE_INFERENCE, + }); + expect(fileInfo).toEqual(fileInfoForString); +}); diff --git a/packages/expo-type-information/tsconfig.json b/packages/expo-type-information/tsconfig.json new file mode 100644 index 00000000000000..ab0b79fcef5946 --- /dev/null +++ b/packages/expo-type-information/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "expo-module-scripts/tsconfig.node", + "include": ["./src"], + "compilerOptions": { + "types": ["node"], + "lib": ["dom", "esnext"], + "outDir": "./build", + "rootDir": "./src", + "isolatedModules": true + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ab6fcacf52c733..ce1e667cc101e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4903,6 +4903,9 @@ importers: '@types/node': specifier: ^22.14.0 version: 22.19.15 + expo-type-information: + specifier: ^0.0.1 + version: link:../expo-type-information glob: specifier: ^13.0.0 version: 13.0.6 @@ -5619,6 +5622,43 @@ importers: specifier: workspace:* version: link:../expo-module-scripts + packages/expo-type-information: + dependencies: + chalk: + specifier: ^4.1.0 + version: 4.1.2 + commander: + specifier: ^12.1.0 + version: 12.1.0 + prettier: + specifier: ^3.0.3 + version: 3.5.3 + typescript: + specifier: ~6.0.3 + version: 6.0.3 + yaml: + specifier: ^2.3.2 + version: 2.8.3 + devDependencies: + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 + '@types/jest': + specifier: ^29.2.1 + version: 29.5.14 + '@types/node': + specifier: ^22.14.0 + version: 22.19.15 + expo-module-scripts: + specifier: workspace:* + version: link:../expo-module-scripts + jest: + specifier: ^29.3.1 + version: 29.7.0(@types/node@22.19.15)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@6.0.3)) + ts-jest: + specifier: ^29.1.2 + version: 29.4.9(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.15)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@6.0.3)))(typescript@6.0.3) + packages/expo-ui: dependencies: react: @@ -26566,6 +26606,26 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.15)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@6.0.3)))(typescript@6.0.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.9 + jest: 29.7.0(@types/node@22.19.15)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@6.0.3)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.4 + type-fest: 4.41.0 + typescript: 6.0.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.29.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.0) + jest-util: 29.7.0 + ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@6.0.3)))(typescript@6.0.3): dependencies: bs-logger: 0.2.6 From a5c834d264d79deac586c81e5dab0a83ad47e79c Mon Sep 17 00:00:00 2001 From: Alan Hughes <30924086+alanjhughes@users.noreply.github.com> Date: Thu, 7 May 2026 19:22:44 +0100 Subject: [PATCH 11/18] [bare-expo] Fix enabling prebuilds (#45510) --- .../ios/BareExpo.xcodeproj/project.pbxproj | 96 +++++++++- apps/bare-expo/ios/Podfile | 4 +- apps/bare-expo/ios/Podfile.lock | 171 ++++-------------- apps/expo-go/ios/Podfile.lock | 2 +- apps/minimal-tester/ios/Podfile | 4 +- .../expo-template-bare-minimum/ios/Podfile | 4 +- 6 files changed, 136 insertions(+), 145 deletions(-) diff --git a/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj b/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj index 96d4bec01f113e..224fa5619015bd 100644 --- a/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj +++ b/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj @@ -369,14 +369,60 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-BareExpoMain-BareExpoTests/Pods-BareExpoMain-BareExpoTests-frameworks.sh", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoBrownfield/ExpoBrownfield.framework/ExpoBrownfield", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoCamera/ExpoCamera.framework/ExpoCamera", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoCameraBarcodeScanning/ExpoCameraBarcodeScanning.framework/ExpoCameraBarcodeScanning", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoCameraBarcodeScanning/ZXingObjC.framework/ZXingObjC", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoContacts/ExpoContacts.framework/ExpoContacts", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem.framework/ExpoFileSystem", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoFont/ExpoFont.framework/ExpoFont", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/ExpoImage.framework/ExpoImage", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImage.framework/SDWebImage", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImageAVIFCoder.framework/SDWebImageAVIFCoder", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImageSVGCoder.framework/SDWebImageSVGCoder", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImageWebPCoder.framework/SDWebImageWebPCoder", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/libavif.framework/libavif", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImageManipulator/ExpoImageManipulator.framework/ExpoImageManipulator", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoLivePhoto/ExpoLivePhoto.framework/ExpoLivePhoto", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoLocation/ExpoLocation.framework/ExpoLocation", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoMaps/ExpoMaps.framework/ExpoMaps", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoMediaLibrary/ExpoMediaLibrary.framework/ExpoMediaLibrary", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesCore/ExpoModulesCore.framework/ExpoModulesCore", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesJSI/ExpoModulesJSI.framework/ExpoModulesJSI", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesWorklets/ExpoModulesWorklets.framework/ExpoModulesWorklets", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoPrint/ExpoPrint.framework/ExpoPrint", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoSensors/ExpoSensors.framework/ExpoSensors", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoVideo/ExpoVideo.framework/ExpoVideo", "${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermesvm.framework/hermesvm", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoBrownfield.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoCamera.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoCameraBarcodeScanning.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoContacts.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoFileSystem.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoFont.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageAVIFCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageSVGCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavif.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoImageManipulator.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoLivePhoto.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoLocation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoMaps.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoMediaLibrary.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesCore.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesJSI.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesWorklets.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoPrint.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoSensors.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoVideo.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermesvm.framework", @@ -455,7 +501,6 @@ "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/ReachabilitySwift.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/LottiePrivacyInfo.bundle", @@ -479,7 +524,6 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ReachabilitySwift.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SDWebImage.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/LottiePrivacyInfo.bundle", @@ -497,14 +541,60 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-BareExpoMain-BareExpo/Pods-BareExpoMain-BareExpo-frameworks.sh", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoBrownfield/ExpoBrownfield.framework/ExpoBrownfield", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoCamera/ExpoCamera.framework/ExpoCamera", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoCameraBarcodeScanning/ExpoCameraBarcodeScanning.framework/ExpoCameraBarcodeScanning", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoCameraBarcodeScanning/ZXingObjC.framework/ZXingObjC", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoContacts/ExpoContacts.framework/ExpoContacts", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem.framework/ExpoFileSystem", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoFont/ExpoFont.framework/ExpoFont", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/ExpoImage.framework/ExpoImage", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImage.framework/SDWebImage", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImageAVIFCoder.framework/SDWebImageAVIFCoder", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImageSVGCoder.framework/SDWebImageSVGCoder", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/SDWebImageWebPCoder.framework/SDWebImageWebPCoder", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImage/libavif.framework/libavif", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoImageManipulator/ExpoImageManipulator.framework/ExpoImageManipulator", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoLivePhoto/ExpoLivePhoto.framework/ExpoLivePhoto", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoLocation/ExpoLocation.framework/ExpoLocation", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoMaps/ExpoMaps.framework/ExpoMaps", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoMediaLibrary/ExpoMediaLibrary.framework/ExpoMediaLibrary", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesCore/ExpoModulesCore.framework/ExpoModulesCore", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesJSI/ExpoModulesJSI.framework/ExpoModulesJSI", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesWorklets/ExpoModulesWorklets.framework/ExpoModulesWorklets", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoPrint/ExpoPrint.framework/ExpoPrint", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoSensors/ExpoSensors.framework/ExpoSensors", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoVideo/ExpoVideo.framework/ExpoVideo", "${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermesvm.framework/hermesvm", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoBrownfield.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoCamera.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoCameraBarcodeScanning.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZXingObjC.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoContacts.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoFileSystem.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoFont.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageAVIFCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageSVGCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageWebPCoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavif.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoImageManipulator.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoLivePhoto.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoLocation.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoMaps.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoMediaLibrary.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesCore.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesJSI.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesWorklets.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoPrint.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoSensors.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoVideo.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermesvm.framework", @@ -537,7 +627,6 @@ "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/ReachabilitySwift.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/LottiePrivacyInfo.bundle", @@ -561,7 +650,6 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ReachabilitySwift.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SDWebImage.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/LottiePrivacyInfo.bundle", diff --git a/apps/bare-expo/ios/Podfile b/apps/bare-expo/ios/Podfile index 1744a544ce07ce..f53a849519d3b6 100644 --- a/apps/bare-expo/ios/Podfile +++ b/apps/bare-expo/ios/Podfile @@ -5,9 +5,9 @@ require 'json' podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {} ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] -ENV['RCT_USE_RN_DEP'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' +ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true' -ENV['RCT_USE_PREBUILT_RNCORE'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' +ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false' platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4' diff --git a/apps/bare-expo/ios/Podfile.lock b/apps/bare-expo/ios/Podfile.lock index c24f78da552495..855e8eea6777b0 100644 --- a/apps/bare-expo/ios/Podfile.lock +++ b/apps/bare-expo/ios/Podfile.lock @@ -409,8 +409,6 @@ PODS: - ExpoModulesCore - ExpoCameraBarcodeScanning (56.0.3): - ExpoCamera - - ZXingObjC/OneD - - ZXingObjC/PDF417 - ExpoCellular (56.0.3): - ExpoModulesCore - ExpoClipboard (56.0.3): @@ -442,22 +440,8 @@ PODS: - ExpoModulesCore - ExpoImage (56.0.4): - ExpoModulesCore - - libavif/libdav1d - - SDWebImage (~> 5.21.0) - - SDWebImageAVIFCoder (~> 0.11.0) - - SDWebImageSVGCoder (~> 1.7.0) - - SDWebImageWebPCoder (~> 0.14.6) - - ExpoImage/Tests (56.0.4): - - ExpoModulesCore - - ExpoModulesTestCore - - libavif/libdav1d - - SDWebImage (~> 5.21.0) - - SDWebImageAVIFCoder (~> 0.11.0) - - SDWebImageSVGCoder (~> 1.7.0) - - SDWebImageWebPCoder (~> 0.14.6) - ExpoImageManipulator (56.0.3): - ExpoModulesCore - - SDWebImageWebPCoder - ExpoImagePicker (56.0.3): - ExpoModulesCore - ExpoInsights (56.0.3): @@ -507,10 +491,6 @@ PODS: - ExpoMediaLibrary (56.0.3): - ExpoModulesCore - React-Core - - ExpoMediaLibrary/Tests (56.0.3): - - ExpoModulesCore - - ExpoModulesTestCore - - React-Core - ExpoMeshGradient (56.0.3): - ExpoModulesCore - ExpoModulesCore (56.0.3): @@ -537,31 +517,6 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - ExpoModulesCore/Tests (56.0.3): - - ExpoModulesJSI - - ExpoModulesTestCore - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-jsinspector - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - ExpoModulesJSI (56.0.1): - React-Core - React-runtimescheduler @@ -774,23 +729,6 @@ PODS: - hermes-engine (250829098.0.10): - hermes-engine/Pre-built (= 250829098.0.10) - hermes-engine/Pre-built (250829098.0.10) - - libavif/core (1.0.0) - - libavif/libdav1d (1.0.0): - - libavif/core - - libdav1d (>= 0.6.0) - - libdav1d (1.2.0) - - libwebp (1.5.0): - - libwebp/demux (= 1.5.0) - - libwebp/mux (= 1.5.0) - - libwebp/sharpyuv (= 1.5.0) - - libwebp/webp (= 1.5.0) - - libwebp/demux (1.5.0): - - libwebp/webp - - libwebp/mux (1.5.0): - - libwebp/demux - - libwebp/sharpyuv (1.5.0) - - libwebp/webp (1.5.0): - - libwebp/sharpyuv - lottie-ios (4.6.0) - lottie-react-native (7.3.6): - hermes-engine @@ -3241,17 +3179,6 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - SDWebImage (5.21.7): - - SDWebImage/Core (= 5.21.7) - - SDWebImage/Core (5.21.7) - - SDWebImageAVIFCoder (0.11.1): - - libavif/core (>= 0.11.0) - - SDWebImage (~> 5.10) - - SDWebImageSVGCoder (1.7.0): - - SDWebImage/Core (~> 5.6) - - SDWebImageWebPCoder (0.14.6): - - libwebp (~> 1.0) - - SDWebImage/Core (~> 5.17) - TestExpoUi (1.0.0): - ExpoModulesCore - ExpoUI @@ -3283,11 +3210,6 @@ PODS: - ReactNativeDependencies - Yoga - Yoga (0.0.0) - - ZXingObjC/Core (3.6.9) - - ZXingObjC/OneD (3.6.9): - - ZXingObjC/Core - - ZXingObjC/PDF417 (3.6.9): - - ZXingObjC/Core DEPENDENCIES: - BenchmarkingModule (from `../modules/benchmarking/ios`) @@ -3322,58 +3244,55 @@ DEPENDENCIES: - ExpoBlob (from `../../../packages/expo-blob/ios`) - ExpoBlur (from `../../../packages/expo-blur/ios`) - ExpoBrightness (from `../../../packages/expo-brightness/ios`) - - ExpoBrownfield (from `../../../packages/expo-brownfield/ios`) + - ExpoBrownfield (from `../../../packages/expo-brownfield/ios/ExpoBrownfield.podspec`) - ExpoCalendar (from `../../../packages/expo-calendar/ios`) - - ExpoCamera (from `../../../packages/expo-camera/ios`) - - ExpoCameraBarcodeScanning (from `../../../packages/expo-camera/ios`) + - ExpoCamera (from `../../../packages/expo-camera/ios/ExpoCamera.podspec`) + - ExpoCameraBarcodeScanning (from `../../../packages/expo-camera/ios/ExpoCameraBarcodeScanning.podspec`) - ExpoCellular (from `../../../packages/expo-cellular/ios`) - ExpoClipboard (from `../../../packages/expo-clipboard/ios`) - ExpoClipboard/Tests (from `../../../packages/expo-clipboard/ios`) - - ExpoContacts (from `../../../packages/expo-contacts/ios`) + - ExpoContacts (from `../../../packages/expo-contacts/ios/ExpoContacts.podspec`) - ExpoCrypto (from `../../../packages/expo-crypto/ios`) - ExpoDevice (from `../../../packages/expo-device/ios`) - ExpoDocumentPicker (from `../../../packages/expo-document-picker/ios`) - "ExpoDomWebView (from `../../../packages/@expo/dom-webview/ios`)" - - ExpoFileSystem (from `../../../packages/expo-file-system/ios`) - - ExpoFont (from `../../../packages/expo-font/ios`) + - ExpoFileSystem (from `../../../packages/expo-file-system/ios/ExpoFileSystem.podspec`) + - ExpoFont (from `../../../packages/expo-font/ios/ExpoFont.podspec`) - ExpoGL (from `../../../packages/expo-gl`) - ExpoGlassEffect (from `../../../packages/expo-glass-effect/ios`) - ExpoHaptics (from `../../../packages/expo-haptics/ios`) - - ExpoImage (from `../../../packages/expo-image/ios`) - - ExpoImage/Tests (from `../../../packages/expo-image/ios`) - - ExpoImageManipulator (from `../../../packages/expo-image-manipulator/ios`) + - ExpoImage (from `../../../packages/expo-image/ios/ExpoImage.podspec`) + - ExpoImageManipulator (from `../../../packages/expo-image-manipulator/ios/ExpoImageManipulator.podspec`) - ExpoImagePicker (from `../../../packages/expo-image-picker/ios`) - ExpoInsights (from `../../../packages/expo-insights/ios`) - ExpoKeepAwake (from `../../../packages/expo-keep-awake/ios`) - ExpoLinearGradient (from `../../../packages/expo-linear-gradient/ios`) - ExpoLinking (from `../../../packages/expo-linking/ios`) - - ExpoLivePhoto (from `../../../packages/expo-live-photo/ios`) + - ExpoLivePhoto (from `../../../packages/expo-live-photo/ios/ExpoLivePhoto.podspec`) - ExpoLocalAuthentication (from `../../../packages/expo-local-authentication/ios`) - ExpoLocalization (from `../../../packages/expo-localization/ios`) - - ExpoLocation (from `../../../packages/expo-location/ios`) + - ExpoLocation (from `../../../packages/expo-location/ios/ExpoLocation.podspec`) - "ExpoLogBox (from `../../../packages/@expo/log-box`)" - ExpoMailComposer (from `../../../packages/expo-mail-composer/ios`) - - ExpoMaps (from `../../../packages/expo-maps/ios`) - - ExpoMediaLibrary (from `../../../packages/expo-media-library/ios`) - - ExpoMediaLibrary/Tests (from `../../../packages/expo-media-library/ios`) + - ExpoMaps (from `../../../packages/expo-maps/ios/ExpoMaps.podspec`) + - ExpoMediaLibrary (from `../../../packages/expo-media-library/ios/ExpoMediaLibrary.podspec`) - ExpoMeshGradient (from `../../../packages/expo-mesh-gradient/ios`) - - ExpoModulesCore (from `../../../packages/expo-modules-core`) - - ExpoModulesCore/Tests (from `../../../packages/expo-modules-core`) + - ExpoModulesCore (from `../../../packages/expo-modules-core/ExpoModulesCore.podspec`) - ExpoModulesJSI (from `../../../packages/expo-modules-jsi/apple`) - ExpoModulesJSI/Tests (from `../../../packages/expo-modules-jsi/apple`) - ExpoModulesTestCore (from `../../../packages/expo-modules-test-core/ios`) - - ExpoModulesWorklets (from `../../../packages/expo-modules-core`) + - ExpoModulesWorklets (from `../../../packages/expo-modules-core/ExpoModulesWorklets.podspec`) - ExpoModulesWorkletsAdapter (from `../../../packages/expo-modules-core`) - ExpoNetwork (from `../../../packages/expo-network/ios`) - ExpoNotifications (from `../../../packages/expo-notifications/ios`) - ExpoNotifications/Tests (from `../../../packages/expo-notifications/ios`) - ExpoObserve (from `../../../packages/expo-observe/ios`) - ExpoObserve/Tests (from `../../../packages/expo-observe/ios`) - - ExpoPrint (from `../../../packages/expo-print/ios`) + - ExpoPrint (from `../../../packages/expo-print/ios/ExpoPrint.podspec`) - ExpoScreenCapture (from `../../../packages/expo-screen-capture/ios`) - ExpoScreenOrientation (from `../../../packages/expo-screen-orientation/ios`) - ExpoSecureStore (from `../../../packages/expo-secure-store/ios`) - - ExpoSensors (from `../../../packages/expo-sensors/ios`) + - ExpoSensors (from `../../../packages/expo-sensors/ios/ExpoSensors.podspec`) - ExpoSharing (from `../../../packages/expo-sharing/ios`) - ExpoSMS (from `../../../packages/expo-sms/ios`) - ExpoSpeech (from `../../../packages/expo-speech/ios`) @@ -3386,7 +3305,7 @@ DEPENDENCIES: - ExpoTaskManager/Tests (from `../../../packages/expo-task-manager/ios`) - ExpoTrackingTransparency (from `../../../packages/expo-tracking-transparency/ios`) - ExpoUI (from `../../../packages/expo-ui/ios`) - - ExpoVideo (from `../../../packages/expo-video/ios`) + - ExpoVideo (from `../../../packages/expo-video/ios/ExpoVideo.podspec`) - ExpoVideoDashSupportModule (from `../modules/expo-video-dash-support-module/ios`) - ExpoVideoThumbnails (from `../../../packages/expo-video-thumbnails/ios`) - ExpoWebBrowser (from `../../../packages/expo-web-browser/ios`) @@ -3496,19 +3415,11 @@ DEPENDENCIES: SPEC REPOS: trunk: - - libavif - - libdav1d - - libwebp - lottie-ios - Nimble - OHHTTPStubs - Quick - ReachabilitySwift - - SDWebImage - - SDWebImageAVIFCoder - - SDWebImageSVGCoder - - SDWebImageWebPCoder - - ZXingObjC EXTERNAL SOURCES: BenchmarkingModule: @@ -3581,15 +3492,15 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-brightness/ios" ExpoBrownfield: inhibit_warnings: false - :path: "../../../packages/expo-brownfield/ios" + :podspec: "../../../packages/expo-brownfield/ios/ExpoBrownfield.podspec" ExpoCalendar: inhibit_warnings: false :path: "../../../packages/expo-calendar/ios" ExpoCamera: inhibit_warnings: false - :path: "../../../packages/expo-camera/ios" + :podspec: "../../../packages/expo-camera/ios/ExpoCamera.podspec" ExpoCameraBarcodeScanning: - :path: "../../../packages/expo-camera/ios" + :podspec: "../../../packages/expo-camera/ios/ExpoCameraBarcodeScanning.podspec" ExpoCellular: inhibit_warnings: false :path: "../../../packages/expo-cellular/ios" @@ -3598,7 +3509,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-clipboard/ios" ExpoContacts: inhibit_warnings: false - :path: "../../../packages/expo-contacts/ios" + :podspec: "../../../packages/expo-contacts/ios/ExpoContacts.podspec" ExpoCrypto: inhibit_warnings: false :path: "../../../packages/expo-crypto/ios" @@ -3613,10 +3524,10 @@ EXTERNAL SOURCES: :path: "../../../packages/@expo/dom-webview/ios" ExpoFileSystem: inhibit_warnings: false - :path: "../../../packages/expo-file-system/ios" + :podspec: "../../../packages/expo-file-system/ios/ExpoFileSystem.podspec" ExpoFont: inhibit_warnings: false - :path: "../../../packages/expo-font/ios" + :podspec: "../../../packages/expo-font/ios/ExpoFont.podspec" ExpoGL: inhibit_warnings: false :path: "../../../packages/expo-gl" @@ -3628,10 +3539,10 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-haptics/ios" ExpoImage: inhibit_warnings: false - :path: "../../../packages/expo-image/ios" + :podspec: "../../../packages/expo-image/ios/ExpoImage.podspec" ExpoImageManipulator: inhibit_warnings: false - :path: "../../../packages/expo-image-manipulator/ios" + :podspec: "../../../packages/expo-image-manipulator/ios/ExpoImageManipulator.podspec" ExpoImagePicker: inhibit_warnings: false :path: "../../../packages/expo-image-picker/ios" @@ -3649,7 +3560,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-linking/ios" ExpoLivePhoto: inhibit_warnings: false - :path: "../../../packages/expo-live-photo/ios" + :podspec: "../../../packages/expo-live-photo/ios/ExpoLivePhoto.podspec" ExpoLocalAuthentication: inhibit_warnings: false :path: "../../../packages/expo-local-authentication/ios" @@ -3658,7 +3569,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-localization/ios" ExpoLocation: inhibit_warnings: false - :path: "../../../packages/expo-location/ios" + :podspec: "../../../packages/expo-location/ios/ExpoLocation.podspec" ExpoLogBox: inhibit_warnings: false :path: "../../../packages/@expo/log-box" @@ -3667,16 +3578,16 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-mail-composer/ios" ExpoMaps: inhibit_warnings: false - :path: "../../../packages/expo-maps/ios" + :podspec: "../../../packages/expo-maps/ios/ExpoMaps.podspec" ExpoMediaLibrary: inhibit_warnings: false - :path: "../../../packages/expo-media-library/ios" + :podspec: "../../../packages/expo-media-library/ios/ExpoMediaLibrary.podspec" ExpoMeshGradient: inhibit_warnings: false :path: "../../../packages/expo-mesh-gradient/ios" ExpoModulesCore: inhibit_warnings: false - :path: "../../../packages/expo-modules-core" + :podspec: "../../../packages/expo-modules-core/ExpoModulesCore.podspec" ExpoModulesJSI: inhibit_warnings: false :path: "../../../packages/expo-modules-jsi/apple" @@ -3684,7 +3595,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-modules-test-core/ios" ExpoModulesWorklets: inhibit_warnings: false - :path: "../../../packages/expo-modules-core" + :podspec: "../../../packages/expo-modules-core/ExpoModulesWorklets.podspec" ExpoModulesWorkletsAdapter: :path: "../../../packages/expo-modules-core" ExpoNetwork: @@ -3698,7 +3609,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-observe/ios" ExpoPrint: inhibit_warnings: false - :path: "../../../packages/expo-print/ios" + :podspec: "../../../packages/expo-print/ios/ExpoPrint.podspec" ExpoScreenCapture: inhibit_warnings: false :path: "../../../packages/expo-screen-capture/ios" @@ -3710,7 +3621,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-secure-store/ios" ExpoSensors: inhibit_warnings: false - :path: "../../../packages/expo-sensors/ios" + :podspec: "../../../packages/expo-sensors/ios/ExpoSensors.podspec" ExpoSharing: inhibit_warnings: false :path: "../../../packages/expo-sharing/ios" @@ -3746,7 +3657,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-ui/ios" ExpoVideo: inhibit_warnings: false - :path: "../../../packages/expo-video/ios" + :podspec: "../../../packages/expo-video/ios/ExpoVideo.podspec" ExpoVideoDashSupportModule: inhibit_warnings: false :path: "../modules/expo-video-dash-support-module/ios" @@ -4007,7 +3918,7 @@ SPEC CHECKSUMS: ExpoImagePicker: 3d6e508fd099fc0dbe5620423c8bd22f268c589d ExpoInsights: 3eccd92f679d5217ca6424a4c49622f8a5b49e9c ExpoKeepAwake: 359c47a1d9ccc3a3c519bca6e39562cce230c5bb - ExpoLinearGradient: 4edd4b2f4ca556c84ee7b7b6ff1ffb77c303a4f4 + ExpoLinearGradient: 646dbfbd67cefcf75df7ea2115770605fd99db22 ExpoLinking: 4ff9681a924c3dd4f4e5a2f32a33085e6a3ec7f1 ExpoLivePhoto: 3c2bd665a63afa8a465b16b564e4c9ab83ea60eb ExpoLocalAuthentication: 64e8c5756df07c8a89f078293ec17899c1325a43 @@ -4018,7 +3929,7 @@ SPEC CHECKSUMS: ExpoMaps: 7fd43313b3be943c93df66df7dd09e6337703a37 ExpoMediaLibrary: ee2d74d5e52154305b8229dcb5c4319c84f30311 ExpoMeshGradient: baf62012104fd9c1719de67f88c69958abcd2ed1 - ExpoModulesCore: 51cc5e98a129465e77e807dab4245c466be6e813 + ExpoModulesCore: 2f7d4080e4d5c7916ea294217b9147b03590e913 ExpoModulesJSI: 15a25b2948cdfe04bced3e08566a34877fe3cc1e ExpoModulesTestCore: 5660ab6b5928747366d4946580622a578865696a ExpoModulesWorklets: 03afe05752b44f35d2c0903525e786b468e6390a @@ -4051,9 +3962,6 @@ SPEC CHECKSUMS: EXUpdatesInterface: 25408a97d682355eb9fb37e5aa6e22caece1881f FBLazyVector: 24e62c765683b8d89006a88a2c8f5cf019f0074d hermes-engine: 725fd85144e1348879039099a6be950c471a4f2c - libavif: 5f8e715bea24debec477006f21ef9e95432e254d - libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f - libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 lottie-ios: 8f959969761e9c45d70353667d00af0e5b9cadb3 lottie-react-native: 615e5f4651bee144ea991ad8e900630b6b3daf5d Nimble: 97d90931cca412a23224ff29e258809f75c258f7 @@ -4149,16 +4057,11 @@ SPEC CHECKSUMS: RNScreens: c476f5f41b7c4ddce3e73f838c23d40c5e33384c RNSVG: 04044c3abcf177fd674a1a3d13097efa1adebcbe RNWorklets: edcd0af162eba9fb81af89a4761f1af35086d1cc - SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf - SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57 - SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c - SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 TestExpoUi: e376582270047f880c7e44afc7f912c97b14da54 UMAppLoader: b7d22886a244871c20b5a8f2fcea13c18534e677 WorkletsTester: 15a12097d67f73fd107ab7dc8236cab805e472b0 Yoga: 77dfa8673de2874e1855002ae59c68b8be9b007b - ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: cded84e5ed31720829134c3bfcd1283e1d36ada7 +PODFILE CHECKSUM: d12a3110d7abf3249571bb761eb2f7d3d67e6a3d COCOAPODS: 1.16.2 diff --git a/apps/expo-go/ios/Podfile.lock b/apps/expo-go/ios/Podfile.lock index 2eb28a16bf16e2..35127e9031b1b9 100644 --- a/apps/expo-go/ios/Podfile.lock +++ b/apps/expo-go/ios/Podfile.lock @@ -4673,7 +4673,7 @@ SPEC CHECKSUMS: ExpoImageManipulator: bbe6550472b04cdeb9d2161a61600dc1e544d024 ExpoImagePicker: 3d6e508fd099fc0dbe5620423c8bd22f268c589d ExpoKeepAwake: 359c47a1d9ccc3a3c519bca6e39562cce230c5bb - ExpoLinearGradient: 4edd4b2f4ca556c84ee7b7b6ff1ffb77c303a4f4 + ExpoLinearGradient: 646dbfbd67cefcf75df7ea2115770605fd99db22 ExpoLinking: 4ff9681a924c3dd4f4e5a2f32a33085e6a3ec7f1 ExpoLocalAuthentication: 64e8c5756df07c8a89f078293ec17899c1325a43 ExpoLocalization: 74b7a2319781fd14f5db01e932c7c3a075ea1b4b diff --git a/apps/minimal-tester/ios/Podfile b/apps/minimal-tester/ios/Podfile index 583272c6359023..7b2391fadd88a1 100644 --- a/apps/minimal-tester/ios/Podfile +++ b/apps/minimal-tester/ios/Podfile @@ -13,8 +13,8 @@ def ccache_enabled?(podfile_properties) end ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] -ENV['RCT_USE_RN_DEP'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' -ENV['RCT_USE_PREBUILT_RNCORE'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' +ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' +ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true' ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false' platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4' diff --git a/templates/expo-template-bare-minimum/ios/Podfile b/templates/expo-template-bare-minimum/ios/Podfile index 26d3e3c96fd274..c3158e3fb9b16f 100644 --- a/templates/expo-template-bare-minimum/ios/Podfile +++ b/templates/expo-template-bare-minimum/ios/Podfile @@ -13,8 +13,8 @@ def ccache_enabled?(podfile_properties) end ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] -ENV['RCT_USE_RN_DEP'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' -ENV['RCT_USE_PREBUILT_RNCORE'] ||= '0' if podfile_properties['ios.buildReactNativeFromSource'] == 'true' +ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' +ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true' ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false' platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4' From 35d32516ea4cb9f8270ca9ba0fba2d131b0a7e0c Mon Sep 17 00:00:00 2001 From: Alan Hughes Date: Thu, 7 May 2026 19:25:03 +0100 Subject: [PATCH 12/18] [chore] lock files [skip ci] --- apps/bare-expo/ios/Podfile.lock | 4 ++-- apps/expo-go/ios/Podfile.lock | 12 ++++++------ pnpm-lock.yaml | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/bare-expo/ios/Podfile.lock b/apps/bare-expo/ios/Podfile.lock index 855e8eea6777b0..4be0bafc42b818 100644 --- a/apps/bare-expo/ios/Podfile.lock +++ b/apps/bare-expo/ios/Podfile.lock @@ -3856,7 +3856,7 @@ EXTERNAL SOURCES: RNReanimated: :path: "../../../node_modules/.pnpm/react-native-reanimated@4.3.0_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_c36a92bb9a27c676b0bae54fbc6a1908/node_modules/react-native-reanimated" RNScreens: - :path: "../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.1_react-native@0.85.3_@babel+core@7.29.0_@react-native_1106fa305397b6dce5495e57c42d635a/node_modules/react-native-screens" + :path: "../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.3_react-native@0.85.3_@babel+core@7.29.0_@react-native_d946f5d10f696c25c0f95066694ac89d/node_modules/react-native-screens" RNSVG: :path: "../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-pres_492c03827e778ae24445fe49da301b55/node_modules/react-native-svg" RNWorklets: @@ -4054,7 +4054,7 @@ SPEC CHECKSUMS: RNDateTimePicker: b9e20c2a3af26f4ab10646359777205bbad1fdac RNGestureHandler: c84901d120acdae2f6f27b5889a7cf144e64e6ec RNReanimated: b64e22b2ee046cd2dcb2a25d134eff25f64eba0d - RNScreens: c476f5f41b7c4ddce3e73f838c23d40c5e33384c + RNScreens: 9d8bbdc7185cc51e594567e50d87c674ccee3e9c RNSVG: 04044c3abcf177fd674a1a3d13097efa1adebcbe RNWorklets: edcd0af162eba9fb81af89a4761f1af35086d1cc TestExpoUi: e376582270047f880c7e44afc7f912c97b14da54 diff --git a/apps/expo-go/ios/Podfile.lock b/apps/expo-go/ios/Podfile.lock index 35127e9031b1b9..aafbade3d96a3c 100644 --- a/apps/expo-go/ios/Podfile.lock +++ b/apps/expo-go/ios/Podfile.lock @@ -3694,7 +3694,7 @@ PODS: - RNWorklets - SocketRocket - Yoga - - RNScreens (4.25.0-beta.1): + - RNScreens (4.25.0-beta.3): - boost - DoubleConversion - fast_float @@ -3721,10 +3721,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNScreens/common (= 4.25.0-beta.1) + - RNScreens/common (= 4.25.0-beta.3) - SocketRocket - Yoga - - RNScreens/common (4.25.0-beta.1): + - RNScreens/common (4.25.0-beta.3): - boost - DoubleConversion - fast_float @@ -4242,7 +4242,7 @@ DEPENDENCIES: - "RNDateTimePicker (from `../../../node_modules/.pnpm/@react-native-community+datetimepicker@9.1.0_expo@packages+expo_react-native@0.85.3_@ba_4da8b598fd3fe2232b688159ab685884/node_modules/@react-native-community/datetimepicker`)" - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.31.1_react-native@0.85.3_@babel+core@7.29.0_@react-nativ_e5f24f573130d9ef91edaa3a7b5d2446/node_modules/react-native-gesture-handler`)" - "RNReanimated (from `../../../node_modules/.pnpm/react-native-reanimated@4.3.0_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_c36a92bb9a27c676b0bae54fbc6a1908/node_modules/react-native-reanimated`)" - - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.1_react-native@0.85.3_@babel+core@7.29.0_@react-native_1106fa305397b6dce5495e57c42d635a/node_modules/react-native-screens`)" + - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.3_react-native@0.85.3_@babel+core@7.29.0_@react-native_d946f5d10f696c25c0f95066694ac89d/node_modules/react-native-screens`)" - "RNSVG (from `../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-pres_492c03827e778ae24445fe49da301b55/node_modules/react-native-svg`)" - "RNWorklets (from `../../../node_modules/.pnpm/react-native-worklets@0.8.3_patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89_42b4111e02dad0db2c0db5ed881424fc/node_modules/react-native-worklets`)" - SocketRocket (~> 0.7.1) @@ -4624,7 +4624,7 @@ EXTERNAL SOURCES: RNReanimated: :path: "../../../node_modules/.pnpm/react-native-reanimated@4.3.0_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_c36a92bb9a27c676b0bae54fbc6a1908/node_modules/react-native-reanimated" RNScreens: - :path: "../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.1_react-native@0.85.3_@babel+core@7.29.0_@react-native_1106fa305397b6dce5495e57c42d635a/node_modules/react-native-screens" + :path: "../../../node_modules/.pnpm/react-native-screens@4.25.0-beta.3_react-native@0.85.3_@babel+core@7.29.0_@react-native_d946f5d10f696c25c0f95066694ac89d/node_modules/react-native-screens" RNSVG: :path: "../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.85.3_@babel+core@7.29.0_@react-native+jest-pres_492c03827e778ae24445fe49da301b55/node_modules/react-native-svg" RNWorklets: @@ -4824,7 +4824,7 @@ SPEC CHECKSUMS: RNDateTimePicker: 73ffdd45f0ce1d00ff981031679a05206e619fdc RNGestureHandler: f0d7f370292ab1ff422eac5a6cbae6feef14bb98 RNReanimated: cb64fa4c41430e6ffd03d5fac7662c2927e0c3eb - RNScreens: 16bd039e76f91145275890a1e1cf848b98c1da7a + RNScreens: 4e2c5f6f16b001928717ed8e508f929544137a4f RNSVG: c9d7c940ad9655eba72c5b9ca7b017c95bb58083 RNWorklets: 057f16d520cd6d64f85e0dcd7565ed3f673ae9dc SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce1e667cc101e9..5bfc4a04e970bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18877,7 +18877,9 @@ snapshots: metro-runtime: 0.84.4 transitivePeerDependencies: - '@babel/core' + - bufferutil - supports-color + - utf-8-validate '@react-native/normalize-colors@0.74.89': {} From d7b4e5edff4bf2e619d2c2f16d158798c6d592ef Mon Sep 17 00:00:00 2001 From: Alan Hughes Date: Thu, 7 May 2026 19:29:24 +0100 Subject: [PATCH 13/18] Publish packages @expo/ui@56.0.3 expo-symbols@56.0.5 expo-router@56.1.0 expo-modules-core@56.0.4 expo-linear-gradient@56.0.4 expo-calendar@56.0.4 expo-brownfield@56.0.4 expo-app-metrics@56.0.4 expo@56.0.0-preview.6 create-expo@3.7.3 @expo/metro-config@56.0.4 @expo/cli@56.0.6 expo-template-default@56.0.6 expo-template-tabs@56.0.6 expo-template-blank@56.0.6 expo-template-blank-typescript@56.0.6 expo-template-bare-minimum@56.0.6 @expo/log-box@56.0.5 expo-asset@56.0.5 expo-constants@56.0.5 expo-task-manager@56.0.4 expo-build-properties@56.0.4 expo-dev-menu@56.0.4 expo-dev-launcher@56.0.4 expo-widgets@56.0.4 patch-project@56.0.6 expo-background-task@56.0.4 expo-background-fetch@56.0.4 expo-sharing@56.0.4 expo-processing@56.0.4 expo-observe@56.0.4 expo-notifications@56.0.4 expo-location@56.0.4 expo-insights@56.0.4 expo-image-picker@56.0.4 expo-image-manipulator@56.0.4 expo-dev-client@56.0.4 expo-updates@56.0.5 --- apps/expo-go/ios/Podfile.lock | 98 +++++++++---------- packages/@expo/cli/CHANGELOG.md | 6 ++ packages/@expo/cli/package.json | 6 +- packages/@expo/log-box/CHANGELOG.md | 4 + packages/@expo/log-box/android/build.gradle | 4 +- packages/@expo/log-box/package.json | 2 +- packages/@expo/metro-config/CHANGELOG.md | 4 + packages/@expo/metro-config/package.json | 2 +- packages/@expo/metro-runtime/package.json | 2 +- packages/@expo/router-server/package.json | 2 +- packages/babel-preset-expo/package.json | 2 +- packages/create-expo/CHANGELOG.md | 4 + packages/create-expo/package.json | 2 +- packages/expo-app-metrics/package.json | 2 +- packages/expo-asset/CHANGELOG.md | 4 + packages/expo-asset/android/build.gradle | 4 +- packages/expo-asset/package.json | 4 +- packages/expo-auth-session/package.json | 2 +- packages/expo-background-fetch/CHANGELOG.md | 4 + .../android/build.gradle | 4 +- packages/expo-background-fetch/package.json | 4 +- packages/expo-background-task/CHANGELOG.md | 4 + .../expo-background-task/android/build.gradle | 4 +- packages/expo-background-task/package.json | 4 +- packages/expo-brownfield/CHANGELOG.md | 8 +- packages/expo-brownfield/android/build.gradle | 4 +- packages/expo-brownfield/package.json | 4 +- packages/expo-build-properties/CHANGELOG.md | 4 + packages/expo-build-properties/package.json | 2 +- packages/expo-calendar/CHANGELOG.md | 4 + packages/expo-calendar/android/build.gradle | 4 +- packages/expo-calendar/package.json | 2 +- packages/expo-constants/CHANGELOG.md | 4 + packages/expo-constants/android/build.gradle | 4 +- packages/expo-constants/package.json | 2 +- packages/expo-dev-client/CHANGELOG.md | 4 + packages/expo-dev-client/android/build.gradle | 4 +- packages/expo-dev-client/package.json | 6 +- packages/expo-dev-launcher/CHANGELOG.md | 4 + .../expo-dev-launcher/android/build.gradle | 4 +- packages/expo-dev-launcher/package.json | 4 +- packages/expo-dev-menu/CHANGELOG.md | 4 + packages/expo-dev-menu/android/build.gradle | 4 +- packages/expo-dev-menu/package.json | 2 +- packages/expo-image-manipulator/CHANGELOG.md | 4 + .../android/build.gradle | 4 +- packages/expo-image-manipulator/package.json | 2 +- packages/expo-image-picker/CHANGELOG.md | 4 + .../expo-image-picker/android/build.gradle | 4 +- packages/expo-image-picker/package.json | 2 +- packages/expo-insights/android/build.gradle | 4 +- packages/expo-insights/package.json | 2 +- packages/expo-linear-gradient/CHANGELOG.md | 8 +- .../expo-linear-gradient/android/build.gradle | 4 +- packages/expo-linear-gradient/package.json | 2 +- packages/expo-linking/package.json | 2 +- packages/expo-location/CHANGELOG.md | 4 + packages/expo-location/android/build.gradle | 4 +- packages/expo-location/package.json | 2 +- packages/expo-module-template/$package.json | 2 +- packages/expo-modules-core/CHANGELOG.md | 4 + .../expo-modules-core/android/build.gradle | 4 +- packages/expo-modules-core/package.json | 2 +- packages/expo-notifications/CHANGELOG.md | 4 + .../expo-notifications/android/build.gradle | 4 +- packages/expo-notifications/package.json | 4 +- packages/expo-observe/package.json | 4 +- packages/expo-processing/package.json | 2 +- packages/expo-router/CHANGELOG.md | 10 +- packages/expo-router/android/build.gradle | 4 +- packages/expo-router/package.json | 10 +- packages/expo-sharing/CHANGELOG.md | 4 + packages/expo-sharing/android/build.gradle | 4 +- packages/expo-sharing/package.json | 2 +- packages/expo-symbols/CHANGELOG.md | 8 +- packages/expo-symbols/package.json | 2 +- packages/expo-task-manager/CHANGELOG.md | 4 + .../expo-task-manager/android/build.gradle | 4 +- packages/expo-task-manager/package.json | 2 +- packages/expo-ui/CHANGELOG.md | 4 + packages/expo-ui/android/build.gradle | 4 +- packages/expo-ui/package.json | 2 +- packages/expo-updates/CHANGELOG.md | 4 + packages/expo-updates/android/build.gradle | 4 +- packages/expo-updates/package.json | 2 +- packages/expo-widgets/CHANGELOG.md | 4 + packages/expo-widgets/package.json | 4 +- packages/expo/CHANGELOG.md | 4 + packages/expo/android/build.gradle | 4 +- packages/expo/bundledNativeModules.json | 48 ++++----- packages/expo/package.json | 14 +-- packages/patch-project/CHANGELOG.md | 4 + packages/patch-project/package.json | 2 +- pnpm-lock.yaml | 54 +++++----- .../expo-template-bare-minimum/package.json | 4 +- .../package.json | 4 +- templates/expo-template-blank/package.json | 4 +- templates/expo-template-default/package.json | 12 +-- templates/expo-template-tabs/package.json | 10 +- 99 files changed, 352 insertions(+), 232 deletions(-) diff --git a/apps/expo-go/ios/Podfile.lock b/apps/expo-go/ios/Podfile.lock index aafbade3d96a3c..091aad224da2d6 100644 --- a/apps/expo-go/ios/Podfile.lock +++ b/apps/expo-go/ios/Podfile.lock @@ -11,7 +11,7 @@ PODS: - ExpoModulesTestCore - EXApplication (56.0.3): - ExpoModulesCore - - EXConstants (56.0.4): + - EXConstants (56.0.5): - ExpoModulesCore - EXJSONUtils (56.0.0) - EXJSONUtils/Tests (56.0.0) @@ -20,7 +20,7 @@ PODS: - EXManifests/Tests (56.0.2): - ExpoModulesCore - ExpoModulesTestCore - - Expo (56.0.0-preview.5): + - Expo (56.0.0-preview.6): - boost - DoubleConversion - ExpoModulesCore @@ -52,7 +52,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - Expo/Tests (56.0.0-preview.5): + - Expo/Tests (56.0.0-preview.6): - boost - DoubleConversion - ExpoModulesCore @@ -85,16 +85,16 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ExpoAsset (56.0.4): + - ExpoAsset (56.0.5): - ExpoModulesCore - ExpoAudio (56.0.3): - ExpoModulesCore - - ExpoBackgroundFetch (56.0.3): + - ExpoBackgroundFetch (56.0.4): - ExpoModulesCore - - ExpoBackgroundTask (56.0.3): + - ExpoBackgroundTask (56.0.4): - ExpoModulesCore - ExpoTaskManager - - ExpoBackgroundTask/Tests (56.0.3): + - ExpoBackgroundTask/Tests (56.0.4): - ExpoModulesCore - ExpoModulesTestCore - ExpoTaskManager @@ -106,7 +106,7 @@ PODS: - ExpoModulesCore - ExpoBrightness (56.0.3): - ExpoModulesCore - - ExpoCalendar (56.0.3): + - ExpoCalendar (56.0.4): - ExpoModulesCore - ExpoCamera (56.0.3): - ExpoModulesCore @@ -158,14 +158,14 @@ PODS: - SDWebImageAVIFCoder (~> 0.11.0) - SDWebImageSVGCoder (~> 1.7.0) - SDWebImageWebPCoder (~> 0.14.6) - - ExpoImageManipulator (56.0.3): + - ExpoImageManipulator (56.0.4): - ExpoModulesCore - SDWebImageWebPCoder - - ExpoImagePicker (56.0.3): + - ExpoImagePicker (56.0.4): - ExpoModulesCore - ExpoKeepAwake (56.0.3): - ExpoModulesCore - - ExpoLinearGradient (56.0.3): + - ExpoLinearGradient (56.0.4): - ExpoModulesCore - ExpoLinking (56.0.3): - ExpoModulesCore @@ -173,9 +173,9 @@ PODS: - ExpoModulesCore - ExpoLocalization (56.0.3): - ExpoModulesCore - - ExpoLocation (56.0.3): + - ExpoLocation (56.0.4): - ExpoModulesCore - - ExpoLogBox (56.0.4): + - ExpoLogBox (56.0.5): - React-Core - ExpoMailComposer (56.0.3): - ExpoModulesCore @@ -186,7 +186,7 @@ PODS: - ExpoModulesCore - ExpoModulesTestCore - React-Core - - ExpoModulesCore (56.0.3): + - ExpoModulesCore (56.0.4): - boost - DoubleConversion - ExpoModulesJSI @@ -216,7 +216,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ExpoModulesCore/Tests (56.0.3): + - ExpoModulesCore/Tests (56.0.4): - boost - DoubleConversion - ExpoModulesJSI @@ -260,27 +260,27 @@ PODS: - Nimble (~> 13.0.0) - Quick (~> 7.3.0) - React-hermes - - ExpoModulesWorklets (56.0.3): + - ExpoModulesWorklets (56.0.4): - ExpoModulesCore - ExpoModulesJSI - - ExpoModulesWorkletsAdapter (56.0.3): + - ExpoModulesWorkletsAdapter (56.0.4): - ExpoModulesCore - ExpoModulesJSI - ExpoModulesWorklets - RNWorklets - ExpoNetwork (56.0.3): - ExpoModulesCore - - ExpoNotifications (56.0.3): + - ExpoNotifications (56.0.4): - ExpoModulesCore - - ExpoNotifications/Tests (56.0.3): + - ExpoNotifications/Tests (56.0.4): - ExpoModulesCore - ExpoModulesTestCore - ExpoPrint (56.0.3): - ExpoModulesCore - - ExpoRouter (56.0.4): + - ExpoRouter (56.1.0): - ExpoModulesCore - RNScreens - - ExpoRouter/Tests (56.0.4): + - ExpoRouter/Tests (56.1.0): - ExpoModulesCore - ExpoModulesTestCore - RNScreens @@ -319,7 +319,7 @@ PODS: - ExpoModulesCore - ExpoSensors (56.0.3): - ExpoModulesCore - - ExpoSharing (56.0.3): + - ExpoSharing (56.0.4): - ExpoModulesCore - ExpoSMS (56.0.3): - ExpoModulesCore @@ -329,20 +329,20 @@ PODS: - ExpoModulesCore - ExpoStoreReview (56.0.3): - ExpoModulesCore - - ExpoSymbols (56.0.4): + - ExpoSymbols (56.0.5): - ExpoModulesCore - ExpoSystemUI (56.0.4): - ExpoModulesCore - - ExpoTaskManager (56.0.3): + - ExpoTaskManager (56.0.4): - ExpoModulesCore - UMAppLoader - - ExpoTaskManager/Tests (56.0.3): + - ExpoTaskManager/Tests (56.0.4): - ExpoModulesCore - ExpoModulesTestCore - UMAppLoader - ExpoTrackingTransparency (56.0.3): - ExpoModulesCore - - ExpoUI (56.0.2): + - ExpoUI (56.0.3): - ExpoModulesCore - ExpoModulesWorklets - React-RCTFabric @@ -354,7 +354,7 @@ PODS: - ExpoModulesCore - EXStructuredHeaders (56.0.0) - EXStructuredHeaders/Tests (56.0.0) - - EXUpdates (56.0.4): + - EXUpdates (56.0.5): - boost - DoubleConversion - EASClient @@ -388,7 +388,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - EXUpdates/Tests (56.0.4): + - EXUpdates/Tests (56.0.5): - boost - DoubleConversion - EASClient @@ -4642,19 +4642,19 @@ SPEC CHECKSUMS: DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb EASClient: 2321f8d99fa86c710a6f68e017f3b54366baed9f EXApplication: e6040c92edc5522accd62852342e6b14742d42c0 - EXConstants: 04f4be37792aa3917244c2209ee4b6bb974a18c1 + EXConstants: 40ef72d504bb4fb716356b2d2ea3b706ee81e76d EXJSONUtils: dba2755f4e24009eaf87a876b2d615ea06c16e42 EXManifests: e20226d12c44cb2d27fca73c274287ff0012b40b - Expo: da6725459b92e8c5f5a5c0995fcb08147b35367f - ExpoAsset: 52087fc68b9ebe9fa189d4c130919dd7ff345e92 + Expo: 29cfaf3d3f20824e35554c8123ee583ad4483fd1 + ExpoAsset: 45b495ad7c9ee655ac727eab9195ab69db9615ab ExpoAudio: fc809158cb86bdad608e8a224331cfb5481d8ea3 - ExpoBackgroundFetch: f647fb54235f1f0bb74451139f094b4c2395c0e1 - ExpoBackgroundTask: be1f4116803962b96e0bc999497d569ae51d518e + ExpoBackgroundFetch: 7ef18d566281354dd3cee6310fbabfb03c8517f8 + ExpoBackgroundTask: e313fa84896cd3a86593e3c808fbf8215a2f1e00 ExpoBattery: 4fbebca8ce0ee2bb4038efbcfa24d763012af07d ExpoBlob: 3e896c97726abf49bdecf63151e09fb4f7e21195 ExpoBlur: caddd80171e5f8f3581ff3d865e99c6465047240 ExpoBrightness: e394ebb59feb3191a0b0db7453861b3d3431381f - ExpoCalendar: e59d3481da0e50151a80a31e21039240cc22b56d + ExpoCalendar: fcf3a20e5228541c7b060fd563d337a83860a19b ExpoCamera: 90595ff52b7cfccf9590a80e23e938e846c112ae ExpoCameraBarcodeScanning: e43e457bb457ce1dfb88b2d812e9457c825bd05c ExpoCellular: 9549bde58e5c8978c342d0a3dfbfc839c44a38c5 @@ -4670,45 +4670,45 @@ SPEC CHECKSUMS: ExpoGlassEffect: 7d4233dc0727ee2b28dd757eda70e1b6abf662fd ExpoHaptics: 89364cf3c3ca2cfd54cafed42f3be3169bab6d42 ExpoImage: 59f71ed6d030241ffadead114064cfd01bd0dc12 - ExpoImageManipulator: bbe6550472b04cdeb9d2161a61600dc1e544d024 - ExpoImagePicker: 3d6e508fd099fc0dbe5620423c8bd22f268c589d + ExpoImageManipulator: ecbacb557e20ec53adb71981cd93314daa8de449 + ExpoImagePicker: d2b6382f243bd2fa26184c4c16801ec6bd6e5490 ExpoKeepAwake: 359c47a1d9ccc3a3c519bca6e39562cce230c5bb - ExpoLinearGradient: 646dbfbd67cefcf75df7ea2115770605fd99db22 + ExpoLinearGradient: 16c2b9c6105444883d34958d573725de1293b8d0 ExpoLinking: 4ff9681a924c3dd4f4e5a2f32a33085e6a3ec7f1 ExpoLocalAuthentication: 64e8c5756df07c8a89f078293ec17899c1325a43 ExpoLocalization: 74b7a2319781fd14f5db01e932c7c3a075ea1b4b - ExpoLocation: 97b584a2f86d56914a0bb7eb6c2add2bfb2581a4 - ExpoLogBox: b916f43d9ebb6cf537c1fec32a7b0c428e4c645b + ExpoLocation: 8d9edece087b82fe9ff2fee8923bf14d357b074c + ExpoLogBox: 3d06486e52b87bd361e05c993b96bc9a6ecdedec ExpoMailComposer: e202b670f62063851ed74c964034037312d523a8 ExpoMediaLibrary: ee2d74d5e52154305b8229dcb5c4319c84f30311 - ExpoModulesCore: 0435b4a32c7c349f499fde499ba7a72a6231ed24 + ExpoModulesCore: 0d77a2de27d2358598cbc93c721fa951bd6c8424 ExpoModulesJSI: 15a25b2948cdfe04bced3e08566a34877fe3cc1e ExpoModulesTestCore: 5660ab6b5928747366d4946580622a578865696a - ExpoModulesWorklets: 03afe05752b44f35d2c0903525e786b468e6390a - ExpoModulesWorkletsAdapter: 35eb5936e68c82e9fbd8c766bd3e67ea7dda62cf + ExpoModulesWorklets: d607309c356375d45e919a12a94f15e418603adc + ExpoModulesWorkletsAdapter: 1c95f525648e755df7407311d4ef20cf7791f891 ExpoNetwork: 6c8e0cc425a2c7f6591fabcab16417506441242c - ExpoNotifications: b719e208007d0296b19a7b8f2cc57851a6ccd2fa + ExpoNotifications: f860fc3daa5585b31fc128e3368ac20b42536ee8 ExpoPrint: 6b5bcac4492908b7e28144c2e7265c1c5ee4ade0 - ExpoRouter: 556058ce6c966e545029e793e4305a88262b1bb6 + ExpoRouter: 0df827bda2ade565926bbe47463462289a4ad57e ExpoScreenCapture: f23a26d9fda8c42c77e7a818a1e20e3e8b94134b ExpoScreenOrientation: 1e3a088b300c7f0d1520679a6c3660fc4738081a ExpoSecureStore: 4d1c0303f8ead59766d7466c3c14d0ce4336fc0f ExpoSensors: 4ed48ba1a8d48e236fd22a966b77498188f8f48c - ExpoSharing: 73e46ca6e450c0801ed2738a297ae2d1084f3815 + ExpoSharing: 5523a31f7767d77c233201cdc51ffb7f714fa04e ExpoSMS: 2cebfd889706da39a397d20c8a68abb0ce7f185d ExpoSpeech: fe3706df8653ab8c16ff88251e33fab79b07a420 ExpoSQLite: 35cd83a1d83122736bf3f39e99020588a8b00848 ExpoStoreReview: f785057aececd9c63a113c69a82b491e5f90694e - ExpoSymbols: 848b9d47bfbaf58173f36de961b426ded5712b5f + ExpoSymbols: f83c91f2897d37102b98b9224c603095630be9d0 ExpoSystemUI: 6f9eddf66c31d074c402ba4a9e5cd2320edda37f - ExpoTaskManager: 2b9822b3848be769172d70d5a2e5e228ff39c9c9 + ExpoTaskManager: c1ae4dd1421e2b3e1b1f4e46e92593c4e3ca1422 ExpoTrackingTransparency: dbdb87acf9ae2d85cb6c70f70a9d87d706949efd - ExpoUI: 53fb4b34e5d1e073ab68a243e0a60b270f0a3410 + ExpoUI: 8aca108741d3e81b4193224df31637019a395640 ExpoVideo: fa20020308f9f8e3458c05c7216d139d47fc1b32 ExpoVideoThumbnails: 116c2563d2bd3a1e98326a267020e25fea8af79e ExpoWebBrowser: fb9b5a94ebaa3483987f4acf4af6fd85c401df3e EXStructuredHeaders: 9e89bcdd636ae2ecb59995cfba3230f5d7547c08 - EXUpdates: 79d810e752407d931b570065d835b2afe44cd952 + EXUpdates: 78a930221095c48ef7612d0a71802df1f8fbed59 EXUpdatesInterface: 25408a97d682355eb9fb37e5aa6e22caece1881f fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 FBLazyVector: 473b935415b82ae4f7f9aa9d5b3378491143ccbf diff --git a/packages/@expo/cli/CHANGELOG.md b/packages/@expo/cli/CHANGELOG.md index 3cd454f28ba875..ab4934e850a34d 100644 --- a/packages/@expo/cli/CHANGELOG.md +++ b/packages/@expo/cli/CHANGELOG.md @@ -8,6 +8,12 @@ ### 🐛 Bug fixes +### 💡 Others + +## 56.0.6 — 2026-05-07 + +### 🐛 Bug fixes + - Drop obsolete webview installation check ([#45489](https://github.com/expo/expo/pull/45489) by [@kitten](https://github.com/kitten)) ### 💡 Others diff --git a/packages/@expo/cli/package.json b/packages/@expo/cli/package.json index 83fbc33d870e9b..614b391f195c89 100644 --- a/packages/@expo/cli/package.json +++ b/packages/@expo/cli/package.json @@ -1,6 +1,6 @@ { "name": "@expo/cli", - "version": "56.0.5", + "version": "56.0.6", "description": "The Expo CLI", "main": "main.js", "bin": { @@ -57,9 +57,9 @@ "@expo/image-utils": "workspace:^0.9.0", "@expo/inline-modules": "workspace:0.0.4", "@expo/json-file": "workspace:^10.1.0", - "@expo/log-box": "workspace:56.0.4", + "@expo/log-box": "workspace:56.0.5", "@expo/metro": "~56.0.0", - "@expo/metro-config": "workspace:~56.0.3", + "@expo/metro-config": "workspace:~56.0.4", "@expo/metro-file-map": "workspace:56.0.0-2", "@expo/osascript": "workspace:^2.5.0", "@expo/package-manager": "workspace:^1.11.0", diff --git a/packages/@expo/log-box/CHANGELOG.md b/packages/@expo/log-box/CHANGELOG.md index 92a373b4184bb1..f7fbb232846afc 100644 --- a/packages/@expo/log-box/CHANGELOG.md +++ b/packages/@expo/log-box/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.5 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.4 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/@expo/log-box/android/build.gradle b/packages/@expo/log-box/android/build.gradle index 4f87944402f9a5..8f6f5e7e009d7b 100644 --- a/packages/@expo/log-box/android/build.gradle +++ b/packages/@expo/log-box/android/build.gradle @@ -6,7 +6,7 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.4' +version = '56.0.5' expoModule { canBePublished false @@ -18,7 +18,7 @@ android { namespace "expo.modules.logbox" defaultConfig { versionCode 1 - versionName "56.0.4" + versionName "56.0.5" buildConfigField "boolean", "EXPO_UNSTABLE_LOG_BOX", isEnabled ? "true" : "false" } diff --git a/packages/@expo/log-box/package.json b/packages/@expo/log-box/package.json index 57b5a3ec2a2dd6..2f2417c4d4c626 100644 --- a/packages/@expo/log-box/package.json +++ b/packages/@expo/log-box/package.json @@ -1,6 +1,6 @@ { "name": "@expo/log-box", - "version": "56.0.4", + "version": "56.0.5", "main": "app/index.ts", "scripts": { "start": "expo start", diff --git a/packages/@expo/metro-config/CHANGELOG.md b/packages/@expo/metro-config/CHANGELOG.md index 2bd4d9e4e41100..5236ce533528d6 100644 --- a/packages/@expo/metro-config/CHANGELOG.md +++ b/packages/@expo/metro-config/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +### 💡 Others + - Drop obsolete `EXPO_USE_EXOTIC` flag warning ([#45494](https://github.com/expo/expo/pull/45494) by [@kitten](https://github.com/kitten)) - Fall back to our own Babel cache key with custom Babel transformer ([#45495](https://github.com/expo/expo/pull/45495) by [@kitten](https://github.com/kitten)) diff --git a/packages/@expo/metro-config/package.json b/packages/@expo/metro-config/package.json index 84c7a7015cd226..9a767718e5160b 100644 --- a/packages/@expo/metro-config/package.json +++ b/packages/@expo/metro-config/package.json @@ -1,6 +1,6 @@ { "name": "@expo/metro-config", - "version": "56.0.3", + "version": "56.0.4", "description": "A Metro config for running React Native projects with the Metro bundler", "main": "build/ExpoMetroConfig.js", "types": "build/ExpoMetroConfig.d.ts", diff --git a/packages/@expo/metro-runtime/package.json b/packages/@expo/metro-runtime/package.json index be7b6a4fd45462..24dc106efc8ec4 100644 --- a/packages/@expo/metro-runtime/package.json +++ b/packages/@expo/metro-runtime/package.json @@ -49,7 +49,7 @@ } }, "dependencies": { - "@expo/log-box": "workspace:56.0.4", + "@expo/log-box": "workspace:56.0.5", "anser": "^1.4.9", "stacktrace-parser": "^0.1.10", "pretty-format": "^29.7.0", diff --git a/packages/@expo/router-server/package.json b/packages/@expo/router-server/package.json index 12cb0d596d04f9..f66d737da0e157 100644 --- a/packages/@expo/router-server/package.json +++ b/packages/@expo/router-server/package.json @@ -36,7 +36,7 @@ "peerDependencies": { "@expo/metro-runtime": "workspace:^56.0.4", "expo": "*", - "expo-constants": "workspace:^56.0.4", + "expo-constants": "workspace:^56.0.5", "expo-font": "workspace:^56.0.3", "expo-router": "*", "expo-server": "workspace:^56.0.0", diff --git a/packages/babel-preset-expo/package.json b/packages/babel-preset-expo/package.json index ff0bc6712ba02a..2cd61a306b069e 100644 --- a/packages/babel-preset-expo/package.json +++ b/packages/babel-preset-expo/package.json @@ -41,7 +41,7 @@ "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", - "expo-widgets": "workspace:^56.0.3", + "expo-widgets": "workspace:^56.0.4", "react-refresh": ">=0.14.0 <1.0.0" }, "peerDependenciesMeta": { diff --git a/packages/create-expo/CHANGELOG.md b/packages/create-expo/CHANGELOG.md index 9b3b39d6006ee1..56d3fbf4988aad 100644 --- a/packages/create-expo/CHANGELOG.md +++ b/packages/create-expo/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 3.7.3 — 2026-05-07 + +### 💡 Others + - Drop automatically setting `node-linker=hoisted` for pnpm ([#45491](https://github.com/expo/expo/pull/45491) by [@kitten](https://github.com/kitten)) ## 3.7.2 — 2026-05-06 diff --git a/packages/create-expo/package.json b/packages/create-expo/package.json index 860e06d9862f77..a1e7aaf156023d 100644 --- a/packages/create-expo/package.json +++ b/packages/create-expo/package.json @@ -1,6 +1,6 @@ { "name": "create-expo", - "version": "3.7.2", + "version": "3.7.3", "bin": "./bin/create-expo.js", "main": "build", "description": "Create universal Expo apps", diff --git a/packages/expo-app-metrics/package.json b/packages/expo-app-metrics/package.json index 5f5414c2e276e4..2ad28d158c496f 100644 --- a/packages/expo-app-metrics/package.json +++ b/packages/expo-app-metrics/package.json @@ -1,7 +1,7 @@ { "name": "expo-app-metrics", "title": "Expo App Metrics", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo module that collects app startup, frame rate, memory, and session metrics", "main": "src/index.ts", "types": "build/index.d.ts", diff --git a/packages/expo-asset/CHANGELOG.md b/packages/expo-asset/CHANGELOG.md index 13db5dd8dadf6a..dfc4afb4faff4f 100644 --- a/packages/expo-asset/CHANGELOG.md +++ b/packages/expo-asset/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.5 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.4 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-asset/android/build.gradle b/packages/expo-asset/android/build.gradle index 2fbb01f07d0c34..885e64d56facb6 100644 --- a/packages/expo-asset/android/build.gradle +++ b/packages/expo-asset/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'expo.modules.asset' -version = '56.0.4' +version = '56.0.5' android { namespace "expo.modules.asset" defaultConfig { versionCode 1 - versionName "56.0.4" + versionName "56.0.5" } } diff --git a/packages/expo-asset/package.json b/packages/expo-asset/package.json index 406819174343b2..14f921326a62b7 100644 --- a/packages/expo-asset/package.json +++ b/packages/expo-asset/package.json @@ -1,6 +1,6 @@ { "name": "expo-asset", - "version": "56.0.4", + "version": "56.0.5", "description": "An Expo universal module to download assets and pass them into other APIs", "main": "build/index.js", "types": "build/index.d.ts", @@ -49,7 +49,7 @@ }, "dependencies": { "@expo/image-utils": "workspace:^0.9.0", - "expo-constants": "workspace:~56.0.4" + "expo-constants": "workspace:~56.0.5" }, "devDependencies": { "@testing-library/react-native": "^13.3.0", diff --git a/packages/expo-auth-session/package.json b/packages/expo-auth-session/package.json index a990d7ab7ca9d5..b318d313306145 100644 --- a/packages/expo-auth-session/package.json +++ b/packages/expo-auth-session/package.json @@ -34,7 +34,7 @@ "homepage": "https://docs.expo.dev/versions/latest/sdk/auth-session", "dependencies": { "expo-application": "workspace:~56.0.3", - "expo-constants": "workspace:~56.0.4", + "expo-constants": "workspace:~56.0.5", "expo-crypto": "workspace:~56.0.3", "expo-linking": "workspace:~56.0.3", "expo-web-browser": "workspace:~56.0.4", diff --git a/packages/expo-background-fetch/CHANGELOG.md b/packages/expo-background-fetch/CHANGELOG.md index f91acb95cc3c55..63fff6f9a20ad7 100644 --- a/packages/expo-background-fetch/CHANGELOG.md +++ b/packages/expo-background-fetch/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-background-fetch/android/build.gradle b/packages/expo-background-fetch/android/build.gradle index 08bbf5230c1405..32cb6f7bb2f882 100644 --- a/packages/expo-background-fetch/android/build.gradle +++ b/packages/expo-background-fetch/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.backgroundfetch" defaultConfig { versionCode 23 - versionName "56.0.3" + versionName "56.0.4" consumerProguardFiles("proguard-rules.pro") } } diff --git a/packages/expo-background-fetch/package.json b/packages/expo-background-fetch/package.json index 19663da7a304c3..96d82253978283 100644 --- a/packages/expo-background-fetch/package.json +++ b/packages/expo-background-fetch/package.json @@ -1,6 +1,6 @@ { "name": "expo-background-fetch", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo universal module for BackgroundFetch API", "main": "build/BackgroundFetch.js", "types": "build/BackgroundFetch.d.ts", @@ -32,7 +32,7 @@ "license": "MIT", "homepage": "https://docs.expo.dev/versions/latest/sdk/background-fetch/", "dependencies": { - "expo-task-manager": "workspace:~56.0.3" + "expo-task-manager": "workspace:~56.0.4" }, "devDependencies": { "@types/node": "^22.14.0", diff --git a/packages/expo-background-task/CHANGELOG.md b/packages/expo-background-task/CHANGELOG.md index 809677fed02075..599a17531034b6 100644 --- a/packages/expo-background-task/CHANGELOG.md +++ b/packages/expo-background-task/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-background-task/android/build.gradle b/packages/expo-background-task/android/build.gradle index aeeaabc2c4792d..931ad63020923c 100644 --- a/packages/expo-background-task/android/build.gradle +++ b/packages/expo-background-task/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.backgroundtask" defaultConfig { versionCode 23 - versionName "56.0.3" + versionName "56.0.4" consumerProguardFiles("proguard-rules.pro") } } diff --git a/packages/expo-background-task/package.json b/packages/expo-background-task/package.json index 21abfc5baf3264..fb9064d019f506 100644 --- a/packages/expo-background-task/package.json +++ b/packages/expo-background-task/package.json @@ -1,6 +1,6 @@ { "name": "expo-background-task", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo Android and iOS module for Background Task APIs", "main": "build/BackgroundTask.js", "types": "build/BackgroundTask.d.ts", @@ -31,7 +31,7 @@ "license": "MIT", "homepage": "https://docs.expo.dev/versions/latest/sdk/background-task/", "dependencies": { - "expo-task-manager": "workspace:~56.0.3" + "expo-task-manager": "workspace:~56.0.4" }, "devDependencies": { "expo": "workspace:*", diff --git a/packages/expo-brownfield/CHANGELOG.md b/packages/expo-brownfield/CHANGELOG.md index a0400f28e287c3..a0cd14f8a3831e 100644 --- a/packages/expo-brownfield/CHANGELOG.md +++ b/packages/expo-brownfield/CHANGELOG.md @@ -8,10 +8,14 @@ ### 🐛 Bug fixes -- Adjust CLI Android/iOS library file discovery to remove symlink following ([#44280](https://github.com/expo/expo/pull/44280) by [@kitten](https://github.com/kitten)) - ### 💡 Others +## 56.0.4 — 2026-05-07 + +### 🐛 Bug fixes + +- Adjust CLI Android/iOS library file discovery to remove symlink following ([#44280](https://github.com/expo/expo/pull/44280) by [@kitten](https://github.com/kitten)) + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-brownfield/android/build.gradle b/packages/expo-brownfield/android/build.gradle index 0285c802e51f9f..4c260bd5a6d0bb 100644 --- a/packages/expo-brownfield/android/build.gradle +++ b/packages/expo-brownfield/android/build.gradle @@ -4,7 +4,7 @@ plugins { } group = 'expo.modules.brownfield' -version = '56.0.3' +version = '56.0.4' expoModule { canBePublished false @@ -14,7 +14,7 @@ android { namespace "expo.modules.brownfield" defaultConfig { versionCode 1 - versionName '56.0.3' + versionName '56.0.4' } } diff --git a/packages/expo-brownfield/package.json b/packages/expo-brownfield/package.json index a4e3825850bb91..68dd6cc7a788a2 100644 --- a/packages/expo-brownfield/package.json +++ b/packages/expo-brownfield/package.json @@ -1,6 +1,6 @@ { "name": "expo-brownfield", - "version": "56.0.3", + "version": "56.0.4", "description": "Toolkit and APIs for adding brownfield setup to Expo projects", "main": "./build/index.js", "types": "./build/index.d.ts", @@ -53,7 +53,7 @@ "chalk": "^4.1.2", "commander": "^14.0.3", "diff": "^5.2.0", - "expo-build-properties": "workspace:~56.0.3", + "expo-build-properties": "workspace:~56.0.4", "expo-manifests": "workspace:~56.0.1", "ora": "^5.4.1", "prompts": "^2.4.2" diff --git a/packages/expo-build-properties/CHANGELOG.md b/packages/expo-build-properties/CHANGELOG.md index 0a00d1d0854ec8..25fef35af70fb9 100644 --- a/packages/expo-build-properties/CHANGELOG.md +++ b/packages/expo-build-properties/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-build-properties/package.json b/packages/expo-build-properties/package.json index 18a53bcab3ac69..1c2d5866a163f9 100644 --- a/packages/expo-build-properties/package.json +++ b/packages/expo-build-properties/package.json @@ -1,6 +1,6 @@ { "name": "expo-build-properties", - "version": "56.0.3", + "version": "56.0.4", "description": "Config plugin to customize native build properties on prebuild", "main": "build/withBuildProperties.js", "types": "build/withBuildProperties.d.ts", diff --git a/packages/expo-calendar/CHANGELOG.md b/packages/expo-calendar/CHANGELOG.md index 1453ca1360f729..6e9c2dfffe011c 100644 --- a/packages/expo-calendar/CHANGELOG.md +++ b/packages/expo-calendar/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-calendar/android/build.gradle b/packages/expo-calendar/android/build.gradle index 0089c9b3f641d4..48dd2b2a5b0a52 100644 --- a/packages/expo-calendar/android/build.gradle +++ b/packages/expo-calendar/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.calendar" defaultConfig { versionCode 17 - versionName '56.0.3' + versionName '56.0.4' } } diff --git a/packages/expo-calendar/package.json b/packages/expo-calendar/package.json index 2881edf57855ba..24276b8c051a93 100644 --- a/packages/expo-calendar/package.json +++ b/packages/expo-calendar/package.json @@ -1,6 +1,6 @@ { "name": "expo-calendar", - "version": "56.0.3", + "version": "56.0.4", "description": "Provides an API for interacting with the device's system calendars, events, reminders, and associated records.", "main": "build/Calendar.js", "types": "build/Calendar.d.ts", diff --git a/packages/expo-constants/CHANGELOG.md b/packages/expo-constants/CHANGELOG.md index 5ccdc5220372e3..ffea314dcd944b 100644 --- a/packages/expo-constants/CHANGELOG.md +++ b/packages/expo-constants/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.5 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.4 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-constants/android/build.gradle b/packages/expo-constants/android/build.gradle index 1a920d8c1993ef..771c1873725b10 100644 --- a/packages/expo-constants/android/build.gradle +++ b/packages/expo-constants/android/build.gradle @@ -6,7 +6,7 @@ plugins { apply from: "../scripts/get-app-config-android.gradle" group = 'host.exp.exponent' -version = '56.0.4' +version = '56.0.5' expoModule { // We can't prebuild the module because we need to apply `get-app-config-android.gradle` script. @@ -17,6 +17,6 @@ android { namespace "expo.modules.constants" defaultConfig { versionCode 33 - versionName "56.0.4" + versionName "56.0.5" } } diff --git a/packages/expo-constants/package.json b/packages/expo-constants/package.json index 661a2e51bf61e0..8bfcf53349002b 100644 --- a/packages/expo-constants/package.json +++ b/packages/expo-constants/package.json @@ -1,6 +1,6 @@ { "name": "expo-constants", - "version": "56.0.4", + "version": "56.0.5", "description": "Provides system information that remains constant throughout the lifetime of your app.", "main": "build/Constants.js", "types": "build/Constants.d.ts", diff --git a/packages/expo-dev-client/CHANGELOG.md b/packages/expo-dev-client/CHANGELOG.md index bd68fd656cd2d3..cca0ec71a7cafa 100644 --- a/packages/expo-dev-client/CHANGELOG.md +++ b/packages/expo-dev-client/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-dev-client/android/build.gradle b/packages/expo-dev-client/android/build.gradle index 01002465f126b6..b12ec6c48d99b2 100644 --- a/packages/expo-dev-client/android/build.gradle +++ b/packages/expo-dev-client/android/build.gradle @@ -8,13 +8,13 @@ expoModule { } group = "host.exp.exponent" -version = "56.0.3" +version = "56.0.4" android { namespace "expo.modules.devclient" defaultConfig { versionCode 1 - versionName "56.0.3" + versionName "56.0.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/packages/expo-dev-client/package.json b/packages/expo-dev-client/package.json index 304a990fda1821..297b3d0e1a90b2 100644 --- a/packages/expo-dev-client/package.json +++ b/packages/expo-dev-client/package.json @@ -1,6 +1,6 @@ { "name": "expo-dev-client", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo Development Client", "main": "build/DevClient.js", "types": "build/DevClient.d.ts", @@ -31,8 +31,8 @@ "license": "MIT", "homepage": "https://docs.expo.dev/versions/latest/sdk/dev-client/", "dependencies": { - "expo-dev-launcher": "workspace:56.0.3", - "expo-dev-menu": "workspace:56.0.3", + "expo-dev-launcher": "workspace:56.0.4", + "expo-dev-menu": "workspace:56.0.4", "expo-dev-menu-interface": "workspace:56.0.0", "expo-manifests": "workspace:~56.0.1", "expo-updates-interface": "workspace:~56.0.1" diff --git a/packages/expo-dev-launcher/CHANGELOG.md b/packages/expo-dev-launcher/CHANGELOG.md index ce2429fd5dc86b..a3835da13bf996 100644 --- a/packages/expo-dev-launcher/CHANGELOG.md +++ b/packages/expo-dev-launcher/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-dev-launcher/android/build.gradle b/packages/expo-dev-launcher/android/build.gradle index c057ffc4837d76..41290fc74f4e58 100644 --- a/packages/expo-dev-launcher/android/build.gradle +++ b/packages/expo-dev-launcher/android/build.gradle @@ -26,13 +26,13 @@ expoModule { } group = "host.exp.exponent" -version = "56.0.3" +version = "56.0.4" android { namespace "expo.modules.devlauncher" defaultConfig { versionCode 9 - versionName "56.0.3" + versionName "56.0.4" } buildTypes { diff --git a/packages/expo-dev-launcher/package.json b/packages/expo-dev-launcher/package.json index 9b21136b33551a..8b0b30d9227064 100644 --- a/packages/expo-dev-launcher/package.json +++ b/packages/expo-dev-launcher/package.json @@ -1,7 +1,7 @@ { "name": "expo-dev-launcher", "title": "Expo Development Launcher", - "version": "56.0.3", + "version": "56.0.4", "description": "Pre-release version of the Expo development launcher package for testing.", "repository": { "type": "git", @@ -20,7 +20,7 @@ "homepage": "https://docs.expo.dev", "dependencies": { "@expo/schema-utils": "workspace:^56.0.0", - "expo-dev-menu": "workspace:56.0.3", + "expo-dev-menu": "workspace:56.0.4", "expo-manifests": "workspace:~56.0.1" }, "peerDependencies": { diff --git a/packages/expo-dev-menu/CHANGELOG.md b/packages/expo-dev-menu/CHANGELOG.md index 131eda6286475c..cd06250a0f8aa1 100644 --- a/packages/expo-dev-menu/CHANGELOG.md +++ b/packages/expo-dev-menu/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-dev-menu/android/build.gradle b/packages/expo-dev-menu/android/build.gradle index 6c1e1177669fa8..e480864661d267 100644 --- a/packages/expo-dev-menu/android/build.gradle +++ b/packages/expo-dev-menu/android/build.gradle @@ -12,7 +12,7 @@ apply plugin: 'expo-module-gradle-plugin' apply plugin: 'org.jetbrains.kotlin.plugin.compose' group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' def hasDevLauncher = findProject(":expo-dev-launcher") != null def configureInRelease = findProperty("expo.devmenu.configureInRelease") == "true" @@ -29,7 +29,7 @@ android { defaultConfig { versionCode 10 - versionName '56.0.3' + versionName '56.0.4' } buildTypes { diff --git a/packages/expo-dev-menu/package.json b/packages/expo-dev-menu/package.json index f27f848d802613..c1b0efa8ba431b 100644 --- a/packages/expo-dev-menu/package.json +++ b/packages/expo-dev-menu/package.json @@ -1,6 +1,6 @@ { "name": "expo-dev-menu", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo/React Native module with the developer menu.", "main": "build/DevMenu.js", "types": "build/DevMenu.d.ts", diff --git a/packages/expo-image-manipulator/CHANGELOG.md b/packages/expo-image-manipulator/CHANGELOG.md index acdf7f8ed39bd5..bf0a149dcc6533 100644 --- a/packages/expo-image-manipulator/CHANGELOG.md +++ b/packages/expo-image-manipulator/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-image-manipulator/android/build.gradle b/packages/expo-image-manipulator/android/build.gradle index 380e7899c22665..b8806a0767a9be 100644 --- a/packages/expo-image-manipulator/android/build.gradle +++ b/packages/expo-image-manipulator/android/build.gradle @@ -4,12 +4,12 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.imagemanipulator" defaultConfig { versionCode 23 - versionName "56.0.3" + versionName "56.0.4" } } diff --git a/packages/expo-image-manipulator/package.json b/packages/expo-image-manipulator/package.json index 6f9260235e2a45..9f708538d9ccd9 100644 --- a/packages/expo-image-manipulator/package.json +++ b/packages/expo-image-manipulator/package.json @@ -1,6 +1,6 @@ { "name": "expo-image-manipulator", - "version": "56.0.3", + "version": "56.0.4", "description": "Provides functions that let you manipulation images on the local file system, eg: resize, crop.", "main": "src/index.ts", "types": "build/index.d.ts", diff --git a/packages/expo-image-picker/CHANGELOG.md b/packages/expo-image-picker/CHANGELOG.md index 1a72ba77c10dc3..348c934d4a51dd 100644 --- a/packages/expo-image-picker/CHANGELOG.md +++ b/packages/expo-image-picker/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-image-picker/android/build.gradle b/packages/expo-image-picker/android/build.gradle index 376538155fdd4d..f6c16d4c8d64c4 100644 --- a/packages/expo-image-picker/android/build.gradle +++ b/packages/expo-image-picker/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.imagepicker" defaultConfig { versionCode 22 - versionName "56.0.3" + versionName "56.0.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } testOptions { diff --git a/packages/expo-image-picker/package.json b/packages/expo-image-picker/package.json index 9156f3ee7408b5..1d1e214d186f55 100644 --- a/packages/expo-image-picker/package.json +++ b/packages/expo-image-picker/package.json @@ -1,6 +1,6 @@ { "name": "expo-image-picker", - "version": "56.0.3", + "version": "56.0.4", "description": "Provides access to the system's UI for selecting images and videos from the phone's library or taking a photo with the camera.", "main": "build/ImagePicker.js", "types": "build/ImagePicker.d.ts", diff --git a/packages/expo-insights/android/build.gradle b/packages/expo-insights/android/build.gradle index aaf4ff8c93b62a..b6094b3f2aefb5 100644 --- a/packages/expo-insights/android/build.gradle +++ b/packages/expo-insights/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.insights" defaultConfig { versionCode 1 - versionName "56.0.3" + versionName "56.0.4" } } diff --git a/packages/expo-insights/package.json b/packages/expo-insights/package.json index efb1a0526ff714..41171df6a957f7 100644 --- a/packages/expo-insights/package.json +++ b/packages/expo-insights/package.json @@ -1,7 +1,7 @@ { "name": "expo-insights", "title": "Expo Insights", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo module that offers developers insight into the usage data of the app", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/packages/expo-linear-gradient/CHANGELOG.md b/packages/expo-linear-gradient/CHANGELOG.md index 53012b630cb13b..a3be3e8423e28f 100644 --- a/packages/expo-linear-gradient/CHANGELOG.md +++ b/packages/expo-linear-gradient/CHANGELOG.md @@ -6,12 +6,16 @@ ### 🎉 New features -- Add macOS support ([#45448](https://github.com/expo/expo/pull/45448) by [@gabrieldonadel](https://github.com/gabrieldonadel)) - ### 🐛 Bug fixes ### 💡 Others +## 56.0.4 — 2026-05-07 + +### 🎉 New features + +- Add macOS support ([#45448](https://github.com/expo/expo/pull/45448) by [@gabrieldonadel](https://github.com/gabrieldonadel)) + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-linear-gradient/android/build.gradle b/packages/expo-linear-gradient/android/build.gradle index 1a94221fb13780..bb6dcc5137d87e 100644 --- a/packages/expo-linear-gradient/android/build.gradle +++ b/packages/expo-linear-gradient/android/build.gradle @@ -4,12 +4,12 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.lineargradient" defaultConfig { versionCode 17 - versionName "56.0.3" + versionName "56.0.4" } } diff --git a/packages/expo-linear-gradient/package.json b/packages/expo-linear-gradient/package.json index a7e7d02036d6d1..3438f98f694031 100644 --- a/packages/expo-linear-gradient/package.json +++ b/packages/expo-linear-gradient/package.json @@ -1,6 +1,6 @@ { "name": "expo-linear-gradient", - "version": "56.0.3", + "version": "56.0.4", "description": "Provides a React component that renders a gradient view.", "main": "build/LinearGradient.js", "types": "build/LinearGradient.d.ts", diff --git a/packages/expo-linking/package.json b/packages/expo-linking/package.json index c67424d7a96aea..ece9ded4f25cfa 100644 --- a/packages/expo-linking/package.json +++ b/packages/expo-linking/package.json @@ -37,7 +37,7 @@ "license": "MIT", "homepage": "https://docs.expo.dev/versions/latest/sdk/linking", "dependencies": { - "expo-constants": "workspace:~56.0.4", + "expo-constants": "workspace:~56.0.5", "invariant": "^2.2.4" }, "devDependencies": { diff --git a/packages/expo-location/CHANGELOG.md b/packages/expo-location/CHANGELOG.md index 19e2874b797566..3835521726e2d5 100644 --- a/packages/expo-location/CHANGELOG.md +++ b/packages/expo-location/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-location/android/build.gradle b/packages/expo-location/android/build.gradle index efb08a57f88397..40fbb61b9b5017 100644 --- a/packages/expo-location/android/build.gradle +++ b/packages/expo-location/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.location" defaultConfig { versionCode 29 - versionName "56.0.3" + versionName "56.0.4" consumerProguardFiles("proguard-rules.pro") } } diff --git a/packages/expo-location/package.json b/packages/expo-location/package.json index 6153b092fad076..1fed3606c48b96 100644 --- a/packages/expo-location/package.json +++ b/packages/expo-location/package.json @@ -1,6 +1,6 @@ { "name": "expo-location", - "version": "56.0.3", + "version": "56.0.4", "description": "Allows reading geolocation information from the device. Your app can poll for the current location or subscribe to location update events.", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/packages/expo-module-template/$package.json b/packages/expo-module-template/$package.json index e6ff6f321bba91..21385859c12368 100644 --- a/packages/expo-module-template/$package.json +++ b/packages/expo-module-template/$package.json @@ -34,7 +34,7 @@ "babel-preset-expo": "~55.0.8", "eslint": "~9.39.4", "eslint-config-universe": "^15.0.3", - "expo": "^56.0.0-preview.5", + "expo": "^56.0.0-preview.6", "jest": "^29.7.0", "jest-expo": "~55.0.9", "prettier": "^3.0.0", diff --git a/packages/expo-modules-core/CHANGELOG.md b/packages/expo-modules-core/CHANGELOG.md index 0bd53f0d61e477..aa9577a4d699dc 100644 --- a/packages/expo-modules-core/CHANGELOG.md +++ b/packages/expo-modules-core/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-modules-core/android/build.gradle b/packages/expo-modules-core/android/build.gradle index d03bd416c17172..49c7b6e79e5c05 100644 --- a/packages/expo-modules-core/android/build.gradle +++ b/packages/expo-modules-core/android/build.gradle @@ -29,7 +29,7 @@ if (shouldIncludeCompose) { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' def isExpoModulesCoreTests = { Gradle gradle = getGradle() @@ -96,7 +96,7 @@ android { defaultConfig { consumerProguardFiles 'proguard-rules.pro' versionCode 1 - versionName "56.0.3" + versionName "56.0.4" buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\"" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", "true" diff --git a/packages/expo-modules-core/package.json b/packages/expo-modules-core/package.json index abdb4b9913f5b4..04f7f8001418a8 100644 --- a/packages/expo-modules-core/package.json +++ b/packages/expo-modules-core/package.json @@ -1,6 +1,6 @@ { "name": "expo-modules-core", - "version": "56.0.3", + "version": "56.0.4", "description": "The core of Expo Modules architecture", "main": "src/index.ts", "types": "build/index.d.ts", diff --git a/packages/expo-notifications/CHANGELOG.md b/packages/expo-notifications/CHANGELOG.md index 63ce5fe6503432..f8da1fc966fe18 100644 --- a/packages/expo-notifications/CHANGELOG.md +++ b/packages/expo-notifications/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-notifications/android/build.gradle b/packages/expo-notifications/android/build.gradle index a532cf34dd843f..efb852fa0f392a 100644 --- a/packages/expo-notifications/android/build.gradle +++ b/packages/expo-notifications/android/build.gradle @@ -5,13 +5,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.notifications" defaultConfig { versionCode 21 - versionName '56.0.3' + versionName '56.0.4' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/packages/expo-notifications/package.json b/packages/expo-notifications/package.json index 186dca8345bb42..80f4a2e4182d2c 100644 --- a/packages/expo-notifications/package.json +++ b/packages/expo-notifications/package.json @@ -1,6 +1,6 @@ { "name": "expo-notifications", - "version": "56.0.3", + "version": "56.0.4", "description": "Provides an API to fetch push notification tokens and to present, schedule, receive, and respond to notifications.", "main": "build/index.js", "types": "build/index.d.ts", @@ -46,7 +46,7 @@ "abort-controller": "^3.0.0", "badgin": "^1.1.5", "expo-application": "workspace:~56.0.3", - "expo-constants": "workspace:~56.0.4" + "expo-constants": "workspace:~56.0.5" }, "devDependencies": { "@types/node": "^22.14.0", diff --git a/packages/expo-observe/package.json b/packages/expo-observe/package.json index f4527764f6dbee..df20f19bc2a6b3 100644 --- a/packages/expo-observe/package.json +++ b/packages/expo-observe/package.json @@ -1,7 +1,7 @@ { "name": "expo-observe", "title": "Expo Observe", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo module that dispatches collected app metrics to EAS Observe", "main": "src/index.ts", "types": "build/index.d.ts", @@ -32,7 +32,7 @@ "author": "650 Industries, Inc.", "license": "MIT", "dependencies": { - "expo-app-metrics": "workspace:~56.0.3", + "expo-app-metrics": "workspace:~56.0.4", "expo-eas-client": "workspace:~56.0.0" }, "devDependencies": { diff --git a/packages/expo-processing/package.json b/packages/expo-processing/package.json index a375e4e2a6fca6..c56181e4e0f1d4 100644 --- a/packages/expo-processing/package.json +++ b/packages/expo-processing/package.json @@ -1,6 +1,6 @@ { "name": "expo-processing", - "version": "56.0.3", + "version": "56.0.4", "description": "Utilities for using Processing.js on Expo", "main": "index.js", "keywords": [ diff --git a/packages/expo-router/CHANGELOG.md b/packages/expo-router/CHANGELOG.md index db4e1905c99d89..de687fdd59e090 100644 --- a/packages/expo-router/CHANGELOG.md +++ b/packages/expo-router/CHANGELOG.md @@ -6,12 +6,18 @@ ### 🎉 New features -- Upgrade react-native-screens version to 4.25.0-beta.3. ([#45482](https://github.com/expo/expo/pull/45482) by [@Ubax](https://github.com/Ubax)) - ### 🐛 Bug fixes ### 💡 Others +## 56.1.0 — 2026-05-07 + +### 🎉 New features + +- Upgrade react-native-screens version to 4.25.0-beta.3. ([#45482](https://github.com/expo/expo/pull/45482) by [@Ubax](https://github.com/Ubax)) + +### 💡 Others + - Move `@jest/globals` to `devDependencies` ([#45469](https://github.com/expo/expo/pull/45469) by [@kitten](https://github.com/kitten)) ## 56.0.4 — 2026-05-06 diff --git a/packages/expo-router/android/build.gradle b/packages/expo-router/android/build.gradle index 281a2037e56efe..e77fb01fc46819 100644 --- a/packages/expo-router/android/build.gradle +++ b/packages/expo-router/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'expo.modules.router' -version = '56.0.4' +version = '56.1.0' android { namespace "expo.modules.router" defaultConfig { versionCode 1 - versionName "56.0.4" + versionName "56.1.0" } lintOptions { abortOnError false diff --git a/packages/expo-router/package.json b/packages/expo-router/package.json index 37e63a7130401d..87a7920a5e65f6 100644 --- a/packages/expo-router/package.json +++ b/packages/expo-router/package.json @@ -1,6 +1,6 @@ { "name": "expo-router", - "version": "56.0.4", + "version": "56.1.0", "description": "Expo Router is a file-based router for React Native and web applications.", "author": "650 Industries, Inc.", "license": "MIT", @@ -88,11 +88,11 @@ "expo" ], "peerDependencies": { - "@expo/log-box": "workspace:56.0.4", + "@expo/log-box": "workspace:56.0.5", "@expo/metro-runtime": "workspace:^56.0.4", "@testing-library/react-native": ">= 13.2.0", "expo": "*", - "expo-constants": "workspace:^56.0.4", + "expo-constants": "workspace:^56.0.5", "expo-linking": "workspace:^56.0.3", "react": "*", "react-dom": "*", @@ -151,7 +151,7 @@ "dependencies": { "@expo/metro-runtime": "workspace:^56.0.4", "@expo/schema-utils": "workspace:^56.0.0", - "@expo/ui": "workspace:^56.0.1", + "@expo/ui": "workspace:^56.0.3", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", @@ -164,7 +164,7 @@ "expo-glass-effect": "workspace:^56.0.4", "expo-image": "workspace:^56.0.4", "expo-server": "workspace:^56.0.0", - "expo-symbols": "workspace:^56.0.4", + "expo-symbols": "workspace:^56.0.5", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", diff --git a/packages/expo-sharing/CHANGELOG.md b/packages/expo-sharing/CHANGELOG.md index ec43d0385dadea..b4cd0c37fa2853 100644 --- a/packages/expo-sharing/CHANGELOG.md +++ b/packages/expo-sharing/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-sharing/android/build.gradle b/packages/expo-sharing/android/build.gradle index 627f97740f7ebf..a135287f32b117 100644 --- a/packages/expo-sharing/android/build.gradle +++ b/packages/expo-sharing/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.sharing" defaultConfig { versionCode 16 - versionName '56.0.3' + versionName '56.0.4' } } diff --git a/packages/expo-sharing/package.json b/packages/expo-sharing/package.json index f69f999fac3cc4..6feff891e70094 100644 --- a/packages/expo-sharing/package.json +++ b/packages/expo-sharing/package.json @@ -1,6 +1,6 @@ { "name": "expo-sharing", - "version": "56.0.3", + "version": "56.0.4", "description": "Provides a way to share files directly with other compatible applications.", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/packages/expo-symbols/CHANGELOG.md b/packages/expo-symbols/CHANGELOG.md index fe291b1acc6fb7..c7266a74a6752b 100644 --- a/packages/expo-symbols/CHANGELOG.md +++ b/packages/expo-symbols/CHANGELOG.md @@ -8,10 +8,14 @@ ### 🐛 Bug fixes -- Fix `useFonts` from `@expo-google-fonts/material-symbols` using an undeclared dependency on `expo-font` and `react` ([#45471](https://github.com/expo/expo/pull/45471) by [@kitten](https://github.com/kitten)) - ### 💡 Others +## 56.0.5 — 2026-05-07 + +### 🐛 Bug fixes + +- Fix `useFonts` from `@expo-google-fonts/material-symbols` using an undeclared dependency on `expo-font` and `react` ([#45471](https://github.com/expo/expo/pull/45471) by [@kitten](https://github.com/kitten)) + ## 56.0.4 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-symbols/package.json b/packages/expo-symbols/package.json index d00de8a41e7f10..54a3a64a2a88c2 100644 --- a/packages/expo-symbols/package.json +++ b/packages/expo-symbols/package.json @@ -1,6 +1,6 @@ { "name": "expo-symbols", - "version": "56.0.4", + "version": "56.0.5", "description": "Provides access to the SF Symbols library on iOS, and Material Symbols on Android and web, for Expo and React Native apps.", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/packages/expo-task-manager/CHANGELOG.md b/packages/expo-task-manager/CHANGELOG.md index 556ca95fea7bac..2dd3cee4943d40 100644 --- a/packages/expo-task-manager/CHANGELOG.md +++ b/packages/expo-task-manager/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-task-manager/android/build.gradle b/packages/expo-task-manager/android/build.gradle index ca1f640064e4d5..a77289903ebad0 100644 --- a/packages/expo-task-manager/android/build.gradle +++ b/packages/expo-task-manager/android/build.gradle @@ -4,13 +4,13 @@ plugins { } group = 'host.exp.exponent' -version = '56.0.3' +version = '56.0.4' android { namespace "expo.modules.taskmanager" defaultConfig { versionCode 23 - versionName "56.0.3" + versionName "56.0.4" } } diff --git a/packages/expo-task-manager/package.json b/packages/expo-task-manager/package.json index ba8a2b5e926abd..0f193487095159 100644 --- a/packages/expo-task-manager/package.json +++ b/packages/expo-task-manager/package.json @@ -1,6 +1,6 @@ { "name": "expo-task-manager", - "version": "56.0.3", + "version": "56.0.4", "description": "Expo module that provides support for tasks that can run in the background.", "main": "build/TaskManager.js", "types": "build/TaskManager.d.ts", diff --git a/packages/expo-ui/CHANGELOG.md b/packages/expo-ui/CHANGELOG.md index e44dde28701c34..972153d75ec1e9 100644 --- a/packages/expo-ui/CHANGELOG.md +++ b/packages/expo-ui/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.3 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.2 — 2026-05-06 ### 🐛 Bug fixes diff --git a/packages/expo-ui/android/build.gradle b/packages/expo-ui/android/build.gradle index 7a9076383d884a..1789451ba54421 100644 --- a/packages/expo-ui/android/build.gradle +++ b/packages/expo-ui/android/build.gradle @@ -12,13 +12,13 @@ apply plugin: 'expo-module-gradle-plugin' apply plugin: 'org.jetbrains.kotlin.plugin.compose' group = 'expo.modules.ui' -version = '56.0.2' +version = '56.0.3' android { namespace "expo.modules.ui" defaultConfig { versionCode 1 - versionName "56.0.2" + versionName "56.0.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildFeatures { diff --git a/packages/expo-ui/package.json b/packages/expo-ui/package.json index dfa4eee7b084fc..c04e3241c98490 100644 --- a/packages/expo-ui/package.json +++ b/packages/expo-ui/package.json @@ -1,6 +1,6 @@ { "name": "@expo/ui", - "version": "56.0.2", + "version": "56.0.3", "description": "A collection of UI components", "sideEffects": [ "*.fx.js" diff --git a/packages/expo-updates/CHANGELOG.md b/packages/expo-updates/CHANGELOG.md index 469d8e6b633209..ff936bc4a8831e 100644 --- a/packages/expo-updates/CHANGELOG.md +++ b/packages/expo-updates/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.5 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.4 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-updates/android/build.gradle b/packages/expo-updates/android/build.gradle index b58c8292ff4056..4cb02d9df5e4a7 100644 --- a/packages/expo-updates/android/build.gradle +++ b/packages/expo-updates/android/build.gradle @@ -42,7 +42,7 @@ expoModule { } group = 'host.exp.exponent' -version = '56.0.4' +version = '56.0.5' // Utility method to derive boolean values from the environment or from Java properties, // and return them as strings to be used in BuildConfig fields @@ -89,7 +89,7 @@ android { namespace "expo.modules.updates" defaultConfig { versionCode 31 - versionName '56.0.4' + versionName '56.0.5' consumerProguardFiles("proguard-rules.pro") testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/packages/expo-updates/package.json b/packages/expo-updates/package.json index 74a008465d491c..ac9985713a20df 100644 --- a/packages/expo-updates/package.json +++ b/packages/expo-updates/package.json @@ -1,6 +1,6 @@ { "name": "expo-updates", - "version": "56.0.4", + "version": "56.0.5", "description": "Fetches and manages remotely-hosted assets and updates to your app's JS bundle.", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/packages/expo-widgets/CHANGELOG.md b/packages/expo-widgets/CHANGELOG.md index c8510fa120005b..f2d8650ddbb2a0 100644 --- a/packages/expo-widgets/CHANGELOG.md +++ b/packages/expo-widgets/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.4 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.3 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-widgets/package.json b/packages/expo-widgets/package.json index 822b4ba5c3ce3d..bdba72a40f5752 100644 --- a/packages/expo-widgets/package.json +++ b/packages/expo-widgets/package.json @@ -1,6 +1,6 @@ { "name": "expo-widgets", - "version": "56.0.3", + "version": "56.0.4", "description": "Widgets.", "main": "build/index.js", "types": "build/index.d.ts", @@ -32,7 +32,7 @@ "homepage": "https://docs.expo.dev/versions/latest/sdk/widgets/", "dependencies": { "@expo/plist": "workspace:^0.6.0", - "@expo/ui": "workspace:~56.0.1" + "@expo/ui": "workspace:~56.0.3" }, "devDependencies": { "@expo/spawn-async": "^1.7.2", diff --git a/packages/expo/CHANGELOG.md b/packages/expo/CHANGELOG.md index cde56320aa6b33..0b14a9ac6fb048 100644 --- a/packages/expo/CHANGELOG.md +++ b/packages/expo/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.0-preview.6 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.0-preview.5 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/expo/android/build.gradle b/packages/expo/android/build.gradle index 9f95f59f9c5ecb..87f9333a7f638e 100644 --- a/packages/expo/android/build.gradle +++ b/packages/expo/android/build.gradle @@ -10,7 +10,7 @@ buildscript { } group = 'host.exp.exponent' -version = '56.0.0-preview.5' +version = '56.0.0-preview.6' expoModule { // We can't prebuild the module because it depends on the generated files. @@ -21,7 +21,7 @@ android { namespace "expo.core" defaultConfig { versionCode 1 - versionName "56.0.0-preview.5" + versionName "56.0.0-preview.6" consumerProguardFiles("proguard-rules.pro") } testOptions { diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json index 50c67cd1a29c79..539740c2257248 100644 --- a/packages/expo/bundledNativeModules.json +++ b/packages/expo/bundledNativeModules.json @@ -2,7 +2,7 @@ "@expo/fingerprint": "~0.17.3", "@expo/metro-runtime": "~56.0.4", "@expo/vector-icons": "^15.0.2", - "@expo/ui": "~56.0.2", + "@expo/ui": "~56.0.3", "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/datetimepicker": "9.1.0", "@react-native-masked-view/masked-view": "0.3.2", @@ -16,28 +16,28 @@ "expo-analytics-amplitude": "~11.3.0", "expo-app-auth": "~11.1.0", "expo-app-loader-provider": "~8.0.0", - "expo-app-metrics": "~56.0.3", + "expo-app-metrics": "~56.0.4", "expo-apple-authentication": "~56.0.3", "expo-application": "~56.0.3", - "expo-asset": "~56.0.4", + "expo-asset": "~56.0.5", "expo-audio": "~56.0.3", "expo-auth-session": "~56.0.3", - "expo-background-fetch": "~56.0.3", - "expo-background-task": "~56.0.3", + "expo-background-fetch": "~56.0.4", + "expo-background-task": "~56.0.4", "expo-battery": "~56.0.3", "expo-blur": "~56.0.3", "expo-brightness": "~56.0.3", - "expo-brownfield": "~56.0.3", - "expo-build-properties": "~56.0.3", - "expo-calendar": "~56.0.3", + "expo-brownfield": "~56.0.4", + "expo-build-properties": "~56.0.4", + "expo-calendar": "~56.0.4", "expo-camera": "~56.0.3", "expo-cellular": "~56.0.3", "expo-checkbox": "~56.0.1", "expo-clipboard": "~56.0.3", - "expo-constants": "~56.0.4", + "expo-constants": "~56.0.5", "expo-contacts": "~56.0.3", "expo-crypto": "~56.0.3", - "expo-dev-client": "~56.0.3", + "expo-dev-client": "~56.0.4", "expo-device": "~56.0.4", "expo-document-picker": "~56.0.3", "expo-file-system": "~56.0.3", @@ -48,16 +48,16 @@ "expo-haptics": "~56.0.3", "expo-image": "~56.0.4", "expo-image-loader": "~56.0.3", - "expo-image-manipulator": "~56.0.3", - "expo-image-picker": "~56.0.3", + "expo-image-manipulator": "~56.0.4", + "expo-image-picker": "~56.0.4", "expo-intent-launcher": "~56.0.3", - "expo-insights": "~56.0.3", + "expo-insights": "~56.0.4", "expo-keep-awake": "~56.0.3", - "expo-linear-gradient": "~56.0.3", + "expo-linear-gradient": "~56.0.4", "expo-linking": "~56.0.3", "expo-local-authentication": "~56.0.3", "expo-localization": "~56.0.3", - "expo-location": "~56.0.3", + "expo-location": "~56.0.4", "expo-mail-composer": "~56.0.3", "expo-manifests": "~56.0.2", "expo-maps": "~56.0.3", @@ -65,35 +65,35 @@ "expo-media-library": "~56.0.3", "expo-mesh-gradient": "~56.0.3", "expo-module-template": "~56.0.2", - "expo-modules-core": "~56.0.3", + "expo-modules-core": "~56.0.4", "expo-navigation-bar": "~56.0.3", "expo-network": "~56.0.3", - "expo-notifications": "~56.0.3", - "expo-observe": "~56.0.3", + "expo-notifications": "~56.0.4", + "expo-observe": "~56.0.4", "expo-print": "~56.0.3", "expo-live-photo": "~56.0.3", - "expo-router": "~56.0.4", + "expo-router": "~56.1.0", "expo-screen-capture": "~56.0.3", "expo-screen-orientation": "~56.0.3", "expo-secure-store": "~56.0.3", "expo-sensors": "~56.0.3", "expo-server": "~56.0.1", - "expo-sharing": "~56.0.3", + "expo-sharing": "~56.0.4", "expo-sms": "~56.0.3", "expo-speech": "~56.0.3", "expo-splash-screen": "~56.0.3", "expo-sqlite": "~56.0.3", "expo-status-bar": "~56.0.4", "expo-store-review": "~56.0.3", - "expo-symbols": "~56.0.4", + "expo-symbols": "~56.0.5", "expo-system-ui": "~56.0.4", - "expo-task-manager": "~56.0.3", + "expo-task-manager": "~56.0.4", "expo-tracking-transparency": "~56.0.3", - "expo-updates": "~56.0.4", + "expo-updates": "~56.0.5", "expo-video-thumbnails": "~56.0.3", "expo-video": "~56.1.0", "expo-web-browser": "~56.0.4", - "expo-widgets": "~56.0.3", + "expo-widgets": "~56.0.4", "jest-expo": "~56.0.0", "lottie-react-native": "~7.3.4", "react": "19.2.3", diff --git a/packages/expo/package.json b/packages/expo/package.json index a91fd1b65093ee..5404970745e246 100644 --- a/packages/expo/package.json +++ b/packages/expo/package.json @@ -1,6 +1,6 @@ { "name": "expo", - "version": "56.0.0-preview.5", + "version": "56.0.0-preview.6", "description": "The Expo SDK", "main": "src/Expo.ts", "module": "src/Expo.ts", @@ -75,26 +75,26 @@ "homepage": "https://github.com/expo/expo/tree/main/packages/expo", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "workspace:56.0.5", + "@expo/cli": "workspace:56.0.6", "@expo/config": "workspace:~56.0.2", "@expo/config-plugins": "workspace:~56.0.2", "@expo/devtools": "workspace:56.0.2", "@expo/dom-webview": "workspace:~56.0.4", "@expo/fingerprint": "workspace:0.17.3", "@expo/local-build-cache-provider": "workspace:56.0.2", - "@expo/log-box": "workspace:56.0.4", + "@expo/log-box": "workspace:56.0.5", "@expo/metro": "~56.0.0", - "@expo/metro-config": "workspace:56.0.3", + "@expo/metro-config": "workspace:56.0.4", "@expo/vector-icons": "^15.0.2", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "workspace:~56.0.4", - "expo-asset": "workspace:~56.0.4", - "expo-constants": "workspace:~56.0.4", + "expo-asset": "workspace:~56.0.5", + "expo-constants": "workspace:~56.0.5", "expo-file-system": "workspace:~56.0.3", "expo-font": "workspace:~56.0.3", "expo-keep-awake": "workspace:~56.0.3", "expo-modules-autolinking": "workspace:56.0.2", - "expo-modules-core": "workspace:56.0.3", + "expo-modules-core": "workspace:56.0.4", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.1" diff --git a/packages/patch-project/CHANGELOG.md b/packages/patch-project/CHANGELOG.md index 0ad75faa78889c..60e2635c5d0009 100644 --- a/packages/patch-project/CHANGELOG.md +++ b/packages/patch-project/CHANGELOG.md @@ -10,6 +10,10 @@ ### 💡 Others +## 56.0.6 — 2026-05-07 + +_This version does not introduce any user-facing changes._ + ## 56.0.5 — 2026-05-06 _This version does not introduce any user-facing changes._ diff --git a/packages/patch-project/package.json b/packages/patch-project/package.json index a7e10d8198c6b6..f672617de2a94e 100644 --- a/packages/patch-project/package.json +++ b/packages/patch-project/package.json @@ -1,6 +1,6 @@ { "name": "patch-project", - "version": "56.0.5", + "version": "56.0.6", "description": "An Expo config-plugin and tool to support patch-based CNG", "main": "build/withPatchPlugin.js", "types": "build/withPatchPlugin.d.ts", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5bfc4a04e970bf..62226c5a5de6ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1798,13 +1798,13 @@ importers: specifier: workspace:^10.1.0 version: link:../json-file '@expo/log-box': - specifier: workspace:56.0.4 + specifier: workspace:56.0.5 version: link:../log-box '@expo/metro': specifier: ~56.0.0 version: 56.0.0 '@expo/metro-config': - specifier: workspace:~56.0.3 + specifier: workspace:~56.0.4 version: link:../metro-config '@expo/metro-file-map': specifier: workspace:56.0.0-2 @@ -2655,7 +2655,7 @@ importers: packages/@expo/metro-runtime: dependencies: '@expo/log-box': - specifier: workspace:56.0.4 + specifier: workspace:56.0.5 version: link:../log-box anser: specifier: ^1.4.9 @@ -2866,7 +2866,7 @@ importers: specifier: ^4.3.4 version: 4.4.3 expo-constants: - specifier: workspace:^56.0.4 + specifier: workspace:^56.0.5 version: link:../../expo-constants expo-font: specifier: workspace:^56.0.3 @@ -3087,7 +3087,7 @@ importers: specifier: ^4.3.4 version: 4.4.3 expo-widgets: - specifier: workspace:^56.0.3 + specifier: workspace:^56.0.4 version: link:../expo-widgets devDependencies: '@babel/core': @@ -3428,7 +3428,7 @@ importers: specifier: ^7.20.0 version: 7.29.2 '@expo/cli': - specifier: workspace:56.0.5 + specifier: workspace:56.0.6 version: link:../@expo/cli '@expo/config': specifier: workspace:~56.0.2 @@ -3449,13 +3449,13 @@ importers: specifier: workspace:56.0.2 version: link:../@expo/local-build-cache-provider '@expo/log-box': - specifier: workspace:56.0.4 + specifier: workspace:56.0.5 version: link:../@expo/log-box '@expo/metro': specifier: ~56.0.0 version: 56.0.0 '@expo/metro-config': - specifier: workspace:56.0.3 + specifier: workspace:56.0.4 version: link:../@expo/metro-config '@expo/vector-icons': specifier: ^15.0.2 @@ -3467,10 +3467,10 @@ importers: specifier: workspace:~56.0.4 version: link:../babel-preset-expo expo-asset: - specifier: workspace:~56.0.4 + specifier: workspace:~56.0.5 version: link:../expo-asset expo-constants: - specifier: workspace:~56.0.4 + specifier: workspace:~56.0.5 version: link:../expo-constants expo-file-system: specifier: workspace:~56.0.3 @@ -3485,7 +3485,7 @@ importers: specifier: workspace:56.0.2 version: link:../expo-modules-autolinking expo-modules-core: - specifier: workspace:56.0.3 + specifier: workspace:56.0.4 version: link:../expo-modules-core pretty-format: specifier: ^29.7.0 @@ -3619,7 +3619,7 @@ importers: specifier: workspace:^0.9.0 version: link:../@expo/image-utils expo-constants: - specifier: workspace:~56.0.4 + specifier: workspace:~56.0.5 version: link:../expo-constants react: specifier: 19.2.3 @@ -3678,7 +3678,7 @@ importers: specifier: workspace:~56.0.3 version: link:../expo-application expo-constants: - specifier: workspace:~56.0.4 + specifier: workspace:~56.0.5 version: link:../expo-constants expo-crypto: specifier: workspace:~56.0.3 @@ -3712,7 +3712,7 @@ importers: packages/expo-background-fetch: dependencies: expo-task-manager: - specifier: workspace:~56.0.3 + specifier: workspace:~56.0.4 version: link:../expo-task-manager devDependencies: '@types/node': @@ -3728,7 +3728,7 @@ importers: packages/expo-background-task: dependencies: expo-task-manager: - specifier: workspace:~56.0.3 + specifier: workspace:~56.0.4 version: link:../expo-task-manager devDependencies: '@types/node': @@ -3831,7 +3831,7 @@ importers: specifier: ^5.2.0 version: 5.2.2 expo-build-properties: - specifier: workspace:~56.0.3 + specifier: workspace:~56.0.4 version: link:../expo-build-properties expo-manifests: specifier: workspace:~56.0.1 @@ -4089,10 +4089,10 @@ importers: packages/expo-dev-client: dependencies: expo-dev-launcher: - specifier: workspace:56.0.3 + specifier: workspace:56.0.4 version: link:../expo-dev-launcher expo-dev-menu: - specifier: workspace:56.0.3 + specifier: workspace:56.0.4 version: link:../expo-dev-menu expo-dev-menu-interface: specifier: workspace:56.0.0 @@ -4123,7 +4123,7 @@ importers: specifier: workspace:^56.0.0 version: link:../@expo/schema-utils expo-dev-menu: - specifier: workspace:56.0.3 + specifier: workspace:56.0.4 version: link:../expo-dev-menu expo-manifests: specifier: workspace:~56.0.1 @@ -4580,7 +4580,7 @@ importers: packages/expo-linking: dependencies: expo-constants: - specifier: workspace:~56.0.4 + specifier: workspace:~56.0.5 version: link:../expo-constants invariant: specifier: ^2.2.4 @@ -4987,7 +4987,7 @@ importers: specifier: workspace:~56.0.3 version: link:../expo-application expo-constants: - specifier: workspace:~56.0.4 + specifier: workspace:~56.0.5 version: link:../expo-constants react: specifier: 19.2.3 @@ -5015,7 +5015,7 @@ importers: packages/expo-observe: dependencies: expo-app-metrics: - specifier: workspace:~56.0.3 + specifier: workspace:~56.0.4 version: link:../expo-app-metrics expo-eas-client: specifier: workspace:~56.0.0 @@ -5060,7 +5060,7 @@ importers: packages/expo-router: dependencies: '@expo/log-box': - specifier: workspace:56.0.4 + specifier: workspace:56.0.5 version: link:../@expo/log-box '@expo/metro-runtime': specifier: workspace:^56.0.4 @@ -5069,7 +5069,7 @@ importers: specifier: workspace:^56.0.0 version: link:../@expo/schema-utils '@expo/ui': - specifier: workspace:^56.0.1 + specifier: workspace:^56.0.3 version: link:../expo-ui '@radix-ui/react-slot': specifier: ^1.2.0 @@ -5099,7 +5099,7 @@ importers: specifier: ^4.0.0 version: 4.0.0 expo-constants: - specifier: workspace:^56.0.4 + specifier: workspace:^56.0.5 version: link:../expo-constants expo-glass-effect: specifier: workspace:^56.0.4 @@ -5114,7 +5114,7 @@ importers: specifier: workspace:^56.0.0 version: link:../expo-server expo-symbols: - specifier: workspace:^56.0.4 + specifier: workspace:^56.0.5 version: link:../expo-symbols fast-deep-equal: specifier: ^3.1.3 @@ -5876,7 +5876,7 @@ importers: specifier: workspace:^0.6.0 version: link:../@expo/plist '@expo/ui': - specifier: workspace:~56.0.1 + specifier: workspace:~56.0.3 version: link:../expo-ui react: specifier: 19.2.3 diff --git a/templates/expo-template-bare-minimum/package.json b/templates/expo-template-bare-minimum/package.json index 55f5965f16f18c..8074745f5e918f 100644 --- a/templates/expo-template-bare-minimum/package.json +++ b/templates/expo-template-bare-minimum/package.json @@ -2,7 +2,7 @@ "name": "expo-template-bare-minimum", "description": "This bare project template includes a minimal setup for using unimodules with React Native.", "license": "0BSD", - "version": "56.0.5", + "version": "56.0.6", "main": "index.js", "scripts": { "start": "expo start --dev-client", @@ -11,7 +11,7 @@ "web": "expo start --web" }, "dependencies": { - "expo": "~56.0.0-preview.5", + "expo": "~56.0.0-preview.6", "expo-status-bar": "~56.0.4", "react": "19.2.3", "react-native": "0.85.3" diff --git a/templates/expo-template-blank-typescript/package.json b/templates/expo-template-blank-typescript/package.json index 56b68607787e97..2223bbeefd8bfe 100644 --- a/templates/expo-template-blank-typescript/package.json +++ b/templates/expo-template-blank-typescript/package.json @@ -2,7 +2,7 @@ "name": "expo-template-blank-typescript", "description": "The Blank project template includes the minimum dependencies to run and an empty root component.", "license": "0BSD", - "version": "56.0.5", + "version": "56.0.6", "main": "index.ts", "scripts": { "start": "expo start", @@ -11,7 +11,7 @@ "web": "expo start --web" }, "dependencies": { - "expo": "~56.0.0-preview.5", + "expo": "~56.0.0-preview.6", "expo-status-bar": "~56.0.4", "react": "19.2.3", "react-native": "0.85.3" diff --git a/templates/expo-template-blank/package.json b/templates/expo-template-blank/package.json index 52f1f4aa8ed9e5..dd3dadc50659d6 100644 --- a/templates/expo-template-blank/package.json +++ b/templates/expo-template-blank/package.json @@ -2,7 +2,7 @@ "name": "expo-template-blank", "description": "The Blank project template includes the minimum dependencies to run and an empty root component.", "license": "0BSD", - "version": "56.0.5", + "version": "56.0.6", "main": "index.js", "scripts": { "start": "expo start", @@ -11,7 +11,7 @@ "web": "expo start --web" }, "dependencies": { - "expo": "~56.0.0-preview.5", + "expo": "~56.0.0-preview.6", "expo-status-bar": "~56.0.4", "react": "19.2.3", "react-native": "0.85.3" diff --git a/templates/expo-template-default/package.json b/templates/expo-template-default/package.json index 61542483b76bdd..30861eb20dd16a 100644 --- a/templates/expo-template-default/package.json +++ b/templates/expo-template-default/package.json @@ -2,7 +2,7 @@ "name": "expo-template-default", "license": "0BSD", "main": "expo-router/entry", - "version": "56.0.5", + "version": "56.0.6", "scripts": { "start": "expo start", "reset-project": "node ./scripts/reset-project.js", @@ -12,18 +12,18 @@ "lint": "expo lint" }, "dependencies": { - "@expo/ui": "~56.0.2", - "expo": "~56.0.0-preview.5", - "expo-constants": "~56.0.4", + "@expo/ui": "~56.0.3", + "expo": "~56.0.0-preview.6", + "expo-constants": "~56.0.5", "expo-device": "~56.0.4", "expo-font": "~56.0.3", "expo-glass-effect": "~56.0.4", "expo-image": "~56.0.4", "expo-linking": "~56.0.3", - "expo-router": "~56.0.4", + "expo-router": "~56.1.0", "expo-splash-screen": "~56.0.3", "expo-status-bar": "~56.0.4", - "expo-symbols": "~56.0.4", + "expo-symbols": "~56.0.5", "expo-system-ui": "~56.0.4", "expo-web-browser": "~56.0.4", "react": "19.2.3", diff --git a/templates/expo-template-tabs/package.json b/templates/expo-template-tabs/package.json index a26973b199436f..d6360521fb20e1 100644 --- a/templates/expo-template-tabs/package.json +++ b/templates/expo-template-tabs/package.json @@ -3,7 +3,7 @@ "main": "expo-router/entry", "description": "The Tab Navigation project template includes several example screens.", "license": "0BSD", - "version": "56.0.5", + "version": "56.0.6", "scripts": { "start": "expo start", "android": "expo start --android", @@ -11,12 +11,12 @@ "web": "expo start --web" }, "dependencies": { - "expo": "~56.0.0-preview.5", - "expo-symbols": "~56.0.4", - "expo-constants": "~56.0.4", + "expo": "~56.0.0-preview.6", + "expo-symbols": "~56.0.5", + "expo-constants": "~56.0.5", "expo-font": "~56.0.3", "expo-linking": "~56.0.3", - "expo-router": "~56.0.4", + "expo-router": "~56.1.0", "expo-splash-screen": "~56.0.3", "expo-status-bar": "~56.0.4", "expo-web-browser": "~56.0.4", From 1896a043cbf2f77e20fbd621bea8ea50d8e8ea29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kosmaty?= Date: Thu, 7 May 2026 20:51:32 +0200 Subject: [PATCH 14/18] [core][Android] Speed up AS sync by generating stub PCH files (#45503) --- .../expo-modules-core/android/build.gradle | 75 +++++++++---------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/packages/expo-modules-core/android/build.gradle b/packages/expo-modules-core/android/build.gradle index 49c7b6e79e5c05..496ea64612260c 100644 --- a/packages/expo-modules-core/android/build.gradle +++ b/packages/expo-modules-core/android/build.gradle @@ -1,6 +1,5 @@ -import com.android.build.gradle.tasks.ExternalNativeBuildJsonTask -import expo.modules.plugin.gradle.ExpoModuleExtension import groovy.json.JsonSlurper +import expo.modules.plugin.gradle.ExpoModuleExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile buildscript { @@ -17,7 +16,6 @@ buildscript { classpath("org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:${kotlinVersion}") } - classpath("org.apache.commons:commons-text:1.14.0") } } @@ -265,55 +263,56 @@ if (shouldTurnWarningsIntoErrors) { } } -// Generates the PCH file during sync if it doesn't exist yet -def generatePCHTask = tasks.register("generatePCH") { - def configureTaskName = "configureCMakeDebug" - dependsOn(configureTaskName) +// Generates minimal stub PCH files from an empty header so the IDE's C++ engine +// doesn't fail during sync. Near-instant unlike the full ExpoHeader.pch. +// The actual build regenerates proper PCH files via ninja. +def cxxDir = project.file(".cxx") +def generateStubPCHTask = tasks.register("generateStubPCH") { + dependsOn("configureCMakeDebug") doLast { - reactNativeArchitectures().each { abi -> - def configureTaskNameForAbi = configureTaskName + "[" + abi + "]" - ExternalNativeBuildJsonTask configureTask = tasks.named(configureTaskNameForAbi).get() as ExternalNativeBuildJsonTask - - // Gets CxxModel for the given ABI - File cxxBuildFolder = configureTask.abi.cxxBuildFolder + if (!cxxDir.exists()) { + return + } - // Gets compile_commands.json file to find the command to generate the PCH file - File compileCommandsFile = new File(cxxBuildFolder, "compile_commands.json") - if (!compileCommandsFile.exists()) { + cxxDir.eachFileRecurse { file -> + if (file.name != "compile_commands.json") { return } - def parsedJson = new JsonSlurper().parseText(compileCommandsFile.text) - for (int i = 0; i < parsedJson.size(); i++) { - def commandObj = parsedJson[i] - - def path = commandObj.file - if (!path.endsWith("cmake_pch.hxx.cxx")) { - continue + new JsonSlurper().parseText(file.text).each { entry -> + if (!entry.file.endsWith("cmake_pch.hxx.cxx")) { + return } - def generatedFilePath = path.substring(0, path.length() - ".cxx".length()) + ".pch" - // Checks if the file already exists, and skip if so - if (new File(generatedFilePath).exists()) { - continue + def pchFile = new File(entry.file.substring(0, entry.file.length() - ".cxx".length()) + ".pch") + + if (!pchFile.exists() || pchFile.length() == 0) { + def stubHeader = new File(entry.directory, "stub_pch.hxx") + stubHeader.text = "" + + def cmd = entry.command + // Replace the forced-include path: `-Xclang -include -Xclang /cmake_pch.hxx` + .replaceAll(/-Xclang -include -Xclang [^\s]+cmake_pch\.hxx(?=\s)/, "-Xclang -include -Xclang ${stubHeader.absolutePath}") + // Replace the source file operand: `/cmake_pch.hxx.cxx` + .replaceAll(/[^\s]+cmake_pch\.hxx\.cxx/, stubHeader.absolutePath) + + def process = new ProcessBuilder(cmd.split(" ").toList()) + .directory(new File(entry.directory)) + .redirectErrorStream(true) + .start() + if (process.waitFor() != 0) { + throw new GradleException("Stub PCH generation failed: ${process.inputStream.text}") + } } - def tokenizer = new org.apache.commons.text.StringTokenizer(commandObj.command, " ") - def tokens = tokenizer.tokenList - - def workingDirFile = new File(commandObj.directory) - - providers.exec { - workingDir(providers.provider { workingDirFile }.get()) - commandLine(tokens) - }.getResult().get().assertNormalExitValue() + // Ensure PCH is older than source so ninja rebuilds the real one during build + pchFile.setLastModified(new File(entry.file).lastModified() - 1) } } } } -// This task will run on the IDE project sync, ensuring the PCH file is generated early enough tasks.register("prepareKotlinBuildScriptModel") { - dependsOn(generatePCHTask) + dependsOn(generateStubPCHTask) } From 7e9d30b1db8f61d6ccb9c5785064f6fe77680d01 Mon Sep 17 00:00:00 2001 From: Alan Hughes Date: Thu, 7 May 2026 19:53:13 +0100 Subject: [PATCH 15/18] [chore] lock files [skip ci] --- .../ios/BareExpo.xcodeproj/project.pbxproj | 4 + apps/bare-expo/ios/Podfile.lock | 142 +++++++++--------- 2 files changed, 75 insertions(+), 71 deletions(-) diff --git a/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj b/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj index 224fa5619015bd..52397667c74d97 100644 --- a/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj +++ b/apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj @@ -392,6 +392,7 @@ "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesWorklets/ExpoModulesWorklets.framework/ExpoModulesWorklets", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoPrint/ExpoPrint.framework/ExpoPrint", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoSensors/ExpoSensors.framework/ExpoSensors", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoUI/ExpoUI.framework/ExpoUI", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoVideo/ExpoVideo.framework/ExpoVideo", "${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies", @@ -422,6 +423,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesWorklets.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoPrint.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoSensors.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoUI.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoVideo.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework", @@ -564,6 +566,7 @@ "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesWorklets/ExpoModulesWorklets.framework/ExpoModulesWorklets", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoPrint/ExpoPrint.framework/ExpoPrint", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoSensors/ExpoSensors.framework/ExpoSensors", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoUI/ExpoUI.framework/ExpoUI", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoVideo/ExpoVideo.framework/ExpoVideo", "${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies", @@ -594,6 +597,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesWorklets.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoPrint.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoSensors.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoUI.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoVideo.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework", diff --git a/apps/bare-expo/ios/Podfile.lock b/apps/bare-expo/ios/Podfile.lock index 4be0bafc42b818..53363825bc5c13 100644 --- a/apps/bare-expo/ios/Podfile.lock +++ b/apps/bare-expo/ios/Podfile.lock @@ -29,7 +29,7 @@ PODS: - ExpoModulesTestCore - EXApplication (56.0.3): - ExpoModulesCore - - EXConstants (56.0.4): + - EXConstants (56.0.5): - ExpoModulesCore - EXJSONUtils (56.0.0) - EXJSONUtils/Tests (56.0.0) @@ -38,7 +38,7 @@ PODS: - EXManifests/Tests (56.0.2): - ExpoModulesCore - ExpoModulesTestCore - - Expo (56.0.0-preview.5): + - Expo (56.0.0-preview.6): - ExpoModulesCore - ExpoModulesJSI - hermes-engine @@ -64,15 +64,15 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - expo-dev-client (56.0.3): + - expo-dev-client (56.0.4): - EXManifests - expo-dev-launcher - expo-dev-menu - expo-dev-menu-interface - EXUpdatesInterface - - expo-dev-launcher (56.0.3): + - expo-dev-launcher (56.0.4): - EXManifests - - expo-dev-launcher/Main (= 56.0.3) + - expo-dev-launcher/Main (= 56.0.4) - expo-dev-menu - expo-dev-menu-interface - ExpoModulesCore @@ -101,7 +101,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - expo-dev-launcher/Main (56.0.3): + - expo-dev-launcher/Main (56.0.4): - EXManifests - expo-dev-launcher/Unsafe - expo-dev-menu @@ -132,7 +132,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - expo-dev-launcher/Tests (56.0.3): + - expo-dev-launcher/Tests (56.0.4): - EXManifests - expo-dev-menu - expo-dev-menu-interface @@ -167,7 +167,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - expo-dev-launcher/Unsafe (56.0.3): + - expo-dev-launcher/Unsafe (56.0.4): - EXManifests - expo-dev-menu - expo-dev-menu-interface @@ -197,8 +197,8 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - expo-dev-menu (56.0.3): - - expo-dev-menu/Main (= 56.0.3) + - expo-dev-menu (56.0.4): + - expo-dev-menu/Main (= 56.0.4) - hermes-engine - RCTRequired - RCTTypeSafety @@ -221,7 +221,7 @@ PODS: - ReactNativeDependencies - Yoga - expo-dev-menu-interface (56.0.1) - - expo-dev-menu/Main (56.0.3): + - expo-dev-menu/Main (56.0.4): - EXManifests - expo-dev-menu-interface - ExpoModulesCore @@ -247,7 +247,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - expo-dev-menu/Tests (56.0.3): + - expo-dev-menu/Tests (56.0.4): - ExpoModulesTestCore - hermes-engine - Nimble @@ -273,7 +273,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - expo-dev-menu/UITests (56.0.3): + - expo-dev-menu/UITests (56.0.4): - ExpoModulesTestCore - hermes-engine - RCTRequired @@ -299,7 +299,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - Expo/Tests (56.0.0-preview.5): + - Expo/Tests (56.0.0-preview.6): - ExpoModulesCore - ExpoModulesJSI - ExpoModulesTestCore @@ -332,7 +332,7 @@ PODS: - ExpoModulesCore - ExpoAppleAuthentication (56.0.3): - ExpoModulesCore - - ExpoAppMetrics (56.0.3): + - ExpoAppMetrics (56.0.4): - ExpoModulesCore - EXUpdatesInterface - hermes-engine @@ -356,7 +356,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - ExpoAppMetrics/Tests (56.0.3): + - ExpoAppMetrics/Tests (56.0.4): - ExpoModulesCore - EXUpdatesInterface - hermes-engine @@ -380,16 +380,16 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - ExpoAsset (56.0.4): + - ExpoAsset (56.0.5): - ExpoModulesCore - ExpoAudio (56.0.3): - ExpoModulesCore - - ExpoBackgroundFetch (56.0.3): + - ExpoBackgroundFetch (56.0.4): - ExpoModulesCore - - ExpoBackgroundTask (56.0.3): + - ExpoBackgroundTask (56.0.4): - ExpoModulesCore - ExpoTaskManager - - ExpoBackgroundTask/Tests (56.0.3): + - ExpoBackgroundTask/Tests (56.0.4): - ExpoModulesCore - ExpoModulesTestCore - ExpoTaskManager @@ -401,9 +401,9 @@ PODS: - ExpoModulesCore - ExpoBrightness (56.0.3): - ExpoModulesCore - - ExpoBrownfield (56.0.3): + - ExpoBrownfield (56.0.4): - ExpoModulesCore - - ExpoCalendar (56.0.3): + - ExpoCalendar (56.0.4): - ExpoModulesCore - ExpoCamera (56.0.3): - ExpoModulesCore @@ -440,11 +440,11 @@ PODS: - ExpoModulesCore - ExpoImage (56.0.4): - ExpoModulesCore - - ExpoImageManipulator (56.0.3): + - ExpoImageManipulator (56.0.4): - ExpoModulesCore - - ExpoImagePicker (56.0.3): + - ExpoImagePicker (56.0.4): - ExpoModulesCore - - ExpoInsights (56.0.3): + - ExpoInsights (56.0.4): - EASClient - ExpoModulesCore - hermes-engine @@ -470,7 +470,7 @@ PODS: - Yoga - ExpoKeepAwake (56.0.3): - ExpoModulesCore - - ExpoLinearGradient (56.0.3): + - ExpoLinearGradient (56.0.4): - ExpoModulesCore - ExpoLinking (56.0.3): - ExpoModulesCore @@ -480,9 +480,9 @@ PODS: - ExpoModulesCore - ExpoLocalization (56.0.3): - ExpoModulesCore - - ExpoLocation (56.0.3): + - ExpoLocation (56.0.4): - ExpoModulesCore - - ExpoLogBox (56.0.4): + - ExpoLogBox (56.0.5): - React-Core - ExpoMailComposer (56.0.3): - ExpoModulesCore @@ -493,7 +493,7 @@ PODS: - React-Core - ExpoMeshGradient (56.0.3): - ExpoModulesCore - - ExpoModulesCore (56.0.3): + - ExpoModulesCore (56.0.4): - ExpoModulesJSI - hermes-engine - RCTRequired @@ -530,22 +530,22 @@ PODS: - Nimble (~> 13.0.0) - Quick (~> 7.3.0) - React-hermes - - ExpoModulesWorklets (56.0.3): + - ExpoModulesWorklets (56.0.4): - ExpoModulesCore - ExpoModulesJSI - - ExpoModulesWorkletsAdapter (56.0.3): + - ExpoModulesWorkletsAdapter (56.0.4): - ExpoModulesCore - ExpoModulesJSI - ExpoModulesWorklets - RNWorklets - ExpoNetwork (56.0.3): - ExpoModulesCore - - ExpoNotifications (56.0.3): + - ExpoNotifications (56.0.4): - ExpoModulesCore - - ExpoNotifications/Tests (56.0.3): + - ExpoNotifications/Tests (56.0.4): - ExpoModulesCore - ExpoModulesTestCore - - ExpoObserve (56.0.3): + - ExpoObserve (56.0.4): - EASClient - ExpoAppMetrics - ExpoModulesCore @@ -570,7 +570,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - ExpoObserve/Tests (56.0.3): + - ExpoObserve/Tests (56.0.4): - EASClient - ExpoAppMetrics - ExpoModulesCore @@ -626,7 +626,7 @@ PODS: - ExpoModulesCore - ExpoSensors (56.0.3): - ExpoModulesCore - - ExpoSharing (56.0.3): + - ExpoSharing (56.0.4): - ExpoModulesCore - ExpoSMS (56.0.3): - ExpoModulesCore @@ -638,20 +638,20 @@ PODS: - ExpoModulesCore - ExpoStoreReview (56.0.3): - ExpoModulesCore - - ExpoSymbols (56.0.4): + - ExpoSymbols (56.0.5): - ExpoModulesCore - ExpoSystemUI (56.0.4): - ExpoModulesCore - - ExpoTaskManager (56.0.3): + - ExpoTaskManager (56.0.4): - ExpoModulesCore - UMAppLoader - - ExpoTaskManager/Tests (56.0.3): + - ExpoTaskManager/Tests (56.0.4): - ExpoModulesCore - ExpoModulesTestCore - UMAppLoader - ExpoTrackingTransparency (56.0.3): - ExpoModulesCore - - ExpoUI (56.0.2): + - ExpoUI (56.0.3): - ExpoModulesCore - ExpoModulesWorklets - React-RCTFabric @@ -666,7 +666,7 @@ PODS: - ExpoModulesCore - EXStructuredHeaders (56.0.0) - EXStructuredHeaders/Tests (56.0.0) - - EXUpdates (56.0.4): + - EXUpdates (56.0.5): - EASClient - EXManifests - ExpoModulesCore @@ -694,7 +694,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - EXUpdates/Tests (56.0.4): + - EXUpdates/Tests (56.0.5): - EASClient - EXManifests - ExpoModulesCore @@ -3304,7 +3304,7 @@ DEPENDENCIES: - ExpoTaskManager (from `../../../packages/expo-task-manager/ios`) - ExpoTaskManager/Tests (from `../../../packages/expo-task-manager/ios`) - ExpoTrackingTransparency (from `../../../packages/expo-tracking-transparency/ios`) - - ExpoUI (from `../../../packages/expo-ui/ios`) + - ExpoUI (from `../../../packages/expo-ui/ios/ExpoUI.podspec`) - ExpoVideo (from `../../../packages/expo-video/ios/ExpoVideo.podspec`) - ExpoVideoDashSupportModule (from `../modules/expo-video-dash-support-module/ios`) - ExpoVideoThumbnails (from `../../../packages/expo-video-thumbnails/ios`) @@ -3654,7 +3654,7 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-tracking-transparency/ios" ExpoUI: inhibit_warnings: false - :path: "../../../packages/expo-ui/ios" + :podspec: "../../../packages/expo-ui/ios/ExpoUI.podspec" ExpoVideo: inhibit_warnings: false :podspec: "../../../packages/expo-video/ios/ExpoVideo.podspec" @@ -3877,28 +3877,28 @@ SPEC CHECKSUMS: BenchmarkingModule: 75a52c0f605790d86e8cd73979f42693e26a5c14 EASClient: 2321f8d99fa86c710a6f68e017f3b54366baed9f EXApplication: e6040c92edc5522accd62852342e6b14742d42c0 - EXConstants: 04f4be37792aa3917244c2209ee4b6bb974a18c1 + EXConstants: 40ef72d504bb4fb716356b2d2ea3b706ee81e76d EXJSONUtils: dba2755f4e24009eaf87a876b2d615ea06c16e42 EXManifests: e20226d12c44cb2d27fca73c274287ff0012b40b - Expo: c9c213003ec48ded7db0ad3ec5777cf3b36661e6 - expo-dev-client: 0007c53337b076282e3b515b9b624a446350d026 - expo-dev-launcher: d9d76969225b39c646e135fcacc45f4145e410a1 - expo-dev-menu: 04ee943d5d984aa035813e8e893850089f96ee4e + Expo: 0aea613fc40cf68d048fb06107280d16a7dbeafd + expo-dev-client: 544df020dce2fc791b571c22a5332cdd1fefe5e2 + expo-dev-launcher: 5b4fbbbc6d32d0d0ed2c13cb8cd99f157959ed6d + expo-dev-menu: c00290f027000dbf86b1db00d3716b483ade13c2 expo-dev-menu-interface: 65402d4affb8b418aa6cec29b3abb0e313c8f443 ExpoAgeRange: c3e104dedb469958077d56961cbc1d4aaf7a858a ExpoAppIntegrity: 43cc62f24c533b960de07b5038568acedc3a567a ExpoAppleAuthentication: 47f6f6c6722a7facef29d15397635b785086bc5e - ExpoAppMetrics: 0885b732a789c85b7ba59d1a81a7ffb8a2491b7b - ExpoAsset: 52087fc68b9ebe9fa189d4c130919dd7ff345e92 + ExpoAppMetrics: 52c75c983bd44219dba5798aeeaeb4e3c232e334 + ExpoAsset: 45b495ad7c9ee655ac727eab9195ab69db9615ab ExpoAudio: fc809158cb86bdad608e8a224331cfb5481d8ea3 - ExpoBackgroundFetch: f647fb54235f1f0bb74451139f094b4c2395c0e1 - ExpoBackgroundTask: be1f4116803962b96e0bc999497d569ae51d518e + ExpoBackgroundFetch: 7ef18d566281354dd3cee6310fbabfb03c8517f8 + ExpoBackgroundTask: e313fa84896cd3a86593e3c808fbf8215a2f1e00 ExpoBattery: 4fbebca8ce0ee2bb4038efbcfa24d763012af07d ExpoBlob: 3e896c97726abf49bdecf63151e09fb4f7e21195 ExpoBlur: caddd80171e5f8f3581ff3d865e99c6465047240 ExpoBrightness: e394ebb59feb3191a0b0db7453861b3d3431381f - ExpoBrownfield: 8d4f69613ed9f2f9f1cb985acdcaa55d2fab60d1 - ExpoCalendar: e59d3481da0e50151a80a31e21039240cc22b56d + ExpoBrownfield: d624ccfe05c6a37714d6cde5e102634a096942df + ExpoCalendar: fcf3a20e5228541c7b060fd563d337a83860a19b ExpoCamera: 90595ff52b7cfccf9590a80e23e938e846c112ae ExpoCameraBarcodeScanning: e43e457bb457ce1dfb88b2d812e9457c825bd05c ExpoCellular: 9549bde58e5c8978c342d0a3dfbfc839c44a38c5 @@ -3914,51 +3914,51 @@ SPEC CHECKSUMS: ExpoGlassEffect: 7d4233dc0727ee2b28dd757eda70e1b6abf662fd ExpoHaptics: 89364cf3c3ca2cfd54cafed42f3be3169bab6d42 ExpoImage: 59f71ed6d030241ffadead114064cfd01bd0dc12 - ExpoImageManipulator: bbe6550472b04cdeb9d2161a61600dc1e544d024 - ExpoImagePicker: 3d6e508fd099fc0dbe5620423c8bd22f268c589d - ExpoInsights: 3eccd92f679d5217ca6424a4c49622f8a5b49e9c + ExpoImageManipulator: ecbacb557e20ec53adb71981cd93314daa8de449 + ExpoImagePicker: d2b6382f243bd2fa26184c4c16801ec6bd6e5490 + ExpoInsights: 1690aafe03de34639471f23a76c8dca65cd5722d ExpoKeepAwake: 359c47a1d9ccc3a3c519bca6e39562cce230c5bb - ExpoLinearGradient: 646dbfbd67cefcf75df7ea2115770605fd99db22 + ExpoLinearGradient: 16c2b9c6105444883d34958d573725de1293b8d0 ExpoLinking: 4ff9681a924c3dd4f4e5a2f32a33085e6a3ec7f1 ExpoLivePhoto: 3c2bd665a63afa8a465b16b564e4c9ab83ea60eb ExpoLocalAuthentication: 64e8c5756df07c8a89f078293ec17899c1325a43 ExpoLocalization: 74b7a2319781fd14f5db01e932c7c3a075ea1b4b - ExpoLocation: 97b584a2f86d56914a0bb7eb6c2add2bfb2581a4 - ExpoLogBox: b916f43d9ebb6cf537c1fec32a7b0c428e4c645b + ExpoLocation: 8d9edece087b82fe9ff2fee8923bf14d357b074c + ExpoLogBox: 3d06486e52b87bd361e05c993b96bc9a6ecdedec ExpoMailComposer: e202b670f62063851ed74c964034037312d523a8 ExpoMaps: 7fd43313b3be943c93df66df7dd09e6337703a37 ExpoMediaLibrary: ee2d74d5e52154305b8229dcb5c4319c84f30311 ExpoMeshGradient: baf62012104fd9c1719de67f88c69958abcd2ed1 - ExpoModulesCore: 2f7d4080e4d5c7916ea294217b9147b03590e913 + ExpoModulesCore: a4f8c4c24dcf030ab15903a84bce2e3e125cfb13 ExpoModulesJSI: 15a25b2948cdfe04bced3e08566a34877fe3cc1e ExpoModulesTestCore: 5660ab6b5928747366d4946580622a578865696a - ExpoModulesWorklets: 03afe05752b44f35d2c0903525e786b468e6390a - ExpoModulesWorkletsAdapter: 35eb5936e68c82e9fbd8c766bd3e67ea7dda62cf + ExpoModulesWorklets: d607309c356375d45e919a12a94f15e418603adc + ExpoModulesWorkletsAdapter: 1c95f525648e755df7407311d4ef20cf7791f891 ExpoNetwork: 6c8e0cc425a2c7f6591fabcab16417506441242c - ExpoNotifications: b719e208007d0296b19a7b8f2cc57851a6ccd2fa - ExpoObserve: 773885fa3aaa305b2462de909371ca5d607d16be + ExpoNotifications: f860fc3daa5585b31fc128e3368ac20b42536ee8 + ExpoObserve: 78455fd2f96b629144234ac2853d4c071de5760f ExpoPrint: 6b5bcac4492908b7e28144c2e7265c1c5ee4ade0 ExpoScreenCapture: f23a26d9fda8c42c77e7a818a1e20e3e8b94134b ExpoScreenOrientation: d009b38c96c03f4ef2bd658cdcf52e130176a7af ExpoSecureStore: 4d1c0303f8ead59766d7466c3c14d0ce4336fc0f ExpoSensors: 4ed48ba1a8d48e236fd22a966b77498188f8f48c - ExpoSharing: 73e46ca6e450c0801ed2738a297ae2d1084f3815 + ExpoSharing: 5523a31f7767d77c233201cdc51ffb7f714fa04e ExpoSMS: 2cebfd889706da39a397d20c8a68abb0ce7f185d ExpoSpeech: fe3706df8653ab8c16ff88251e33fab79b07a420 ExpoSplashScreen: bc5713a9cfcecfb26d9c53c142e08c0e1d863c52 ExpoSQLite: 35cd83a1d83122736bf3f39e99020588a8b00848 ExpoStoreReview: f785057aececd9c63a113c69a82b491e5f90694e - ExpoSymbols: 848b9d47bfbaf58173f36de961b426ded5712b5f + ExpoSymbols: f83c91f2897d37102b98b9224c603095630be9d0 ExpoSystemUI: 6f9eddf66c31d074c402ba4a9e5cd2320edda37f - ExpoTaskManager: 2b9822b3848be769172d70d5a2e5e228ff39c9c9 + ExpoTaskManager: c1ae4dd1421e2b3e1b1f4e46e92593c4e3ca1422 ExpoTrackingTransparency: dbdb87acf9ae2d85cb6c70f70a9d87d706949efd - ExpoUI: 53fb4b34e5d1e073ab68a243e0a60b270f0a3410 + ExpoUI: 8aca108741d3e81b4193224df31637019a395640 ExpoVideo: fa20020308f9f8e3458c05c7216d139d47fc1b32 ExpoVideoDashSupportModule: a8197584e7b7e533a67e75d3349c5fa827358ad6 ExpoVideoThumbnails: 116c2563d2bd3a1e98326a267020e25fea8af79e ExpoWebBrowser: fb9b5a94ebaa3483987f4acf4af6fd85c401df3e EXStructuredHeaders: 9e89bcdd636ae2ecb59995cfba3230f5d7547c08 - EXUpdates: d669854f27ea70d9521f09d92342fb789a307b4c + EXUpdates: 0703a27d9033eb420bb0de7ecd5dfb561fe7ae9b EXUpdatesInterface: 25408a97d682355eb9fb37e5aa6e22caece1881f FBLazyVector: 24e62c765683b8d89006a88a2c8f5cf019f0074d hermes-engine: 725fd85144e1348879039099a6be950c471a4f2c From 918cbc04f6bd763ed2a9ec03bf91805e44d0c1e6 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Thu, 7 May 2026 11:54:57 -0700 Subject: [PATCH 16/18] [docs] Update prebuilt Expo modules docs for SDK 55/56 and iOS (#45474) --- docs/pages/guides/prebuilt-expo-modules.mdx | 73 +++++++-------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/docs/pages/guides/prebuilt-expo-modules.mdx b/docs/pages/guides/prebuilt-expo-modules.mdx index a7290c57141283..16f4d8afbe479b 100644 --- a/docs/pages/guides/prebuilt-expo-modules.mdx +++ b/docs/pages/guides/prebuilt-expo-modules.mdx @@ -1,60 +1,35 @@ --- -title: Prebuilt Expo Modules for Android -sidebar_title: Prebuilt Expo Modules -description: Learn how prebuilt Expo Modules reduce Android build times by up to 25% on your machine. +title: Prebuilt Expo Modules +description: Learn how prebuilt Expo Modules reduce native build times on Android and iOS. --- -import { ContentSpotlight } from '~/ui/components/ContentSpotlight'; +import { Collapsible } from '~/ui/components/Collapsible'; +import { Terminal } from '~/ui/components/Snippet'; -When building React Native apps, longer build times can slow down your development workflow and reduce productivity. Each time you make changes to your code, you might need to wait for the build process to complete, which can add up to significant delays. +Native build times can slow down your development workflow. Expo provides prebuilt versions of its most complex modules so your project links pre-compiled binaries instead of recompiling them from source on every build. On Android, those binaries ship as `.aar` files linked through Gradle; on iOS, they ship as `XCFrameworks` linked through CocoaPods. Both are bundled into the regular Expo npm packages, and packages that aren't yet precompiled fall back to building from source automatically — precompiled and source-built modules coexist in the same project. -Expo provides prebuilt Expo Modules for Android to address this pain point. Instead of compiling Expo Modules source code from scratch during each build, your project can use pre-compiled versions of these modules. This results in faster build times. +**Most projects don't need to do anything** — prebuilt Expo Modules are enabled automatically in new and existing projects with a supported SDK version. -## Benefits +- **Android**: enabled by default since SDK 53. +- **iOS**: enabled by default in SDK 56+. In SDK 55, enabled by default only on EAS Build — set `EXPO_USE_PRECOMPILED_MODULES=1` in your shell to opt in for local builds. -- **Faster local development**: Up to 25% reduction in Android build times on local machines -- **Improved developer experience**: Less waiting time during development iterations -- **Automatic optimization**: Works out of the box with new projects + -## How prebuilt Expo Modules for Android work +Set `EXPO_USE_PRECOMPILED_MODULES` to `0`. For local builds, export the env var in your shell. -During your project's Android build process, look for the `[📦]` emoji prefix next to package names in the build output. This indicates that those packages are using prebuilt versions rather than being compiled from source. +For EAS Build, create an [EAS environment variable](/eas/environment-variables/manage/): -For example, after creating a project with SDK 53's default template, and running the `npx expo run:android` command, you will notice the `[📦 package-name` prefix next to packages that are precompiled: - - -## Configuration - -**No configuration steps are required for projects** that are created with one of the available [Expo templates](/more/create-expo/#--template). - -### Opting out of prebuilt Expo Modules - -You can opt out of prebuilt modules. This might be required when you are modifying the module source code yourself. In this scenario, you can configure the Expo Autolinking configuration by adding `buildFromSource` to the **package.json** file: +The CLI will prompt you to select which environment(s) (`development`, `preview`, `production`) the variable applies to. -{/* prettier-ignore */} -```json package.json -{ - "name": "your-app-name", - "expo": { - "autolinking": { - "android": { - "buildFromSource": [ - ".*" - ] - } - } - } -} -``` + -### Selectively opt out + -You can also opt out of specific modules while keeping others prebuilt by specifying individual package names instead of the wildcard `".*"`: +Configure Expo Autolinking with `buildFromSource` in **package.json**. Use `".*"` to opt out of every prebuilt module, or list specific package names. The same setting is available for both `android` and `ios`: {/* prettier-ignore */} ```json package.json @@ -63,18 +38,16 @@ You can also opt out of specific modules while keeping others prebuilt by specif "expo": { "autolinking": { "android": { - "buildFromSource": [ - "expo-camera", - "expo-web-browser", - "expo-linking", - ] + "buildFromSource": [".*"] + }, + "ios": { + "buildFromSource": [".*"] } } } } ``` -## Considerations +This is typically only needed when you're modifying module source code yourself. -- Performance improvements may vary based on your hardware configuration -- Current improvements on EAS Builds are more modest but provide groundwork for future caching mechanisms + From 66808a3b1c5d0e13eddca9cadbf9dd2dfc9ae862 Mon Sep 17 00:00:00 2001 From: Douglas Lowder Date: Thu, 7 May 2026 12:01:13 -0700 Subject: [PATCH 17/18] [updates] Add runtime version header to asset requests (#45465) # Why For enrichment of the updates dashboard in EAS, it would be helpful to have channel and runtime version headers in all asset requests for updates. # How Inspection of the code indicates that the channel is already included in the headers for asset requests, but runtime version was only added for the full update requests. The runtime version headers are now added for assets in both iOS and Android versions of the FileDownloader class. # Test Plan Tests for the presence of the correct headers are added to the Updates E2E (enabled) CI. --- packages/expo-updates/CHANGELOG.md | 2 ++ .../expo/modules/updates/loader/FileDownloader.kt | 4 ++++ .../maestro/tests/basic_checkRequestHeaders.yml | 12 +++++++++++- .../maestro/tests/basic_updateMultipleAssets.yml | 15 +++++++++++++++ .../maestro/tests/maestroUpdatesApi.js | 7 +++++++ .../maestro/updates-server/server.ts | 15 ++++++++++++++- .../ios/EXUpdates/AppLoader/FileDownloader.swift | 1 + 7 files changed, 54 insertions(+), 2 deletions(-) diff --git a/packages/expo-updates/CHANGELOG.md b/packages/expo-updates/CHANGELOG.md index ff936bc4a8831e..ad2ae3cd4ece7d 100644 --- a/packages/expo-updates/CHANGELOG.md +++ b/packages/expo-updates/CHANGELOG.md @@ -10,6 +10,8 @@ ### 💡 Others +- Add runtime version header to asset requests. ([#45465](https://github.com/expo/expo/pull/45465) by [@douglowder](https://github.com/douglowder)) + ## 56.0.5 — 2026-05-07 _This version does not introduce any user-facing changes._ diff --git a/packages/expo-updates/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt b/packages/expo-updates/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt index 3b0e6b7a54dc79..dd3e8e544e0342 100644 --- a/packages/expo-updates/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt +++ b/packages/expo-updates/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt @@ -787,6 +787,10 @@ class FileDownloader( } else { removeHeader(A_IM_HEADER) } + val runtimeVersion = configuration.runtimeVersionRaw + if (!runtimeVersion.isNullOrEmpty()) { + header("Expo-Runtime-Version", runtimeVersion) + } } .apply { for ((key, value) in configuration.requestHeaders) { diff --git a/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_checkRequestHeaders.yml b/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_checkRequestHeaders.yml index 12bf3bc5c6b701..b64225a2ed9981 100644 --- a/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_checkRequestHeaders.yml +++ b/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_checkRequestHeaders.yml @@ -13,7 +13,17 @@ onFlowStart: label: Assert update string is from embedded bundle - assertTrue: condition: ${output.api.lastRequestHeaders().host == 'localhost:' + MAESTRO_UPDATES_SERVER_PORT} - label: Check that request contains correct headers + label: Check that request contains correct host header + env: + MAESTRO_UPDATES_SERVER_PORT: ${MAESTRO_UPDATES_SERVER_PORT} +- assertTrue: + condition: ${output.api.lastRequestHeaders()['expo-channel-name'] == 'default'} + label: Check that request contains correct channel name header + env: + MAESTRO_UPDATES_SERVER_PORT: ${MAESTRO_UPDATES_SERVER_PORT} +- assertTrue: + condition: ${output.api.lastRequestHeaders()['expo-runtime-version'] == '1.0.0'} + label: Check that request contains correct runtime version header env: MAESTRO_UPDATES_SERVER_PORT: ${MAESTRO_UPDATES_SERVER_PORT} - stopApp diff --git a/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_updateMultipleAssets.yml b/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_updateMultipleAssets.yml index bf1a2843305581..1489c6f69258ea 100644 --- a/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_updateMultipleAssets.yml +++ b/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/basic_updateMultipleAssets.yml @@ -30,4 +30,19 @@ onFlowStart: - assertTrue: condition: ${maestro.copiedText == "test-update-2"} label: Assert update string is from downloaded update +- assertTrue: + condition: ${output.api.lastAssetRequestHeaders().host == 'localhost:' + MAESTRO_UPDATES_SERVER_PORT} + label: Check that asset request contains correct host header + env: + MAESTRO_UPDATES_SERVER_PORT: ${MAESTRO_UPDATES_SERVER_PORT} +- assertTrue: + condition: ${output.api.lastAssetRequestHeaders()['expo-channel-name'] == 'default'} + label: Check that asset request contains correct channel name header + env: + MAESTRO_UPDATES_SERVER_PORT: ${MAESTRO_UPDATES_SERVER_PORT} +- assertTrue: + condition: ${output.api.lastAssetRequestHeaders()['expo-runtime-version'] == '1.0.0'} + label: Check that asset request contains correct runtime version header + env: + MAESTRO_UPDATES_SERVER_PORT: ${MAESTRO_UPDATES_SERVER_PORT} - stopApp diff --git a/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/maestroUpdatesApi.js b/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/maestroUpdatesApi.js index 2d3e0735cc60ac..7e2f2a68efd337 100644 --- a/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/maestroUpdatesApi.js +++ b/packages/expo-updates/e2e/fixtures/project_files/maestro/tests/maestroUpdatesApi.js @@ -18,6 +18,12 @@ function lastRequestHeaders() { return JSON.parse(response.body); } +function lastAssetRequestHeaders() { + var requestString = `${serverBaseUrl}/last-asset-request-headers`; + const response = http.get(requestString); + return JSON.parse(response.body); +} + function stopUpdatesServer() { http.get(`${serverBaseUrl}/stop-server`); } @@ -69,6 +75,7 @@ output.api = { installClient: installClient, uninstallClient: uninstallClient, lastRequestHeaders: lastRequestHeaders, + lastAssetRequestHeaders: lastAssetRequestHeaders, logEntries: logEntries, restartUpdatesServer: restartUpdatesServer, serveManifest: serveManifest, diff --git a/packages/expo-updates/e2e/fixtures/project_files/maestro/updates-server/server.ts b/packages/expo-updates/e2e/fixtures/project_files/maestro/updates-server/server.ts index 42d1321bcac733..2973ce3788b83d 100644 --- a/packages/expo-updates/e2e/fixtures/project_files/maestro/updates-server/server.ts +++ b/packages/expo-updates/e2e/fixtures/project_files/maestro/updates-server/server.ts @@ -38,6 +38,7 @@ let messages: any[] = []; let responsesToServe: any[] = []; let updateRequest: Request | null = null; +let assetRequest: Request | null = null; let manifestToServe: null = null; let manifestHeadersToServe: { [x: string]: any } | null = null; @@ -82,6 +83,7 @@ function stop() { messages = []; responsesToServe = []; updateRequest = null; + assetRequest = null; manifestToServe = null; manifestHeadersToServe = null; serveChannel = null; @@ -104,10 +106,12 @@ app.use(express.json({ limit: '200kb' })); app.use( '/static', ( - req: { url: string; headers: Record }, + req: any, res: any, next: () => void ) => { + console.log('Requested static file: ', JSON.stringify(req.headers, null, 2)); + assetRequest = req; requestedStaticFiles.push(path.basename(req.url)); next(); } @@ -468,6 +472,15 @@ app.get('/last-request-headers', (_: Request, res: Response) => { return; }); +app.get('/last-asset-request-headers', (_: Request, res: Response) => { + if (!assetRequest) { + res.status(404).send('No asset request'); + return; + } + res.status(200).json(assetRequest.headers).end(); + return; +}); + app.get('/serve-manifest', async (req: Request, res: Response) => { if (req.query.channel) { console.log( diff --git a/packages/expo-updates/ios/EXUpdates/AppLoader/FileDownloader.swift b/packages/expo-updates/ios/EXUpdates/AppLoader/FileDownloader.swift index e8f89a4c1c64aa..db7f92a4dc8ac3 100644 --- a/packages/expo-updates/ios/EXUpdates/AppLoader/FileDownloader.swift +++ b/packages/expo-updates/ios/EXUpdates/AppLoader/FileDownloader.swift @@ -440,6 +440,7 @@ public final class FileDownloader { request.setValue("1", forHTTPHeaderField: "Expo-API-Version") request.setValue("BARE", forHTTPHeaderField: "Expo-Updates-Environment") request.setValue(EASClientID.uuid().uuidString, forHTTPHeaderField: "EAS-Client-ID") + request.setValue(config.runtimeVersion, forHTTPHeaderField: "Expo-Runtime-Version") for (key, value) in config.requestHeaders { request.setValue(value, forHTTPHeaderField: key) From adb8e41f24a1f49c54a09489f793631220e22db7 Mon Sep 17 00:00:00 2001 From: Evan Bacon Date: Thu, 7 May 2026 14:39:24 -0700 Subject: [PATCH 18/18] fix(cli): fix broken loading bar in CI (#45513) # Why - The Metro loading bar will show up multiple times in CI and non-interactive terminals. This change removes any progress updates until the bundling is complete. When observed in agents this appears to make it clearer that a fix has been applied and the dev server does not need to reset. - I also fixed the `--port 0` issue and changed the behavior so it finds the first available port instead of a random port. # Test Plan - Reproduced first with unit tests, then developed against the tests. - Tested manually in a project. --------- Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com> --- packages/@expo/cli/CHANGELOG.md | 3 + .../start/__tests__/resolveOptions-test.ts | 16 ++ .../@expo/cli/src/start/resolveOptions.ts | 4 +- .../server/metro/MetroTerminalReporter.ts | 14 ++ .../__tests__/MetroTerminalReporter-test.ts | 172 ++++++++++++++++++ .../cli/src/utils/__tests__/freeport.test.ts | 54 ++++++ .../cli/src/utils/__tests__/port.test.ts | 28 ++- packages/@expo/cli/src/utils/port.ts | 8 + 8 files changed, 294 insertions(+), 5 deletions(-) create mode 100644 packages/@expo/cli/src/utils/__tests__/freeport.test.ts diff --git a/packages/@expo/cli/CHANGELOG.md b/packages/@expo/cli/CHANGELOG.md index ab4934e850a34d..e9c89433e73abe 100644 --- a/packages/@expo/cli/CHANGELOG.md +++ b/packages/@expo/cli/CHANGELOG.md @@ -8,6 +8,9 @@ ### 🐛 Bug fixes +- Prevent Metro loading indicator from showing broken states in headless runs. ([#45513](https://github.com/expo/expo/pull/45513) by [@EvanBacon](https://github.com/EvanBacon)) +- Fix `--port 0` exiting silently in `expo start` when the port is busy. ([#45513](https://github.com/expo/expo/pull/45513) by [@EvanBacon](https://github.com/EvanBacon)) + ### 💡 Others ## 56.0.6 — 2026-05-07 diff --git a/packages/@expo/cli/src/start/__tests__/resolveOptions-test.ts b/packages/@expo/cli/src/start/__tests__/resolveOptions-test.ts index 1a544b8a055c70..227e6e6818b580 100644 --- a/packages/@expo/cli/src/start/__tests__/resolveOptions-test.ts +++ b/packages/@expo/cli/src/start/__tests__/resolveOptions-test.ts @@ -250,6 +250,22 @@ describe(resolvePortsAsync, () => { metroPort: 8081, }); }); + it(`does not abort when port resolves to 0`, async () => { + jest.mocked(resolvePortAsync).mockResolvedValueOnce(0); + await expect( + resolvePortsAsync('/noop', { port: 0 }, { webOnly: false }) + ).resolves.toStrictEqual({ + metroPort: 0, + }); + }); + it(`does not abort when webpack port resolves to 0`, async () => { + jest.mocked(resolvePortAsync).mockResolvedValueOnce(0); + await expect(resolvePortsAsync('/noop', { port: 0 }, { webOnly: true })).resolves.toStrictEqual( + { + webpackPort: 0, + } + ); + }); it(`resolves default port for webpack`, async () => { await expect(resolvePortsAsync('/noop', {}, { webOnly: true })).resolves.toStrictEqual({ webpackPort: 19006, diff --git a/packages/@expo/cli/src/start/resolveOptions.ts b/packages/@expo/cli/src/start/resolveOptions.ts index e48e7f1ef16433..5d741df8706715 100644 --- a/packages/@expo/cli/src/start/resolveOptions.ts +++ b/packages/@expo/cli/src/start/resolveOptions.ts @@ -170,7 +170,7 @@ export async function resolvePortsAsync( // Default web port fallbackPort: 19006, }); - if (!webpackPort) { + if (webpackPort == null) { throw new AbortCommandError(); } multiBundlerSettings.webpackPort = webpackPort; @@ -182,7 +182,7 @@ export async function resolvePortsAsync( defaultPort: options.port, fallbackPort, }); - if (!metroPort) { + if (metroPort == null) { throw new AbortCommandError(); } multiBundlerSettings.metroPort = metroPort; diff --git a/packages/@expo/cli/src/start/server/metro/MetroTerminalReporter.ts b/packages/@expo/cli/src/start/server/metro/MetroTerminalReporter.ts index c690393d93653c..58dfdfd32c8b0a 100644 --- a/packages/@expo/cli/src/start/server/metro/MetroTerminalReporter.ts +++ b/packages/@expo/cli/src/start/server/metro/MetroTerminalReporter.ts @@ -22,6 +22,7 @@ import { import { attachImportStackToRootMessage, nearestImportStack } from './metroErrorInterface'; import { events, shouldReduceLogs } from '../../../events'; import { stripAnsi } from '../../../utils/ansi'; +import { isInteractive } from '../../../utils/interactive'; type ClientLogLevel = | 'trace' @@ -99,6 +100,19 @@ export class MetroTerminalReporter extends TerminalReporter { super(terminal); } + /** + * Suppress status messages in non-interactive mode. + * In TTY mode, Terminal overwrites status lines in-place (progress bars). + * In non-TTY mode, Terminal writes status via a 3500ms throttle, producing + * permanent output that interleaves with log messages like "Bundled Xms". + */ + _getStatusMessage(): string { + if (!isInteractive()) { + return ''; + } + return super._getStatusMessage(); + } + _log(event: TerminalReportableEvent): void { this.#captureLog(event); switch (event.type) { diff --git a/packages/@expo/cli/src/start/server/metro/__tests__/MetroTerminalReporter-test.ts b/packages/@expo/cli/src/start/server/metro/__tests__/MetroTerminalReporter-test.ts index 573f4f9a269cde..c4826811b8ca34 100644 --- a/packages/@expo/cli/src/start/server/metro/__tests__/MetroTerminalReporter-test.ts +++ b/packages/@expo/cli/src/start/server/metro/__tests__/MetroTerminalReporter-test.ts @@ -22,6 +22,8 @@ import { } from './fixtures/terminal-logs'; const asBundleDetails = (value: any) => value as BundleDetails; +const DARK_BLOCK_CHAR = '\u2593'; +const LIGHT_BLOCK_CHAR = '\u2591'; jest.useFakeTimers(); @@ -410,6 +412,176 @@ describe(formatUsingNodeStandardLibraryError, () => { }); }); +describe('non-interactive terminal output', () => { + /** + * Reproduces the bug where progress bar status lines interleave with "Bundled" log messages + * in non-TTY mode. In TTY mode, status lines are overwritten in-place by the Terminal class. + * In non-TTY mode, Terminal.log() writes immediately while Terminal.status() writes through + * a 3500ms throttle (#writeStatusThrottled), causing progress bars to appear as permanent + * output between "Bundled" completion messages: + * + * Web Bundled 2967ms node_modules/expo-router/entry.js (964 modules) + * Web node_modules/expo-router/entry.js ▓▓▓░░░░░░░░░░░░░ 21.3% ( 97/210) + * Web Bundled 1185ms node_modules/expo-router/entry.js (965 modules) + */ + + const buildID1 = 'build-1'; + const buildID2 = 'build-2'; + const entryFile = 'node_modules/expo-router/entry.js'; + const bundleDetails = asBundleDetails({ + entryFile, + platform: 'web', + bundleType: 'bundle', + }); + + function createNonInteractiveReporter() { + const terminal = { + log: jest.fn(), + persistStatus: jest.fn(), + status: jest.fn(), + flush: jest.fn(), + } satisfies Partial; + + const reporter = new MetroTerminalReporter('/', terminal as any); + reporter._getElapsedTime = jest.fn(() => BigInt(2_967_000_000)); + return { reporter, terminal }; + } + + /** + * Helper that collects the interleaved order of terminal.log and terminal.status calls. + * Each entry records the call type and stripped content to make assertions readable. + */ + function collectOutputOrder(terminal: { log: jest.Mock; status: jest.Mock }) { + const output: { type: 'log' | 'status'; content: string }[] = []; + terminal.log.mockImplementation((...args: any[]) => { + output.push({ type: 'log', content: stripAnsi(args.join(' ')) }); + }); + terminal.status.mockImplementation((...args: any[]) => { + const content = stripAnsi(args.join(' ')); + if (content) { + output.push({ type: 'status', content }); + } + }); + return output; + } + + it('progress bar status should not interleave with Bundled log messages', () => { + const { reporter, terminal } = createNonInteractiveReporter(); + const output = collectOutputOrder(terminal); + + // Simulate first bundle: start → progress → done + reporter.update({ + type: 'bundle_build_started', + buildID: buildID1, + bundleDetails: { ...bundleDetails, buildID: buildID1 }, + isPrefetch: false, + } as any); + + // Progress updates (normally throttled at 100ms, we simulate the throttled event directly) + reporter.update({ + type: 'bundle_transform_progressed_throttled', + buildID: buildID1, + transformedFileCount: 500, + totalFileCount: 964, + } as any); + + // First bundle completes + reporter.update({ + type: 'bundle_build_done', + buildID: buildID1, + bundleDetails: { ...bundleDetails, buildID: buildID1 }, + } as any); + + // Second bundle starts immediately (e.g. HMR rebuild) + reporter.update({ + type: 'bundle_build_started', + buildID: buildID2, + bundleDetails: { ...bundleDetails, buildID: buildID2 }, + isPrefetch: false, + } as any); + + // Progress update for second bundle + reporter.update({ + type: 'bundle_transform_progressed_throttled', + buildID: buildID2, + transformedFileCount: 97, + totalFileCount: 210, + } as any); + + // Second bundle completes + reporter._getElapsedTime = jest.fn(() => BigInt(1_185_000_000)); + reporter.update({ + type: 'bundle_build_done', + buildID: buildID2, + bundleDetails: { ...bundleDetails, buildID: buildID2 }, + } as any); + + // Extract only the log calls (what gets permanently written in non-TTY mode) + const logMessages = output.filter((o) => o.type === 'log'); + + // Both "Bundled" messages should appear in the logs + expect(logMessages).toEqual( + expect.arrayContaining([ + expect.objectContaining({ content: expect.stringContaining('Bundled') }), + expect.objectContaining({ content: expect.stringContaining('Bundled') }), + ]) + ); + + // No progress bar should appear in the log output (progress bars belong only in status) + for (const msg of logMessages) { + expect(msg.content).not.toContain(DARK_BLOCK_CHAR); + expect(msg.content).not.toContain(LIGHT_BLOCK_CHAR); + } + + // Now check the status calls: in non-TTY mode, these become permanent output. + // After a bundle completes, the status should not contain progress bars for completed bundles. + const statusMessages = output.filter((o) => o.type === 'status'); + + // Find the status call that happens right after the first "Bundled" log + const firstBundledIndex = output.findIndex( + (o) => o.type === 'log' && o.content.includes('Bundled') + ); + const statusAfterFirstBundled = output + .slice(firstBundledIndex + 1) + .filter((o) => o.type === 'status'); + + // The status after the first "Bundled" should not contain a progress bar for the completed bundle + for (const msg of statusAfterFirstBundled) { + // If there's a progress bar, it should only be for bundle 2 (not stale data from bundle 1) + if (msg.content.includes(DARK_BLOCK_CHAR) || msg.content.includes(LIGHT_BLOCK_CHAR)) { + // This is the bug: a progress bar status appears in the output stream + // between the two "Bundled" messages, which in non-TTY mode is permanent output. + // The status should be empty or suppressed in non-interactive mode. + expect(msg.content).not.toContain(DARK_BLOCK_CHAR); + } + } + }); + + it('_getStatusMessage returns empty string in non-interactive mode', () => { + const { reporter } = createNonInteractiveReporter(); + + // Start a bundle so there's an active bundle + reporter.update({ + type: 'bundle_build_started', + buildID: buildID1, + bundleDetails: { ...bundleDetails, buildID: buildID1 }, + isPrefetch: false, + } as any); + + // Add some progress + reporter.update({ + type: 'bundle_transform_progressed_throttled', + buildID: buildID1, + transformedFileCount: 50, + totalFileCount: 100, + } as any); + + // In non-interactive mode, _getStatusMessage() should return empty + // since status lines can't be overwritten and would produce permanent noise. + expect(reporter._getStatusMessage()).toBe(''); + }); +}); + describe('extractCodeFrame', () => { it('extracts code frame from a message', () => { const inputMessage = ` diff --git a/packages/@expo/cli/src/utils/__tests__/freeport.test.ts b/packages/@expo/cli/src/utils/__tests__/freeport.test.ts new file mode 100644 index 00000000000000..71f5634774b45f --- /dev/null +++ b/packages/@expo/cli/src/utils/__tests__/freeport.test.ts @@ -0,0 +1,54 @@ +import net from 'node:net'; + +import { freePortAsync, testPortAsync } from '../freeport'; + +jest.unmock('net'); +jest.unmock('node:net'); + +describe(freePortAsync, () => { + it(`returns the starting port if it is free`, async () => { + // Find a port we know is free by binding to 0 + const server = net.createServer(); + const freePort = await new Promise((resolve) => { + server.listen(0, () => { + const addr = server.address(); + const port = typeof addr === 'object' && addr ? addr.port : 0; + server.close(() => resolve(port)); + }); + }); + + const result = await freePortAsync(freePort); + expect(result).toBe(freePort); + }); +}); + +describe(testPortAsync, () => { + it(`returns true for a free port`, async () => { + const server = net.createServer(); + const freePort = await new Promise((resolve) => { + server.listen(0, () => { + const addr = server.address(); + const port = typeof addr === 'object' && addr ? addr.port : 0; + server.close(() => resolve(port)); + }); + }); + + expect(await testPortAsync(freePort)).toBe(true); + }); + + it(`returns false for a busy port`, async () => { + const server = net.createServer(); + const busyPort = await new Promise((resolve) => { + server.listen(0, () => { + const addr = server.address(); + resolve(typeof addr === 'object' && addr ? addr.port : 0); + }); + }); + + try { + expect(await testPortAsync(busyPort)).toBe(false); + } finally { + await new Promise((resolve) => server.close(() => resolve())); + } + }); +}); diff --git a/packages/@expo/cli/src/utils/__tests__/port.test.ts b/packages/@expo/cli/src/utils/__tests__/port.test.ts index b3d804e4f18fa9..b9c4f166e1e135 100644 --- a/packages/@expo/cli/src/utils/__tests__/port.test.ts +++ b/packages/@expo/cli/src/utils/__tests__/port.test.ts @@ -1,6 +1,11 @@ import { freePortAsync, testPortAsync } from '../freeport'; import { getRunningProcess } from '../getRunningProcess'; -import { choosePortAsync, ensurePortAvailabilityAsync } from '../port'; +import { + choosePortAsync, + ensurePortAvailabilityAsync, + getFreePortAsync, + resolvePortAsync, +} from '../port'; import { confirmAsync } from '../prompts'; jest.mock('../freeport', () => ({ @@ -41,9 +46,9 @@ describe(ensurePortAvailabilityAsync, () => { describe(choosePortAsync, () => { it(`returns any port when given port is 0`, async () => { - jest.mocked(freePortAsync).mockResolvedValueOnce(1000); + jest.mocked(freePortAsync).mockResolvedValueOnce(1024); const port = await choosePortAsync('/', { defaultPort: 0 }); - expect(port).toBe(1000); + expect(port).toBe(1024); expect(confirmAsync).not.toHaveBeenCalled(); }); it(`returns same port when given port is available`, async () => { @@ -89,3 +94,20 @@ describe(choosePortAsync, () => { expect(confirmAsync).not.toHaveBeenCalled(); }); }); + +describe(resolvePortAsync, () => { + it(`finds the first available port from the fallback when port is 0`, async () => { + jest.mocked(freePortAsync).mockResolvedValueOnce(8081); + const port = await resolvePortAsync('/', { defaultPort: 0, fallbackPort: 8081 }); + expect(port).toBe(8081); + expect(freePortAsync).toHaveBeenCalledWith(8081, [null, 'localhost']); + expect(confirmAsync).not.toHaveBeenCalled(); + }); + it(`finds the next available port from the fallback when port is 0 and fallback is busy`, async () => { + jest.mocked(freePortAsync).mockResolvedValueOnce(8082); + const port = await resolvePortAsync('/', { defaultPort: 0, fallbackPort: 8081 }); + expect(port).toBe(8082); + expect(freePortAsync).toHaveBeenCalledWith(8081, [null, 'localhost']); + expect(confirmAsync).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/@expo/cli/src/utils/port.ts b/packages/@expo/cli/src/utils/port.ts index 3047ffb70e86cb..cbf56a205be7b6 100644 --- a/packages/@expo/cli/src/utils/port.ts +++ b/packages/@expo/cli/src/utils/port.ts @@ -150,6 +150,14 @@ export async function resolvePortAsync( port = env.RCT_METRO_PORT || fallbackPort || 8081; } + // Port 0 means "pick any available port" — scan from the fallback port without prompting. + if (port === 0) { + const scanFrom = env.RCT_METRO_PORT || fallbackPort || 8081; + const resolvedPort = await getFreePortAsync(scanFrom); + process.env.RCT_METRO_PORT = String(resolvedPort); + return resolvedPort; + } + // Only check the port when the bundler is running. const resolvedPort = await choosePortAsync(projectRoot, { defaultPort: port,