mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c02b997d8 |
+1
-7
@@ -26,9 +26,6 @@
|
||||
; helloworld
|
||||
<PROJECT_ROOT>/packages/helloworld/ios/Pods/
|
||||
|
||||
; Ignore rn-tester Pods
|
||||
<PROJECT_ROOT>/packages/rn-tester/Pods/
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/@react-native-community/cli/.*/.*
|
||||
|
||||
@@ -44,7 +41,6 @@ packages/react-native/flow/
|
||||
|
||||
[options]
|
||||
enums=true
|
||||
as_const=true
|
||||
casting_syntax=both
|
||||
|
||||
emoji=true
|
||||
@@ -73,8 +69,6 @@ suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FlowFixMeEmpty
|
||||
|
||||
ban_spread_key_props=true
|
||||
|
||||
[lints]
|
||||
sketchy-null-number=warn
|
||||
sketchy-null-mixed=warn
|
||||
@@ -96,4 +90,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.255.0
|
||||
^0.251.1
|
||||
|
||||
@@ -43,7 +43,7 @@ runs:
|
||||
shell: powershell
|
||||
run: |
|
||||
if (-not(Test-Path -Path $Env:HERMES_WS_DIR\win64-bin\hermesc.exe)) {
|
||||
choco install --no-progress cmake --version 3.14.7 --allow-downgrade
|
||||
choco install --no-progress cmake --version 3.14.7
|
||||
if (-not $?) { throw "Failed to install CMake" }
|
||||
|
||||
cd $Env:HERMES_WS_DIR\icu
|
||||
|
||||
@@ -3,6 +3,9 @@ description: Prepare iOS Tests
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: brew install xcbeautify
|
||||
run: brew install xcbeautify
|
||||
shell: bash
|
||||
- name: Run Ruby Tests
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -121,21 +121,21 @@ runs:
|
||||
if: ${{ inputs.run-unit-tests != 'true' && inputs.run-e2e-tests == 'false' }}
|
||||
shell: bash
|
||||
run: |
|
||||
xcodebuild build \
|
||||
set -o pipefail && xcodebuild build \
|
||||
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
|
||||
-scheme RNTester \
|
||||
-sdk iphonesimulator
|
||||
-sdk iphonesimulator | xcbeautify
|
||||
- name: Build RNTester (E2E Tests)
|
||||
shell: bash
|
||||
if: ${{ inputs.run-e2e-tests == 'true' }}
|
||||
run: |
|
||||
xcodebuild \
|
||||
set -o pipefail && xcodebuild \
|
||||
-scheme "RNTester" \
|
||||
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
|
||||
-configuration "${{ inputs.flavor }}" \
|
||||
-sdk "iphonesimulator" \
|
||||
-destination "generic/platform=iOS Simulator" \
|
||||
-derivedDataPath "/tmp/RNTesterBuild"
|
||||
-derivedDataPath "/tmp/RNTesterBuild" | xcbeautify
|
||||
|
||||
echo "Print path to *.app file"
|
||||
find "/tmp/RNTesterBuild" -type d -name "*.app"
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
name: test-library-on-nightly
|
||||
description: Tests a library on a nightly
|
||||
inputs:
|
||||
library-npm-package:
|
||||
description: The library npm package to add
|
||||
required: true
|
||||
platform:
|
||||
description: whether we want to build for iOS or Android
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Create new app
|
||||
shell: bash
|
||||
run: |
|
||||
cd /tmp
|
||||
npx @react-native-community/cli init RNApp --skip-install --version nightly
|
||||
- name: Add library
|
||||
shell: bash
|
||||
run: |
|
||||
cd /tmp/RNApp
|
||||
yarn add ${{ inputs.library-npm-package }}
|
||||
|
||||
- name: Build iOS
|
||||
shell: bash
|
||||
if: ${{ inputs.platform == 'ios' }}
|
||||
run: |
|
||||
cd /tmp/RNApp/ios
|
||||
bundle install
|
||||
bundle exec pod install
|
||||
xcodebuild build \
|
||||
-workspace RNApp.xcworkspace \
|
||||
-scheme RNApp \
|
||||
-sdk iphonesimulator
|
||||
- name: Setup Java for Android
|
||||
if: ${{ inputs.platform == 'android' }}
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Build Android
|
||||
shell: bash
|
||||
if: ${{ inputs.platform == 'android' }}
|
||||
run: |
|
||||
cd /tmp/RNApp/android
|
||||
./gradlew assembleDebug
|
||||
@@ -48,84 +48,96 @@ module.exports = async (github, context, labelWithContext) => {
|
||||
switch (labelWithContext.label) {
|
||||
case 'Type: Invalid':
|
||||
await addComment(
|
||||
`> [!CAUTION]\n` +
|
||||
`> **Invalid issue**: This issue is not valid, either is not a bug in React Native, it doesn't match any of the issue template, or we can't help further with this.`,
|
||||
`| :warning: | Issue is Invalid |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | This issue doesn't match any of the expected types for this repository - closing. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Question':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Not a bug report**: This issue looks like a question. We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/).`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Resolution: For Stack Overflow':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Not a bug report**: This issue looks like a question. We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/).`,
|
||||
`| :warning: | Issue is a Question |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/). |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Docs':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Docs issue**: This issue looks like an issue related to our docs. Please report documentation issues in the [react-native-website](https://github.com/facebook/react-native-website/issues) repository.`,
|
||||
`| :warning: | Documentation Issue |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | Please report documentation issues in the [react-native-website](https://github.com/facebook/react-native-website/issues) repository. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Resolution: For Stack Overflow':
|
||||
await addComment(
|
||||
`| :warning: | Issue is a Question |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We are using GitHub issues exclusively to track bugs in the core React Native library. Please try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native) as it is better suited for this type of question. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Expo':
|
||||
await addComment(
|
||||
`> [!NOTE]\n` +
|
||||
`> **Expo related**: It looks like your issue is related to Expo and not React Native core. Please open your issue in [Expo's repository](https://github.com/expo/expo/issues/new). If you are able to create a repro that showcases that this issue is also happening in React Native vanilla, we will be happy to re-open.`,
|
||||
`| :warning: | Issue is Related to Expo |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue is related to Expo and not React Native core. Please open your issue in [Expo's repository](https://github.com/expo/expo/issues/new). If you are able to create a repro that showcases that this issue is also happening in React Native vanilla, we will be happy to re-open. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Needs: Issue Template':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Missing issue template**: It looks like your issue may be missing some necessary information. GitHub provides an example template whenever a [new issue is created](https://github.com/facebook/react-native/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A&projects=&template=bug_report.yml). Could you go back and make sure to fill out the template? You may edit this issue, or close it and open a new one.`,
|
||||
`| :warning: | Missing Required Fields |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue may be missing some necessary information. GitHub provides an example template whenever a [new issue is created](https://github.com/facebook/react-native/issues/new?template=bug_report.md). Could you go back and make sure to fill out the template? You may edit this issue, or close it and open a new one. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Needs: Environment Info':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Missing info**: It looks like your issue may be missing information about your development environment. You can obtain the missing information by running <code>react-native info</code> in a console.`,
|
||||
`| :warning: | Missing Environment Information |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | Your issue may be missing information about your development environment. You can obtain the missing information by running <code>react-native info</code> in a console. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Newer Patch Available':
|
||||
await addComment(
|
||||
`> [!TIP]\n` +
|
||||
`> **Newer version available**: You are on a supported minor version, but it looks like there's a newer patch available - ${labelWithContext.newestPatch}. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases.`,
|
||||
`| :warning: | Newer Version of React Native is Available! |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | You are on a supported minor version, but it looks like there's a newer patch available - ${labelWithContext.newestPatch}. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |`,
|
||||
);
|
||||
return;
|
||||
case 'Needs: Version Info':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Could not parse version**: We could not find or parse the version number of React Native in your issue report. Please use the template, and report your version including major, minor, and patch numbers - e.g. 0.76.2.`,
|
||||
`| :warning: | Add or Reformat Version Info |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not find or parse the version number of React Native in your issue report. Please use the template, and report your version including major, minor, and patch numbers - e.g. 0.70.2 |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Needs: Repro':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Missing reproducer**: We could not detect a reproducible example in your issue report. Please provide either: <br/><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/upgrade related: a project using our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate)</li><li>Otherwise send us a Pull Request with the [RNTesterPlayground.js](https://github.com/facebook/react-native/blob/main/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js) edited to reproduce your bug.</li></ul>`,
|
||||
`| :warning: | Missing Reproducible Example |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not detect a reproducible example in your issue report. Please provide either: <br /><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/update related: use our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate)</li></ul> |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Type: Unsupported Version':
|
||||
await addComment(
|
||||
`> [!WARNING]\n` +
|
||||
`> **Unsupported version**: It looks like your issue or the example you provided uses an [unsupported version of React Native](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support.`,
|
||||
`| :warning: | Unsupported Version of React Native |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue or the example you provided uses an [unsupported version of React Native](https://github.com/reactwg/react-native-releases/blob/main/README.md#releases-support-policy).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Type: Too Old Version':
|
||||
await addComment(
|
||||
`> [!CAUTION]\n` +
|
||||
`> **Too old version**: It looks like your issue or the example you provided uses a [**Too Old Version of React Native**](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support.`,
|
||||
`| :warning: | Too Old Version of React Native |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue or the example you provided uses a [**Too Old Version of React Native**](https://github.com/reactwg/react-native-releases/blob/main/README.md#releases-support-policy).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
const NEEDS_REPRO_LABEL = 'Needs: Repro';
|
||||
const NEEDS_AUTHOR_FEEDBACK_LABEL = 'Needs: Author Feedback';
|
||||
const NEEDS_REPRO_HEADER = 'Missing Reproducible Example';
|
||||
const NEEDS_REPRO_MESSAGE =
|
||||
`| :warning: | Missing Reproducible Example |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not detect a reproducible example in your issue report. Please provide either: <br /><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/update related: use our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate). A reproducer needs to be in a GitHub repository under your username.</li></ul> |`;
|
||||
const SKIP_ISSUES_OLDER_THAN = '2023-07-01T00:00:00Z';
|
||||
|
||||
module.exports = async (github, context) => {
|
||||
@@ -20,6 +25,7 @@ module.exports = async (github, context) => {
|
||||
|
||||
const issue = await github.rest.issues.get(issueData);
|
||||
const comments = await github.rest.issues.listComments(issueData);
|
||||
|
||||
const author = issue.data.user.login;
|
||||
|
||||
const issueDate = issue.data.created_at;
|
||||
@@ -37,6 +43,10 @@ module.exports = async (github, context) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const botComment = comments.data.find(comment =>
|
||||
comment.body.includes(NEEDS_REPRO_HEADER),
|
||||
);
|
||||
|
||||
const entities = [issue.data, ...comments.data];
|
||||
|
||||
// Look for Snack or a GH repo associated with the user that added an issue or comment
|
||||
@@ -64,11 +74,25 @@ module.exports = async (github, context) => {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!botComment) return;
|
||||
|
||||
await github.rest.issues.deleteComment({
|
||||
...issueData,
|
||||
comment_id: botComment.id,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.addLabels({
|
||||
...issueData,
|
||||
labels: [NEEDS_REPRO_LABEL, NEEDS_AUTHOR_FEEDBACK_LABEL],
|
||||
});
|
||||
|
||||
if (botComment) return;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
...issueData,
|
||||
body: NEEDS_REPRO_MESSAGE,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,7 +101,7 @@ function containsPattern(body, pattern) {
|
||||
return body.search(regexp) !== -1;
|
||||
}
|
||||
|
||||
// Prevents the bot from responding when maintainer has changed the 'Needs: Repro' label
|
||||
// Prevents the bot from responding when maintainer has changed Needs: Repro the label
|
||||
async function hasMaintainerChangedLabel(github, issueData, author) {
|
||||
const timeline = await github.rest.issues.listEventsForTimeline(issueData);
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
module.exports = async (github, context) => {
|
||||
const issue = context.payload.issue;
|
||||
|
||||
// Ignore issues using upgrade template (they use a special label)
|
||||
if (issue.labels.find(label => label.name === 'Type: Upgrade Issue')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const issueVersionUnparsed =
|
||||
getReactNativeVersionFromIssueBodyIfExists(issue);
|
||||
const issueVersion = parseVersionFromString(issueVersionUnparsed);
|
||||
|
||||
@@ -13,8 +13,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Check nightly
|
||||
run: |
|
||||
TODAY=$(date "+%Y%m%d")
|
||||
@@ -26,7 +24,3 @@ jobs:
|
||||
else
|
||||
echo 'Nightly Worked, All Good!'
|
||||
fi
|
||||
|
||||
test-libraries:
|
||||
uses: ./.github/workflows/test-libraries-on-nightlies.yml
|
||||
needs: check-nightly
|
||||
|
||||
@@ -421,9 +421,7 @@ jobs:
|
||||
run-e2e-tests: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
|
||||
test_e2e_android_rntester:
|
||||
# Temporarily disable RNTester tests on Android as they are quite flaky and they make CI always red
|
||||
# if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
if: ${{ contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_android]
|
||||
strategy:
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
name: Test Libraries on Nightlies
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test-library-on-nightly-android:
|
||||
name: "[Android] ${{ matrix.library }}"
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
library: [
|
||||
"react-native-async-storage",
|
||||
"react-native-blob-util",
|
||||
"@react-native-clipboard/clipboard",
|
||||
"@react-native-community/datetimepicker",
|
||||
"react-native-gesture-handler",
|
||||
"react-native-image-picker",
|
||||
"react-native-linear-gradient",
|
||||
"@react-native-masked-view/masked-view",
|
||||
"react-native-maps",
|
||||
"@react-native-community/netinfo",
|
||||
"react-native-reanimated",
|
||||
"react-native-svg",
|
||||
"react-native-video",
|
||||
"react-native-webview",
|
||||
"react-native-mmkv",
|
||||
"react-native-screens",
|
||||
"react-native-pager-view",
|
||||
"@react-native-community/slider"
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Test ${{ inputs.library-name }}
|
||||
uses: ./.github/actions/test-library-on-nightly
|
||||
with:
|
||||
library-npm-package: ${{ matrix.library }}
|
||||
platform: android
|
||||
|
||||
test-library-on-nightly-ios:
|
||||
name: "[iOS] ${{ matrix.library }}"
|
||||
runs-on: macos-13-large
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
library: [
|
||||
"react-native-async-storage",
|
||||
"react-native-blob-util",
|
||||
"@react-native-clipboard/clipboard",
|
||||
"@react-native-community/datetimepicker",
|
||||
"react-native-gesture-handler",
|
||||
"react-native-image-picker",
|
||||
"react-native-linear-gradient",
|
||||
"@react-native-masked-view/masked-view",
|
||||
"react-native-maps",
|
||||
"@react-native-community/netinfo",
|
||||
"react-native-reanimated",
|
||||
"react-native-svg",
|
||||
"react-native-video",
|
||||
"react-native-webview",
|
||||
"react-native-mmkv",
|
||||
"react-native-screens",
|
||||
"react-native-pager-view",
|
||||
"@react-native-community/slider"
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Test ${{ inputs.library-name }}
|
||||
uses: ./.github/actions/test-library-on-nightly
|
||||
with:
|
||||
library-npm-package: ${{ matrix.library }}
|
||||
platform: ios
|
||||
+1
-4
@@ -124,7 +124,7 @@ vendor/
|
||||
!/packages/rn-tester/Pods/__offline_mirrors_jsc__
|
||||
|
||||
# @react-native/codegen
|
||||
/packages/react-native/React/FBReactNativeSpec/
|
||||
/packages/react-native/React/FBReactNativeSpec/FBReactNativeSpec
|
||||
/packages/react-native-codegen/lib
|
||||
/packages/react-native-codegen/tmp/
|
||||
/packages/react-native/ReactCommon/react/renderer/components/rncore/
|
||||
@@ -155,6 +155,3 @@ vendor/
|
||||
|
||||
# CircleCI
|
||||
.circleci/generated_config.yml
|
||||
|
||||
# Jest Integration
|
||||
/jest/integration/build/
|
||||
|
||||
-442
@@ -1,432 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## v0.77.0-rc.0
|
||||
|
||||
### Breaking
|
||||
|
||||
- Bridgeless: Make NativeModules.foo load turbomodules (unset turboModuleProxy in bridgeless). ([cc5f17d5a2](https://github.com/facebook/react-native/commit/cc5f17d5a2b185de1e7dec2a56a97b088e4c7a81) by [@RSNara](https://github.com/RSNara))
|
||||
- dev-middleware: Frameworks should specify `serverBaseUrl` relative to the middleware host. ([acf384a72e](https://github.com/facebook/react-native/commit/acf384a72e599691e4c9d53043f1801da01c58fd) by [@robhogan](https://github.com/robhogan))
|
||||
- `position` of sticky headers on `ScrollView` will now be taken into account ([cbab004eb9](https://github.com/facebook/react-native/commit/cbab004eb94f8312e9b10dae1502d3ca8632a006) by [@joevilches](https://github.com/joevilches))
|
||||
- Remove ReactFabricInternals module ([0c21db360c](https://github.com/facebook/react-native/commit/0c21db360cecc6a3265eea50d628106c58b67af8) by [@huntie](https://github.com/huntie))
|
||||
- Make ReactDebugOverlayTags, DebugOverlayTags, Printer, PrinterHolder, NoopPrinter internal ([623d481991](https://github.com/facebook/react-native/commit/623d4819915e7e6fafb8006c8e3b3b796e394974) by [@cortinico](https://github.com/cortinico))
|
||||
- More spec compliant absolute positioning ([0a2dec175e](https://github.com/facebook/react-native/commit/0a2dec175e92185943907f3e1f6073bae6cd663d) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Native looping animation will not send React state update every time it finishes. ([4b035d820d](https://github.com/facebook/react-native/commit/4b035d820d3f1c3c9a98ce4f55bcc95a7ab064bf) by [@dmytrorykun](https://github.com/dmytrorykun))
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Removed ReactViewGroup.getBackgroundColor() ([6a472c5cf2](https://github.com/facebook/react-native/commit/6a472c5cf25d72f72ec7e261282d611a5ab0a662) by Thomas Nardone)
|
||||
- ReadableArray non-primitive getters are now correctly typed as optional ([145c72f816](https://github.com/facebook/react-native/commit/145c72f8163048f0eee30d5ce850911f5dad865c) by [@javache](https://github.com/javache))
|
||||
- Remove jsBundleLoader from DefaultReactHost.getDefaultReactHost() ([fbe4c0ed34](https://github.com/facebook/react-native/commit/fbe4c0ed347156a7ea24da29e09083a499c80cf5) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Reduce visibility of TaskCompletionSource class ([4f55161132](https://github.com/facebook/react-native/commit/4f551611326d63b6fb5cd53e63d536c2c6f04647) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Stable API - Make ImageStoreManager internal ([846c4b1ea2](https://github.com/facebook/react-native/commit/846c4b1ea2d139e3f3cbafa2f8ddbf159e3322e4) by [@arushikesarwani94](https://github.com/arushikesarwani94))
|
||||
- Stable API - Make SwipeRefreshLayoutManager internal ([d02da992a4](https://github.com/facebook/react-native/commit/d02da992a4c0893313b9f059a8be228f43fffa7a) by Thomas Nardone)
|
||||
- Undo breaking change of UiManager.eventDispatcher return type ([7817ab5de2](https://github.com/facebook/react-native/commit/7817ab5de2ce324df734a5dfd705f2454937328f) by [@cortinico](https://github.com/cortinico))
|
||||
- Stable API - Make classes inside `com.facebook.react.views.progressbar` internal ([46526fc2fe](https://github.com/facebook/react-native/commit/46526fc2fe1dd0ce937fad35469b64b9fb05eaa2) by [@cortinico](https://github.com/cortinico))
|
||||
- Undo breaking change of UiManager.eventDispatcher return type ([dbe509a23a](https://github.com/facebook/react-native/commit/dbe509a23a974f16804aefea055a24c06910b259) by [@cortinico](https://github.com/cortinico))
|
||||
- Stable API - Make OkHttpCallUtil internal ([abd118a719](https://github.com/facebook/react-native/commit/abd118a719fe0aeb13f980729ff9ce5fb8358b83) by [@arushikesarwani94](https://github.com/arushikesarwani94))
|
||||
- Stable API - Make SimpleSettableFuture internal ([3dec672398](https://github.com/facebook/react-native/commit/3dec672398729cd668aff92249f1fdde231fb928) by [@arushikesarwani94](https://github.com/arushikesarwani94))
|
||||
- Stable API - Make `ClipboardModule` internal ([10f6d5adb5](https://github.com/facebook/react-native/commit/10f6d5adb538a9b20043312fc09b192759100d63) by [@cortinico](https://github.com/cortinico))
|
||||
- Reduce visibility of ReactVirtualTextShadowNode to internal ([496b0a8729](https://github.com/facebook/react-native/commit/496b0a8729b41266683fdd84de5618b23d06ce3d) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Reduce visibility of ReactVirtualTextViewManager to internal ([4a119c4c3a](https://github.com/facebook/react-native/commit/4a119c4c3ac9bf4b234e2942a27a6efd68a801cc) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Stable API - Make classes in `com.facebook.react.views.safeareaview` internal ([39dfbadd5d](https://github.com/facebook/react-native/commit/39dfbadd5d3468d079bf3b039401237c6e7f363c) by [@cortinico](https://github.com/cortinico))
|
||||
- Stable API - Make ClipboardModule internal ([a72c35f98c](https://github.com/facebook/react-native/commit/a72c35f98ccd1a49d367678b46a29c814ad5de43) by [@cortinico](https://github.com/cortinico))
|
||||
- Undo a breaking change on ReactViewGroup constructor ([bbe714e487](https://github.com/facebook/react-native/commit/bbe714e487fb51c61820fdc5d89c9782da79b657) by [@cortinico](https://github.com/cortinico))
|
||||
- Stable API - Make NativeModulePerfLogger internal ([d7d5de9f96](https://github.com/facebook/react-native/commit/d7d5de9f9630e7dcd0194830d7ccb32f167b619c) by [@cortinico](https://github.com/cortinico))
|
||||
- Make `DevLoadingModule` internal ([8c50bf0beb](https://github.com/facebook/react-native/commit/8c50bf0beb17ced7fdafeae7a734edfc03e6e0b2) by [@cortinico](https://github.com/cortinico))
|
||||
- Stable API - Convert to Kotlin and make internal `NotThreadSafeViewHierarchyUpdateDebugListener` ([287e200332](https://github.com/facebook/react-native/commit/287e20033207df5e59d199a347b7ae2b4cd7a59e) by [@cortinico](https://github.com/cortinico))
|
||||
- Rename DevSupportManagerBase.getCurrentContext() -> getCurrentReactContext() ([0e7ba9094e](https://github.com/facebook/react-native/commit/0e7ba9094ea573d1512b2dc71e46f55b24201b7a) by [@RSNara](https://github.com/RSNara))
|
||||
- Make DevSupportManagerBase.getCurrentReactContext() public ([5a6a42c7d0](https://github.com/facebook/react-native/commit/5a6a42c7d029d44799cb907c0ca3c8aa38fa1770) by [@RSNara](https://github.com/RSNara))
|
||||
- Reduce visibility of ReactUnimplementedViewManager to internal ([fe656be26e](https://github.com/facebook/react-native/commit/fe656be26e0d71bf2505032578dbea54af36b2c5) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Stable API - Make InteropModuleRegistry internal ([cba1d4bae7](https://github.com/facebook/react-native/commit/cba1d4bae7285ba160b05f31ca18cfa0b91e9ef5) by [@cortinico](https://github.com/cortinico))
|
||||
- Stable API - Make ReactDevToolsSettingsManagerModule and ReactDevToolsRuntimeSettingsModule internal ([d7550293a2](https://github.com/facebook/react-native/commit/d7550293a2530f02f75b4249b7e6003edaf28ac9) by [@cortinico](https://github.com/cortinico))
|
||||
- Added JSBundleLoader as parameter of DefaultReactHost ([143b9d172c](https://github.com/facebook/react-native/commit/143b9d172ca755e2457e8dfc6009eeef2475a4a1) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Deleting deprecated CompositeReactPackage ([2cb5198f1b](https://github.com/facebook/react-native/commit/2cb5198f1b589a57a4cfd3cc40a9ed6224fc5d75) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Make ReactHost.createSurface() method non nullable ([70c7616535](https://github.com/facebook/react-native/commit/70c761653564653bdfcb77a8c5ef3608dafcf5d7) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Stable API - Make AppStateModule internal ([dbf09fbe58](https://github.com/facebook/react-native/commit/dbf09fbe5823d77556b451317c14f833735067d9) by [@cortinico](https://github.com/cortinico))
|
||||
- Undo breaking change on UIManager eventDispatcher accessor ([dc1a498d39](https://github.com/facebook/react-native/commit/dc1a498d3974680f2257efd8ff9ec3f989204c68) by [@cortinico](https://github.com/cortinico))
|
||||
- Make `AccessibilityInfoModule` internal ([7168a9d1a2](https://github.com/facebook/react-native/commit/7168a9d1a2ed7459ebb056ebe45d86de791013e3) by [@cortinico](https://github.com/cortinico))
|
||||
- Undo breaking change on ViewManagerDelegate.kt String params ([2d2bb9c588](https://github.com/facebook/react-native/commit/2d2bb9c58824af34392bda196fbf0be17498cc05) by [@cortinico](https://github.com/cortinico))
|
||||
- Add 3 methods to ReactInstanceDevHelper ([c867aba2f3](https://github.com/facebook/react-native/commit/c867aba2f3dd7773be9d2ee0827bcd69481a394e) by [@cortinico](https://github.com/cortinico))
|
||||
- Add test case for set opacity in new arch examples ([848471b69f](https://github.com/facebook/react-native/commit/848471b69f59094780ace25c6963e480d94ec5c3) by [@poonamjain96](https://github.com/poonamjain96))
|
||||
- Add test for Console.log measure in new-arch-examples ([8cf27e8b6f](https://github.com/facebook/react-native/commit/8cf27e8b6f112d646111ddaba0b5036cafac3299) by [@poonamjain96](https://github.com/poonamjain96))
|
||||
- Remove Deprecated DefaultDevSupportManagerFactory.create() ([f25abe51ce](https://github.com/facebook/react-native/commit/f25abe51ce93b97ef1fe97af5fc76f13a5a6ff03) by [@cortinico](https://github.com/cortinico))
|
||||
- Remove BaseViewManagerInterface ([7fb3d830be](https://github.com/facebook/react-native/commit/7fb3d830beae3daf431ac90e9326b744ff8300a1) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Chore: test case added for Image ([d0e5053528](https://github.com/facebook/react-native/commit/d0e50535287088030e60e131691c8d9ed1d57989) by [@sarthak-d11](https://github.com/sarthak-d11))
|
||||
- Remove ReactNativeFlipper object, deprecated in 0.75 ([d1a256f51a](https://github.com/facebook/react-native/commit/d1a256f51a43f465823bdfb8a70fae5f92473d7c) by [@cortinico](https://github.com/cortinico))
|
||||
- Add test for background color and border width in text.yml ([fa62b7e1ed](https://github.com/facebook/react-native/commit/fa62b7e1ed00c69819d85819c6209fb42bedb233) by [@muskan27797](https://github.com/muskan27797))
|
||||
- Added Submit Application test to button.yml ([699f73a6b0](https://github.com/facebook/react-native/commit/699f73a6b0734fe716b01d263e9579bca38c4652) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
|
||||
- Use BackgroundStyleApplicator when setting background color in BaseViewManager ([309cdea337](https://github.com/facebook/react-native/commit/309cdea337101cfe2212cfb6abebf1e783e43282) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Delete useTurboModules, enableFabricRenderer and enableBridgelessArchitecture fields from ReactFeatureFlags class ([10a33e0479](https://github.com/facebook/react-native/commit/10a33e04793befbeab6ae82d4068b1ebd7fdffd0) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Remove ReactViewBackgroundManager and ReactViewBackgroundDrawable ([51673e41ae](https://github.com/facebook/react-native/commit/51673e41ae12f06b2b378e048094ad39ca30c317) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Use the RCTDependencyProvider in the RCTAppDelegate, breaking the dependency with Codegen ([b91626af26](https://github.com/facebook/react-native/commit/b91626af2626bf611958b1e7d0dd0b7338ccc29e) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Delete experimental API RCTConstants.RCTGetMemoryPressureUnloadLevel ([d79dc48abd](https://github.com/facebook/react-native/commit/d79dc48abd2e65e4d203e488f99eb554c473a1fc) by [@mdvacca](https://github.com/mdvacca))
|
||||
- ([6fc500ee99](https://github.com/facebook/react-native/commit/6fc500ee9942e51519545c1ba1026bacad03dc61) by [@philIip](https://github.com/philIip))
|
||||
- ([538bff710f](https://github.com/facebook/react-native/commit/538bff710f7afb4afa7ce91f20074668ad5c739d) by [@philIip](https://github.com/philIip))
|
||||
- Replace uses of `CGColorRef` with UIColor to avoid manual memory management ([b70709dbc2](https://github.com/facebook/react-native/commit/b70709dbc27c75c69e9fd2b082ffa27e7e8db7fd) by [@Saadnajmi](https://github.com/Saadnajmi))
|
||||
- Cocoapods decide the C++ version for iOS pods ([bd50c4a460](https://github.com/facebook/react-native/commit/bd50c4a460a01dad3cd7cade8191273563675d24) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Delete partialBatchDidFlush ([a777a8937e](https://github.com/facebook/react-native/commit/a777a8937ee165993d7d9b35c7c981fe6698f9dc) by [@philIip](https://github.com/philIip))
|
||||
- We deprecated RCTRuntimeExecutor in 0.76, so let's get rid of the code now. ([cf8d09b279](https://github.com/facebook/react-native/commit/cf8d09b279c4bd667d96f9445c1c0b9acb0a0dfc) by [@philIip](https://github.com/philIip))
|
||||
- Unbreak `RCTHermesInstance` constructor breaking change ([aec6666bfa](https://github.com/facebook/react-native/commit/aec6666bfabf93cde70fa869b3eea68590998dee) by [@tido64](https://github.com/tido64))
|
||||
|
||||
### Added
|
||||
|
||||
- Add FuseboxPerfettoDataSource to emit Fusebox traces using Perfetto ([ef0ea4d834](https://github.com/facebook/react-native/commit/ef0ea4d834ec61c5deede487b46a787a363f6a64) by Benoit Girard)
|
||||
- Add support for `rn_rootThreshold` in Intersection Observer ([a77d8d9d50](https://github.com/facebook/react-native/commit/a77d8d9d50e69a6a4563737c2ce68d26204eda7f) by [@lunaleaps](https://github.com/lunaleaps))
|
||||
- Codegen: Support negative values in enums ([177bf4d043](https://github.com/facebook/react-native/commit/177bf4d043ce862911e477e0f0039214d8541cfd) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Use the TypeScript key in syntax to restrict permissions and types of results ([0244710c4b](https://github.com/facebook/react-native/commit/0244710c4b1e5016069ec9f7b8e7116ff51f59f1) by [@qnnp-me](https://github.com/qnnp-me))
|
||||
- Image `resizeMode` and `objectFit` support for `'none'`. ([d8cfd98070](https://github.com/facebook/react-native/commit/d8cfd98070cbccc5e8a49446d76bdc2cb0c6939f) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- Add NumberLiteralTypeAnnotation support ([dd472101b7](https://github.com/facebook/react-native/commit/dd472101b76a964b7a64f0bb84d967f702500cad) by [@elicwhite](https://github.com/elicwhite))
|
||||
- Eliminate usage of more than 1-arg `React.AbstractComponent` in React codebase ([6205aad81e](https://github.com/facebook/react-native/commit/6205aad81ef8154a106fa253a1f4b00aee568650) by [@SamChou19815](https://github.com/SamChou19815))
|
||||
- Added support for `display: contents` ([e7a3f479fe](https://github.com/facebook/react-native/commit/e7a3f479fe37a5d503770bafc03c80b1c2dcb8f7) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
- Added the missing `announceForAccessibilityWithOptions` function mock in the `packages/react-native/jest/setup.js` file. ([4ae999b90b](https://github.com/facebook/react-native/commit/4ae999b90b2a67233890d30a8bff0dbdd58364f2) by [@ChrisMattew](https://github.com/ChrisMattew))
|
||||
- Add support for reload-to-profile in Fusebox (Part 2 of 2: JS) ([4df224ca6d](https://github.com/facebook/react-native/commit/4df224ca6df9dc593ab7090520578f27c520f361) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
|
||||
- Add JS layer for new text content type cellular EID and cellular IMEI ([118c1f7035](https://github.com/facebook/react-native/commit/118c1f7035cfcadb567b1ccd40d85c751dd65162) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Add support for reload-to-profile in Fusebox. (Part 1 of 2: native) ([91a40a28de](https://github.com/facebook/react-native/commit/91a40a28de3f74a389c6e6ad05fb917d58fc072d) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
|
||||
- Add cli --help details to combine-js-toschema-cli.js ([e4814b0d6d](https://github.com/facebook/react-native/commit/e4814b0d6d981cf96eef2803e8f20548263ea0e4) by [@blakef](https://github.com/blakef))
|
||||
- Codegen for Native Modules now supports string literals ([d2f3f06826](https://github.com/facebook/react-native/commit/d2f3f06826e2287ad5f5dc4e27201fc5dc9fcd5c) by [@elicwhite](https://github.com/elicwhite))
|
||||
- Codegen now supports Union Types in NativeModules ([3af126b562](https://github.com/facebook/react-native/commit/3af126b562cf7e0828906a4fe0ac79a886b557e6) by [@elicwhite](https://github.com/elicwhite))
|
||||
- Updated FlatList setNativeProps type ([b0ac99b477](https://github.com/facebook/react-native/commit/b0ac99b47781e3b68bee2ff737b109f58eeeba78) by [@JDMathew](https://github.com/JDMathew))
|
||||
- Added Jest mocks for `NativeAnimatedModule` ([fd355308fa](https://github.com/facebook/react-native/commit/fd355308faa2da30d4e0d68ae9b4d136d2a5f1c3) by [@yungsters](https://github.com/yungsters))
|
||||
- Added `HostInstance` type to represent the instance of a `HostComponent<T>`. ([e24f9917c2](https://github.com/facebook/react-native/commit/e24f9917c25ed8c32c6e01d50a5fa49fe66a6ee1) by [@yungsters](https://github.com/yungsters))
|
||||
- Export `DevMenu` from `react-native` ([e12c0d9551](https://github.com/facebook/react-native/commit/e12c0d95516924b5e6ca4f0d5ebcadb42bb19f30) by [@frankcalise](https://github.com/frankcalise))
|
||||
- Removed `experimental` prefix and fully released `mixBlendMode` prop ([d2c48f3b1a](https://github.com/facebook/react-native/commit/d2c48f3b1a2a15e9832ea3240c19aea5186ceb24) by [@jorge-cab](https://github.com/jorge-cab))
|
||||
- Add Playground to RNTester for testing out features & submitting reproducers. ([256adcab7b](https://github.com/facebook/react-native/commit/256adcab7b02e8a80227d44b76d1a74d8c4973de) by [@shwanton](https://github.com/shwanton))
|
||||
- Add color formatting to codegen output ([1747f57c67](https://github.com/facebook/react-native/commit/1747f57c6708ffa59ea511f9fbbacf37364fde72) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Added overlayColor prop to modal component for customisable background overlay ([4e1d7015c1](https://github.com/facebook/react-native/commit/4e1d7015c1d4e2703133b1347ed97a0cc93b1318) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
|
||||
- Created an experimental optimization to improve memoization within `Animated` to improve product performance ([dc84d00db6](https://github.com/facebook/react-native/commit/dc84d00db64b78234e91c2b73f4d4fce8782cd02) by [@yungsters](https://github.com/yungsters))
|
||||
- Expose missing text content type to JS ([d3d48cb357](https://github.com/facebook/react-native/commit/d3d48cb357e55b1f2ae0042a5960451fbe5ff5c7) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Created an experimental (unstable) method for allowlisting props when using `Animated` ([f3f652daab](https://github.com/facebook/react-native/commit/f3f652daabc4a1d374190165ac38715ad31a5214) by [@yungsters](https://github.com/yungsters))
|
||||
- Upgrade Flow to 0.245.2 ([1f65bf9545](https://github.com/facebook/react-native/commit/1f65bf9545cd84bbf1be7a7a91cb0b4f8b4b47ba) by [@SamChou19815](https://github.com/SamChou19815))
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Image `force-cache` caching control option ([a0be88fd72](https://github.com/facebook/react-native/commit/a0be88fd727898d4626ca51876d0bfb4e50dcb77) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- Add overlapping radii resolution logic preventing incorrect rendering ([451ff70da4](https://github.com/facebook/react-native/commit/451ff70da422beefccfff5b87024145003bb49ff) by [@jorge-cab](https://github.com/jorge-cab))
|
||||
- Marked ReactPackage#getModule as stable. ([8fba7ebb5e](https://github.com/facebook/react-native/commit/8fba7ebb5e874d001dc5c16eb4229054a2ef4812) by [@javache](https://github.com/javache))
|
||||
- ReactDelegate and ReactActivityDelegate#getCurrentReactContext can be used to access the current context ([fe8cc62824](https://github.com/facebook/react-native/commit/fe8cc62824372229d90445b2769fed9c08604a7e) by [@javache](https://github.com/javache))
|
||||
- Add exceptionHandler as a parameter of DefaultReactHost.getDefaultReactHost() method ([7a5a10c95c](https://github.com/facebook/react-native/commit/7a5a10c95ce6af1964ce5bd273c0c6513fb78a1e) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Logic to check for grayscale mode on android ([e70202e606](https://github.com/facebook/react-native/commit/e70202e606be3101da33d28f5403443c3e84749e) by [@oddlyspaced](https://github.com/oddlyspaced))
|
||||
- TextTransform ktx ([7794d7af43](https://github.com/facebook/react-native/commit/7794d7af43b90b581574361af102f67ad7961a5e) by Thomas Nardone)
|
||||
- Add navigationBarTranslucent prop to Modal component ([7a6c7a462a](https://github.com/facebook/react-native/commit/7a6c7a462a7898e13327438a6603d83a39147abb) by [@zoontek](https://github.com/zoontek))
|
||||
- Trigger Java GC on app reload ([de3c1ee097](https://github.com/facebook/react-native/commit/de3c1ee097f7041d6f9754a55a45cea80fd25813) by [@mrousavy](https://github.com/mrousavy))
|
||||
- Add cmake arguments to support 16KB page size for native libraries ([65cdd5b82c](https://github.com/facebook/react-native/commit/65cdd5b82ce7652630b1920fa3a48c8f256c7983) by [@alanleedev](https://github.com/alanleedev))
|
||||
- Enabling basic `Image` cache control for Android ([e5dd7d68bf](https://github.com/facebook/react-native/commit/e5dd7d68bf264669fc5c4ce5e69b24249d28558b) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- Add OnLayoutChange API for scroll views ([d825a4d712](https://github.com/facebook/react-native/commit/d825a4d712a1ba53c0f4209c9da5d51578209a6d) by Thomas Nardone)
|
||||
- React Activity exposes ReactHost ([d78cb78b15](https://github.com/facebook/react-native/commit/d78cb78b15a520f3bebcdf00b82b26bf120f4180) by [@shwanton](https://github.com/shwanton))
|
||||
- Added PixelUtil extensions for Int and Long ([9406a09f87](https://github.com/facebook/react-native/commit/9406a09f871d3efa66e3d10237a6d1fd08ddee0b) by Thomas Nardone)
|
||||
- Add boxShadow support to BaseViewManager ([b69a92e2c9](https://github.com/facebook/react-native/commit/b69a92e2c95990fcfa95a6ab7b7260ac492f942c) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Test: pressable test cases ([3102a58df3](https://github.com/facebook/react-native/commit/3102a58df38d96f3dacef0530e4dbb399037fcd2) by [@deepanshushuklad11](https://github.com/deepanshushuklad11))
|
||||
- Added showcase for Android `resizeMethod` options when applied to a large image ([768a1d8664](https://github.com/facebook/react-native/commit/768a1d86649e391964d404a15733c227c57c0d38) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Adds a new `resizeMethod`, `none`, which disables downsampling for an image ([6202319ed5](https://github.com/facebook/react-native/commit/6202319ed544e4d23f1f327ff5334c480af3819d) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Add Modal Testing to modal.yml ([1a2532b1fc](https://github.com/facebook/react-native/commit/1a2532b1fc32ec989e05576121b5e669697d29af) by [@ahmedbilal008](https://github.com/ahmedbilal008))
|
||||
- Add a new Fresco decoder for XML resource types ([118b7c18a6](https://github.com/facebook/react-native/commit/118b7c18a6f827dabb00522bbd6a2416e1bf99da) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Added `isHighTextContrastEnabled()` to `AccessibilityInfo` to read `ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED` setting value ([d4ea147b41](https://github.com/facebook/react-native/commit/d4ea147b41e4d22253f80be8b74731dcf0439302) by Ariel Lin)
|
||||
- Outline properties `outline-width`, `outline-color`, `outline-style` & `outline-offset` ([17faac4170](https://github.com/facebook/react-native/commit/17faac417035f2cc5f12ec60a46270991be0989a) by [@jorge-cab](https://github.com/jorge-cab))
|
||||
- Flag in ReactFragment to allow unmounting a surface without destroying ReactHost. ([bb3ec4d6c3](https://github.com/facebook/react-native/commit/bb3ec4d6c342d3afcb109e8c65f99e7693c962b5) by [@rozele](https://github.com/rozele))
|
||||
- ReactDelegate `unloadApp` methods for unmounting surfaces without destroying ReactHost ([38593c440e](https://github.com/facebook/react-native/commit/38593c440e949a9b52df0a6821b80ac47b19a693) by [@rozele](https://github.com/rozele))
|
||||
- New feature flag for line height calculation ([f338e7c0a1](https://github.com/facebook/react-native/commit/f338e7c0a1072974b5ac76567c8d1d06f5b7c1e2) by [@mellyeliu](https://github.com/mellyeliu))
|
||||
- Adds support for importing XML assets as images ([2e80f5acf1](https://github.com/facebook/react-native/commit/2e80f5acf11cd9726921a00a58700cab9e0bb0a7) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Image `only-if-cached` cache control option ([dc9db01665](https://github.com/facebook/react-native/commit/dc9db01665308ac931967326abfc86deb9ae7e2a) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- TextInput `inputAccessoryViewButtonLabel` prop ([32931466ed](https://github.com/facebook/react-native/commit/32931466ed7e3d8d9eeeb65f12ce146e123870ba) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- Fix: Correct Layout Behavior for Combined align-content and align-items ([73a2be1243](https://github.com/facebook/react-native/commit/73a2be12437c93bbd138e0d63cd45d834529a3c4) by [@phuccvx12](https://github.com/phuccvx12))
|
||||
- Extract RCTAppDependencyProvider in the ReactAppDependencyProvider pod ([102062fbc7](https://github.com/facebook/react-native/commit/102062fbc7d6a5c81192562c3ccb87bc4222a0cf) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Pass the `RCTAppDependencyProvider` to the `RCTAppDelegate` ([95fc906930](https://github.com/facebook/react-native/commit/95fc906930ece9b30482eb1f0924d7e8614af7c6) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Introduce the RCTAppDependencyProvider to minimize the changes required y the users ([41c2502b36](https://github.com/facebook/react-native/commit/41c2502b3650e238b0a5d86b5044abcb538b76e3) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Add RCTDependencyProvider protocol ([f2b3716426](https://github.com/facebook/react-native/commit/f2b371642684682916522dc82adee93464ba31fe) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Added `disabledButtonTintColor` prop to ActionSheetIOS ([089c87e22e](https://github.com/facebook/react-native/commit/089c87e22e9f431d0e7f35292dce2e36fa86d09a) by [@henninghall](https://github.com/henninghall))
|
||||
- Scroll the cursor into view when text input is focused ([e021e50d53](https://github.com/facebook/react-native/commit/e021e50d537884a55a9f5bea931adb19e9069dd6) by [@dominictb](https://github.com/dominictb))
|
||||
- Introduce RCTArchConfiguratorProtocol ([ec0dbb729d](https://github.com/facebook/react-native/commit/ec0dbb729d3774184dee83efbff5f9beebce72ce) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Introduce RCTUIConfiguratorProtocol ([8850736188](https://github.com/facebook/react-native/commit/8850736188321f13c7bdeadedeed15c759ad72c1) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- TvOS support for Hermes artifacts ([f673759c83](https://github.com/facebook/react-native/commit/f673759c83fed130964ea7dfe677c04608b8e64d) by [@douglowder](https://github.com/douglowder))
|
||||
- Add `CallInvoker` to `BindingsInstaller` ([87bae7f734](https://github.com/facebook/react-native/commit/87bae7f7349976cfc269b25584330c4d3d897d79) by [@mrousavy](https://github.com/mrousavy))
|
||||
- Added `isDarkerSystemColorsEnabled()` to `AccessibilityInfo` to read "Increase Contrast" setting value ([af3bee6511](https://github.com/facebook/react-native/commit/af3bee6511fe72fda7415bf974f937012b3eefec) by Ariel Lin)
|
||||
- Expose RCT_NEW_ARCH_ENABLED to Swift ([d24507611d](https://github.com/facebook/react-native/commit/d24507611de7fefc71286fd54b2c909d98a4bf27) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Add `systemCyan` and `systemMint` colors on iOS ([4caf548a9f](https://github.com/facebook/react-native/commit/4caf548a9f2e485aef9cbaeeb0a666cf9b9d3e59) by [@EvanBacon](https://github.com/EvanBacon))
|
||||
- Outline properties `outline-width`, `outline-color`, `outline-style` & `outline-offset` ([1288e38423](https://github.com/facebook/react-native/commit/1288e38423f93ed57737dd9b40ad55696494d6f4) by [@jorge-cab](https://github.com/jorge-cab))
|
||||
- Declare supportedInterfaceOrientations only on iOS ([40c5e6b64a](https://github.com/facebook/react-native/commit/40c5e6b64a1d82b5b481717b9086340eca2aaef9) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- New text content type cellular EID and cellular IMEI ([14e0d0dffb](https://github.com/facebook/react-native/commit/14e0d0dffb9ee8b1d41d60ccbcfd63d53bfe4d48) by [@pasc0al](https://github.com/pasc0al))
|
||||
- User-configurable BUNDLE_NAME when building bundles ([f8287e25e1](https://github.com/facebook/react-native/commit/f8287e25e11d56beb66ace414ca5f8a6a32405a9) by [@fivecar](https://github.com/fivecar))
|
||||
- Line break mode for TextInput components. **This includes JS APIs for the new mode.** ([ce2d34f194](https://github.com/facebook/react-native/commit/ce2d34f19451c91a90f0bd820064208912c86092) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
|
||||
|
||||
### Changed
|
||||
|
||||
- Fixed a typo in the README file. ([30e75a51f3](https://github.com/facebook/react-native/commit/30e75a51f3af7fbad83e4b002526b69bba021753) by [@Aryan2727-debug](https://github.com/Aryan2727-debug))
|
||||
- Fix unnececary rerenders of VirtualizedListCells with strictMode={true} ([aafe696453](https://github.com/facebook/react-native/commit/aafe696453186d0e87ae96d0bca4c6650234d222) by [@Tom910](https://github.com/Tom910))
|
||||
- The `AnimatedNode` graph will not occur during the insertion effect phase, which means animations can now be reliably started during layout effects. ([316170ce8d](https://github.com/facebook/react-native/commit/316170ce8d0aac1df3261c792b9f768665d134c5) by [@yungsters](https://github.com/yungsters))
|
||||
- AttributedString `appendFragment` and `prependFragment` take an rval instead of a const ref; append/prependAttributedString have been removed ([2c31fe99e1](https://github.com/facebook/react-native/commit/2c31fe99e1cc5bfdb393d4f5c70231a042ea67ef) by [@javache](https://github.com/javache))
|
||||
- Improved AttributedText generation for raw text nodes. ([2f7957f2fd](https://github.com/facebook/react-native/commit/2f7957f2fd424fdaa980d99a4ff05eb3237d662e) by [@javache](https://github.com/javache))
|
||||
- Callbacks passed to `animation.start(<callback>)` will be scheduled for execution in a microtask. Previously, there were certain scenarios in which the callback could be synchronously executed by `start`. ([090501d26d](https://github.com/facebook/react-native/commit/090501d26d83be5c5d2df885c60d05ec133d7a54) by [@yungsters](https://github.com/yungsters))
|
||||
- Optimized the performance of updating `Animated` components. ([f0ffcd4f5d](https://github.com/facebook/react-native/commit/f0ffcd4f5dfeab794fbfa3257bb9a8fd793ff2bc) by [@yungsters](https://github.com/yungsters))
|
||||
- Bump serve-static to 1.16.2 to fix CVE-2024-43800 ([50e38cc9f1](https://github.com/facebook/react-native/commit/50e38cc9f1e6713228a91ad50f426c4f65e65e1a) by [@cortinico](https://github.com/cortinico))
|
||||
- Bump Folly to 2024.10.14.00 ([37375d8aba](https://github.com/facebook/react-native/commit/37375d8aba0869531567426466478b0de9a1aea3) by [@alanleedev](https://github.com/alanleedev))
|
||||
- `useMergeRefs` and components using it (e.g. `Pressable`) now support ref cleanup functions. ([01e210fd28](https://github.com/facebook/react-native/commit/01e210fd28bc961e8c1b5fa454b3c947adda296c) by [@yungsters](https://github.com/yungsters))
|
||||
- : Update Metro to 0.81.0 ([0902b0af75](https://github.com/facebook/react-native/commit/0902b0af75ba30ec9d4abeda71769d0685637afa) by [@robhogan](https://github.com/robhogan))
|
||||
- Animations started with incompatible `useNativeDriver` and `AnimatedValue` configurations will now synchronously fail. Previously, spring and timing animations with non-zero delays would throw the error asynchronously. ([fd8cf19625](https://github.com/facebook/react-native/commit/fd8cf1962585aa49e8921475d89c1a5c2423c51c) by [@yungsters](https://github.com/yungsters))
|
||||
- The `Animation` superclass no longer exposes `__onEnd` as a property. Subclasses must instead invoke `super.start(…)` in their `start()` implementation. ([b3fe06b268](https://github.com/facebook/react-native/commit/b3fe06b2685e526fe2bc420a902a3ccd4e1381df) by [@yungsters](https://github.com/yungsters))
|
||||
- Simplified Flow types to use `HostInstance` (which changing nominal types). ([177697f539](https://github.com/facebook/react-native/commit/177697f539ec68a47cbb8f57260cebe701589ef1) by [@yungsters](https://github.com/yungsters))
|
||||
- Upgrade React DevTools to 6.0.0. ([ed4f6d6891](https://github.com/facebook/react-native/commit/ed4f6d68910677ab050e3fef5aaa87e42d582fe0) by [@hoxyq](https://github.com/hoxyq))
|
||||
- Fix: use public instance in Fiber renderer and expose it from getInspectorDataForViewAtPoint (#31068) ([633ad4933e](https://github.com/facebook/react-native/commit/633ad4933e9514d4168d6dcdb7e56c9a1859482a) by [@hoxyq](https://github.com/hoxyq))
|
||||
- Get react-native package name from package.json in codegen script ([65575e8399](https://github.com/facebook/react-native/commit/65575e8399a08841a0ccbc5b28cafeee6d41714c) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Bring back shouldSkipStateUpdatesForLoopingAnimations feature flag ([6e0e712c2a](https://github.com/facebook/react-native/commit/6e0e712c2a680cf4b4de1ee5fb25cc5282b242c5) by [@dmytrorykun](https://github.com/dmytrorykun))
|
||||
- AnimatedNode (and its subclasses) once again implement `toJSON()`. ([7bd4a54968](https://github.com/facebook/react-native/commit/7bd4a5496815943b031b68ca46792560d8d798d8) by [@yungsters](https://github.com/yungsters))
|
||||
- Do not print Bridgeless Mode is enabled on console anymore ([f3a969f38d](https://github.com/facebook/react-native/commit/f3a969f38d7a2c74bf63ee05c4c819c0873059a9) by [@cortinico](https://github.com/cortinico))
|
||||
- Bump main to 0.77-main ([120558c0cd](https://github.com/facebook/react-native/commit/120558c0cd6ae50156d2f7b958d3a29fd7ae4623) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Improved the performance of unmounting (and updating, when an enclosing Activity becomes hidden) Animated components ([46abda55b9](https://github.com/facebook/react-native/commit/46abda55b9749dc171e0fec551ba83c027818eb7) by Royi Hagigi)
|
||||
- AnimatedNode (and its subclasses) no longer implement `toJSON()`. ([fe6228512e](https://github.com/facebook/react-native/commit/fe6228512e076820c9c11869cfe24b19d1abfb58) by [@yungsters](https://github.com/yungsters))
|
||||
- Animated now resolves `style` to the original prop value if it contains no `AnimatedNode` instances. Previously, it would resolve to a flattened style object. ([ca234ba10e](https://github.com/facebook/react-native/commit/ca234ba10e8d06630da7ea00aac515b222137645) by [@yungsters](https://github.com/yungsters))
|
||||
- Bump Metro dependencies to 0.81.0-alpha.0 ([40f98b5eee](https://github.com/facebook/react-native/commit/40f98b5eeef18bb9c20a9a2762d0b1d648c4ae91) by [@robhogan](https://github.com/robhogan))
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Consolidated ReactViewGroup add/remove overrides ([0b22b955f1](https://github.com/facebook/react-native/commit/0b22b955f1494f0e7441a01dd19b3fdf5e20c3dc) by Thomas Nardone)
|
||||
- Migrated systeminfo module code from Java to Kotlin ([8dc2c90ce5](https://github.com/facebook/react-native/commit/8dc2c90ce5f4b30f4729560aed2412e6d29f39fa) by [@oddlyspaced](https://github.com/oddlyspaced))
|
||||
- Updating targetSdk to 35 (apps can still choose their own targetSdk regardless of RN version) ([48ea6867a9](https://github.com/facebook/react-native/commit/48ea6867a96bd16dc7aed9af5a8e9ce12a487c22) by [@alanleedev](https://github.com/alanleedev))
|
||||
- Invocations to JS will now invoke their callbacks immediately if the instance is ready. Surface starts will not wait for the main thread to become available to dispatch the work in JS. ([9fa4845136](https://github.com/facebook/react-native/commit/9fa4845136969ec95ce5615b7ea78feaf0f7f109) by [@javache](https://github.com/javache))
|
||||
- TurboModules marked as requiring eager init will now be constructed on the mqt_native thread to increase concurrency in React Native init. ([663b5f9d19](https://github.com/facebook/react-native/commit/663b5f9d19a905520bd0aef62cda890f76ef9b6e) by [@javache](https://github.com/javache))
|
||||
- Reduce visibility of Continuation to internal, although this interface wasn't being exposed in any public API ([7b21b9e69c](https://github.com/facebook/react-native/commit/7b21b9e69c6176c7f66af0e479623ed1c2be0d62) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Update documentation for ReactHost.destroy() APIs ([443bc32dc4](https://github.com/facebook/react-native/commit/443bc32dc49a86534fce1d6ec0e31c97b8f33053) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Deprecate CatalystInstance in old architecture ([3e27ef1f6e](https://github.com/facebook/react-native/commit/3e27ef1f6e024bba8725a3bd64e2648ffd6af496) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Deprecate BridgelessCatalystInstance class ([72bd840dd3](https://github.com/facebook/react-native/commit/72bd840dd3dc7b6e3e88a74ac9ddb000a0cb3a60) by [@mdvacca](https://github.com/mdvacca))
|
||||
- AGP to 8.7.2 ([e1a1cead43](https://github.com/facebook/react-native/commit/e1a1cead434a6856b2b018274876b9ba8eab706a) by [@cortinico](https://github.com/cortinico))
|
||||
- Migrate ReactFeatureFlags to Kotlin ([4076dbfc86](https://github.com/facebook/react-native/commit/4076dbfc8651fcd193b886bf63b23728fad466d7) by [@mdvacca](https://github.com/mdvacca))
|
||||
- Android NDK to 27.1 ([ba061a5d18](https://github.com/facebook/react-native/commit/ba061a5d18176fd455c3aa6350127506dac05211) by [@alanleedev](https://github.com/alanleedev))
|
||||
- Migrate MainReactPackage to Kotlin (and make it final) ([7bbac8ee27](https://github.com/facebook/react-native/commit/7bbac8ee27daf092b580b57c2c7ee46d2723cd09) by [@cortinico](https://github.com/cortinico))
|
||||
- Bump fbjni to 0.7.0 ([1c002c7b4e](https://github.com/facebook/react-native/commit/1c002c7b4ea4f22729920e54a9032402247ea350) by [@alanleedev](https://github.com/alanleedev))
|
||||
- Fresco to 3.4.0 ([091025e18b](https://github.com/facebook/react-native/commit/091025e18b1dc5212031e3ed06bfb6c450e788e2) by [@cortinico](https://github.com/cortinico))
|
||||
- Bump Kotlin 1.9.x to 2.0.x ([972c2c864c](https://github.com/facebook/react-native/commit/972c2c864c0b563163a36080a13908d1c0a3fb87) by [@cortinico](https://github.com/cortinico))
|
||||
- Fix: change opacity logic from random to decrement by -0.20 ([af4907025e](https://github.com/facebook/react-native/commit/af4907025ef358c312d469118a52699dcf14507d) by [@sarthak-d11](https://github.com/sarthak-d11))
|
||||
- Bump Android Gradle Plugin (AGP) to 8.7.0 ([cbc0978bb6](https://github.com/facebook/react-native/commit/cbc0978bb65dcfd2a18a54201c845785a626b1b3) by [@cortinico](https://github.com/cortinico))
|
||||
- Improve FpsDebugFrameCallback.getTotalTimeMS() accuracy ([d54c25fdae](https://github.com/facebook/react-native/commit/d54c25fdaee4d2642cdbca812b61c6973d3f203d) by [@aamagda](https://github.com/aamagda))
|
||||
- Update Fresco from 3.2.0 to 3.3.0 ([86d92e41d2](https://github.com/facebook/react-native/commit/86d92e41d2e129d12589848f75dfe2b2db09ed1a) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Disabling `outline` props on Android to stay consistent with iOS ([7ab0002799](https://github.com/facebook/react-native/commit/7ab0002799d52a876a8cdd32f25ebef6d431650e) by [@jorge-cab](https://github.com/jorge-cab))
|
||||
- Gradle to 8.10.1 ([90f89a830a](https://github.com/facebook/react-native/commit/90f89a830acced9e6b8e80ef58aefd7e2c9666a8) by [@cortinico](https://github.com/cortinico))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Make `prefetchImageWithMetadata`'s `queryRootName` nullable in the spec ([4dd60acb7d](https://github.com/facebook/react-native/commit/4dd60acb7ddc2811453e84e3567c1a114fa5e6f9) by [@TheRogue76](https://github.com/TheRogue76))
|
||||
- Change how components automatically register ([8becc2514d](https://github.com/facebook/react-native/commit/8becc2514d484c99b51ea76f479f06a8fcdd8265) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Stop generating the RCTThirdPartyLibraryComponentProvider ([60b9d3d89e](https://github.com/facebook/react-native/commit/60b9d3d89eba90a945070646c6220b3c03b3aeba) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- `RCTSurfaceHostingProxyRootView` no longer has different behavior (whether it calls `start` on the provided *surface*) depending on which initializer is used. Call `start` yourself on the *surface* instead. ([13b93cfdda](https://github.com/facebook/react-native/commit/13b93cfddaa559697968ac1c19e55f7aaa053070) by Nolan O'Brien)
|
||||
- Use `newArchEnabled` flag in RCTAppDelegate and RCTRootViewFactory ([7e1674fc59](https://github.com/facebook/react-native/commit/7e1674fc59abeeb70d946ee082a829fae4c671b7) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Do not move to the main queue synchronously when starting a new surface ([ab2c47be28](https://github.com/facebook/react-native/commit/ab2c47be285fde99a77d189fd04220ef8ad0933a) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Rename `RCTUIGraphicsImageRenderer` to `RCTMakeUIGraphicsImageRenderer` ([6a09fc09af](https://github.com/facebook/react-native/commit/6a09fc09af8eedbf409ab870d5714e44892b2a16) by [@Saadnajmi](https://github.com/Saadnajmi))
|
||||
- Refactor RCTDevLoadingView to use constraints ([fbda60e657](https://github.com/facebook/react-native/commit/fbda60e65783d9a3f257cd427cbffc1c9b2cc01b) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Deprecated shadows for ReadableNative[Map|Array].[Readable|Writable] ([d424bb9d7c](https://github.com/facebook/react-native/commit/d424bb9d7cf101dc5609e8f787ba8af2a33d0262) by [@javache](https://github.com/javache))
|
||||
- ReactContext.getFabricUIManager() method ([fb737ca7d3](https://github.com/facebook/react-native/commit/fb737ca7d34b636a3aa337a0935bf9a5a10c641d) by [@mdvacca](https://github.com/mdvacca))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Deprecating RCTBridgeModule batchDidComplete and adding configuration to disable it ([731bd95c43](https://github.com/facebook/react-native/commit/731bd95c430c752126aaaa34e4911ba2b87b382f) by [@philIip](https://github.com/philIip))
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove `BackHandler.removeEventListener` ([44d619414c](https://github.com/facebook/react-native/commit/44d619414c1de3dbf17a421afa8dbcec7cdab025) by [@retyui](https://github.com/retyui))
|
||||
- Removed type for useConcurrentRoot from AppRegistry, as it was already ignored ([2ec547ad28](https://github.com/facebook/react-native/commit/2ec547ad28ca914c17e276abb91174dfa0dc87b2) by [@javache](https://github.com/javache))
|
||||
- Remove "run on iOS" and "run on Android" from the dev server key commands ([19b971ff94](https://github.com/facebook/react-native/commit/19b971ff94a0fe353f82363e788c13f86815663b) by [@huntie](https://github.com/huntie))
|
||||
- Removed `refs` property from `NativeMethods` TypeScript definition. ([223e98cc4b](https://github.com/facebook/react-native/commit/223e98cc4b656b94b48c88940114bfdc025f8ddf) by [@yungsters](https://github.com/yungsters))
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Removed hasConstants constructor from ReactModuleInfo ([aec7a66ae8](https://github.com/facebook/react-native/commit/aec7a66ae84bd7689d902686711db8eabc21c1f1) by [@javache](https://github.com/javache))
|
||||
- Removed TurboReactPackage, which was replaced by BaseReactPackage ([bf5c98cf5e](https://github.com/facebook/react-native/commit/bf5c98cf5e1ce5c041d3d9321a0ba2fd3c755b46) by [@javache](https://github.com/javache))
|
||||
- DevToolsReactPerfLogger stats gathering now uses an internal API ([f503fe3f10](https://github.com/facebook/react-native/commit/f503fe3f100d96a31fc56451d7846d80ce5c342f) by [@javache](https://github.com/javache))
|
||||
- BindingImpl is no longer part of the public interface ([18faf68b48](https://github.com/facebook/react-native/commit/18faf68b4825118253cf247572084c4da8f6366e) by [@javache](https://github.com/javache))
|
||||
- FabricComponents is removed from public API ([300db67b27](https://github.com/facebook/react-native/commit/300db67b270a5d6fc85d27188d0d1089675f89c0) by [@javache](https://github.com/javache))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Remove available for RCTKeyWindow check ([e98c221e5e](https://github.com/facebook/react-native/commit/e98c221e5e54e79c25acd06f14e7d01221823305) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Hermes: revert Intl removal ([4cffff35e0](https://github.com/facebook/react-native/commit/4cffff35e030f256c32bf69c5971dfee4e60723f) by [@robhogan](https://github.com/robhogan))
|
||||
- Fix the nodes' owners not being updated when `display: contents` is used ([aa53bde21b](https://github.com/facebook/react-native/commit/aa53bde21b8952533cf17ffee234b273766f2133) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
- dev-middleware: Rewrite URLs in the inspector proxy to cover all configurations, not just Android emulators. ([74995bc90a](https://github.com/facebook/react-native/commit/74995bc90aa039b880e4875ad356d3bce324d902) by [@robhogan](https://github.com/robhogan))
|
||||
- Fix C++ bridging template compatibility with MSVC ([e6848ba5ba](https://github.com/facebook/react-native/commit/e6848ba5ba997d102cbaf6181c7c8c73e25a0827) by [@acoates-ms](https://github.com/acoates-ms))
|
||||
- Accessing KeyboardAvoidingEvent event in onLayout handler ([68db74205a](https://github.com/facebook/react-native/commit/68db74205afdd190304eb73ef71710781fa580b9) by [@mhoran](https://github.com/mhoran))
|
||||
- dev-middleware: Fix URL rewriting where device and debugger reach the server on different ports/protocols. ([5da7ebf99a](https://github.com/facebook/react-native/commit/5da7ebf99ae317c104d8e4bfbf36d3d89f66b5c9) by [@robhogan](https://github.com/robhogan))
|
||||
- dev-middleware: Regex-escape IP addresses in urlRegex replacements ([aae3e03e57](https://github.com/facebook/react-native/commit/aae3e03e57096c3dc51589a3de240d49a8b9fadf) by [@robhogan](https://github.com/robhogan))
|
||||
- Fixed jest error from Appearance.js ([ce838a4bcf](https://github.com/facebook/react-native/commit/ce838a4bcfb1c08728b637a9addd24cc6e3477e0) by [@Kudo](https://github.com/Kudo))
|
||||
- When using Babel with plain JavaScript files, support for additional user syntax plugins should be fixed (now uses Babel's parser instead of hermes-parser). There is no change for JS files annotated with `flow`, where extended JS syntax remains unsupported. ([3de9892353](https://github.com/facebook/react-native/commit/3de989235365504468d2b6c0bb194e944bf1ce8e) by [@huntie](https://github.com/huntie))
|
||||
- Fix `Appearance.setColorScheme(null)` not resetting color scheme value ([7d63235086](https://github.com/facebook/react-native/commit/7d63235086352d8c424d634c7039551f0a5025dc) by [@sangonz193](https://github.com/sangonz193))
|
||||
- Fix text not taking full width ([550b0c0ed1](https://github.com/facebook/react-native/commit/550b0c0ed16a64ce58102f15d4657abe92aac71c) by [@s77rt](https://github.com/s77rt))
|
||||
- Linear gradient start and end point algorithm. ([221d1eceda](https://github.com/facebook/react-native/commit/221d1eceda0e5ab870e96dcdd26e22ab17a3870c) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
||||
- Codegen: Support nested objects in arrays ([13780126d3](https://github.com/facebook/react-native/commit/13780126d3cb17ad00c2954f9830a3623812dc3e) by [@tvanlaerhoven](https://github.com/tvanlaerhoven))
|
||||
- RN DevTools: Don't assume 10.0.2.2 is an alias for localhost unless it's used to establish a connection to the server ([69400be4fc](https://github.com/facebook/react-native/commit/69400be4fc0abd38072f6586f3e7d5b6c33e54be) by [@robhogan](https://github.com/robhogan))
|
||||
- Do not discard props in the patch when they are not null while using `useNativeProps` ([4c3112c8d8](https://github.com/facebook/react-native/commit/4c3112c8d8685d6c34be9acf07b18871b3cee5b2) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- : dev-middleware: Remove URL.canParse, restore compat with Node < 18.17 ([99767d43b0](https://github.com/facebook/react-native/commit/99767d43b04e41c83e3bcbfebe267d6fdc284549) by [@robhogan](https://github.com/robhogan))
|
||||
- RN DevTools: Fix fetching sources and source maps when the dev-server is remote and not tunnelled via the same port+protocol. ([d1b0e9a30b](https://github.com/facebook/react-native/commit/d1b0e9a30b3afc56b9355453cf7f6e690bdd8aff) by [@robhogan](https://github.com/robhogan))
|
||||
- Fix npm react-native start when cli-server-api isn't installed ([e0be2efe4e](https://github.com/facebook/react-native/commit/e0be2efe4e80edf99f96a2ae6a25856f6df5e0ca) by [@blakef](https://github.com/blakef))
|
||||
- AnsiHighlight style in RTL layout ([9a3958a619](https://github.com/facebook/react-native/commit/9a3958a619fddb75ed3c6eddebd94f11c0d00e9f) by [@hexboy](https://github.com/hexboy))
|
||||
- Fixes typo in ReactHostImpl ([e3f03269c5](https://github.com/facebook/react-native/commit/e3f03269c5cea28977e44ddf5c5125968336b0e6) by [@rozele](https://github.com/rozele))
|
||||
- TextTransform: capitalize better reflects the web behaviour ([dc2000c875](https://github.com/facebook/react-native/commit/dc2000c8750f42b2f01bdad75455750814d567c6) by [@javache](https://github.com/javache))
|
||||
- Fix for nodes with `display: contents` not being cleaned in some cases ([a88ddcecc9](https://github.com/facebook/react-native/commit/a88ddcecc93a9fa2d231907439d02b11bac8a944) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
- Microtasks are now correctly executed after the code evaluation in Console panel of DevTools. ([3dfe22bd27](https://github.com/facebook/react-native/commit/3dfe22bd27429a43b4648c597b71f7965f31ca65) by [@hoxyq](https://github.com/hoxyq))
|
||||
- Passed height and width as native props to support cases where source is an array. ([45b177f50d](https://github.com/facebook/react-native/commit/45b177f50de624eefcb66bb2d8bc1ffb00855863) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
|
||||
- `PerformanceEntryReporter::reportMark` and `PerformanceEntryReporter::reportMeasaure` now return created performance entries. ([32f7b3b4e0](https://github.com/facebook/react-native/commit/32f7b3b4e0b8be1d1138f43c46b3c86d9a64c29a) by [@robik](https://github.com/robik))
|
||||
- Make Codegen work with local modules ([7b6e8e7765](https://github.com/facebook/react-native/commit/7b6e8e776574e683821133f0c814969d74c4de61) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Fix KeyboardAvoidingView not aware of the keyboard closing it is unmounted ([08bd8ac47d](https://github.com/facebook/react-native/commit/08bd8ac47da60121225e7b281bbf566e2c5a291e) by [@QichenZhu](https://github.com/QichenZhu))
|
||||
- Fix onEndReached not being called when getItemLayout is present and we scroll past render window ([3485e9ed87](https://github.com/facebook/react-native/commit/3485e9ed871886b3e7408f90d623da5c018da493) by YunPeng Chong)
|
||||
- Fix cast and control paths errors on windows ([0794fa909b](https://github.com/facebook/react-native/commit/0794fa909b2e06fad5c40dce402c5f14a24bb946) by [@TatianaKapos](https://github.com/TatianaKapos))
|
||||
- Plumbing to get boxSizing prop to Yoga round 2 ([3ca796edc3](https://github.com/facebook/react-native/commit/3ca796edc327c5287533dcc8f4394033d5398c2d) by [@joevilches](https://github.com/joevilches))
|
||||
- Fix onEndReached not being called when getItemLayout is present and we scroll past render window ([62b7396bf4](https://github.com/facebook/react-native/commit/62b7396bf45c04bd47e74fe4c1e5b5e59918244d) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- TurboModule::get is now a final method, override `create` to customize property lookup ([5b5e150eaf](https://github.com/facebook/react-native/commit/5b5e150eaff015540720225b9e61acb306e1d107) by [@javache](https://github.com/javache))
|
||||
- Improved types for AnimatedProps ([390925ea39](https://github.com/facebook/react-native/commit/390925ea39eb469768f21cf7069b8f75ccdec09d) by [@javache](https://github.com/javache))
|
||||
- Upgrade Codegen dependency `jscodeshift@17.0.0` to resolve outdated dependencies ([39c98fb8f8](https://github.com/facebook/react-native/commit/39c98fb8f8af98aa40dc89a1580d6c1901fa86cf) by [@byCedric](https://github.com/byCedric))
|
||||
- Fixed issues with W3C PointerEvents testsx ([1dcaf823f5](https://github.com/facebook/react-native/commit/1dcaf823f5e7d9b114dd803ce3181aa0b8f827ad) by [@rozele](https://github.com/rozele))
|
||||
- Fixed issue with W3C PointerEvents tests ([68a6b69b27](https://github.com/facebook/react-native/commit/68a6b69b27275998b4083797942f3e26a92d3adb) by [@rozele](https://github.com/rozele))
|
||||
- Fix setImmediate/clearTimeout mismatch in NativeAnimatedHelper that could clear an unrelated setTimeout. ([a5dd1be889](https://github.com/facebook/react-native/commit/a5dd1be889be21f8daefbc609702989ec7c156cf) by Benoit Girard)
|
||||
- Improved error message when no view config is found. ([bca232ad90](https://github.com/facebook/react-native/commit/bca232ad90692da7a87be5e37ee2680380f94bef) by [@javache](https://github.com/javache))
|
||||
- : Order of operations related to platformConfig propagation in NativeAnimated ([a64183b0c6](https://github.com/facebook/react-native/commit/a64183b0c6a56e9d482c7b8b0f80965493ed87af) by [@rozele](https://github.com/rozele))
|
||||
- Rename overlayColor prop in Modal to backdropColor ([7aeff18970](https://github.com/facebook/react-native/commit/7aeff18970a2b47cbb3fffc1408e4bb21eec6fed) by [@alanleedev](https://github.com/alanleedev))
|
||||
- Fix source mapping for codegenNativeCommands ([8fba154b66](https://github.com/facebook/react-native/commit/8fba154b6655b5d87609d7c9f136997141ea5e99) by [@vzaidman](https://github.com/vzaidman))
|
||||
- Fixed accuracy of FlatList estimations to determine what elements are visible in the rendering window. ([40aaeb7181](https://github.com/facebook/react-native/commit/40aaeb71814a1987482d97fd3170af0add55bc6a) by [@rubennorte](https://github.com/rubennorte))
|
||||
- Fix type conversion error in react native windows build. ([13db1cb88b](https://github.com/facebook/react-native/commit/13db1cb88bdd454cf19be358d6f0cd62f5a6d0cc) by [@marlenecota](https://github.com/marlenecota))
|
||||
- Correctly pass down isLooping in parallel animation ([4014aa4528](https://github.com/facebook/react-native/commit/4014aa4528d43e905246850c83007a635938d7cb) by [@zeyap](https://github.com/zeyap))
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Yoga: Fix YogaConfig getting garbage collected #1678 ([7dcb10b6e7](https://github.com/facebook/react-native/commit/7dcb10b6e7e226034a496eaed5351601ae0a1ae2) by [@michaeltroger](https://github.com/michaeltroger))
|
||||
- Enable mix-blend-mode on ReactRootView so blending works with app background ([24b0ded3cf](https://github.com/facebook/react-native/commit/24b0ded3cf715bb0e849d9f7ca8cd2d4d42cbf90) by [@jorge-cab](https://github.com/jorge-cab))
|
||||
- RN DevTools: Fix source loading when using an Android emulator connecting to a dev server on the host. ([ca9c56329f](https://github.com/facebook/react-native/commit/ca9c56329fe548b6631934afee0c9be63e1752a1) by [@robhogan](https://github.com/robhogan))
|
||||
- Fixes some deadlocks when doing commits and state updates synchronously from the UI thread (e.g.: from reanimated). ([3986eefed1](https://github.com/facebook/react-native/commit/3986eefed1733f305db5410737a96b635f0159e7) by [@rubennorte](https://github.com/rubennorte))
|
||||
- Ensure setSelection in onAttachedToWindow is within text range ([08759121cd](https://github.com/facebook/react-native/commit/08759121cda3785e4d7ee1f1c82011a3e3a955a9) by [@zeyap](https://github.com/zeyap))
|
||||
- Fixed crash in legacy ReactFontManager ([3da23f7093](https://github.com/facebook/react-native/commit/3da23f7093730e10aeda6b58f4934a381e226dd2) by [@javache](https://github.com/javache))
|
||||
- Dispatch onMomentumScrollEnd after programmatic scrolling ([c69e330324](https://github.com/facebook/react-native/commit/c69e330324724a1e363f4786b2b03ee7ff4b35c5) by [@Biki-das](https://github.com/Biki-das))
|
||||
- RNGP - Do not attempt to substring to 1024 while logging ([e64513bf4e](https://github.com/facebook/react-native/commit/e64513bf4ecce60aff5c04e3bed91b203429d12f) by [@cortinico](https://github.com/cortinico))
|
||||
- Missing isInvertColorsEnabled implementation for Android ([cc1d2853fb](https://github.com/facebook/react-native/commit/cc1d2853fb2b64adfb884cb30c8d22ce0260be15) by [@oddlyspaced](https://github.com/oddlyspaced))
|
||||
- Addressed race condition in surface start. ([6ba7cb3102](https://github.com/facebook/react-native/commit/6ba7cb310273a0ecce6a168bf3aae45fb85bf955) by [@javache](https://github.com/javache))
|
||||
- The definition of ts of resizeMethod attribute is none. ([758892a7d8](https://github.com/facebook/react-native/commit/758892a7d89cc1e316984f8f522738021410f530) by [@nianxiongdi](https://github.com/nianxiongdi))
|
||||
- Reimplement Android lineHeight positioning/determination ([41265bac6b](https://github.com/facebook/react-native/commit/41265bac6b83ee0bb92d645ace81e314065bf5e0) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Fix legacy arch RTL horizontal ScrollView regression ([bfca7cfe7a](https://github.com/facebook/react-native/commit/bfca7cfe7a8e0da10fdb776100fbc706233c0d8d) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Fix RTL ScrollView position when content smaller than container ([0df59d4f03](https://github.com/facebook/react-native/commit/0df59d4f03f79c0fcb9ede2d21bf4d49c97c21ef) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Avoid null reference exception in bridgeless ReactDelegate ([0d664100bb](https://github.com/facebook/react-native/commit/0d664100bbf608550a5c42a4e9b02c6c5bd0f5b8) by [@rozele](https://github.com/rozele))
|
||||
- Fix generating empty line at the end of multiline text view when `textAlign` is set to `justify` ([08e8f6adfd](https://github.com/facebook/react-native/commit/08e8f6adfdcdfec59002f34bb7acf35bb842b331) by [@coado](https://github.com/coado))
|
||||
- Fix Frame Callback not being called after Host Resume ([e8f8ee3c0f](https://github.com/facebook/react-native/commit/e8f8ee3c0f28b8c5751ffaef495adea0b8daf1eb) by [@s77rt](https://github.com/s77rt))
|
||||
- Fix crash in getViewState when using suspense fallbacks. ([bd133b5dd5](https://github.com/facebook/react-native/commit/bd133b5dd57b18140eae51c6d7aaab02874455c1) by [@javache](https://github.com/javache))
|
||||
- Text without explicit font styles was potentially cut-off. ([95a5d1c628](https://github.com/facebook/react-native/commit/95a5d1c6287c7301265207d1962ba8b50d178b20) by [@javache](https://github.com/javache))
|
||||
- Merge Android ViewNativeComponent ViewConfig into BaseViewConfig ([0ba00fc998](https://github.com/facebook/react-native/commit/0ba00fc99891a333d3625db15d9dd832ca7eac88) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Fixed styling on alert dialog titles to wrap two lines and retain bold appearance ([c54b23ff9e](https://github.com/facebook/react-native/commit/c54b23ff9ed7a6bfbb52c081c5afe4b3911d0dd2) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Prevent ArrayIndexOutOfBoundsException in permission check ([6aeca53b3e](https://github.com/facebook/react-native/commit/6aeca53b3ed4530e57a31d7a5593ae16b550b985) by [@antFrancon](https://github.com/antFrancon))
|
||||
- Account for items dynamically scaling with the container when using `maintainVisibleContentPosition` in virtualized lists ([6c19996e10](https://github.com/facebook/react-native/commit/6c19996e10eda97a3501f53a68da246d1f122d01) by [@fabriziocucci](https://github.com/fabriziocucci))
|
||||
- Apps will no longer fatally crash when trying to draw large images ([483b928224](https://github.com/facebook/react-native/commit/483b92822496fa2e6339f75049a33be1e9567f52) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Add missing BaseViewManager props to BaseViewManagerDelegate ([6741fd94ad](https://github.com/facebook/react-native/commit/6741fd94ad26012938caa65a5129f0eca6f2246e) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Fix TextInput caret moving to the beginning when attached to window ([ca0abd1b9e](https://github.com/facebook/react-native/commit/ca0abd1b9ea164a566b39cb9090eaa75647aad5a) by [@QichenZhu](https://github.com/QichenZhu))
|
||||
- Fix issue where `onDropViewInstance` cleanup was not being handled after `ReactRootView.unmountReactApplication` ([0449630612](https://github.com/facebook/react-native/commit/04496306123c46730b46accb2cd6239531e51fef) by [@rozele](https://github.com/rozele))
|
||||
- Fix issues with Modals and lifecycle events in multi-surface apps ([1ffef5669c](https://github.com/facebook/react-native/commit/1ffef5669c21f4b2c5fec6bc58a85f95518cf10e) by [@rozele](https://github.com/rozele))
|
||||
- Fix mising `ANTI_ALIAS_FLAG` when resetting Text Paint ([276e3a7df7](https://github.com/facebook/react-native/commit/276e3a7df7de1b04dec0891fa7ed72917568ee7b) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Fix some cases where we override setBackgroundColor on View-level instead of VM level ([0b0ac81fbe](https://github.com/facebook/react-native/commit/0b0ac81fbeebf819e744b6ecc19d549aaab8406d) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Avoid blocking the main thread when decompressing drawable resources ([420229d669](https://github.com/facebook/react-native/commit/420229d66946320f06485c5a3d3c167eae1a407e) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Reenable `setAndroidLayoutDirection` by default ([6cf0cfb5a4](https://github.com/facebook/react-native/commit/6cf0cfb5a47a437b8a17b50b4c70460be15ee1cd) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Properly fix measurement of trailing newlines ([060c594457](https://github.com/facebook/react-native/commit/060c59445740f9b92188d2193623b36c3d859ba7) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Fix crash for Modal not attached to window manager ([eaa780de1c](https://github.com/facebook/react-native/commit/eaa780de1c799bf35fded2914d27b1953b093340) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Fix NPE on ReactTextInputManager.setTextDecorationLine ([41c6ad5597](https://github.com/facebook/react-native/commit/41c6ad55978184cad1a32ec63c2d1f07e8282d5e) by [@cortinico](https://github.com/cortinico))
|
||||
- BoxShadow now supports platformColor. ([4ede9205a0](https://github.com/facebook/react-native/commit/4ede9205a0559fcaf7ac58a3d70bc902eb23fcb6) by [@javache](https://github.com/javache))
|
||||
- MixBlendMode now properly does state updates ([fae572d815](https://github.com/facebook/react-native/commit/fae572d815c7fb9684fc6c3b7f001de35ea8fb69) by [@jorge-cab](https://github.com/jorge-cab))
|
||||
- Fix interactions between removeClippedSubviews and RTL ([513e9669e7](https://github.com/facebook/react-native/commit/513e9669e78a4bfd9b0380335c61f581343c4009) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- LayoutAnimations work on full new architecture ([43af902693](https://github.com/facebook/react-native/commit/43af902693f0befde802a7f684e26b19ec7126c8) by [@javache](https://github.com/javache))
|
||||
- Fix: ReactDelegate/ReactFragment crashing on New Architecture apps ([12dda31bc1](https://github.com/facebook/react-native/commit/12dda31bc12f4a04ec9df70d30328b1001bb2cec) by [@cortinico](https://github.com/cortinico))
|
||||
- ReactFragment should properly instantiate ReactDelegate on Bridgeless ([7176d11ce4](https://github.com/facebook/react-native/commit/7176d11ce468ca37e9cbe8afcc1f6344c250dd0c) by [@cortinico](https://github.com/cortinico))
|
||||
- Fixed text being measured incorrectly when ending with an empty line on the new architecture ([bd323929dc](https://github.com/facebook/react-native/commit/bd323929dc5be5666ee36043babec7d981a095dc) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
- Linear gradient with platform colors ([6866968a79](https://github.com/facebook/react-native/commit/6866968a79d44518884965959760983acdadc17c) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
||||
- ARG_DISABLE_HOST_LIFECYCLE_EVENTS in ReactFragment to allow unmounting a surface without destroying ReactHost. ([40c875deca](https://github.com/facebook/react-native/commit/40c875decabaa56d6dd45ce03b22e8b3931781ac) by [@vincenzovitale](https://github.com/vincenzovitale))
|
||||
- Fixed incorrect scroll event/position for scroll views when doing a smooth scroll animation. ([b4c41ec768](https://github.com/facebook/react-native/commit/b4c41ec7685da6e8ef35c41c30aa402639bc42c1) by [@rubennorte](https://github.com/rubennorte))
|
||||
- Use appropriate Nullable attribute for ReactRootView field in ReactDelegate ([cbddcfc691](https://github.com/facebook/react-native/commit/cbddcfc6911101608df36f2a8d047768296c63b2) by [@rozele](https://github.com/rozele))
|
||||
- Hover events were dispatched incorrectly when multiple ReactRoots were layered. ([533ef2ca37](https://github.com/facebook/react-native/commit/533ef2ca37d3b19fc909315f183e3f30dbf4b93d) by [@javache](https://github.com/javache))
|
||||
- Improve text line height calculation ([65d8f66b50](https://github.com/facebook/react-native/commit/65d8f66b50471d2fb4ddd5e63e17fcc808623110) by [@mellyeliu](https://github.com/mellyeliu))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Fix possible NSRangeException when updating typing attributes in response to new text content ([6e06a810f0](https://github.com/facebook/react-native/commit/6e06a810f0ab1002f1d10351bc878babde36b1f1) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- Ensure artifacts directory exists when building Hermes from local source ([c3091ccfed](https://github.com/facebook/react-native/commit/c3091ccfed4440d7f0b906a7eb954718656b71b2) by [@kraenhansen](https://github.com/kraenhansen))
|
||||
- "Reconnect DevTools" button not working sometimes ([8507204b53](https://github.com/facebook/react-native/commit/8507204b533cf87d1e4345a9c062cd10cf0022c1) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
|
||||
- Fixed use of view commands from layout effects ([6f1c2a512e](https://github.com/facebook/react-native/commit/6f1c2a512e44d25edefea53e864f688018745c07) by [@sammy-SC](https://github.com/sammy-SC))
|
||||
- Fix `r` & `d` not working from Metro sometimes ([9a60038a40](https://github.com/facebook/react-native/commit/9a60038a40e16925ea1adeb3e3c937c22a615485) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
|
||||
- Resolve deprecated function prototype warning in RCTAppearance.h ([594c9d9a46](https://github.com/facebook/react-native/commit/594c9d9a46623016abb6bbd0d8f2982bf68bdc34) by [@eli-front](https://github.com/eli-front))
|
||||
- Fixes rn-tester bundled images examples ([8cbc7c3357](https://github.com/facebook/react-native/commit/8cbc7c3357ac4043e6c423261c090a1bf656f68e) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
- Fixed `onMomentumScrollBegin` event not firing on command-driven scroll events ([5b609cca09](https://github.com/facebook/react-native/commit/5b609cca099b3b0d4fc66d4cf50f69d3c5b7fc8e) by [@Abbondanzo](https://github.com/Abbondanzo))
|
||||
- Typo in spm.rb ([5e18f7f788](https://github.com/facebook/react-native/commit/5e18f7f788ccbea60e96b8e7deab29d423ccf1a6) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Add png extension only if file exist when load local image ([44f2a08371](https://github.com/facebook/react-native/commit/44f2a083716205b7560bef2f09d25830e29cd0c5) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
- FIxes CornerRadiiAreEqualAndSymmetrical error when check topLeftHorizontal == topLeftVertical ([af384a914a](https://github.com/facebook/react-native/commit/af384a914a4e9ef6a5d25b00bc14b0483e5af879) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
- Fix numerous class interfaces having incorrect designated initializer patterns ([b98846c2e3](https://github.com/facebook/react-native/commit/b98846c2e37c3ec895536ab942978d7701f51a5e) by Nolan O'Brien)
|
||||
- AutomaticallyAdjustKeyboardInsets not shifting scrollview content ([2d9933e616](https://github.com/facebook/react-native/commit/2d9933e616c3efe57ed0ca141277638182a69d9c) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
- Fix launching App Clips with nullish URLs. ([043e2fe14a](https://github.com/facebook/react-native/commit/043e2fe14a6f13885a552211f17d61292001fa76) by [@EvanBacon](https://github.com/EvanBacon))
|
||||
- Fixes scrollIndicatorInsets not work in old arch ([c1178ac208](https://github.com/facebook/react-native/commit/c1178ac2085e073afb07453eefc9095a1f5d530f) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
- Silenced 'set but unused variable' warning. ([f7b28e86aa](https://github.com/facebook/react-native/commit/f7b28e86aaded58f76978179d8d83f11e913b026) by [@nlutsenko](https://github.com/nlutsenko))
|
||||
- Fixed crash on promise rejection handler in iOS 18. ([26d8d490e4](https://github.com/facebook/react-native/commit/26d8d490e47bd3fa46dc4a3b8e66e9ec35c15cf7) by David Rickard)
|
||||
- Fixed scroll view ([ab8f3ff3e9](https://github.com/facebook/react-native/commit/ab8f3ff3e9e6445fa9961467e965792908d4c2bd) by [@coado](https://github.com/coado))
|
||||
- Fixes missing char mode of linebreakmode ([77889afa1c](https://github.com/facebook/react-native/commit/77889afa1c9d0bdb966102860a5d1d1d91187ae8) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
- Removed usage of set but unused variable. ([d386dfc804](https://github.com/facebook/react-native/commit/d386dfc804842ed36565966da5aed15d9df7960e) by [@nlutsenko](https://github.com/nlutsenko))
|
||||
- Cast the UIScene to UIWindowScene only if the scene respond to the selector ([fdee0ebbcb](https://github.com/facebook/react-native/commit/fdee0ebbcb88f40c23b92b07792fbb9d1041c546) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Move RCTNotifyEventDispatcherObserversOfEvent_DEPRECATED to const ([a1ec345e2a](https://github.com/facebook/react-native/commit/a1ec345e2a2cdb4ccf255293616ed5e90f519e40) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Fixes the exported synchronous method not being called on the method queue when it's the main queue ([8bfd7e1039](https://github.com/facebook/react-native/commit/8bfd7e10393e649554c7246df430019c4f78d5e0) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
- Make sure that the Increment and Decrement accessibility actions works on iOS ([303e0ed764](https://github.com/facebook/react-native/commit/303e0ed7641409acf2d852c077f6be426afd7a0c) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Subscribe to orientation changes in RCTUIManager only on iOS ([2f5adc3874](https://github.com/facebook/react-native/commit/2f5adc3874bcdfc8d7d2c3cd5293eefec63a91f8) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Fix ActionSheetIOS crash `attempt to insert nil object from objects` ([bebd6531b5](https://github.com/facebook/react-native/commit/bebd6531b5f4ef0300aa5a4b6f9d23e60b57a25e) by [@RodolfoGS](https://github.com/RodolfoGS))
|
||||
- Allow pods mixte type settings on post-install ([1e59f2e3f8](https://github.com/facebook/react-native/commit/1e59f2e3f8f0ab3ee4173bddaa089bbecf61d1eb) by [@MasGaNo](https://github.com/MasGaNo))
|
||||
- Fallback to old resolve mechanism when node require fails to resolve react native path ([3cbaddbc16](https://github.com/facebook/react-native/commit/3cbaddbc164b9dc326b2a7ddc0b35ce885bc7d9d) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
- Fixed warnings when validating SVC ([de39a204c3](https://github.com/facebook/react-native/commit/de39a204c3588a3c02dc2e72464174c75b3a6749) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Solved SVC warnings for RNTester ([fad4a0783b](https://github.com/facebook/react-native/commit/fad4a0783b0a0478c147d9bde2ef9ab082a08297) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Don't reference PrivacyInfo.xcprivacy twice for new projects ([cadd41b1a2](https://github.com/facebook/react-native/commit/cadd41b1a2e16b1c77a8d3022f4ccbdbd5ea295f) by [@okwasniewski](https://github.com/okwasniewski))
|
||||
|
||||
## v0.76.3
|
||||
|
||||
### Fixed
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Look for sdkmanager.bat ([6460d2b3e7](https://github.com/facebook/react-native/commit/6460d2b3e74c3a6e4075e9f12304c16427c3b1b2) by [@blakef](https://github.com/blakef))
|
||||
- CMake Windows path normalization ([9946838bedd](https://github.com/facebook/react-native/commit/9946838beddac549053a3ba3eb3b1b49c22a3fd9) by [@blakef](https://github.com/blakef))
|
||||
- Fix build failure on windows in android ([08b83005481](https://github.com/facebook/react-native/commit/08b830054812f4011becbbacdf1525701225df39) by [@FouadMagdy01](https://github.com/FouadMagdy01))
|
||||
|
||||
## v0.76.2
|
||||
|
||||
### Added
|
||||
|
||||
- **TypeScript** Add CodegenTypes for TS ([20b141508b](https://github.com/facebook/react-native/commit/20b141508b30324d52080c255dd3fb318718d746) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
|
||||
### Changed
|
||||
|
||||
- **infra** Bump CLI to 15.0.1 ([51b98c24bd](https://github.com/facebook/react-native/commit/51b98c24bdc6369ce6fabcacaf8df2d2a706eada) by [@szymonrybczak](https://github.com/szymonrybczak))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- **TextInput** Include existing attributes in newly typed text ([557e3447f5](https://github.com/facebook/react-native/commit/557e3447f520e40a1ec0ae344126b4f2836d2e83) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Hermes** Update Hermes to support Intl ([94d4bfd7c8](https://github.com/facebook/react-native/commit/94d4bfd7c80ba0d55adbff656441b55d59055bcc) by [@blakef](https://github.com/blakef))
|
||||
- **infra** Skip hermes-parser under Babel for non-Flow JS code ([ff1261e7dc](https://github.com/facebook/react-native/commit/ff1261e7dc0ab7e241e1f14aa0d6fd17f2ba9328) by [@huntie](https://github.com/huntie))
|
||||
- **infra** fix `semver` not being found in pnpm setups ([0def73d1a6](https://github.com/facebook/react-native/commit/0def73d1a6e398d451585032ea1213f96d84fe9c) by [@tido64](https://github.com/tido64))
|
||||
- **Error Handling** Fix `setUpErrorHandling` to show early JS errors ([dac6d508af](https://github.com/facebook/react-native/commit/dac6d508afd0f919943d8053330d6314201319c3) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
|
||||
#### Android specific
|
||||
|
||||
- **infra** Use absolute path when compiling appmodules.so sources ([3956955eaa](https://github.com/facebook/react-native/commit/3956955eaa3cd8c50dfe35a68a6cb8fdcac43155) by [@cortinico](https://github.com/cortinico))
|
||||
- **infra** Properly handle paths with spaces in autolinking ([1f62529dc4](https://github.com/facebook/react-native/commit/1f62529dc4583af88ef06bee04c89ce6c2ef737f) by [@cortinico](https://github.com/cortinico))
|
||||
- **Modal** Fix Regression - Modal content rendering below system bar on < API 30 when activity is edge-to-edge ([2cd48ef351](https://github.com/facebook/react-native/commit/2cd48ef351d10333a14091188bbe8e3bcd6a7a01) by [@alanleedev](https://github.com/alanleedev))
|
||||
- **runtime** Fix timers in headless tasks on bridgeless mode ([ee7b4e2763](https://github.com/facebook/react-native/commit/ee7b4e276355146be53958b402bfb2d5af2dd1bc) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- **Codegen** Properly stop generating component registration for components defined in app. ([97a4234b6e](https://github.com/facebook/react-native/commit/97a4234b6e51b3c35c82095029ef00270ad02e29) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- **infra** Give apps access to Yoga headers ([e851e73c18](https://github.com/facebook/react-native/commit/e851e73c1806a7b7b898a67716be87f42ced491a) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- **TextInput** Fix missing emitter attributes on iOS TextInput when controlled component value specified using `value` instead of `children` ([52cdedb40e](https://github.com/facebook/react-native/commit/52cdedb40e242c9ed280b821f8493a3872ef2b54) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
- **TextInput** Fix cursor moving in iOS controlled single line TextInput on Autocorrection (New Arch) ([36fd5533f6](https://github.com/facebook/react-native/commit/36fd5533f68b0f907a949db87884b58820015ba8) by [@NickGerleman](https://github.com/NickGerleman))
|
||||
|
||||
## v0.76.1
|
||||
|
||||
### Fixed
|
||||
@@ -1833,21 +1406,6 @@ created on the mqt_native thread. ([c4a6bbc8fd](https://github.com/facebook/reac
|
||||
|
||||
- Bump activesupport to minimum 6.1.7.5 CVE-2023-38037. ([07a159f279](https://github.com/facebook/react-native/commit/07a159f279cdcbed29c9c437dec1c0b8ac2d852f) by [@lunaleaps](https://github.com/lunaleaps))
|
||||
|
||||
## v0.73.11
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
|
||||
#### Android specific
|
||||
|
||||
- Suppress path adjustment when not actually drawing a border ([c9cf6d4b60](https://github.com/facebook/react-native/commit/c9cf6d4b60b6c5f717b3e5c9f3e3720e8d588707) by [@tjzel](https://github.com/tjzel))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Stop generating dSYM path in Hermes for the framework ([e992405e87](https://github.com/facebook/react-native/commit/e992405e87) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
- Pin Xcodeproj to < 1.26.0 ([dfcad7c678](https://github.com/facebook/react-native/commit/dfcad7c678) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
|
||||
## v0.73.10
|
||||
|
||||
### Removed
|
||||
|
||||
@@ -87,7 +87,7 @@ The full documentation for React Native can be found on our [website][docs].
|
||||
|
||||
The React Native documentation discusses components, APIs, and topics that are specific to React Native. For further documentation on the React API that is shared between React Native and React DOM, refer to the [React documentation][r-docs].
|
||||
|
||||
The source for the React Native documentation and website is hosted on a separate repository, [**@facebook/react-native-website**][repo-website].
|
||||
The source for the React Native documentation and website is hosted on a separate repo, [**@facebook/react-native-website**][repo-website].
|
||||
|
||||
[docs]: https://reactnative.dev/docs/getting-started
|
||||
[r-docs]: https://react.dev/learn
|
||||
|
||||
Vendored
-17
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
declare module 'deep-equal' {
|
||||
declare module.exports: (
|
||||
actual: mixed,
|
||||
expected: mixed,
|
||||
options?: {strict: boolean},
|
||||
) => boolean;
|
||||
}
|
||||
Vendored
-40
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
declare module 'jest-diff' {
|
||||
import type {CompareKeys} from 'pretty-format';
|
||||
|
||||
declare export type DiffOptionsColor = (arg: string) => string; // subset of Chalk type
|
||||
|
||||
declare export type DiffOptions = {
|
||||
aAnnotation?: string,
|
||||
aColor?: DiffOptionsColor,
|
||||
aIndicator?: string,
|
||||
bAnnotation?: string,
|
||||
bColor?: DiffOptionsColor,
|
||||
bIndicator?: string,
|
||||
changeColor?: DiffOptionsColor,
|
||||
changeLineTrailingSpaceColor?: DiffOptionsColor,
|
||||
commonColor?: DiffOptionsColor,
|
||||
commonIndicator?: string,
|
||||
commonLineTrailingSpaceColor?: DiffOptionsColor,
|
||||
contextLines?: number,
|
||||
emptyFirstOrLastLinePlaceholder?: string,
|
||||
expand?: boolean,
|
||||
includeChangeCounts?: boolean,
|
||||
omitAnnotationLines?: boolean,
|
||||
patchColor?: DiffOptionsColor,
|
||||
compareKeys?: CompareKeys,
|
||||
};
|
||||
|
||||
declare export function diff(
|
||||
a: mixed,
|
||||
b: mixed,
|
||||
options?: DiffOptions,
|
||||
): string | null;
|
||||
}
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
declare module '@pkgjs/parseargs' {
|
||||
declare export function parseArgs<
|
||||
TOptions: {[string]: util$ParseArgsOption} = {},
|
||||
>(config: {
|
||||
args?: Array<string>,
|
||||
options?: TOptions,
|
||||
strict?: boolean,
|
||||
allowPositionals?: boolean,
|
||||
tokens?: false,
|
||||
}): {
|
||||
values: util$ParseArgsOptionsToValues<TOptions>,
|
||||
positionals: Array<string>,
|
||||
};
|
||||
|
||||
declare export function parseArgs<
|
||||
TOptions: {[string]: util$ParseArgsOption} = {},
|
||||
>(config: {
|
||||
args?: Array<string>,
|
||||
options?: TOptions,
|
||||
strict?: boolean,
|
||||
allowPositionals?: boolean,
|
||||
tokens: true,
|
||||
}): {
|
||||
values: util$ParseArgsOptionsToValues<TOptions>,
|
||||
positionals: Array<string>,
|
||||
tokens: Array<util$ParseArgsToken>,
|
||||
};
|
||||
}
|
||||
+1
-4
@@ -19,6 +19,7 @@ declare type Colors = {
|
||||
tag: {close: string, open: string},
|
||||
value: {close: string, open: string},
|
||||
};
|
||||
declare type CompareKeys = ((a: string, b: string) => number) | null | void;
|
||||
|
||||
declare type PrettyFormatPlugin =
|
||||
| {
|
||||
@@ -37,10 +38,6 @@ declare type PrettyFormatPlugin =
|
||||
};
|
||||
|
||||
declare module 'pretty-format' {
|
||||
declare export type CompareKeys =
|
||||
| ((a: string, b: string) => number)
|
||||
| null
|
||||
| void;
|
||||
declare export function format(
|
||||
value: mixed,
|
||||
options?: ?{
|
||||
|
||||
Vendored
-20
@@ -16,13 +16,6 @@ declare interface undici$Agent$Options {
|
||||
}
|
||||
|
||||
declare module 'undici' {
|
||||
declare export type RequestOptions = $ReadOnly<{
|
||||
dispatcher?: Dispatcher,
|
||||
method?: string,
|
||||
headers?: HeadersInit,
|
||||
...
|
||||
}>;
|
||||
|
||||
declare export class Dispatcher extends events$EventEmitter {
|
||||
constructor(): void;
|
||||
}
|
||||
@@ -30,17 +23,4 @@ declare module 'undici' {
|
||||
declare export class Agent extends Dispatcher {
|
||||
constructor(opts?: undici$Agent$Options): void;
|
||||
}
|
||||
|
||||
declare export function request(
|
||||
url: string | URL,
|
||||
options: RequestOptions,
|
||||
): Promise<{
|
||||
statusCode: number,
|
||||
headers: Headers,
|
||||
body: {
|
||||
read(): Promise<Buffer>,
|
||||
...
|
||||
},
|
||||
...
|
||||
}>;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = {
|
||||
getHasteName(filePath) {
|
||||
if (filePath.endsWith('ReactNativeInternalFeatureFlags.js')) {
|
||||
return 'ReactNativeInternalFeatureFlags';
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getCacheKey() {
|
||||
return crypto
|
||||
.createHash('sha1')
|
||||
.update(fs.readFileSync(__filename))
|
||||
.digest('hex');
|
||||
},
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const baseConfig = require('../../../jest.config');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
rootDir: path.resolve(__dirname, '../../..'),
|
||||
roots: [
|
||||
'<rootDir>/packages/react-native',
|
||||
'<rootDir>/jest/integration/runtime',
|
||||
],
|
||||
moduleFileExtensions: [...baseConfig.moduleFileExtensions, 'cpp', 'h'],
|
||||
// This allows running Meta-internal tests with the `-test.fb.js` suffix.
|
||||
testRegex: '/__tests__/.*-itest(\\.fb)?\\.js$',
|
||||
testPathIgnorePatterns: baseConfig.testPathIgnorePatterns,
|
||||
transformIgnorePatterns: ['.*'],
|
||||
testRunner: './jest/integration/runner/index.js',
|
||||
watchPathIgnorePatterns: ['<rootDir>/jest/integration/build/'],
|
||||
globalSetup: './jest/integration/runner/warmup/index.js',
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
require('../../../scripts/build/babel-register').registerForMonorepo();
|
||||
module.exports = require('@react-native/metro-babel-transformer');
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {getDefaultConfig} = require('@react-native/metro-config');
|
||||
const {mergeConfig} = require('metro-config');
|
||||
const path = require('path');
|
||||
|
||||
const rnTesterConfig = getDefaultConfig(
|
||||
path.resolve('../../../packages/rn-tester'),
|
||||
);
|
||||
|
||||
const JS_DIR = process.env.JS_DIR
|
||||
? path.resolve(process.cwd(), process.env.JS_DIR)
|
||||
: null;
|
||||
|
||||
const config = {
|
||||
projectRoot: path.resolve(__dirname, '../../..'),
|
||||
reporter: {
|
||||
update: () => {},
|
||||
},
|
||||
resolver: {
|
||||
blockList: /\/RendererProxy\.fb\.js$/, // Disable dependency injection for the renderer
|
||||
disableHierarchicalLookup: !!JS_DIR,
|
||||
sourceExts: ['fb.js', ...rnTesterConfig.resolver.sourceExts],
|
||||
nodeModulesPaths: JS_DIR
|
||||
? [path.join(JS_DIR, 'public', 'node_modules')]
|
||||
: [],
|
||||
hasteImplModulePath: path.resolve(__dirname, 'hasteImpl.js'),
|
||||
},
|
||||
transformer: {
|
||||
// We need to wrap the default transformer so we can run it from source
|
||||
// using babel-register.
|
||||
babelTransformerPath: path.resolve(__dirname, 'metro-babel-transformer.js'),
|
||||
},
|
||||
watchFolders: JS_DIR
|
||||
? [
|
||||
path.join(JS_DIR, 'RKJSModules', 'vendor', 'react'),
|
||||
path.join(JS_DIR, 'tools', 'metro'),
|
||||
path.join(JS_DIR, 'node_modules'),
|
||||
path.join(JS_DIR, 'public', 'node_modules'),
|
||||
]
|
||||
: [],
|
||||
};
|
||||
|
||||
module.exports = mergeConfig(rnTesterConfig, config);
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
module.exports = function entrypointTemplate({
|
||||
testPath,
|
||||
setupModulePath,
|
||||
}: {
|
||||
testPath: string,
|
||||
setupModulePath: string,
|
||||
}): string {
|
||||
return `/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* ${'@'}generated
|
||||
* @noformat
|
||||
* @noflow
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {registerTest} from '${setupModulePath}';
|
||||
|
||||
registerTest(() => require('${testPath}'));
|
||||
`;
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
require('../../../scripts/build/babel-register').registerForMonorepo();
|
||||
|
||||
module.exports = require('./runner');
|
||||
@@ -1,229 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type {TestSuiteResult} from '../runtime/setup';
|
||||
|
||||
import entrypointTemplate from './entrypoint-template';
|
||||
import {
|
||||
getBuckModeForPlatform,
|
||||
getDebugInfoFromCommandResult,
|
||||
getFantomTestConfig,
|
||||
getShortHash,
|
||||
runBuck2,
|
||||
symbolicateStackTrace,
|
||||
} from './utils';
|
||||
import fs from 'fs';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import {formatResultsErrors} from 'jest-message-util';
|
||||
import Metro from 'metro';
|
||||
import nullthrows from 'nullthrows';
|
||||
import path from 'path';
|
||||
|
||||
const BUILD_OUTPUT_PATH = path.resolve(__dirname, '..', 'build');
|
||||
|
||||
const PRINT_FANTOM_OUTPUT: false = false;
|
||||
|
||||
function parseRNTesterCommandResult(result: ReturnType<typeof runBuck2>): {
|
||||
logs: string,
|
||||
testResult: TestSuiteResult,
|
||||
} {
|
||||
const stdout = result.stdout.toString();
|
||||
|
||||
const outputArray = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(log => !log.startsWith('Running "')); // remove AppRegistry logs.
|
||||
|
||||
// The last line should be the test output in JSON format
|
||||
const testResultJSON = outputArray.pop();
|
||||
|
||||
let testResult;
|
||||
try {
|
||||
testResult = JSON.parse(nullthrows(testResultJSON));
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
'Failed to parse test results from RN tester binary result.\n' +
|
||||
getDebugInfoFromCommandResult(result),
|
||||
);
|
||||
}
|
||||
|
||||
return {logs: outputArray.join('\n'), testResult};
|
||||
}
|
||||
|
||||
function generateBytecodeBundle({
|
||||
sourcePath,
|
||||
bytecodePath,
|
||||
isOptimizedMode,
|
||||
}: {
|
||||
sourcePath: string,
|
||||
bytecodePath: string,
|
||||
isOptimizedMode: boolean,
|
||||
}): void {
|
||||
const hermesCompilerCommandResult = runBuck2([
|
||||
'run',
|
||||
getBuckModeForPlatform(isOptimizedMode),
|
||||
'//xplat/hermes/tools/hermesc:hermesc',
|
||||
'--',
|
||||
'-emit-binary',
|
||||
'-O',
|
||||
'-max-diagnostic-width',
|
||||
'80',
|
||||
'-out',
|
||||
bytecodePath,
|
||||
sourcePath,
|
||||
]);
|
||||
|
||||
if (hermesCompilerCommandResult.status !== 0) {
|
||||
throw new Error(getDebugInfoFromCommandResult(hermesCompilerCommandResult));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async function runTest(
|
||||
globalConfig: {...},
|
||||
config: {...},
|
||||
environment: {...},
|
||||
runtime: {...},
|
||||
testPath: string,
|
||||
): mixed {
|
||||
const startTime = Date.now();
|
||||
|
||||
const testConfig = getFantomTestConfig(testPath);
|
||||
|
||||
const isOptimizedMode = testConfig.mode === 'opt';
|
||||
|
||||
const metroConfig = await Metro.loadConfig({
|
||||
config: path.resolve(__dirname, '..', 'config', 'metro.config.js'),
|
||||
});
|
||||
|
||||
const setupModulePath = path.resolve(__dirname, '../runtime/setup.js');
|
||||
|
||||
const entrypointContents = entrypointTemplate({
|
||||
testPath: `${path.relative(BUILD_OUTPUT_PATH, testPath)}`,
|
||||
setupModulePath: `${path.relative(BUILD_OUTPUT_PATH, setupModulePath)}`,
|
||||
});
|
||||
|
||||
const entrypointPath = path.join(
|
||||
BUILD_OUTPUT_PATH,
|
||||
`${getShortHash(entrypointContents)}-${path.basename(testPath)}`,
|
||||
);
|
||||
const testBundlePath = entrypointPath + '.bundle';
|
||||
const testJSBundlePath = testBundlePath + '.js';
|
||||
const testBytecodeBundlePath = testJSBundlePath + '.hbc';
|
||||
|
||||
fs.mkdirSync(path.dirname(entrypointPath), {recursive: true});
|
||||
fs.writeFileSync(entrypointPath, entrypointContents, 'utf8');
|
||||
|
||||
const sourceMapPath = path.join(
|
||||
path.dirname(testJSBundlePath),
|
||||
path.basename(testJSBundlePath, '.js') + '.map',
|
||||
);
|
||||
|
||||
await Metro.runBuild(metroConfig, {
|
||||
entry: entrypointPath,
|
||||
out: testJSBundlePath,
|
||||
platform: 'android',
|
||||
minify: isOptimizedMode,
|
||||
dev: !isOptimizedMode,
|
||||
sourceMap: true,
|
||||
sourceMapUrl: sourceMapPath,
|
||||
});
|
||||
|
||||
if (isOptimizedMode) {
|
||||
generateBytecodeBundle({
|
||||
sourcePath: testJSBundlePath,
|
||||
bytecodePath: testBytecodeBundlePath,
|
||||
isOptimizedMode,
|
||||
});
|
||||
}
|
||||
|
||||
const rnTesterCommandResult = runBuck2([
|
||||
'run',
|
||||
getBuckModeForPlatform(isOptimizedMode),
|
||||
'//xplat/ReactNative/react-native-cxx/samples/tester:tester',
|
||||
'--',
|
||||
'--bundlePath',
|
||||
testBundlePath,
|
||||
]);
|
||||
|
||||
if (rnTesterCommandResult.status !== 0) {
|
||||
throw new Error(getDebugInfoFromCommandResult(rnTesterCommandResult));
|
||||
}
|
||||
|
||||
if (PRINT_FANTOM_OUTPUT) {
|
||||
console.log(getDebugInfoFromCommandResult(rnTesterCommandResult));
|
||||
}
|
||||
|
||||
const rnTesterParsedOutput = parseRNTesterCommandResult(
|
||||
rnTesterCommandResult,
|
||||
);
|
||||
|
||||
const testResultError = rnTesterParsedOutput.testResult.error;
|
||||
if (testResultError) {
|
||||
const error = new Error(testResultError.message);
|
||||
error.stack = symbolicateStackTrace(sourceMapPath, testResultError.stack);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const endTime = Date.now();
|
||||
|
||||
if (process.env.SANDCASTLE == null) {
|
||||
console.log(rnTesterParsedOutput.logs);
|
||||
}
|
||||
|
||||
const testResults =
|
||||
nullthrows(rnTesterParsedOutput.testResult.testResults).map(testResult => ({
|
||||
ancestorTitles: [] as Array<string>,
|
||||
failureDetails: [] as Array<string>,
|
||||
testFilePath: testPath,
|
||||
...testResult,
|
||||
failureMessages: testResult.failureMessages.map(maybeStackTrace =>
|
||||
symbolicateStackTrace(sourceMapPath, maybeStackTrace),
|
||||
),
|
||||
})) ?? [];
|
||||
|
||||
return {
|
||||
testFilePath: testPath,
|
||||
failureMessage: formatResultsErrors(
|
||||
testResults,
|
||||
config,
|
||||
globalConfig,
|
||||
testPath,
|
||||
),
|
||||
leaks: false,
|
||||
openHandles: [],
|
||||
perfStats: {
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
duration: endTime - startTime,
|
||||
runtime: endTime - startTime,
|
||||
slow: false,
|
||||
},
|
||||
snapshot: {
|
||||
added: 0,
|
||||
fileDeleted: false,
|
||||
matched: 0,
|
||||
unchecked: 0,
|
||||
uncheckedKeys: [],
|
||||
unmatched: 0,
|
||||
updated: 0,
|
||||
},
|
||||
numTotalTests: testResults.length,
|
||||
numPassingTests: testResults.filter(test => test.status === 'passed')
|
||||
.length,
|
||||
numFailingTests: testResults.filter(test => test.status === 'failed')
|
||||
.length,
|
||||
numPendingTests: testResults.filter(test => test.status === 'pending')
|
||||
.length,
|
||||
numTodoTests: 0,
|
||||
skipped: false,
|
||||
testResults,
|
||||
};
|
||||
};
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {spawnSync} from 'child_process';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import {extract, parse} from 'jest-docblock';
|
||||
import os from 'os';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import {SourceMapConsumer} from 'source-map';
|
||||
|
||||
type DocblockPragmas = {[key: string]: string | string[]};
|
||||
type FantomTestMode = 'dev' | 'opt';
|
||||
type FantomTestConfig = {
|
||||
mode: FantomTestMode,
|
||||
};
|
||||
|
||||
const DEFAULT_MODE: FantomTestMode = 'dev';
|
||||
|
||||
/**
|
||||
* Extracts the Fantom configuration from the test file, specified as part of
|
||||
* the docblock comment. E.g.:
|
||||
*
|
||||
* ```
|
||||
* /**
|
||||
* * @flow strict-local
|
||||
* * @fantom mode:opt
|
||||
* *
|
||||
* ```
|
||||
*
|
||||
* So far the only supported option is `mode`, which can be 'dev' or 'opt'.
|
||||
*/
|
||||
export function getFantomTestConfig(testPath: string): FantomTestConfig {
|
||||
const docblock = extract(fs.readFileSync(testPath, 'utf8'));
|
||||
const pragmas = parse(docblock) as DocblockPragmas;
|
||||
|
||||
const config = {
|
||||
mode: DEFAULT_MODE,
|
||||
};
|
||||
|
||||
const maybeMode = pragmas.fantom_mode;
|
||||
|
||||
if (maybeMode != null) {
|
||||
if (Array.isArray(maybeMode)) {
|
||||
throw new Error('Expected a single value for @fantom_mode');
|
||||
}
|
||||
|
||||
const mode = maybeMode;
|
||||
|
||||
if (mode === 'dev' || mode === 'opt') {
|
||||
config.mode = mode;
|
||||
} else {
|
||||
throw new Error(`Invalid Fantom mode: ${mode}`);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
export function getBuckModeForPlatform(enableRelease: boolean = false): string {
|
||||
const mode = enableRelease ? 'opt' : 'dev';
|
||||
|
||||
switch (os.platform()) {
|
||||
case 'linux':
|
||||
return `@//arvr/mode/linux/${mode}`;
|
||||
case 'darwin':
|
||||
return os.arch() === 'arm64'
|
||||
? `@//arvr/mode/mac-arm/${mode}`
|
||||
: `@//arvr/mode/mac/${mode}`;
|
||||
case 'win32':
|
||||
return `@//arvr/mode/win/${mode}`;
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
|
||||
type SpawnResultWithOriginalCommand = {
|
||||
...ReturnType<typeof spawnSync>,
|
||||
originalCommand: string,
|
||||
...
|
||||
};
|
||||
|
||||
export function runBuck2(args: Array<string>): SpawnResultWithOriginalCommand {
|
||||
const result = spawnSync('buck2', args, {
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `/usr/local/bin:${process.env.PATH ?? ''}`,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...result,
|
||||
originalCommand: `buck2 ${args.join(' ')}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function getDebugInfoFromCommandResult(
|
||||
commandResult: SpawnResultWithOriginalCommand,
|
||||
): string {
|
||||
const logLines = [
|
||||
`Command ${commandResult.status === 0 ? 'succeeded' : 'failed'}: ${commandResult.originalCommand}`,
|
||||
'',
|
||||
'stdout:',
|
||||
commandResult.stdout,
|
||||
'',
|
||||
'stderr:',
|
||||
commandResult.stderr,
|
||||
];
|
||||
|
||||
if (commandResult.error) {
|
||||
logLines.push('', 'error:', String(commandResult.error));
|
||||
}
|
||||
|
||||
return logLines.join('\n');
|
||||
}
|
||||
|
||||
export function getShortHash(contents: string): string {
|
||||
return crypto.createHash('md5').update(contents).digest('hex').slice(0, 8);
|
||||
}
|
||||
|
||||
export function symbolicateStackTrace(
|
||||
sourceMapPath: string,
|
||||
stackTrace: string,
|
||||
): string {
|
||||
const sourceMapData = JSON.parse(fs.readFileSync(sourceMapPath, 'utf8'));
|
||||
const consumer = new SourceMapConsumer(sourceMapData);
|
||||
|
||||
return stackTrace
|
||||
.split('\n')
|
||||
.map(line => {
|
||||
const match = line.match(/at (.*) \((.*):(\d+):(\d+)\)/);
|
||||
if (match) {
|
||||
const functionName = match[1];
|
||||
// const fileName = match[2];
|
||||
const lineNumber = parseInt(match[3], 10);
|
||||
const columnNumber = parseInt(match[4], 10);
|
||||
// Get the original position
|
||||
const originalPosition = consumer.originalPositionFor({
|
||||
line: lineNumber,
|
||||
column: columnNumber,
|
||||
});
|
||||
return `at ${originalPosition.name ?? functionName} (${originalPosition.source}:${originalPosition.line}:${originalPosition.column})`;
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
require('../../../../scripts/build/babel-register').registerForMonorepo();
|
||||
|
||||
module.exports = require('./warmup');
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {
|
||||
getBuckModeForPlatform,
|
||||
getDebugInfoFromCommandResult,
|
||||
runBuck2,
|
||||
} from '../utils';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import fs from 'fs';
|
||||
import Metro from 'metro';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
export default async function warmUp(
|
||||
globalConfig: {...},
|
||||
projectConfig: {...},
|
||||
): Promise<void> {
|
||||
try {
|
||||
warmUpHermesCompiler();
|
||||
warmUpRNTesterCLI();
|
||||
await warmUpMetro();
|
||||
} catch (e) {
|
||||
// Sandcastle fails to parse the test output if we log stuff to stdout/stderr.
|
||||
if ((process.env.SANDCASTLE ?? '') !== '') {
|
||||
console.error(
|
||||
'Global warmup failed. Tests will continue to run but will likely fail. Details:\n',
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function warmUpMetro(): Promise<void> {
|
||||
const metroConfig = await Metro.loadConfig({
|
||||
config: path.resolve(__dirname, '..', '..', 'config', 'metro.config.js'),
|
||||
});
|
||||
|
||||
const entrypointPath = path.resolve(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'runtime',
|
||||
'WarmUpEntryPoint.js',
|
||||
);
|
||||
|
||||
const bundlePath = path.join(
|
||||
os.tmpdir(),
|
||||
`fantom-warmup-bundle-${Date.now()}.js`,
|
||||
);
|
||||
|
||||
await Metro.runBuild(metroConfig, {
|
||||
entry: entrypointPath,
|
||||
out: bundlePath,
|
||||
platform: 'android',
|
||||
minify: false,
|
||||
dev: true,
|
||||
});
|
||||
|
||||
try {
|
||||
fs.unlinkSync(bundlePath);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function warmUpHermesCompiler(): void {
|
||||
const buildHermesCompilerCommandResult = runBuck2([
|
||||
'build',
|
||||
getBuckModeForPlatform(),
|
||||
'//xplat/hermes/tools/hermesc:hermesc',
|
||||
]);
|
||||
|
||||
if (buildHermesCompilerCommandResult.status !== 0) {
|
||||
throw new Error(
|
||||
getDebugInfoFromCommandResult(buildHermesCompilerCommandResult),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function warmUpRNTesterCLI(): void {
|
||||
const buildRNTesterCommandResult = runBuck2([
|
||||
'build',
|
||||
getBuckModeForPlatform(),
|
||||
'//xplat/ReactNative/react-native-cxx/samples/tester:tester',
|
||||
]);
|
||||
|
||||
if (buildRNTesterCommandResult.status !== 0) {
|
||||
throw new Error(getDebugInfoFromCommandResult(buildRNTesterCommandResult));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is just an entrypoint to warm up the Metro cache before the tests run.
|
||||
*/
|
||||
|
||||
import 'react-native/Libraries/Core/InitializeCore.js';
|
||||
import 'react-native/src/private/__tests__/ReactNativeTester';
|
||||
import './setup';
|
||||
@@ -1,451 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import deepEqual from 'deep-equal';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
export type TestCaseResult = {
|
||||
ancestorTitles: Array<string>,
|
||||
title: string,
|
||||
fullName: string,
|
||||
status: 'passed' | 'failed' | 'pending',
|
||||
duration: number,
|
||||
failureMessages: Array<string>,
|
||||
numPassingAsserts: number,
|
||||
// location: string,
|
||||
};
|
||||
|
||||
export type TestSuiteResult =
|
||||
| {
|
||||
testResults: Array<TestCaseResult>,
|
||||
}
|
||||
| {
|
||||
error: {
|
||||
message: string,
|
||||
stack: string,
|
||||
},
|
||||
};
|
||||
|
||||
const tests: Array<{
|
||||
title: string,
|
||||
ancestorTitles: Array<string>,
|
||||
implementation: () => mixed,
|
||||
isFocused: boolean,
|
||||
isSkipped: boolean,
|
||||
result?: TestCaseResult,
|
||||
}> = [];
|
||||
|
||||
const ancestorTitles: Array<string> = [];
|
||||
|
||||
const globalModifiers: Array<'focused' | 'skipped'> = [];
|
||||
|
||||
const globalDescribe = (global.describe = (
|
||||
title: string,
|
||||
implementation: () => mixed,
|
||||
) => {
|
||||
ancestorTitles.push(title);
|
||||
implementation();
|
||||
ancestorTitles.pop();
|
||||
});
|
||||
|
||||
const globalIt =
|
||||
(global.it =
|
||||
global.test =
|
||||
(title: string, implementation: () => mixed) =>
|
||||
tests.push({
|
||||
title,
|
||||
implementation,
|
||||
ancestorTitles: ancestorTitles.slice(),
|
||||
isFocused:
|
||||
globalModifiers.length > 0 &&
|
||||
globalModifiers[globalModifiers.length - 1] === 'focused',
|
||||
isSkipped:
|
||||
globalModifiers.length > 0 &&
|
||||
globalModifiers[globalModifiers.length - 1] === 'skipped',
|
||||
}));
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.fdescribe = global.describe.only = (
|
||||
title: string,
|
||||
implementation: () => mixed,
|
||||
) => {
|
||||
globalModifiers.push('focused');
|
||||
globalDescribe(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.it.only =
|
||||
global.fit =
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.test.only =
|
||||
(title: string, implementation: () => mixed) => {
|
||||
globalModifiers.push('focused');
|
||||
globalIt(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.xdescribe = global.describe.skip = (
|
||||
title: string,
|
||||
implementation: () => mixed,
|
||||
) => {
|
||||
globalModifiers.push('skipped');
|
||||
globalDescribe(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.it.skip =
|
||||
global.xit =
|
||||
// $FlowExpectedError[prop-missing]
|
||||
global.test.skip =
|
||||
global.xtest =
|
||||
(title: string, implementation: () => mixed) => {
|
||||
globalModifiers.push('skipped');
|
||||
globalIt(title, implementation);
|
||||
globalModifiers.pop();
|
||||
};
|
||||
|
||||
global.jest = {
|
||||
fn: createMockFunction,
|
||||
};
|
||||
|
||||
const MOCK_FN_TAG = Symbol('mock function');
|
||||
|
||||
function createMockFunction<TArgs: $ReadOnlyArray<mixed>, TReturn>(
|
||||
initialImplementation?: (...TArgs) => TReturn,
|
||||
): JestMockFn<TArgs, TReturn> {
|
||||
let implementation: ?(...TArgs) => TReturn = initialImplementation;
|
||||
|
||||
const mock: JestMockFn<TArgs, TReturn>['mock'] = {
|
||||
calls: [],
|
||||
// $FlowExpectedError[incompatible-type]
|
||||
lastCall: undefined,
|
||||
instances: [],
|
||||
contexts: [],
|
||||
results: [],
|
||||
};
|
||||
|
||||
const mockFunction = function (this: mixed, ...args: TArgs): TReturn {
|
||||
let result: JestMockFn<TArgs, TReturn>['mock']['results'][number] = {
|
||||
isThrow: false,
|
||||
// $FlowExpectedError[incompatible-type]
|
||||
value: undefined,
|
||||
};
|
||||
|
||||
if (implementation != null) {
|
||||
try {
|
||||
result.value = implementation.apply(this, args);
|
||||
} catch (error) {
|
||||
result.isThrow = true;
|
||||
result.value = error;
|
||||
}
|
||||
}
|
||||
|
||||
mock.calls.push(args);
|
||||
mock.lastCall = args;
|
||||
// $FlowExpectedError[incompatible-call]
|
||||
mock.instances.push(new.target ? this : undefined);
|
||||
mock.contexts.push(this);
|
||||
mock.results.push(result);
|
||||
|
||||
if (result.isThrow) {
|
||||
throw result.value;
|
||||
}
|
||||
|
||||
return result.value;
|
||||
};
|
||||
|
||||
mockFunction.mock = mock;
|
||||
// $FlowExpectedError[invalid-computed-prop]
|
||||
mockFunction[MOCK_FN_TAG] = true;
|
||||
|
||||
// $FlowExpectedError[prop-missing]
|
||||
return mockFunction;
|
||||
}
|
||||
|
||||
// flowlint unsafe-getters-setters:off
|
||||
|
||||
class ErrorWithCustomBlame extends Error {
|
||||
// Initially 5 to ignore all the frames from Babel helpers to instantiate this
|
||||
// custom error class.
|
||||
#ignoredFrameCount: number = 5;
|
||||
#cachedProcessedStack: ?string;
|
||||
|
||||
blameToPreviousFrame(): this {
|
||||
this.#ignoredFrameCount++;
|
||||
return this;
|
||||
}
|
||||
|
||||
get stack(): string {
|
||||
if (this.#cachedProcessedStack == null) {
|
||||
const originalStack = super.stack;
|
||||
|
||||
if (originalStack == null) {
|
||||
this.#cachedProcessedStack = originalStack;
|
||||
} else {
|
||||
const lines = originalStack.split('\n');
|
||||
const index = lines.findIndex(line =>
|
||||
/at (.*) \((.*):(\d+):(\d+)\)/.test(line),
|
||||
);
|
||||
lines.splice(index > -1 ? index : 1, this.#ignoredFrameCount);
|
||||
this.#cachedProcessedStack = lines.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
return this.#cachedProcessedStack;
|
||||
}
|
||||
|
||||
set stack(value: string) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
class Expect {
|
||||
#received: mixed;
|
||||
#isNot: boolean = false;
|
||||
|
||||
constructor(received: mixed) {
|
||||
this.#received = received;
|
||||
}
|
||||
|
||||
get not(): this {
|
||||
this.#isNot = !this.#isNot;
|
||||
return this;
|
||||
}
|
||||
|
||||
toEqual(expected: mixed): void {
|
||||
const pass = deepEqual(this.#received, expected, {strict: true});
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected${this.#maybeNotLabel()} to equal ${String(expected)} but received ${String(this.#received)}.`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toBe(expected: mixed): void {
|
||||
const pass = this.#received === expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected${this.#maybeNotLabel()} ${String(expected)} but received ${String(this.#received)}.`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toBeInstanceOf(expected: Class<mixed>): void {
|
||||
const pass = this.#received instanceof expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`expected ${String(this.#received)}${this.#maybeNotLabel()} to be an instance of ${String(expected)}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toBeCloseTo(expected: number, precision: number = 2): void {
|
||||
const pass =
|
||||
Math.abs(expected - Number(this.#received)) < Math.pow(10, -precision);
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be close to ${expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toBeNull(): void {
|
||||
const pass = this.#received == null;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be null`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toThrow(expected?: string): void {
|
||||
if (expected != null && typeof expected !== 'string') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
'toThrow() implementation only accepts strings as arguments.',
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
let pass = false;
|
||||
try {
|
||||
// $FlowExpectedError[not-a-function]
|
||||
this.#received();
|
||||
} catch (error) {
|
||||
pass = expected != null ? error.message === expected : true;
|
||||
}
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to throw`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toHaveBeenCalled(): void {
|
||||
const mock = this.#requireMock();
|
||||
const pass = mock.calls.length > 0;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to have been called, but it was${this.#isNot ? '' : "n't"}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toHaveBeenCalledTimes(times: number): void {
|
||||
const mock = this.#requireMock();
|
||||
const pass = mock.calls.length === times;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to have been called ${times} times, but it was called ${mock.calls.length} times`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toBeGreaterThanOrEqual(expected: number): void {
|
||||
if (typeof this.#received !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)} to be a number but it was a ${typeof this.#received}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
if (typeof expected !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(expected)} to be a number but it was a ${typeof expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
const pass = this.#received >= expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be greater than or equal to ${expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toBeLessThanOrEqual(expected: number): void {
|
||||
if (typeof this.#received !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)} to be a number but it was a ${typeof this.#received}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
if (typeof expected !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(expected)} to be a number but it was a ${typeof expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
const pass = this.#received <= expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be less than or equal to ${expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
#isExpectedResult(pass: boolean): boolean {
|
||||
return this.#isNot ? !pass : pass;
|
||||
}
|
||||
|
||||
#maybeNotLabel(): string {
|
||||
return this.#isNot ? ' not' : '';
|
||||
}
|
||||
|
||||
#requireMock(): JestMockFn<$ReadOnlyArray<mixed>, mixed>['mock'] {
|
||||
// $FlowExpectedError[incompatible-use]
|
||||
if (!this.#received?.[MOCK_FN_TAG]) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)} to be a mock function, but it wasn't`,
|
||||
)
|
||||
.blameToPreviousFrame()
|
||||
.blameToPreviousFrame();
|
||||
}
|
||||
|
||||
// $FlowExpectedError[incompatible-use]
|
||||
return this.#received.mock;
|
||||
}
|
||||
}
|
||||
|
||||
global.expect = (received: mixed) => new Expect(received);
|
||||
|
||||
function runWithGuard(fn: () => void) {
|
||||
try {
|
||||
fn();
|
||||
} catch (error) {
|
||||
let reportedError =
|
||||
error instanceof Error ? error : new Error(String(error));
|
||||
reportTestSuiteResult({
|
||||
error: {
|
||||
message: reportedError.message,
|
||||
stack: reportedError.stack,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function executeTests() {
|
||||
const hasFocusedTests = tests.some(test => test.isFocused);
|
||||
|
||||
for (const test of tests) {
|
||||
const result: TestCaseResult = {
|
||||
title: test.title,
|
||||
fullName: [...test.ancestorTitles, test.title].join(' '),
|
||||
ancestorTitles: test.ancestorTitles,
|
||||
status: 'pending',
|
||||
duration: 0,
|
||||
failureMessages: [],
|
||||
numPassingAsserts: 0,
|
||||
};
|
||||
|
||||
test.result = result;
|
||||
|
||||
if (!test.isSkipped && (!hasFocusedTests || test.isFocused)) {
|
||||
let status;
|
||||
let error;
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
try {
|
||||
test.implementation();
|
||||
status = 'passed';
|
||||
} catch (e) {
|
||||
error = e;
|
||||
status = 'failed';
|
||||
}
|
||||
|
||||
result.status = status;
|
||||
result.duration = Date.now() - start;
|
||||
result.failureMessages =
|
||||
status === 'failed' && error
|
||||
? [error.stack ?? error.message ?? String(error)]
|
||||
: [];
|
||||
}
|
||||
}
|
||||
|
||||
reportTestSuiteResult({
|
||||
testResults: tests.map(test => nullthrows(test.result)),
|
||||
});
|
||||
}
|
||||
|
||||
function reportTestSuiteResult(testSuiteResult: TestSuiteResult): void {
|
||||
console.log(JSON.stringify(testSuiteResult));
|
||||
}
|
||||
|
||||
global.$$RunTests$$ = () => {
|
||||
executeTests();
|
||||
};
|
||||
|
||||
export function registerTest(setUpTest: () => void) {
|
||||
runWithGuard(() => {
|
||||
setUpTest();
|
||||
});
|
||||
}
|
||||
+10
-11
@@ -48,6 +48,7 @@
|
||||
"@babel/preset-flow": "^7.24.7",
|
||||
"@definitelytyped/dtslint": "^0.0.127",
|
||||
"@jest/create-cache-key-function": "^29.6.3",
|
||||
"@pkgjs/parseargs": "^0.11.0",
|
||||
"@react-native/metro-babel-transformer": "0.77.0-main",
|
||||
"@react-native/metro-config": "0.77.0-main",
|
||||
"@tsconfig/node18": "1.0.1",
|
||||
@@ -55,13 +56,12 @@
|
||||
"@typescript-eslint/parser": "^7.1.1",
|
||||
"ansi-styles": "^4.2.1",
|
||||
"babel-plugin-minify-dead-code-elimination": "^0.5.2",
|
||||
"babel-plugin-syntax-hermes-parser": "0.25.1",
|
||||
"babel-plugin-syntax-hermes-parser": "0.24.0",
|
||||
"babel-plugin-transform-define": "^2.1.4",
|
||||
"babel-plugin-transform-flow-enums": "^0.0.2",
|
||||
"chalk": "^4.0.0",
|
||||
"clang-format": "^1.8.0",
|
||||
"connect": "^3.6.5",
|
||||
"deep-equal": "1.1.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-babel": "^5.3.1",
|
||||
@@ -76,14 +76,13 @@
|
||||
"eslint-plugin-react-native": "^4.0.0",
|
||||
"eslint-plugin-redundant-undefined": "^0.4.0",
|
||||
"eslint-plugin-relay": "^1.8.3",
|
||||
"flow-api-translator": "0.25.1",
|
||||
"flow-bin": "^0.255.0",
|
||||
"flow-api-translator": "0.24.0",
|
||||
"flow-bin": "^0.251.1",
|
||||
"glob": "^7.1.1",
|
||||
"hermes-eslint": "0.25.1",
|
||||
"hermes-transform": "0.25.1",
|
||||
"hermes-eslint": "0.24.0",
|
||||
"hermes-transform": "0.24.0",
|
||||
"inquirer": "^7.1.0",
|
||||
"jest": "^29.6.3",
|
||||
"jest-diff": "^29.7.0",
|
||||
"jest-junit": "^10.0.0",
|
||||
"jscodeshift": "^0.14.0",
|
||||
"metro-babel-register": "^0.81.0",
|
||||
@@ -93,9 +92,9 @@
|
||||
"node-fetch": "^2.2.0",
|
||||
"nullthrows": "^1.1.1",
|
||||
"prettier": "2.8.8",
|
||||
"prettier-plugin-hermes-parser": "0.25.1",
|
||||
"react": "18.3.1",
|
||||
"react-test-renderer": "18.3.1",
|
||||
"prettier-plugin-hermes-parser": "0.24.0",
|
||||
"react": "19.0.0-rc-fb9a90fa48-20240614",
|
||||
"react-test-renderer": "19.0.0-rc-fb9a90fa48-20240614",
|
||||
"rimraf": "^3.0.2",
|
||||
"shelljs": "^0.8.5",
|
||||
"signedsource": "^1.0.0",
|
||||
@@ -104,6 +103,6 @@
|
||||
"ws": "^6.2.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"react-is": "18.3.1"
|
||||
"react-is": "19.0.0-rc-fb9a90fa48-20240614"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"metro": "^0.81.0",
|
||||
"metro-config": "^0.81.0",
|
||||
"metro-core": "^0.81.0",
|
||||
"node-fetch": "^2.2.0",
|
||||
"readline": "^1.3.0",
|
||||
"semver": "^7.1.3"
|
||||
},
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import type TerminalReporter from 'metro/src/lib/TerminalReporter';
|
||||
|
||||
import chalk from 'chalk';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
type PageDescription = $ReadOnly<{
|
||||
id: string,
|
||||
|
||||
@@ -19,7 +19,10 @@ import isDevServerRunning from '../../utils/isDevServerRunning';
|
||||
import loadMetroConfig from '../../utils/loadMetroConfig';
|
||||
import * as version from '../../utils/version';
|
||||
import attachKeyHandlers from './attachKeyHandlers';
|
||||
import {createDevServerMiddleware, indexPageMiddleware} from './middleware';
|
||||
import {
|
||||
createDevServerMiddleware,
|
||||
indexPageMiddleware,
|
||||
} from '@react-native-community/cli-server-api';
|
||||
import {createDevMiddleware} from '@react-native/dev-middleware';
|
||||
import chalk from 'chalk';
|
||||
import Metro from 'metro';
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
import net from 'net';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
/**
|
||||
* Determine whether we can run the dev server.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@generated SignedSource<<cecad43da3fd917e15322ee3efbed875>>
|
||||
Git revision: 486803f6bf272e0629297265dee8048a2f1269dd
|
||||
@generated SignedSource<<b5e82d2eb99e1ed4c012065a530ca78b>>
|
||||
Git revision: ff343d805527223750fafb8573ee48f8e2fb0d1e
|
||||
Built with --nohooks: false
|
||||
Is local checkout: false
|
||||
Remote URL: https://github.com/facebookexperimental/rn-chrome-devtools-frontend
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -42,7 +42,7 @@ import*as e from"../../ui/legacy/legacy.js";import*as t from"../../core/host/hos
|
||||
<p>${d(a.docsDebuggingBasicsDetail)}</p>
|
||||
</div>
|
||||
</button>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this.#o.bind(this,"https://reactnative.dev/docs/react-native-devtools")} title=${d(a.docsReactNativeDevTools)}>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this.#o.bind(this,"https://reactnative.dev/docs/react-devtools")} title=${d(a.docsReactNativeDevTools)}>
|
||||
<div class="rn-welcome-image" style="background-image: url('${c}')"></div>
|
||||
<div>
|
||||
<p class="devtools-link">${d(a.docsReactNativeDevTools)}</p>
|
||||
|
||||
+14
-14
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -10,30 +10,24 @@
|
||||
*/
|
||||
|
||||
import type {JSONSerializable} from '../inspector-proxy/types';
|
||||
import type {RequestOptions} from 'undici';
|
||||
|
||||
import {Agent, request} from 'undici';
|
||||
import {Agent} from 'undici';
|
||||
|
||||
declare var globalThis: $FlowFixMe;
|
||||
|
||||
/**
|
||||
* A version of `fetch` that is usable with the HTTPS server created in
|
||||
* ServerUtils (which uses a self-signed certificate).
|
||||
*/
|
||||
export async function requestLocal(
|
||||
export async function fetchLocal(
|
||||
url: string,
|
||||
options?: RequestOptions,
|
||||
): Promise<{
|
||||
statusCode: number,
|
||||
headers: Headers,
|
||||
bodyBuffer: Buffer,
|
||||
}> {
|
||||
const {
|
||||
statusCode,
|
||||
headers: rawHeaders,
|
||||
body,
|
||||
} = await request(url, {
|
||||
options?: Partial<Parameters<typeof fetch>[1] & {dispatcher?: mixed}>,
|
||||
): ReturnType<typeof fetch> {
|
||||
return await fetch(url, {
|
||||
...options,
|
||||
|
||||
// Use undici's `dispatcher` to make it accept self-signed certificates.
|
||||
// Node's native `fetch` comes from undici and supports the same options,
|
||||
// including `dispatcher` which we use to make it accept self-signed
|
||||
// certificates.
|
||||
dispatcher:
|
||||
options?.dispatcher ??
|
||||
new Agent({
|
||||
@@ -42,48 +36,41 @@ export async function requestLocal(
|
||||
},
|
||||
}),
|
||||
});
|
||||
return {
|
||||
statusCode,
|
||||
bodyBuffer: await body.read(),
|
||||
headers: new Headers(rawHeaders),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchJson<T: JSONSerializable>(url: string): Promise<T> {
|
||||
const response = await requestLocal(url);
|
||||
if (response.statusCode !== 200) {
|
||||
throw new Error(`HTTP ${response.statusCode}`);
|
||||
const response = await fetchLocal(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
||||
}
|
||||
if (!response.headers.get('Content-Type')?.startsWith('application/json')) {
|
||||
throw new Error('Expected Content-Type: application/json');
|
||||
}
|
||||
return JSON.parse(response.bodyBuffer.toString());
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the global fetch dispatcher to allow self-signed certificates.
|
||||
* This runs with Jest's `beforeAll` and `afterAll`, and restores the original dispatcher.
|
||||
*/
|
||||
export function withFetchSelfSignedCertsForAllTests(
|
||||
fetchSpy: JestMockFn<Parameters<typeof fetch>, ReturnType<typeof fetch>>,
|
||||
fetchOriginal: typeof fetch,
|
||||
) {
|
||||
export function withFetchSelfSignedCertsForAllTests() {
|
||||
const fetchOriginal = globalThis.fetch;
|
||||
const selfSignedCertDispatcher = new Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
});
|
||||
|
||||
let fetchSpy;
|
||||
|
||||
beforeAll(() => {
|
||||
// For some reason, setting the `selfSignedCertDispatcher` with `setGlobalDispatcher` doesn't work.
|
||||
// Instead of using `setGlobalDispatcher`, we'll use a spy to intercept the fetch calls and add the dispatcher.
|
||||
fetchSpy.mockImplementation((url, options) =>
|
||||
fetchOriginal(url, {
|
||||
...options,
|
||||
// $FlowFixMe[prop-missing]: dispatcher
|
||||
dispatcher: options?.dispatcher ?? selfSignedCertDispatcher,
|
||||
}),
|
||||
);
|
||||
fetchSpy = jest
|
||||
.spyOn(globalThis, 'fetch')
|
||||
.mockImplementation((url, options) =>
|
||||
fetchOriginal(url, {
|
||||
...options,
|
||||
dispatcher: options?.dispatcher ?? selfSignedCertDispatcher,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
|
||||
@@ -23,11 +23,10 @@ export class DebuggerAgent {
|
||||
#ws: ?WebSocket;
|
||||
#readyPromise: Promise<void>;
|
||||
|
||||
constructor(url: string, signal?: AbortSignal, hostHeader?: ?string) {
|
||||
constructor(url: string, signal?: AbortSignal) {
|
||||
const ws = new WebSocket(url, {
|
||||
// The mock server uses a self-signed certificate.
|
||||
rejectUnauthorized: false,
|
||||
...(hostHeader != null ? {headers: {Host: hostHeader}} : {}),
|
||||
});
|
||||
this.#ws = ws;
|
||||
ws.on('message', data => {
|
||||
@@ -116,9 +115,8 @@ export class DebuggerMock extends DebuggerAgent {
|
||||
export async function createDebuggerMock(
|
||||
url: string,
|
||||
signal: AbortSignal,
|
||||
hostHeader?: ?string,
|
||||
): Promise<DebuggerMock> {
|
||||
const debuggerMock = new DebuggerMock(url, signal, hostHeader);
|
||||
const debuggerMock = new DebuggerMock(url, signal);
|
||||
await debuggerMock.ready();
|
||||
return debuggerMock;
|
||||
}
|
||||
|
||||
@@ -27,17 +27,10 @@ export class DeviceAgent {
|
||||
#ws: ?WebSocket;
|
||||
#readyPromise: Promise<void>;
|
||||
|
||||
constructor(url: string, signal?: AbortSignal, host?: ?string) {
|
||||
constructor(url: string, signal?: AbortSignal) {
|
||||
const ws = new WebSocket(url, {
|
||||
// The mock server uses a self-signed certificate.
|
||||
rejectUnauthorized: false,
|
||||
...(host != null
|
||||
? {
|
||||
headers: {
|
||||
Host: host,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
this.#ws = ws;
|
||||
ws.on('message', data => {
|
||||
@@ -167,9 +160,8 @@ export class DeviceMock extends DeviceAgent {
|
||||
export async function createDeviceMock(
|
||||
url: string,
|
||||
signal: AbortSignal,
|
||||
host?: ?string,
|
||||
): Promise<DeviceMock> {
|
||||
const device = new DeviceMock(url, signal, host);
|
||||
const device = new DeviceMock(url, signal);
|
||||
await device.ready();
|
||||
return device;
|
||||
}
|
||||
|
||||
@@ -126,15 +126,7 @@ export async function createAndConnectTarget(
|
||||
}>,
|
||||
signal: AbortSignal,
|
||||
page: PageFromDevice,
|
||||
{
|
||||
debuggerHostHeader = null,
|
||||
deviceId = null,
|
||||
deviceHostHeader = null,
|
||||
}: $ReadOnly<{
|
||||
debuggerHostHeader?: ?string,
|
||||
deviceId?: ?string,
|
||||
deviceHostHeader?: ?string,
|
||||
}> = {},
|
||||
deviceId: ?string = null,
|
||||
): Promise<{device: DeviceMock, debugger_: DebuggerMock}> {
|
||||
let device;
|
||||
let debugger_;
|
||||
@@ -144,7 +136,6 @@ export async function createAndConnectTarget(
|
||||
deviceId ?? 'device' + Date.now()
|
||||
}&name=foo&app=bar`,
|
||||
signal,
|
||||
deviceHostHeader,
|
||||
);
|
||||
device.getPages.mockImplementation(() => [page]);
|
||||
|
||||
@@ -159,11 +150,7 @@ export async function createAndConnectTarget(
|
||||
const [{webSocketDebuggerUrl}] = pageList;
|
||||
expect(webSocketDebuggerUrl).toBeDefined();
|
||||
|
||||
debugger_ = await createDebuggerMock(
|
||||
webSocketDebuggerUrl,
|
||||
signal,
|
||||
debuggerHostHeader,
|
||||
);
|
||||
debugger_ = await createDebuggerMock(webSocketDebuggerUrl, signal);
|
||||
await until(() => expect(device.connect).toBeCalled());
|
||||
} catch (e) {
|
||||
device?.close();
|
||||
|
||||
@@ -33,18 +33,12 @@ jest.useRealTimers();
|
||||
|
||||
jest.setTimeout(10000);
|
||||
|
||||
const fetchOriginal = fetch;
|
||||
const fetchSpy: JestMockFn<
|
||||
Parameters<typeof fetch>,
|
||||
ReturnType<typeof fetch>,
|
||||
> = jest.spyOn(globalThis, 'fetch');
|
||||
|
||||
describe.each(['HTTP', 'HTTPS'])(
|
||||
'inspector proxy CDP rewriting hacks over %s',
|
||||
protocol => {
|
||||
// Inspector proxy tests are using a self-signed certificate for HTTPS tests.
|
||||
if (protocol === 'HTTPS') {
|
||||
withFetchSelfSignedCertsForAllTests(fetchSpy, fetchOriginal);
|
||||
withFetchSelfSignedCertsForAllTests();
|
||||
}
|
||||
|
||||
const serverRef = withServerForEachTest({
|
||||
@@ -52,7 +46,6 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
projectRoot: __dirname,
|
||||
secure: protocol === 'HTTPS',
|
||||
});
|
||||
|
||||
const autoCleanup = withAbortSignalForEachTest();
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -195,52 +188,7 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
}
|
||||
});
|
||||
|
||||
test("does not rewrite urls in Debugger.scriptParsed that don't match the device connection host", async () => {
|
||||
serverRef.app.use('/source-map', serveStaticJson({version: 3}));
|
||||
const {device, debugger_} = await createAndConnectTarget(
|
||||
serverRef,
|
||||
autoCleanup.signal,
|
||||
{
|
||||
app: 'bar-app',
|
||||
id: 'page1',
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
},
|
||||
{
|
||||
deviceHostHeader: '192.168.0.123:' + serverRef.port,
|
||||
},
|
||||
);
|
||||
try {
|
||||
let fetchCalledWithURL;
|
||||
fetchSpy.mockImplementationOnce(async url => {
|
||||
fetchCalledWithURL = url instanceof URL ? url : null;
|
||||
throw new Error('Unreachable');
|
||||
});
|
||||
const sourceMapURL = `${protocol.toLowerCase()}://127.0.0.1:${
|
||||
serverRef.port
|
||||
}/source-map`;
|
||||
const scriptParsedMessage = await sendFromTargetToDebugger(
|
||||
device,
|
||||
debugger_,
|
||||
'page1',
|
||||
{
|
||||
method: 'Debugger.scriptParsed',
|
||||
params: {
|
||||
sourceMapURL,
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(fetchCalledWithURL?.href).toEqual(sourceMapURL);
|
||||
expect(scriptParsedMessage.params.sourceMapURL).toEqual(
|
||||
`${protocol.toLowerCase()}://127.0.0.1:${serverRef.port}/source-map`,
|
||||
);
|
||||
} finally {
|
||||
device.close();
|
||||
debugger_.close();
|
||||
}
|
||||
});
|
||||
|
||||
describe.each(['10.0.2.2:8080', '[::1]', 'example.com:2000'])(
|
||||
describe.each(['10.0.2.2', '10.0.3.2', '127.0.0.1'])(
|
||||
'%s aliasing to and from localhost',
|
||||
sourceHost => {
|
||||
test('in source map fetching during Debugger.scriptParsed', async () => {
|
||||
@@ -254,9 +202,6 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
},
|
||||
{
|
||||
deviceHostHeader: sourceHost,
|
||||
},
|
||||
);
|
||||
try {
|
||||
const scriptParsedMessage = await sendFromTargetToDebugger(
|
||||
@@ -266,7 +211,9 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
{
|
||||
method: 'Debugger.scriptParsed',
|
||||
params: {
|
||||
sourceMapURL: `${protocol.toLowerCase()}://${sourceHost}/source-map`,
|
||||
sourceMapURL: `${protocol.toLowerCase()}://${sourceHost}:${
|
||||
serverRef.port
|
||||
}/source-map`,
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -289,10 +236,6 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
},
|
||||
{
|
||||
debuggerHostHeader: 'localhost:' + serverRef.port,
|
||||
deviceHostHeader: sourceHost,
|
||||
},
|
||||
);
|
||||
try {
|
||||
const scriptParsedMessage = await sendFromTargetToDebugger(
|
||||
@@ -302,7 +245,9 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
{
|
||||
method: 'Debugger.scriptParsed',
|
||||
params: {
|
||||
url: `${protocol.toLowerCase()}://${sourceHost}/some/file.js`,
|
||||
url: `${protocol.toLowerCase()}://${sourceHost}:${
|
||||
serverRef.port
|
||||
}/some/file.js`,
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -328,7 +273,9 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
},
|
||||
);
|
||||
expect(setBreakpointByUrlMessage.params.url).toEqual(
|
||||
`${protocol.toLowerCase()}://${sourceHost}/some/file.js`,
|
||||
`${protocol.toLowerCase()}://${sourceHost}:${
|
||||
serverRef.port
|
||||
}/some/file.js`,
|
||||
);
|
||||
|
||||
const setBreakpointByUrlRegexMessage =
|
||||
@@ -337,67 +284,17 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
method: 'Debugger.setBreakpointByUrl',
|
||||
params: {
|
||||
lineNumber: 1,
|
||||
urlRegex: `localhost:${serverRef.port}|example.com:2000`,
|
||||
urlRegex: 'localhost:1000|localhost:2000',
|
||||
},
|
||||
});
|
||||
|
||||
// urlRegex rewriting is restricted to specific Android IPs that
|
||||
// are well-known to route to the host. In this case we only
|
||||
// replace hostname - longstanding behaviour.
|
||||
if (sourceHost === '10.0.2.2:8080') {
|
||||
expect(setBreakpointByUrlRegexMessage.params.urlRegex).toEqual(
|
||||
`10\\.0\\.2\\.2:${serverRef.port}|example.com:2000`,
|
||||
);
|
||||
} else {
|
||||
// Otherwise expect no change.
|
||||
expect(setBreakpointByUrlRegexMessage.params.urlRegex).toEqual(
|
||||
`localhost:${serverRef.port}|example.com:2000`,
|
||||
);
|
||||
}
|
||||
expect(setBreakpointByUrlRegexMessage.params.urlRegex).toEqual(
|
||||
`${sourceHost}:1000|${sourceHost}:2000`,
|
||||
);
|
||||
} finally {
|
||||
device.close();
|
||||
debugger_.close();
|
||||
}
|
||||
});
|
||||
|
||||
describe('Network.loadNetworkResource', () => {
|
||||
test('should respond with an error without forwarding to the client', async () => {
|
||||
const {device, debugger_} = await createAndConnectTarget(
|
||||
serverRef,
|
||||
autoCleanup.signal,
|
||||
{
|
||||
app: 'bar-app',
|
||||
id: 'page1',
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
},
|
||||
{
|
||||
deviceHostHeader: sourceHost,
|
||||
},
|
||||
);
|
||||
try {
|
||||
const response = await debugger_.sendAndGetResponse({
|
||||
id: 1,
|
||||
method: 'Network.loadNetworkResource',
|
||||
params: {
|
||||
url: 'http://example.com',
|
||||
},
|
||||
});
|
||||
expect(response.result).toEqual(
|
||||
expect.objectContaining({
|
||||
error: {
|
||||
code: -32601,
|
||||
message:
|
||||
'[inspector-proxy]: Page lacks nativeSourceCodeFetching capability.',
|
||||
},
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
device.close();
|
||||
debugger_.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -411,9 +308,6 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
},
|
||||
{
|
||||
deviceHostHeader: '127.0.0.1:' + serverRef.port,
|
||||
},
|
||||
);
|
||||
try {
|
||||
const scriptParsedMessage = await sendFromTargetToDebugger(
|
||||
@@ -687,33 +581,6 @@ describe.each(['HTTP', 'HTTPS'])(
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Network.loadNetworkResource', () => {
|
||||
test('should forward event directly to client (does not rewrite url host)', async () => {
|
||||
const {device, debugger_} = await createAndConnectTarget(
|
||||
serverRef,
|
||||
autoCleanup.signal,
|
||||
pageDescription,
|
||||
);
|
||||
try {
|
||||
const message = {
|
||||
id: 1,
|
||||
method: 'Network.loadNetworkResource',
|
||||
params: {
|
||||
url: `${protocol.toLowerCase()}://10.0.2.2:${serverRef.port}`,
|
||||
},
|
||||
};
|
||||
await sendFromDebuggerToTarget(debugger_, device, 'page1', message);
|
||||
expect(device.wrappedEventParsed).toBeCalledWith({
|
||||
pageId: 'page1',
|
||||
wrappedEvent: message,
|
||||
});
|
||||
} finally {
|
||||
device.close();
|
||||
debugger_.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ import type {
|
||||
} from '../inspector-proxy/types';
|
||||
|
||||
import DefaultBrowserLauncher from '../utils/DefaultBrowserLauncher';
|
||||
import {fetchJson, requestLocal} from './FetchUtils';
|
||||
import {fetchJson, fetchLocal} from './FetchUtils';
|
||||
import {createDeviceMock} from './InspectorDeviceUtils';
|
||||
import {withAbortSignalForEachTest} from './ResourceUtils';
|
||||
import {withServerForEachTest} from './ServerUtils';
|
||||
@@ -362,7 +362,7 @@ describe('inspector proxy HTTP API', () => {
|
||||
|
||||
jest.advanceTimersByTime(PAGES_POLLING_DELAY);
|
||||
|
||||
const response = await requestLocal(
|
||||
const response = await fetchLocal(
|
||||
`${serverRef.serverBaseUrl}${endpoint}`,
|
||||
);
|
||||
expect(response.headers.get('Content-Length')).not.toBeNull();
|
||||
@@ -415,12 +415,10 @@ describe('inspector proxy HTTP API', () => {
|
||||
);
|
||||
openUrl.searchParams.set('target', firstPage.id);
|
||||
// Request to open the debugger for the first device
|
||||
const response = await requestLocal(openUrl.toString(), {
|
||||
method: 'POST',
|
||||
});
|
||||
const response = await fetchLocal(openUrl.toString(), {method: 'POST'});
|
||||
|
||||
// Ensure the request was handled properly
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.status).toBe(200);
|
||||
// Ensure the debugger was launched
|
||||
expect(launchDebuggerSpy).toHaveBeenCalledWith(expect.any(String));
|
||||
} finally {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {requestLocal} from './FetchUtils';
|
||||
import {fetchLocal} from './FetchUtils';
|
||||
import {withServerForEachTest} from './ServerUtils';
|
||||
|
||||
jest.useRealTimers();
|
||||
@@ -22,10 +22,11 @@ describe('embedder script', () => {
|
||||
});
|
||||
|
||||
test('is always served', async () => {
|
||||
const resp = await requestLocal(
|
||||
const resp = await fetchLocal(
|
||||
serverRef.serverBaseUrl +
|
||||
'/debugger-frontend/embedder-static/embedderScript.js',
|
||||
);
|
||||
expect(resp.statusCode).toBe(200);
|
||||
expect(resp.ok).toBeTruthy();
|
||||
expect(resp.status).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import getBaseUrlFromRequest from '../utils/getBaseUrlFromRequest';
|
||||
|
||||
test('returns a base url based on req.headers.host', () => {
|
||||
expect(
|
||||
getBaseUrlFromRequest(makeRequest('localhost:8081', false))?.href,
|
||||
).toEqual('http://localhost:8081/');
|
||||
});
|
||||
|
||||
test('identifies https using socket.encrypted', () => {
|
||||
expect(
|
||||
getBaseUrlFromRequest(makeRequest('secure.net:8443', true))?.href,
|
||||
).toEqual('https://secure.net:8443/');
|
||||
});
|
||||
|
||||
test('works with ipv6 hosts', () => {
|
||||
expect(getBaseUrlFromRequest(makeRequest('[::1]:8081', false))?.href).toEqual(
|
||||
'http://[::1]:8081/',
|
||||
);
|
||||
});
|
||||
|
||||
test('returns null on an invalid host header', () => {
|
||||
expect(getBaseUrlFromRequest(makeRequest('local[]host', false))).toBeNull();
|
||||
});
|
||||
|
||||
test('returns null on an empty host header', () => {
|
||||
expect(getBaseUrlFromRequest(makeRequest(null, false))).toBeNull();
|
||||
});
|
||||
|
||||
function makeRequest(
|
||||
host: ?string,
|
||||
encrypted: boolean,
|
||||
): http$IncomingMessage<> | http$IncomingMessage<tls$TLSSocket> {
|
||||
// $FlowIgnore[incompatible-return] Partial mock of request
|
||||
return {
|
||||
socket: encrypted ? {encrypted: true} : {},
|
||||
headers: host != null ? {host} : {},
|
||||
};
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import type {CreateCustomMessageHandlerFn} from './inspector-proxy/CustomMessageHandler';
|
||||
import type {BrowserLauncher} from './types/BrowserLauncher';
|
||||
import type {EventReporter, ReportableEvent} from './types/EventReporter';
|
||||
import type {EventReporter} from './types/EventReporter';
|
||||
import type {Experiments, ExperimentsConfig} from './types/Experiments';
|
||||
import type {Logger} from './types/Logger';
|
||||
import type {NextHandleFunction} from 'connect';
|
||||
@@ -28,8 +28,11 @@ type Options = $ReadOnly<{
|
||||
projectRoot: string,
|
||||
|
||||
/**
|
||||
* The base URL to the dev server, as reachable from the machine on which
|
||||
* dev-middleware is hosted. Typically `http://localhost:${metroPort}`.
|
||||
* The base URL to the dev server, as addressible from the local developer
|
||||
* machine. This is used in responses which return URLs to other endpoints,
|
||||
* e.g. the debugger frontend and inspector proxy targets.
|
||||
*
|
||||
* Example: `'http://localhost:8081'`.
|
||||
*/
|
||||
serverBaseUrl: string,
|
||||
|
||||
@@ -81,15 +84,11 @@ export default function createDevMiddleware({
|
||||
unstable_customInspectorMessageHandler,
|
||||
}: Options): DevMiddlewareAPI {
|
||||
const experiments = getExperiments(experimentConfig);
|
||||
const eventReporter = createWrappedEventReporter(
|
||||
unstable_eventReporter,
|
||||
logger,
|
||||
);
|
||||
|
||||
const inspectorProxy = new InspectorProxy(
|
||||
projectRoot,
|
||||
serverBaseUrl,
|
||||
eventReporter,
|
||||
unstable_eventReporter,
|
||||
experiments,
|
||||
unstable_customInspectorMessageHandler,
|
||||
);
|
||||
@@ -101,7 +100,7 @@ export default function createDevMiddleware({
|
||||
serverBaseUrl,
|
||||
inspectorProxy,
|
||||
browserLauncher: unstable_browserLauncher,
|
||||
eventReporter,
|
||||
eventReporter: unstable_eventReporter,
|
||||
experiments,
|
||||
logger,
|
||||
}),
|
||||
@@ -133,26 +132,3 @@ function getExperiments(config: ExperimentsConfig): Experiments {
|
||||
enableNetworkInspector: config.enableNetworkInspector ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapped EventReporter that locally intercepts events to
|
||||
* log to the terminal.
|
||||
*/
|
||||
function createWrappedEventReporter(
|
||||
reporter: ?EventReporter,
|
||||
logger: ?Logger,
|
||||
): EventReporter {
|
||||
return {
|
||||
logEvent(event: ReportableEvent) {
|
||||
switch (event.type) {
|
||||
case 'profiling_target_registered':
|
||||
logger?.info(
|
||||
`Profiling build target "${event.appId}" registered for debugging`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
reporter?.logEvent(event);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,6 +37,22 @@ const debug = require('debug')('Metro:InspectorProxy');
|
||||
|
||||
const PAGES_POLLING_INTERVAL = 1000;
|
||||
|
||||
// Replace hosts appearing in the `url` and `sourceMapURL` fields of
|
||||
// `Debugger.scriptParsed`, and back again in messages from the debugger,
|
||||
// to account for device/debugger/proxy running on different networks.
|
||||
const REWRITE_HOSTS_TO_LOCALHOST: Array<string> = [
|
||||
// A device may retrieve a bundle through 127.0.0.1 via a (SSH) tunnel, but
|
||||
// the (remote) Metro server may be on a host without an IPv4 loopback, so
|
||||
// 127.0.0.1 may not be addressible locally for (e.g., for source map
|
||||
// fetching). Replacing with the more general 'localhost' should always be
|
||||
// safe while also more compatible with IPv6-only setups.
|
||||
'127.0.0.1',
|
||||
// Android's stock emulator and other emulators such as genymotion use a
|
||||
// standard localhost alias.
|
||||
'10.0.2.2',
|
||||
'10.0.3.2',
|
||||
];
|
||||
|
||||
// Prefix for script URLs that are alphanumeric IDs. See comment in #processMessageFromDeviceLegacy method for
|
||||
// more details.
|
||||
const FILE_PREFIX = 'file://';
|
||||
@@ -44,28 +60,17 @@ const FILE_PREFIX = 'file://';
|
||||
type DebuggerConnection = {
|
||||
// Debugger web socket connection
|
||||
socket: WS,
|
||||
// If we replaced address (like '10.0.2.2') to localhost we need to store original
|
||||
// address because Chrome uses URL or urlRegex params (instead of scriptId) to set breakpoints.
|
||||
originalSourceURLAddress?: string,
|
||||
prependedFilePrefix: boolean,
|
||||
pageId: string,
|
||||
userAgent: string | null,
|
||||
customHandler: ?CustomMessageHandler,
|
||||
debuggerRelativeBaseUrl: URL,
|
||||
};
|
||||
|
||||
const REACT_NATIVE_RELOADABLE_PAGE_ID = '-1';
|
||||
|
||||
export type DeviceOptions = $ReadOnly<{
|
||||
id: string,
|
||||
name: string,
|
||||
app: string,
|
||||
socket: WS,
|
||||
projectRoot: string,
|
||||
eventReporter: ?EventReporter,
|
||||
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
|
||||
deviceRelativeBaseUrl: URL,
|
||||
serverRelativeBaseUrl: URL,
|
||||
isProfilingBuild: boolean,
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Device class represents single device connection to Inspector Proxy. Each device
|
||||
* can have multiple inspectable pages.
|
||||
@@ -120,36 +125,40 @@ export default class Device {
|
||||
|
||||
#connectedPageIds: Set<string> = new Set();
|
||||
|
||||
// A base HTTP(S) URL to this server, reachable from the device. Derived from
|
||||
// the http request that created the connection.
|
||||
#deviceRelativeBaseUrl: URL;
|
||||
|
||||
// A base HTTP(S) URL to the server, relative to this server.
|
||||
#serverRelativeBaseUrl: URL;
|
||||
|
||||
constructor(deviceOptions: DeviceOptions) {
|
||||
this.#dangerouslyConstruct(deviceOptions);
|
||||
constructor(
|
||||
id: string,
|
||||
name: string,
|
||||
app: string,
|
||||
socket: WS,
|
||||
projectRoot: string,
|
||||
eventReporter: ?EventReporter,
|
||||
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
|
||||
) {
|
||||
this.#dangerouslyConstruct(
|
||||
id,
|
||||
name,
|
||||
app,
|
||||
socket,
|
||||
projectRoot,
|
||||
eventReporter,
|
||||
createMessageMiddleware,
|
||||
);
|
||||
}
|
||||
|
||||
#dangerouslyConstruct({
|
||||
id,
|
||||
name,
|
||||
app,
|
||||
socket,
|
||||
projectRoot,
|
||||
eventReporter,
|
||||
createMessageMiddleware,
|
||||
serverRelativeBaseUrl,
|
||||
deviceRelativeBaseUrl,
|
||||
isProfilingBuild,
|
||||
}: DeviceOptions) {
|
||||
#dangerouslyConstruct(
|
||||
id: string,
|
||||
name: string,
|
||||
app: string,
|
||||
socket: WS,
|
||||
projectRoot: string,
|
||||
eventReporter: ?EventReporter,
|
||||
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
|
||||
) {
|
||||
this.#id = id;
|
||||
this.#name = name;
|
||||
this.#app = app;
|
||||
this.#deviceSocket = socket;
|
||||
this.#projectRoot = projectRoot;
|
||||
this.#serverRelativeBaseUrl = serverRelativeBaseUrl;
|
||||
this.#deviceRelativeBaseUrl = deviceRelativeBaseUrl;
|
||||
this.#deviceEventReporter = eventReporter
|
||||
? new DeviceEventReporter(eventReporter, {
|
||||
deviceId: id,
|
||||
@@ -159,10 +168,6 @@ export default class Device {
|
||||
: null;
|
||||
this.#createCustomMessageHandler = createMessageMiddleware;
|
||||
|
||||
if (isProfilingBuild) {
|
||||
this.#deviceEventReporter?.logProfilingTargetRegistered();
|
||||
}
|
||||
|
||||
// $FlowFixMe[incompatible-call]
|
||||
this.#deviceSocket.on('message', (message: string) => {
|
||||
this.#messageFromDeviceQueue = this.#messageFromDeviceQueue
|
||||
@@ -233,15 +238,23 @@ export default class Device {
|
||||
* This hack attempts to allow users to reload the app, either as result of a
|
||||
* crash, or manually reloading, without having to restart the debugger.
|
||||
*/
|
||||
dangerouslyRecreateDevice(deviceOptions: DeviceOptions) {
|
||||
dangerouslyRecreateDevice(
|
||||
id: string,
|
||||
name: string,
|
||||
app: string,
|
||||
socket: WS,
|
||||
projectRoot: string,
|
||||
eventReporter: ?EventReporter,
|
||||
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
|
||||
) {
|
||||
invariant(
|
||||
deviceOptions.id === this.#id,
|
||||
id === this.#id,
|
||||
'dangerouslyRecreateDevice() can only be used for the same device ID',
|
||||
);
|
||||
|
||||
const oldDebugger = this.#debuggerConnection;
|
||||
|
||||
if (this.#app !== deviceOptions.app || this.#name !== deviceOptions.name) {
|
||||
if (this.#app !== app || this.#name !== name) {
|
||||
this.#deviceSocket.close();
|
||||
this.#terminateDebuggerConnection();
|
||||
}
|
||||
@@ -252,12 +265,19 @@ export default class Device {
|
||||
oldDebugger.socket.removeAllListeners();
|
||||
this.#deviceSocket.close();
|
||||
this.handleDebuggerConnection(oldDebugger.socket, oldDebugger.pageId, {
|
||||
debuggerRelativeBaseUrl: oldDebugger.debuggerRelativeBaseUrl,
|
||||
userAgent: oldDebugger.userAgent,
|
||||
});
|
||||
}
|
||||
|
||||
this.#dangerouslyConstruct(deviceOptions);
|
||||
this.#dangerouslyConstruct(
|
||||
id,
|
||||
name,
|
||||
app,
|
||||
socket,
|
||||
projectRoot,
|
||||
eventReporter,
|
||||
createMessageMiddleware,
|
||||
);
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
@@ -283,11 +303,7 @@ export default class Device {
|
||||
handleDebuggerConnection(
|
||||
socket: WS,
|
||||
pageId: string,
|
||||
{
|
||||
debuggerRelativeBaseUrl,
|
||||
userAgent,
|
||||
}: $ReadOnly<{
|
||||
debuggerRelativeBaseUrl: URL,
|
||||
metadata: $ReadOnly<{
|
||||
userAgent: string | null,
|
||||
}>,
|
||||
) {
|
||||
@@ -298,8 +314,7 @@ export default class Device {
|
||||
|
||||
if (!page) {
|
||||
debug(
|
||||
`Got new debugger connection via ${debuggerRelativeBaseUrl.href} for ` +
|
||||
`page ${pageId} of ${this.#name}, but no such page exists`,
|
||||
`Got new debugger connection for page ${pageId} of ${this.#name}, but no such page exists`,
|
||||
);
|
||||
socket.close();
|
||||
return;
|
||||
@@ -313,24 +328,20 @@ export default class Device {
|
||||
|
||||
this.#deviceEventReporter?.logConnection('debugger', {
|
||||
pageId,
|
||||
frontendUserAgent: userAgent,
|
||||
frontendUserAgent: metadata.userAgent,
|
||||
});
|
||||
|
||||
const debuggerInfo = {
|
||||
socket,
|
||||
prependedFilePrefix: false,
|
||||
pageId,
|
||||
userAgent: userAgent,
|
||||
userAgent: metadata.userAgent,
|
||||
customHandler: null,
|
||||
debuggerRelativeBaseUrl,
|
||||
};
|
||||
|
||||
this.#debuggerConnection = debuggerInfo;
|
||||
|
||||
debug(
|
||||
`Got new debugger connection via ${debuggerRelativeBaseUrl.href} for ` +
|
||||
`page ${pageId} of ${this.#name}`,
|
||||
);
|
||||
debug(`Got new debugger connection for page ${pageId} of ${this.#name}`);
|
||||
|
||||
if (this.#debuggerConnection && this.#createCustomMessageHandler) {
|
||||
this.#debuggerConnection.customHandler = this.#createCustomMessageHandler(
|
||||
@@ -384,7 +395,7 @@ export default class Device {
|
||||
const debuggerRequest = JSON.parse(message);
|
||||
this.#deviceEventReporter?.logRequest(debuggerRequest, 'debugger', {
|
||||
pageId: this.#debuggerConnection?.pageId ?? null,
|
||||
frontendUserAgent: userAgent,
|
||||
frontendUserAgent: metadata.userAgent,
|
||||
prefersFuseboxFrontend: this.#isPageFuseboxFrontend(
|
||||
this.#debuggerConnection?.pageId,
|
||||
),
|
||||
@@ -661,54 +672,6 @@ export default class Device {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URL from the debugger frontend, returns the equivalent URL
|
||||
* reachable from the device.
|
||||
*/
|
||||
#debuggerRelativeToDeviceRelativeUrl(
|
||||
debuggerRelativeUrl: URL,
|
||||
{debuggerRelativeBaseUrl}: DebuggerConnection,
|
||||
): URL {
|
||||
const deviceRelativeUrl = new URL(debuggerRelativeUrl.href);
|
||||
if (debuggerRelativeUrl.origin === debuggerRelativeBaseUrl.origin) {
|
||||
deviceRelativeUrl.hostname = this.#deviceRelativeBaseUrl.hostname;
|
||||
deviceRelativeUrl.port = this.#deviceRelativeBaseUrl.port;
|
||||
deviceRelativeUrl.protocol = this.#deviceRelativeBaseUrl.protocol;
|
||||
}
|
||||
return deviceRelativeUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URL from the device, returns the equivalent URL reachable from
|
||||
* the debugger frontend.
|
||||
*/
|
||||
#deviceRelativeUrlToDebuggerRelativeUrl(
|
||||
deviceRelativeUrl: URL,
|
||||
{debuggerRelativeBaseUrl}: DebuggerConnection,
|
||||
): URL {
|
||||
const debuggerRelativeUrl = new URL(deviceRelativeUrl.href);
|
||||
if (deviceRelativeUrl.origin === this.#deviceRelativeBaseUrl.origin) {
|
||||
debuggerRelativeUrl.hostname = debuggerRelativeBaseUrl.hostname;
|
||||
debuggerRelativeUrl.port = debuggerRelativeBaseUrl.port;
|
||||
debuggerRelativeUrl.protocol = debuggerRelativeUrl.protocol;
|
||||
}
|
||||
return debuggerRelativeUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URL from the device, returns the equivalent URL reachable from
|
||||
* this proxy.
|
||||
*/
|
||||
#deviceRelativeUrlToServerRelativeUrl(deviceRelativeUrl: URL): URL {
|
||||
const debuggerRelativeUrl = new URL(deviceRelativeUrl.href);
|
||||
if (deviceRelativeUrl.origin === this.#deviceRelativeBaseUrl.origin) {
|
||||
debuggerRelativeUrl.hostname = this.#serverRelativeBaseUrl.hostname;
|
||||
debuggerRelativeUrl.port = this.#serverRelativeBaseUrl.port;
|
||||
debuggerRelativeUrl.protocol = this.#serverRelativeBaseUrl.protocol;
|
||||
}
|
||||
return debuggerRelativeUrl;
|
||||
}
|
||||
|
||||
// Allows to make changes in incoming message from device.
|
||||
async #processMessageFromDeviceLegacy(
|
||||
payload: CDPServerMessage,
|
||||
@@ -728,25 +691,25 @@ export default class Device {
|
||||
) {
|
||||
const params = payload.params;
|
||||
if ('sourceMapURL' in params) {
|
||||
for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) {
|
||||
if (params.sourceMapURL.includes(hostToRewrite)) {
|
||||
payload.params.sourceMapURL = params.sourceMapURL.replace(
|
||||
hostToRewrite,
|
||||
'localhost',
|
||||
);
|
||||
debuggerInfo.originalSourceURLAddress = hostToRewrite;
|
||||
}
|
||||
}
|
||||
|
||||
const sourceMapURL = this.#tryParseHTTPURL(params.sourceMapURL);
|
||||
if (sourceMapURL) {
|
||||
// Rewrite device-relative URLs to de debugger-relative URLs for the
|
||||
// frontend.
|
||||
payload.params.sourceMapURL =
|
||||
this.#deviceRelativeUrlToDebuggerRelativeUrl(
|
||||
sourceMapURL,
|
||||
debuggerInfo,
|
||||
).href;
|
||||
|
||||
// Some debug clients do not support fetching HTTP URLs. If the
|
||||
// message headed to the debug client identifies the source map with
|
||||
// an HTTP URL, fetch the content here and convert the content to a
|
||||
// Data URL (which is more widely supported) before passing the
|
||||
// message to the debug client.
|
||||
try {
|
||||
const sourceMap = await this.#fetchText(
|
||||
this.#deviceRelativeUrlToServerRelativeUrl(sourceMapURL),
|
||||
);
|
||||
const sourceMap = await this.#fetchText(sourceMapURL);
|
||||
payload.params.sourceMapURL =
|
||||
'data:application/json;charset=utf-8;base64,' +
|
||||
Buffer.from(sourceMap).toString('base64');
|
||||
@@ -758,19 +721,11 @@ export default class Device {
|
||||
}
|
||||
}
|
||||
if ('url' in params) {
|
||||
let serverRelativeUrl = params.url;
|
||||
const parsedUrl = this.#tryParseHTTPURL(params.url);
|
||||
if (parsedUrl) {
|
||||
// Rewrite device-relative URLs pointing to the server so that they're
|
||||
// reachable from the frontend.
|
||||
payload.params.url = this.#deviceRelativeUrlToDebuggerRelativeUrl(
|
||||
parsedUrl,
|
||||
debuggerInfo,
|
||||
).href;
|
||||
|
||||
// Determine the server-relative URL.
|
||||
serverRelativeUrl =
|
||||
this.#deviceRelativeUrlToServerRelativeUrl(parsedUrl).href;
|
||||
for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) {
|
||||
if (params.url.includes(hostToRewrite)) {
|
||||
payload.params.url = params.url.replace(hostToRewrite, 'localhost');
|
||||
debuggerInfo.originalSourceURLAddress = hostToRewrite;
|
||||
}
|
||||
}
|
||||
|
||||
// Chrome doesn't download source maps if URL param is not a valid
|
||||
@@ -782,13 +737,9 @@ export default class Device {
|
||||
debuggerInfo.prependedFilePrefix = true;
|
||||
}
|
||||
|
||||
if ('scriptId' in params && params.scriptId != null) {
|
||||
// Set a server-relative URL to locally fetch source by script ID
|
||||
// on Debugger.getScriptSource.
|
||||
this.#scriptIdToSourcePathMapping.set(
|
||||
params.scriptId,
|
||||
serverRelativeUrl,
|
||||
);
|
||||
// $FlowFixMe[prop-missing]
|
||||
if (params.scriptId != null) {
|
||||
this.#scriptIdToSourcePathMapping.set(params.scriptId, params.url);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -848,31 +799,6 @@ export default class Device {
|
||||
// Sends response to debugger via side-effect
|
||||
this.#processDebuggerGetScriptSource(req, socket);
|
||||
return null;
|
||||
case 'Network.loadNetworkResource':
|
||||
// If we're rewriting URLs (to frontend-relative), we don't want to
|
||||
// pass these URLs to the device, since it may try to fetch, return a
|
||||
// CDP *result* (not error) with a network failure, and CDT
|
||||
// will *not* then fall back to fetching locally.
|
||||
//
|
||||
// Instead, take the absence of a nativeSourceCodeFetching
|
||||
// capability as a signal to never pass a loadNetworkResource request
|
||||
// to the device. By returning a CDP error, the frontend should fetch.
|
||||
const result = {
|
||||
error: {
|
||||
code: -32601, // Method not found
|
||||
message:
|
||||
'[inspector-proxy]: Page lacks nativeSourceCodeFetching capability.',
|
||||
},
|
||||
};
|
||||
const response = {id: req.id, result};
|
||||
socket.send(JSON.stringify(response));
|
||||
const pageId = this.#debuggerConnection?.pageId ?? null;
|
||||
this.#deviceEventReporter?.logResponse(response, 'proxy', {
|
||||
pageId,
|
||||
frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
|
||||
prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId),
|
||||
});
|
||||
return null;
|
||||
default:
|
||||
return req;
|
||||
}
|
||||
@@ -883,52 +809,36 @@ export default class Device {
|
||||
debuggerInfo: DebuggerConnection,
|
||||
): CDPRequest<'Debugger.setBreakpointByUrl'> {
|
||||
// If we replaced Android emulator's address to localhost we need to change it back.
|
||||
const {debuggerRelativeBaseUrl, prependedFilePrefix} = debuggerInfo;
|
||||
if (debuggerInfo.originalSourceURLAddress != null) {
|
||||
const processedReq = {...req, params: {...req.params}};
|
||||
if (processedReq.params.url != null) {
|
||||
processedReq.params.url = processedReq.params.url.replace(
|
||||
'localhost',
|
||||
debuggerInfo.originalSourceURLAddress,
|
||||
);
|
||||
|
||||
const processedReq = {...req, params: {...req.params}};
|
||||
if (processedReq.params.url != null) {
|
||||
const originalUrlParam = processedReq.params.url;
|
||||
const httpUrl = this.#tryParseHTTPURL(originalUrlParam);
|
||||
if (httpUrl) {
|
||||
processedReq.params.url = this.#debuggerRelativeToDeviceRelativeUrl(
|
||||
httpUrl,
|
||||
debuggerInfo,
|
||||
).href;
|
||||
} else if (
|
||||
originalUrlParam.startsWith(FILE_PREFIX) &&
|
||||
prependedFilePrefix
|
||||
) {
|
||||
// Remove fake URL prefix if we modified URL in #processMessageFromDeviceLegacy.
|
||||
processedReq.params.url = originalUrlParam.slice(FILE_PREFIX.length);
|
||||
if (
|
||||
processedReq.params.url &&
|
||||
processedReq.params.url.startsWith(FILE_PREFIX) &&
|
||||
debuggerInfo.prependedFilePrefix
|
||||
) {
|
||||
// Remove fake URL prefix if we modified URL in #processMessageFromDeviceLegacy.
|
||||
// $FlowFixMe[incompatible-use]
|
||||
processedReq.params.url = processedReq.params.url.slice(
|
||||
FILE_PREFIX.length,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (processedReq.params.urlRegex != null) {
|
||||
processedReq.params.urlRegex = processedReq.params.urlRegex.replace(
|
||||
/localhost/g,
|
||||
// $FlowFixMe[incompatible-call]
|
||||
debuggerInfo.originalSourceURLAddress,
|
||||
);
|
||||
}
|
||||
return processedReq;
|
||||
}
|
||||
|
||||
// Retain special case rewriting of localhost to device-relative IPs
|
||||
// within regex patterns. We don't rewrite the protocol here because
|
||||
// these patterns typically come from CDT reinterpreting the source URL
|
||||
// `file://host/path` into the regex `host/path|file://host/path`. See:
|
||||
//
|
||||
// https://github.com/ChromeDevTools/devtools-frontend/blob/f913cc6d76f2e2639c05b11ba673fc880b5490dd/front_end/core/sdk/DebuggerModel.ts#L505
|
||||
//
|
||||
// This has always been fragile and probably unnecessary - we don't set
|
||||
// `file://` source URLs. It can be removed when we drop support for
|
||||
// legacy targets, if not sooner.
|
||||
if (
|
||||
// Android's stock emulator and other emulators such as genymotion use a
|
||||
// standard localhost alias.
|
||||
new Set(['10.0.2.2', '10.0.3.2']).has(
|
||||
this.#deviceRelativeBaseUrl.hostname,
|
||||
) &&
|
||||
debuggerRelativeBaseUrl.hostname === 'localhost' &&
|
||||
processedReq.params.urlRegex != null
|
||||
) {
|
||||
processedReq.params.urlRegex = processedReq.params.urlRegex.replaceAll(
|
||||
'localhost',
|
||||
// regex-escape IPv4
|
||||
this.#deviceRelativeBaseUrl.hostname.replaceAll('.', '\\.'),
|
||||
);
|
||||
}
|
||||
return processedReq;
|
||||
return req;
|
||||
}
|
||||
|
||||
#processDebuggerGetScriptSource(
|
||||
@@ -971,7 +881,6 @@ export default class Device {
|
||||
if (pathToSource != null) {
|
||||
const httpURL = this.#tryParseHTTPURL(pathToSource);
|
||||
if (httpURL) {
|
||||
// URL is server-relatve, so we should be able to fetch it from here.
|
||||
this.#fetchText(httpURL).then(
|
||||
text => sendSuccessResponse(text),
|
||||
err =>
|
||||
|
||||
@@ -145,17 +145,6 @@ class DeviceEventReporter {
|
||||
});
|
||||
}
|
||||
|
||||
logProfilingTargetRegistered() {
|
||||
this.#eventReporter.logEvent({
|
||||
type: 'profiling_target_registered',
|
||||
status: 'success',
|
||||
appId: this.#metadata.appId,
|
||||
deviceName: this.#metadata.deviceName,
|
||||
deviceId: this.#metadata.deviceId,
|
||||
pageId: null,
|
||||
});
|
||||
}
|
||||
|
||||
logConnection(
|
||||
connectedEntity: 'debugger',
|
||||
metadata: $ReadOnly<{
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
import type {EventReporter} from '../types/EventReporter';
|
||||
import type {Experiments} from '../types/Experiments';
|
||||
import type {CreateCustomMessageHandlerFn} from './CustomMessageHandler';
|
||||
import type {DeviceOptions} from './Device';
|
||||
import type {
|
||||
JsonPagesListResponse,
|
||||
JsonVersionResponse,
|
||||
@@ -23,7 +22,6 @@ import type {IncomingMessage, ServerResponse} from 'http';
|
||||
// $FlowFixMe[cannot-resolve-module] libdef missing in RN OSS
|
||||
import type {Timeout} from 'timers';
|
||||
|
||||
import getBaseUrlFromRequest from '../utils/getBaseUrlFromRequest';
|
||||
import Device from './Device';
|
||||
import nullthrows from 'nullthrows';
|
||||
// Import these from node:timers to get the correct Flow types.
|
||||
@@ -49,7 +47,7 @@ export interface InspectorProxyQueries {
|
||||
* Returns list of page descriptions ordered by device connection order, then
|
||||
* page addition order.
|
||||
*/
|
||||
getPageDescriptions(requestorRelativeBaseUrl: URL): Array<PageDescription>;
|
||||
getPageDescriptions(): Array<PageDescription>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,8 +57,8 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
// Root of the project used for relative to absolute source path conversion.
|
||||
#projectRoot: string;
|
||||
|
||||
// The base URL to the dev server from the dev-middleware host.
|
||||
#serverBaseUrl: URL;
|
||||
/** The base URL to the dev server from the developer machine. */
|
||||
#serverBaseUrl: string;
|
||||
|
||||
// Maps device ID to Device instance.
|
||||
#devices: Map<string, Device>;
|
||||
@@ -83,14 +81,14 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
customMessageHandler: ?CreateCustomMessageHandlerFn,
|
||||
) {
|
||||
this.#projectRoot = projectRoot;
|
||||
this.#serverBaseUrl = new URL(serverBaseUrl);
|
||||
this.#serverBaseUrl = serverBaseUrl;
|
||||
this.#devices = new Map();
|
||||
this.#eventReporter = eventReporter;
|
||||
this.#experiments = experiments;
|
||||
this.#customMessageHandler = customMessageHandler;
|
||||
}
|
||||
|
||||
getPageDescriptions(requestorRelativeBaseUrl: URL): Array<PageDescription> {
|
||||
getPageDescriptions(): Array<PageDescription> {
|
||||
// Build list of pages from all devices.
|
||||
let result: Array<PageDescription> = [];
|
||||
Array.from(this.#devices.entries()).forEach(([deviceId, device]) => {
|
||||
@@ -98,12 +96,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
device
|
||||
.getPagesList()
|
||||
.map((page: Page) =>
|
||||
this.#buildPageDescription(
|
||||
deviceId,
|
||||
device,
|
||||
page,
|
||||
requestorRelativeBaseUrl,
|
||||
),
|
||||
this.#buildPageDescription(deviceId, device, page),
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -124,12 +117,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
pathname === PAGES_LIST_JSON_URL ||
|
||||
pathname === PAGES_LIST_JSON_URL_2
|
||||
) {
|
||||
this.#sendJsonResponse(
|
||||
response,
|
||||
this.getPageDescriptions(
|
||||
getBaseUrlFromRequest(request) ?? this.#serverBaseUrl,
|
||||
),
|
||||
);
|
||||
this.#sendJsonResponse(response, this.getPageDescriptions());
|
||||
} else if (pathname === PAGES_LIST_JSON_VERSION_URL) {
|
||||
this.#sendJsonResponse(response, {
|
||||
Browser: 'Mobile JavaScript',
|
||||
@@ -155,9 +143,8 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
deviceId: string,
|
||||
device: Device,
|
||||
page: Page,
|
||||
requestorRelativeBaseUrl: URL,
|
||||
): PageDescription {
|
||||
const {host, protocol} = requestorRelativeBaseUrl;
|
||||
const {host, protocol} = new URL(this.#serverBaseUrl);
|
||||
const webSocketScheme = protocol === 'https:' ? 'wss' : 'ws';
|
||||
|
||||
const webSocketUrlWithoutProtocol = `${host}${WS_DEBUGGER_URL}?device=${deviceId}&page=${page.id}`;
|
||||
@@ -225,38 +212,36 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
const deviceId = query.device || fallbackDeviceId;
|
||||
const deviceName = query.name || 'Unknown';
|
||||
const appName = query.app || 'Unknown';
|
||||
const isProfilingBuild = query.profiling === 'true';
|
||||
|
||||
const deviceRelativeBaseUrl =
|
||||
getBaseUrlFromRequest(req) ?? this.#serverBaseUrl;
|
||||
|
||||
const oldDevice = this.#devices.get(deviceId);
|
||||
|
||||
let newDevice;
|
||||
const deviceOptions: DeviceOptions = {
|
||||
id: deviceId,
|
||||
name: deviceName,
|
||||
app: appName,
|
||||
socket,
|
||||
projectRoot: this.#projectRoot,
|
||||
eventReporter: this.#eventReporter,
|
||||
createMessageMiddleware: this.#customMessageHandler,
|
||||
deviceRelativeBaseUrl,
|
||||
serverRelativeBaseUrl: this.#serverBaseUrl,
|
||||
isProfilingBuild,
|
||||
};
|
||||
|
||||
if (oldDevice) {
|
||||
oldDevice.dangerouslyRecreateDevice(deviceOptions);
|
||||
oldDevice.dangerouslyRecreateDevice(
|
||||
deviceId,
|
||||
deviceName,
|
||||
appName,
|
||||
socket,
|
||||
this.#projectRoot,
|
||||
this.#eventReporter,
|
||||
this.#customMessageHandler,
|
||||
);
|
||||
newDevice = oldDevice;
|
||||
} else {
|
||||
newDevice = new Device(deviceOptions);
|
||||
newDevice = new Device(
|
||||
deviceId,
|
||||
deviceName,
|
||||
appName,
|
||||
socket,
|
||||
this.#projectRoot,
|
||||
this.#eventReporter,
|
||||
this.#customMessageHandler,
|
||||
);
|
||||
}
|
||||
|
||||
this.#devices.set(deviceId, newDevice);
|
||||
|
||||
debug(
|
||||
`Got new connection: name=${deviceName}, app=${appName}, device=${deviceId}, via=${deviceRelativeBaseUrl.origin}`,
|
||||
`Got new connection: name=${deviceName}, app=${appName}, device=${deviceId}`,
|
||||
);
|
||||
|
||||
socket.on('close', () => {
|
||||
@@ -292,8 +277,6 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
const query = url.parse(req.url || '', true).query || {};
|
||||
const deviceId = query.device;
|
||||
const pageId = query.page;
|
||||
const debuggerRelativeBaseUrl =
|
||||
getBaseUrlFromRequest(req) ?? this.#serverBaseUrl;
|
||||
|
||||
if (deviceId == null || pageId == null) {
|
||||
throw new Error('Incorrect URL - must provide device and page IDs');
|
||||
@@ -307,7 +290,6 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
this.#startHeartbeat(socket, DEBUGGER_HEARTBEAT_INTERVAL_MS);
|
||||
|
||||
device.handleDebuggerConnection(socket, pageId, {
|
||||
debuggerRelativeBaseUrl,
|
||||
userAgent: req.headers['user-agent'] ?? query.userAgent ?? null,
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
@@ -44,7 +44,6 @@ export type CDPClientMessage =
|
||||
| CDPRequest<'Debugger.getScriptSource'>
|
||||
| CDPRequest<'Debugger.scriptParsed'>
|
||||
| CDPRequest<'Debugger.setBreakpointByUrl'>
|
||||
| CDPRequest<'Network.loadNetworkResource'>
|
||||
| CDPRequest<>;
|
||||
|
||||
export type CDPServerMessage =
|
||||
|
||||
@@ -72,14 +72,12 @@ export default function openDebuggerMiddleware({
|
||||
...
|
||||
} = query;
|
||||
|
||||
const targets = inspectorProxy
|
||||
.getPageDescriptions(new URL(serverBaseUrl))
|
||||
.filter(
|
||||
// Only use targets with better reloading support
|
||||
app =>
|
||||
app.title === LEGACY_SYNTHETIC_PAGE_TITLE ||
|
||||
app.reactNative.capabilities?.nativePageReloads === true,
|
||||
);
|
||||
const targets = inspectorProxy.getPageDescriptions().filter(
|
||||
// Only use targets with better reloading support
|
||||
app =>
|
||||
app.title === LEGACY_SYNTHETIC_PAGE_TITLE ||
|
||||
app.reactNative.capabilities?.nativePageReloads === true,
|
||||
);
|
||||
|
||||
let target;
|
||||
|
||||
|
||||
@@ -18,10 +18,6 @@ export interface BrowserLauncher {
|
||||
* Attempt to open a debugger frontend URL in a browser app window,
|
||||
* optionally returning an object to control the launched browser instance.
|
||||
* The browser used should be capable of running Chrome DevTools.
|
||||
*
|
||||
* The provided url is based on serverBaseUrl, and therefore reachable from
|
||||
* the host of dev-middleware. Implementations are responsible for rewriting
|
||||
* this as necessary where the server is remote.
|
||||
*/
|
||||
launchDebuggerAppWindow: (url: string) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -77,11 +77,6 @@ export type ReportableEvent =
|
||||
| 'PROTOCOL_ERROR',
|
||||
>,
|
||||
}
|
||||
| {
|
||||
type: 'profiling_target_registered',
|
||||
status: 'success',
|
||||
...DebuggerSessionIDs,
|
||||
}
|
||||
| {
|
||||
type: 'proxy_error',
|
||||
status: 'error',
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
// Determine the base URL (scheme and host) used by a client to reach this
|
||||
// server.
|
||||
//
|
||||
// TODO: Support X-Forwarded-Host, etc. for trusted proxies
|
||||
export default function getBaseUrlFromRequest(
|
||||
req: http$IncomingMessage<tls$TLSSocket> | http$IncomingMessage<net$Socket>,
|
||||
): ?URL {
|
||||
const hostHeader = req.headers.host;
|
||||
if (hostHeader == null) {
|
||||
return null;
|
||||
}
|
||||
// `encrypted` is always true for TLS sockets and undefined for net
|
||||
// https://github.com/nodejs/node/issues/41863#issuecomment-1030709186
|
||||
const scheme = req.socket.encrypted === true ? 'https' : 'http';
|
||||
const url = `${scheme}://${req.headers.host}`;
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -65,11 +65,7 @@ function getWsParam({
|
||||
const serverHost = new URL(devServerUrl).host;
|
||||
let value;
|
||||
if (wsUrl.host === serverHost) {
|
||||
// Use a path-absolute (host-relative) URL if the WS server and frontend
|
||||
// server are colocated. This is more robust for cases where the frontend
|
||||
// may actually load through a tunnel or proxy, and the WS connection
|
||||
// should therefore do the same.
|
||||
//
|
||||
// Use a path-absolute (host-relative) URL
|
||||
// Depends on https://github.com/facebookexperimental/rn-chrome-devtools-frontend/pull/4
|
||||
value = wsUrl.pathname + wsUrl.search + wsUrl.hash;
|
||||
} else {
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"main": "index.js",
|
||||
"devDependencies": {
|
||||
"babel-plugin-syntax-hermes-parser": "0.25.1",
|
||||
"hermes-eslint": "0.25.1"
|
||||
"babel-plugin-syntax-hermes-parser": "0.24.0",
|
||||
"hermes-eslint": "0.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"source-map-support": "0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-syntax-hermes-parser": "0.25.1",
|
||||
"hermes-eslint": "0.25.1"
|
||||
"babel-plugin-syntax-hermes-parser": "0.24.0",
|
||||
"hermes-eslint": "0.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+3
-7
@@ -12,7 +12,6 @@ import com.facebook.react.utils.detectOSAwareHermesCommand
|
||||
import com.facebook.react.utils.moveTo
|
||||
import com.facebook.react.utils.windowsAwareCommandLine
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileTree
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
@@ -20,7 +19,6 @@ import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
abstract class BundleHermesCTask : DefaultTask() {
|
||||
|
||||
@@ -28,8 +26,6 @@ abstract class BundleHermesCTask : DefaultTask() {
|
||||
group = "react"
|
||||
}
|
||||
|
||||
@get:Inject abstract val execOperations: ExecOperations
|
||||
|
||||
@get:Internal abstract val root: DirectoryProperty
|
||||
|
||||
@get:InputFiles
|
||||
@@ -131,9 +127,9 @@ abstract class BundleHermesCTask : DefaultTask() {
|
||||
File(jsIntermediateSourceMapsDir.get().asFile, "$bundleAssetName.compiler.map")
|
||||
|
||||
private fun runCommand(command: List<Any>) {
|
||||
execOperations.exec { exec ->
|
||||
exec.workingDir(root.get().asFile)
|
||||
exec.commandLine(command)
|
||||
project.exec {
|
||||
it.workingDir(root.get().asFile)
|
||||
it.commandLine(command)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ abstract class BuildCodegenCLITask : Exec() {
|
||||
}
|
||||
|
||||
override fun exec() {
|
||||
val logfile = "${project.layout.buildDirectory.getAsFile().get()}/build-cli.log"
|
||||
val logfile = "${project.layout.buildDirectory}/build-cli.log"
|
||||
File(logfile).apply {
|
||||
parentFile.mkdirs()
|
||||
if (exists()) {
|
||||
|
||||
+1
-5
@@ -15,7 +15,6 @@ import java.math.BigInteger
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.min
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.initialization.Settings
|
||||
@@ -160,10 +159,7 @@ abstract class ReactSettingsExtension @Inject constructor(val settings: Settings
|
||||
val logger = Logging.getLogger("ReactSettingsExtension")
|
||||
logger.error(message)
|
||||
if (cacheJsonConfig.length() != 0L) {
|
||||
logger.error(
|
||||
cacheJsonConfig
|
||||
.readText()
|
||||
.substring(0, min(1024, cacheJsonConfig.length().toInt())))
|
||||
logger.error(cacheJsonConfig.readText().substring(0, 1024))
|
||||
}
|
||||
cacheJsonConfig.delete()
|
||||
throw GradleException(message)
|
||||
|
||||
@@ -97,7 +97,6 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
activesupport (>= 6.1.7.5, < 7.1.0)
|
||||
cocoapods (~> 1.13, != 1.15.1, != 1.15.0)
|
||||
xcodeproj (< 1.26.0)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.3.0p0
|
||||
|
||||
@@ -10,7 +10,7 @@ buildscript {
|
||||
buildToolsVersion = "35.0.0"
|
||||
minSdkVersion = 24
|
||||
compileSdkVersion = 35
|
||||
targetSdkVersion = 35
|
||||
targetSdkVersion = 34
|
||||
ndkVersion = "27.1.12297006"
|
||||
kotlinVersion = "2.0.21"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
|
||||
0C80B921A6F3F58F76C31292 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */; };
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
68D852E4B70E7C539AF156EA /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */; };
|
||||
6EA01F72FAC10D00AECACF94 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 0EC7AB76F90EED035707BA4E /* PrivacyInfo.xcprivacy */; };
|
||||
7699B88040F8A987B510C191 /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */; };
|
||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
||||
D463203D20D2FDD34F945C74 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -39,13 +39,13 @@
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HelloWorld/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = HelloWorld/main.m; sourceTree = "<group>"; };
|
||||
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = HelloWorld/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld-HelloWorldTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B4392A12AC88292D35C810B /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5709B34CF0A7D63546082F79 /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; };
|
||||
5B7EB9410499542E8C5724F5 /* Pods-HelloWorld-HelloWorldTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = HelloWorld/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
89C6BE57DB24E9ADA2F236DE /* Pods-HelloWorld-HelloWorldTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld-HelloWorldTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
68D852E4B70E7C539AF156EA /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */,
|
||||
7699B88040F8A987B510C191 /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -62,7 +62,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D463203D20D2FDD34F945C74 /* libPods-HelloWorld.a in Frameworks */,
|
||||
0C80B921A6F3F58F76C31292 /* libPods-HelloWorld.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -105,8 +105,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
82822864BCFA4BE42C6C2969 /* libPods-HelloWorld.a */,
|
||||
CE12D37B885C99EE7D4A2086 /* libPods-HelloWorld-HelloWorldTests.a */,
|
||||
5DCACB8F33CDC322A6C60F78 /* libPods-HelloWorld.a */,
|
||||
19F6CBCC0A4E27FBF8BF4A61 /* libPods-HelloWorld-HelloWorldTests.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -165,7 +165,6 @@
|
||||
00E356EB1AD99517003FC87E /* Frameworks */,
|
||||
00E356EC1AD99517003FC87E /* Resources */,
|
||||
F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */,
|
||||
A44ED3CC3037C88F69E3AF15 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -187,7 +186,6 @@
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
|
||||
D32CB2BA406E97DB62F51C6B /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -272,23 +270,6 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\n\nexport CONFIG_JSON=$(sed -e \"s|HELLOWORLD_PATH|$(realpath \"${SRCROOT}/../\")|g\" \"${SRCROOT}/../.react-native.config\")\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
|
||||
};
|
||||
A44ED3CC3037C88F69E3AF15 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -333,23 +314,6 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D32CB2BA406E97DB62F51C6B /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -571,17 +535,6 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
@@ -602,14 +555,8 @@
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native";
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -655,17 +602,6 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
@@ -685,13 +621,8 @@
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native";
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -8,14 +8,12 @@
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.moduleName = @"HelloWorld";
|
||||
self.dependencyProvider = [RCTAppDependencyProvider new];
|
||||
// You can add your custom initial props in the dictionary below.
|
||||
// They will be passed down to the ViewController used by React Native.
|
||||
self.initialProps = @{};
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "18.3.1",
|
||||
"react": "19.0.0-rc-fb9a90fa48-20240614",
|
||||
"react-native": "1000.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -28,7 +28,7 @@
|
||||
"eslint": "^8.19.0",
|
||||
"jest": "^29.6.3",
|
||||
"listr2": "^8.2.1",
|
||||
"react-test-renderer": "18.3.1",
|
||||
"react-test-renderer": "19.0.0-rc-fb9a90fa48-20240614",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -89,6 +89,7 @@ export function getDefaultConfig(projectRoot: string): ConfigT {
|
||||
babelTransformerPath: require.resolve(
|
||||
'@react-native/metro-babel-transformer',
|
||||
),
|
||||
hermesParser: true,
|
||||
getTransformOptions: async () => ({
|
||||
transform: {
|
||||
experimentalImportSupport: false,
|
||||
|
||||
@@ -553,48 +553,6 @@ if (global.nativeLoggingHook) {
|
||||
assert: consoleAssertPolyfill,
|
||||
};
|
||||
|
||||
// TODO(T206796580): This was copy-pasted from ExceptionsManager.js
|
||||
// Delete the copy there after the c++ pipeline is rolled out everywhere.
|
||||
if (global.RN$useAlwaysAvailableJSErrorHandling === true) {
|
||||
let originalConsoleError = console.error;
|
||||
console.reportErrorsAsExceptions = true;
|
||||
function stringifySafe(arg) {
|
||||
return inspect(arg, {depth: 10}).replaceAll(/\n\s*/g, ' ');
|
||||
}
|
||||
console.error = function (...args) {
|
||||
originalConsoleError.apply(this, args);
|
||||
if (!console.reportErrorsAsExceptions) {
|
||||
return;
|
||||
}
|
||||
if (global.RN$inExceptionHandler?.()) {
|
||||
return;
|
||||
}
|
||||
let error;
|
||||
|
||||
const firstArg = args[0];
|
||||
if (firstArg?.stack) {
|
||||
// RN$handleException will console.error this with high enough fidelity.
|
||||
error = firstArg;
|
||||
} else {
|
||||
if (typeof firstArg === 'string' && firstArg.startsWith('Warning: ')) {
|
||||
// React warnings use console.error so that a stack trace is shown, but
|
||||
// we don't (currently) want these to show a redbox
|
||||
return;
|
||||
}
|
||||
const message = args
|
||||
.map(arg => (typeof arg === 'string' ? arg : stringifySafe(arg)))
|
||||
.join(' ');
|
||||
|
||||
error = new Error(message);
|
||||
error.name = 'console.error';
|
||||
}
|
||||
|
||||
const isFatal = false;
|
||||
const reportToConsole = false;
|
||||
global.RN$handleException(error, isFatal, reportToConsole);
|
||||
};
|
||||
}
|
||||
|
||||
Object.defineProperty(console, '_isPolyfilled', {
|
||||
value: true,
|
||||
enumerable: false,
|
||||
|
||||
@@ -19,12 +19,12 @@ type Fn<Args, Return> = (...Args) => Return;
|
||||
* when loading a module. This will report any errors encountered before
|
||||
* ExceptionsManager is configured.
|
||||
*/
|
||||
let _globalHandler: ErrorHandler =
|
||||
global.RN$useAlwaysAvailableJSErrorHandling === true
|
||||
? global.RN$handleException
|
||||
: (e: mixed, isFatal: boolean) => {
|
||||
throw e;
|
||||
};
|
||||
let _globalHandler: ErrorHandler = function onError(
|
||||
e: mixed,
|
||||
isFatal: boolean,
|
||||
) {
|
||||
throw e;
|
||||
};
|
||||
|
||||
/**
|
||||
* The particular require runtime that we are using looks for a global
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"@babel/plugin-transform-unicode-regex": "^7.24.7",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@react-native/babel-plugin-codegen": "0.77.0-main",
|
||||
"babel-plugin-syntax-hermes-parser": "0.25.1",
|
||||
"babel-plugin-syntax-hermes-parser": "0.24.0",
|
||||
"babel-plugin-transform-flow-enums": "^0.0.2",
|
||||
"react-refresh": "^0.14.0"
|
||||
},
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ function isTSXSource(fileName) {
|
||||
const loose = true;
|
||||
|
||||
const defaultPlugins = [
|
||||
[require('babel-plugin-syntax-hermes-parser'), {parseLangTypes: 'flow'}],
|
||||
[require('babel-plugin-syntax-hermes-parser')],
|
||||
[require('babel-plugin-transform-flow-enums')],
|
||||
[require('@babel/plugin-transform-block-scoping')],
|
||||
[require('@babel/plugin-transform-class-properties'), {loose}],
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@react-native/babel-preset": "0.77.0-main",
|
||||
"hermes-parser": "0.25.1",
|
||||
"hermes-parser": "0.24.0",
|
||||
"nullthrows": "^1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
-1
@@ -23,7 +23,6 @@ type OnChangeEvent = $ReadOnly<{|
|
||||
source: {url: string, ...},
|
||||
x: Int32,
|
||||
y: Int32,
|
||||
arrayOfObjects: $ReadOnlyArray<{value: $ReadOnly<{str: string}>}>,
|
||||
...
|
||||
},
|
||||
|}>;
|
||||
|
||||
-14
@@ -161,20 +161,6 @@ void EventNestedObjectPropsNativeComponentViewEventEmitter::onChange(OnChange $e
|
||||
}
|
||||
location.setProperty(runtime, \\"x\\", $event.location.x);
|
||||
location.setProperty(runtime, \\"y\\", $event.location.y);
|
||||
|
||||
auto arrayOfObjects = jsi::Array(runtime, $event.location.arrayOfObjects.size());
|
||||
size_t arrayOfObjectsIndex = 0;
|
||||
for (auto arrayOfObjectsValue : $event.location.arrayOfObjects) {
|
||||
auto arrayOfObjectsObject = jsi::Object(runtime);
|
||||
{
|
||||
auto value = jsi::Object(runtime);
|
||||
value.setProperty(runtime, \\"str\\", arrayOfObjectsValue.value.str);
|
||||
arrayOfObjectsObject.setProperty(runtime, \\"value\\", value);
|
||||
}
|
||||
arrayOfObjects.setValueAtIndex(runtime, arrayOfObjectsIndex++, arrayOfObjectsObject);
|
||||
}
|
||||
location.setProperty(runtime, \\"arrayOfObjects\\", arrayOfObjects);
|
||||
|
||||
$payload.setProperty(runtime, \\"location\\", location);
|
||||
}
|
||||
return $payload;
|
||||
|
||||
-9
@@ -199,19 +199,10 @@ class EventNestedObjectPropsNativeComponentViewEventEmitter : public ViewEventEm
|
||||
std::string url;
|
||||
};
|
||||
|
||||
struct OnChangeLocationArrayOfObjectsValue {
|
||||
std::string str;
|
||||
};
|
||||
|
||||
struct OnChangeLocationArrayOfObjects {
|
||||
OnChangeLocationArrayOfObjectsValue value;
|
||||
};
|
||||
|
||||
struct OnChangeLocation {
|
||||
OnChangeLocationSource source;
|
||||
int x;
|
||||
int y;
|
||||
std::vector<OnChangeLocationArrayOfObjects> arrayOfObjects;
|
||||
};
|
||||
|
||||
struct OnChange {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.25.3",
|
||||
"glob": "^7.1.1",
|
||||
"hermes-parser": "0.25.1",
|
||||
"hermes-parser": "0.24.0",
|
||||
"invariant": "^2.2.4",
|
||||
"jscodeshift": "^17.0.0",
|
||||
"nullthrows": "^1.1.1",
|
||||
@@ -49,7 +49,7 @@
|
||||
"@babel/plugin-transform-flow-strip-types": "^7.25.2",
|
||||
"@babel/preset-env": "^7.25.3",
|
||||
"chalk": "^4.0.0",
|
||||
"hermes-estree": "0.25.1",
|
||||
"hermes-estree": "0.24.0",
|
||||
"micromatch": "^4.0.4",
|
||||
"prettier": "2.8.8",
|
||||
"rimraf": "^3.0.2"
|
||||
|
||||
+1
-1
@@ -327,7 +327,7 @@ export interface NativeModuleBooleanTypeAnnotation {
|
||||
|
||||
export type NativeModuleEnumMember = {
|
||||
readonly name: string;
|
||||
readonly value: NativeModuleStringLiteralTypeAnnotation | NativeModuleNumberLiteralTypeAnnotation,
|
||||
readonly value: string | number;
|
||||
};
|
||||
|
||||
export type NativeModuleEnumMemberType =
|
||||
|
||||
+1
-1
@@ -311,7 +311,7 @@ export type NativeModuleNumberTypeAnnotation = $ReadOnly<{
|
||||
|
||||
export type NativeModuleEnumMember = {
|
||||
name: string,
|
||||
value: StringLiteralTypeAnnotation | NumberLiteralTypeAnnotation,
|
||||
value: string | number,
|
||||
};
|
||||
|
||||
export type NativeModuleEnumMemberType =
|
||||
|
||||
@@ -96,7 +96,7 @@ function combineSchemasInFileListAndWriteToFile(
|
||||
exclude: ?RegExp,
|
||||
): void {
|
||||
const combined = combineSchemasInFileList(fileList, platform, exclude);
|
||||
const formattedSchema = JSON.stringify(combined);
|
||||
const formattedSchema = JSON.stringify(combined, null, 2);
|
||||
fs.writeFileSync(outfile, formattedSchema);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,4 +84,4 @@ for (const file of schemaFiles) {
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(output, JSON.stringify({modules}));
|
||||
fs.writeFileSync(output, JSON.stringify({modules}, null, 2));
|
||||
|
||||
+2
-2
@@ -104,7 +104,7 @@ function generateSetter(
|
||||
) {
|
||||
const eventChain = usingEvent
|
||||
? `$event.${[...propertyParts, propertyName].join('.')}`
|
||||
: [...propertyParts, propertyName].join('.');
|
||||
: [propertyParts, propertyName].join('.');
|
||||
return `${variableName}.setProperty(runtime, "${propertyName}", ${valueMapper(
|
||||
eventChain,
|
||||
)});`;
|
||||
@@ -157,7 +157,7 @@ function generateArraySetter(
|
||||
): string {
|
||||
const eventChain = usingEvent
|
||||
? `$event.${[...propertyParts, propertyName].join('.')}`
|
||||
: [...propertyParts, propertyName].join('.');
|
||||
: [propertyParts, propertyName].join('.');
|
||||
const indexVar = `${propertyName}Index`;
|
||||
const innerLoopVar = `${propertyName}Value`;
|
||||
return `
|
||||
|
||||
@@ -406,14 +406,6 @@ struct Bridging<${enumName}> {
|
||||
};`;
|
||||
};
|
||||
|
||||
function getMemberValueAppearance(member: NativeModuleEnumMember['value']) {
|
||||
if (member.type === 'StringLiteralTypeAnnotation') {
|
||||
return `"${member.value}"`;
|
||||
} else {
|
||||
return member.value;
|
||||
}
|
||||
}
|
||||
|
||||
function generateEnum(
|
||||
hasteModuleName: string,
|
||||
origEnumName: string,
|
||||
@@ -425,6 +417,9 @@ function generateEnum(
|
||||
const nativeEnumMemberType: NativeEnumMemberValueType =
|
||||
memberType === 'StringTypeAnnotation' ? 'std::string' : 'int32_t';
|
||||
|
||||
const getMemberValueAppearance = (value: string | number) =>
|
||||
memberType === 'StringTypeAnnotation' ? `"${value}"` : `${value}`;
|
||||
|
||||
const fromCases =
|
||||
members
|
||||
.map(
|
||||
|
||||
+16
-62
@@ -163,17 +163,11 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'ONE',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1,
|
||||
},
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: 'TWO',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 2,
|
||||
},
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -184,24 +178,15 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'POINT_ZERO',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0.0,
|
||||
},
|
||||
value: '0.0',
|
||||
},
|
||||
{
|
||||
name: 'POINT_ONE',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0.1,
|
||||
},
|
||||
value: '0.1',
|
||||
},
|
||||
{
|
||||
name: 'POINT_TWO',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0.2,
|
||||
},
|
||||
value: '0.2',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -212,17 +197,11 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'HELLO',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'hello',
|
||||
},
|
||||
value: 'hello',
|
||||
},
|
||||
{
|
||||
name: 'GoodBye',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'goodbye',
|
||||
},
|
||||
value: 'goodbye',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1738,7 +1717,6 @@ const REAL_MODULE_EXAMPLE: SchemaType = {
|
||||
|
||||
const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
modules: {
|
||||
// $FlowFixMe[incompatible-type]
|
||||
NativeSampleTurboModule: {
|
||||
type: 'NativeModule',
|
||||
aliasMap: {
|
||||
@@ -1947,17 +1925,11 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'IA',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 23,
|
||||
},
|
||||
value: '23',
|
||||
},
|
||||
{
|
||||
name: 'IB',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 42,
|
||||
},
|
||||
value: '42',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1968,17 +1940,11 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'FA',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1.23,
|
||||
},
|
||||
value: '1.23',
|
||||
},
|
||||
{
|
||||
name: 'FB',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 4.56,
|
||||
},
|
||||
value: '4.56',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1989,17 +1955,11 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'NA',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'NA',
|
||||
},
|
||||
value: 'NA',
|
||||
},
|
||||
{
|
||||
name: 'NB',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'NB',
|
||||
},
|
||||
value: 'NB',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2010,17 +1970,11 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'SA',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 's---a',
|
||||
},
|
||||
value: 's---a',
|
||||
},
|
||||
{
|
||||
name: 'SB',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 's---b',
|
||||
},
|
||||
value: 's---b',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2718,7 +2672,7 @@ const UNION_MODULE: SchemaType = {
|
||||
},
|
||||
};
|
||||
|
||||
const STRING_LITERALS: SchemaType = {
|
||||
const STRING_LITERALS = {
|
||||
modules: {
|
||||
NativeSampleTurboModule: {
|
||||
type: 'NativeModule',
|
||||
|
||||
+2
-2
@@ -2047,7 +2047,7 @@ template <>
|
||||
struct Bridging<NativeSampleTurboModuleFloatEnum> {
|
||||
static NativeSampleTurboModuleFloatEnum fromJs(jsi::Runtime &rt, const jsi::Value &rawValue) {
|
||||
double value = (double)rawValue.asNumber();
|
||||
if (value == 0) {
|
||||
if (value == 0.0) {
|
||||
return NativeSampleTurboModuleFloatEnum::POINT_ZERO;
|
||||
} else if (value == 0.1) {
|
||||
return NativeSampleTurboModuleFloatEnum::POINT_ONE;
|
||||
@@ -2060,7 +2060,7 @@ struct Bridging<NativeSampleTurboModuleFloatEnum> {
|
||||
|
||||
static jsi::Value toJs(jsi::Runtime &rt, NativeSampleTurboModuleFloatEnum value) {
|
||||
if (value == NativeSampleTurboModuleFloatEnum::POINT_ZERO) {
|
||||
return bridging::toJs(rt, 0);
|
||||
return bridging::toJs(rt, 0.0);
|
||||
} else if (value == NativeSampleTurboModuleFloatEnum::POINT_ONE) {
|
||||
return bridging::toJs(rt, 0.1);
|
||||
} else if (value == NativeSampleTurboModuleFloatEnum::POINT_TWO) {
|
||||
|
||||
+4
-16
@@ -478,17 +478,11 @@ describe('typeEnumResolution', () => {
|
||||
members: [
|
||||
{
|
||||
name: 'Hello',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'hello',
|
||||
},
|
||||
value: 'hello',
|
||||
},
|
||||
{
|
||||
name: 'Goodbye',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'goodbye',
|
||||
},
|
||||
value: 'goodbye',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -527,17 +521,11 @@ describe('typeEnumResolution', () => {
|
||||
members: [
|
||||
{
|
||||
name: 'On',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1,
|
||||
},
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: 'Off',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0,
|
||||
},
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
-30
@@ -265,35 +265,6 @@ export interface Spec extends TurboModule {
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('MixedValuesEnumNativeModule');
|
||||
`;
|
||||
|
||||
const NUMERIC_VALUES_ENUM_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export enum SomeEnum {
|
||||
NUM = 1,
|
||||
NEGATIVE = -1,
|
||||
SUBFACTORIAL = !5,
|
||||
}
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getEnums: (a: SomeEnum) => string;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('NumericValuesEnumNativeModule');
|
||||
`;
|
||||
|
||||
const MAP_WITH_EXTRA_KEYS_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@@ -333,6 +304,5 @@ module.exports = {
|
||||
TWO_NATIVE_EXTENDING_TURBO_MODULE,
|
||||
EMPTY_ENUM_NATIVE_MODULE,
|
||||
MIXED_VALUES_ENUM_NATIVE_MODULE,
|
||||
NUMERIC_VALUES_ENUM_NATIVE_MODULE,
|
||||
MAP_WITH_EXTRA_KEYS_NATIVE_MODULE,
|
||||
};
|
||||
|
||||
-1
@@ -782,7 +782,6 @@ export enum Quality {
|
||||
}
|
||||
|
||||
export enum Resolution {
|
||||
Corrupted = -1,
|
||||
Low = 720,
|
||||
High = 1080,
|
||||
}
|
||||
|
||||
+14
-69
@@ -25,12 +25,6 @@ exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_REA
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_UNNAMED_PARAMS 1`] = `"Module NativeSampleTurboModule: All function parameters must be named."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NUMERIC_VALUES_ENUM_NATIVE_MODULE 1`] = `
|
||||
"Syntax error in path/NativeSampleTurboModule.js: 'true', 'false', 'string', 'number' or 'bigint' expected in enum member initializer (20:17)
|
||||
SUBFACTORIAL = !5,
|
||||
~~~~~~~~~~~~~~~^"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_EXTENDING_TURBO_MODULE 1`] = `"Module NativeSampleTurboModule: Every NativeModule spec file must declare exactly one NativeModule Flow interface. This file declares 2: 'Spec', and 'Spec2'. Please remove the extraneous Flow interface declarations."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT 1`] = `"Module NativeSampleTurboModule: No Flow interfaces extending TurboModule were detected in this NativeModule spec."`;
|
||||
@@ -147,17 +141,11 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'SD',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'SD'
|
||||
}
|
||||
'value': 'SD'
|
||||
},
|
||||
{
|
||||
'name': 'HD',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'HD'
|
||||
}
|
||||
'value': 'HD'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -166,26 +154,13 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`]
|
||||
'type': 'EnumDeclarationWithMembers',
|
||||
'memberType': 'NumberTypeAnnotation',
|
||||
'members': [
|
||||
{
|
||||
'name': 'Corrupted',
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': -1
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 720
|
||||
}
|
||||
'value': 720
|
||||
},
|
||||
{
|
||||
'name': 'High',
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 1080
|
||||
}
|
||||
'value': 1080
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -196,24 +171,15 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'One',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'one'
|
||||
}
|
||||
'value': 'one'
|
||||
},
|
||||
{
|
||||
'name': 'Two',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'two'
|
||||
}
|
||||
'value': 'two'
|
||||
},
|
||||
{
|
||||
'name': 'Three',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'three'
|
||||
}
|
||||
'value': 'three'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -495,17 +461,11 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'SD',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'SD'
|
||||
}
|
||||
'value': 'SD'
|
||||
},
|
||||
{
|
||||
'name': 'HD',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'HD'
|
||||
}
|
||||
'value': 'HD'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -516,17 +476,11 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 720
|
||||
}
|
||||
'value': 720
|
||||
},
|
||||
{
|
||||
'name': 'High',
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 1080
|
||||
}
|
||||
'value': 1080
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -537,24 +491,15 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'One',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'one'
|
||||
}
|
||||
'value': 'one'
|
||||
},
|
||||
{
|
||||
'name': 'Two',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'two'
|
||||
}
|
||||
'value': 'two'
|
||||
},
|
||||
{
|
||||
'name': 'Three',
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'three'
|
||||
}
|
||||
'value': 'three'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user