Compare commits

..
1096 changed files with 17783 additions and 23512 deletions
-3
View File
@@ -35,9 +35,6 @@ module.exports = {
// Flow handles these checks for us, so they aren't required
'no-undef': 'off',
'no-unreachable': 'off',
// Throwing from function or rejecting promises with non-error values could result in unclear error stack traces and lead to harder debugging
'prefer-promise-reject-errors': 'error',
'no-throw-literal': 'error',
},
},
{
+1 -1
View File
@@ -98,4 +98,4 @@ untyped-import
untyped-type-import
[version]
^0.289.0
^0.288.0
@@ -0,0 +1,103 @@
name: build-apple-slices-hermes
description: This action builds hermesc for Apple platforms
inputs:
hermes-version:
required: true
description: The version of Hermes
react-native-version:
required: true
description: The version of Hermes
slice:
required: true
description: The slice of hermes you want to build. It could be iphone, iphonesimulator, macos, catalyst, appletvos, appletvsimulator, xros, or xrossimulator
flavor:
required: true
description: The flavor we want to build. It can be Debug or Release
runs:
using: composite
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
- name: Restore Hermes workspace
uses: ./.github/actions/restore-hermes-workspace
- name: Restore HermesC Artifact
uses: actions/download-artifact@v4
with:
name: hermesc-apple
path: ./packages/react-native/sdks/hermes/build_host_hermesc
- name: Restore Slice From Cache
id: restore-slice-cache
uses: actions/cache/restore@v4
with:
path: ./packages/react-native/sdks/hermes/build_${{ inputs.slice }}_${{ inputs.flavor }}
key: v6-hermes-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}-${{ inputs.slice }}-${{ inputs.flavor }}
- name: Build the Hermes ${{ inputs.slice }} frameworks
shell: bash
run: |
cd ./packages/react-native/sdks/hermes || exit 1
SLICE=${{ inputs.slice }}
FLAVOR=${{ inputs.flavor }}
FINAL_PATH=build_"$SLICE"_"$FLAVOR"
echo "Final path for this slice is: $FINAL_PATH"
if [[ -d "$FINAL_PATH" ]]; then
echo "[HERMES] Skipping! Found the requested slice at $FINAL_PATH".
exit 0
fi
if [[ "$ARTIFACTS_EXIST" ]]; then
echo "[HERMES] Skipping! Artifacts exists already."
exit 0
fi
export RELEASE_VERSION=${{ inputs.react-native-version }}
# HermesC is used to build hermes, so it has to be executable
chmod +x ./build_host_hermesc/bin/hermesc
if [[ "$SLICE" == "macosx" ]]; then
echo "[HERMES] Building Hermes for MacOS"
chmod +x ./utils/build-mac-framework.sh
BUILD_TYPE="${{ inputs.flavor }}" ./utils/build-mac-framework.sh
else
echo "[HERMES] Building Hermes for iOS: $SLICE"
chmod +x ./utils/build-ios-framework.sh
BUILD_TYPE="${{ inputs.flavor }}" ./utils/build-ios-framework.sh "$SLICE"
fi
echo "Moving from build_$SLICE to $FINAL_PATH"
mv build_"$SLICE" "$FINAL_PATH"
# check whether everything is there
if [[ -d "$FINAL_PATH/lib/hermesvm.framework" ]]; then
echo "Successfully built hermesvm.framework for $SLICE in $FLAVOR"
else
echo "Failed to built hermesvm.framework for $SLICE in $FLAVOR"
exit 1
fi
if [[ -d "$FINAL_PATH/lib/hermesvm.framework.dSYM" ]]; then
echo "Successfully built hermesvm.framework.dSYM for $SLICE in $FLAVOR"
else
echo "Failed to built hermesvm.framework.dSYM for $SLICE in $FLAVOR"
echo "Please try again"
exit 1
fi
- name: Compress slices to preserve Symlinks
shell: bash
run: |
cd ./packages/react-native/sdks/hermes
tar -czv -f build_${{ matrix.slice }}_${{ matrix.flavor }}.tar.gz build_${{ matrix.slice }}_${{ matrix.flavor }}
- name: Upload Artifact for Slice (${{ inputs.slice }}, ${{ inputs.flavor }}}
uses: actions/upload-artifact@v4.3.4
with:
name: slice-${{ inputs.slice }}-${{ inputs.flavor }}
path: ./packages/react-native/sdks/hermes/build_${{ inputs.slice }}_${{ inputs.flavor }}.tar.gz
- name: Save slice cache
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
uses: actions/cache/save@v4
with:
path: ./packages/react-native/sdks/hermes/build_${{ inputs.slice }}_${{ inputs.flavor }}
key: v6-hermes-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}-${{ inputs.SLICE }}-${{ inputs.FLAVOR }}
@@ -0,0 +1,227 @@
name: build-hermes-macos
description: This action builds hermesc for Apple platforms
inputs:
hermes-version:
required: true
description: The version of Hermes
react-native-version:
required: true
description: The version of React Native
flavor:
required: true
description: The flavor we want to build. It can be Debug or Release
runs:
using: composite
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
- name: Restore Hermes workspace
uses: ./.github/actions/restore-hermes-workspace
- name: Restore Cached Artifacts
uses: actions/cache/restore@v4
with:
key: v4-hermes-artifacts-${{ inputs.flavor }}-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
path: |
/tmp/hermes/osx-bin/${{ inputs.flavor }}
/tmp/hermes/dSYM/${{ inputs.flavor }}
/tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ inputs.flavor }}.tar.gz
- name: Check if the required artifacts already exist
id: check_if_apple_artifacts_are_there
shell: bash
run: |
FLAVOR="${{ inputs.flavor }}"
echo "Flavor is $FLAVOR"
OSX_BIN="/tmp/hermes/osx-bin/$FLAVOR"
DSYM="/tmp/hermes/dSYM/$FLAVOR"
HERMES="/tmp/hermes/hermes-runtime-darwin/hermes-ios-$FLAVOR.tar.gz"
if [[ -d "$OSX_BIN" ]] && \
[[ -d "$DSYM" ]] && \
[[ -f "$HERMES" ]]; then
echo "Artifacts are there!"
echo "ARTIFACTS_EXIST=true" >> $GITHUB_ENV
echo "ARTIFACTS_EXIST=true" >> $GITHUB_OUTPUT
fi
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Yarn- Install Dependencies
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: ./.github/actions/yarn-install
- name: Slice cache macosx
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-macosx-${{ inputs.flavor }}
- name: Slice cache iphoneos
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-iphoneos-${{ inputs.flavor }}
- name: Slice cache iphonesimulator
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-iphonesimulator-${{ inputs.flavor }}
- name: Slice cache appletvos
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-appletvos-${{ inputs.flavor }}
- name: Slice cache appletvsimulator
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-appletvsimulator-${{ inputs.flavor }}
- name: Slice cache catalyst
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-catalyst-${{ inputs.flavor }}
- name: Slice cache xros
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-xros-${{ inputs.flavor }}
- name: Slice cache xrsimulator
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
uses: actions/download-artifact@v4
with:
path: ./packages/react-native/sdks/hermes/
name: slice-xrsimulator-${{ inputs.flavor }}
- name: Unzip slices
shell: bash
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
run: |
cd ./packages/react-native/sdks/hermes
ls -l .
tar -xzv -f build_catalyst_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_iphoneos_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_iphonesimulator_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_appletvos_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_appletvsimulator_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_macosx_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_xros_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_xrsimulator_${{ matrix.flavor }}.tar.gz
- name: Move back build folders
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
shell: bash
run: |
ls -l ./packages/react-native/sdks/hermes
cd ./packages/react-native/sdks/hermes || exit 1
mv build_macosx_${{ inputs.flavor }} build_macosx
mv build_iphoneos_${{ inputs.flavor }} build_iphoneos
mv build_iphonesimulator_${{ inputs.flavor }} build_iphonesimulator
mv build_appletvos_${{ inputs.flavor }} build_appletvos
mv build_appletvsimulator_${{ inputs.flavor }} build_appletvsimulator
mv build_catalyst_${{ inputs.flavor }} build_catalyst
mv build_xros_${{ inputs.flavor }} build_xros
mv build_xrsimulator_${{ inputs.flavor }} build_xrsimulator
- name: Prepare destroot folder
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
shell: bash
run: |
cd ./packages/react-native/sdks/hermes || exit 1
chmod +x ./utils/build-apple-framework.sh
. ./utils/build-apple-framework.sh
prepare_dest_root_for_ci
- name: Create fat framework for iOS
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
shell: bash
run: |
cd ./packages/react-native/sdks/hermes || exit 1
echo "[HERMES] Creating the universal framework"
chmod +x ./utils/build-ios-framework.sh
./utils/build-ios-framework.sh build_framework
chmod +x ./destroot/bin/hermesc
- name: Package the Hermes Apple frameworks
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
shell: bash
run: |
BUILD_TYPE="${{ inputs.flavor }}"
echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"
TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX)
TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "$BUILD_TYPE")
echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"
TARBALL_OUTPUT_PATH=$(node ./packages/react-native/scripts/hermes/create-tarball.js \
--inputDir ./packages/react-native/sdks/hermes \
--buildType "$BUILD_TYPE" \
--outputDir $TARBALL_OUTPUT_DIR)
echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH"
mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR
cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/.
mkdir -p /tmp/hermes/osx-bin/${{ inputs.flavor }}
cp ./packages/react-native/sdks/hermes/build_macosx/bin/* /tmp/hermes/osx-bin/${{ inputs.flavor }}
ls -lR /tmp/hermes/osx-bin/
- name: Create dSYM archive
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
shell: bash
run: |
FLAVOR=${{ inputs.flavor }}
WORKING_DIR="/tmp/hermes_tmp/dSYM/$FLAVOR"
mkdir -p "$WORKING_DIR/macosx"
mkdir -p "$WORKING_DIR/catalyst"
mkdir -p "$WORKING_DIR/iphoneos"
mkdir -p "$WORKING_DIR/iphonesimulator"
mkdir -p "$WORKING_DIR/appletvos"
mkdir -p "$WORKING_DIR/appletvsimulator"
mkdir -p "$WORKING_DIR/xros"
mkdir -p "$WORKING_DIR/xrsimulator"
cd ./packages/react-native/sdks/hermes || exit 1
DSYM_FILE_PATH=lib/hermesvm.framework.dSYM
cp -r build_macosx/$DSYM_FILE_PATH "$WORKING_DIR/macosx/"
cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/"
cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/"
cp -r build_iphonesimulator/$DSYM_FILE_PATH "$WORKING_DIR/iphonesimulator/"
cp -r build_appletvos/$DSYM_FILE_PATH "$WORKING_DIR/appletvos/"
cp -r build_appletvsimulator/$DSYM_FILE_PATH "$WORKING_DIR/appletvsimulator/"
cp -r build_xros/$DSYM_FILE_PATH "$WORKING_DIR/xros/"
cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/"
DEST_DIR="/tmp/hermes/dSYM/$FLAVOR"
tar -C "$WORKING_DIR" -czvf "hermesvm.framework.dSYM" .
mkdir -p "$DEST_DIR"
mv "hermesvm.framework.dSYM" "$DEST_DIR"
- name: Upload hermes dSYM artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-dSYM-${{ inputs.flavor }}
path: /tmp/hermes/dSYM/${{ inputs.flavor }}
- name: Upload hermes Runtime artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-darwin-bin-${{ inputs.flavor }}
path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ inputs.flavor }}.tar.gz
- name: Upload hermes osx artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-osx-bin-${{ inputs.flavor }}
path: /tmp/hermes/osx-bin/${{ inputs.flavor }}
- name: Upload Hermes Artifacts
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
with:
key: v4-hermes-artifacts-${{ inputs.flavor }}-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
path: |
/tmp/hermes/osx-bin/${{ inputs.flavor }}
/tmp/hermes/dSYM/${{ inputs.flavor }}
/tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ inputs.flavor }}.tar.gz
@@ -0,0 +1,39 @@
name: build-hermesc-apple
description: This action builds hermesc for Apple platforms
inputs:
hermes-version:
required: true
description: The version of Hermes
react-native-version:
required: true
description: The version of React Native
runs:
using: composite
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
- name: Restore Hermes workspace
uses: ./.github/actions/restore-hermes-workspace
- name: Hermes apple cache
uses: actions/cache/restore@v4
with:
path: ./packages/react-native/sdks/hermes/build_host_hermesc
key: v2-hermesc-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
- name: Build HermesC Apple
shell: bash
run: |
cd ./packages/react-native/sdks/hermes || exit 1
. ./utils/build-apple-framework.sh
build_host_hermesc_if_needed
- name: Upload HermesC Artifact
uses: actions/upload-artifact@v4.3.4
with:
name: hermesc-apple
path: ./packages/react-native/sdks/hermes/build_host_hermesc
- name: Cache hermesc apple
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
with:
path: ./packages/react-native/sdks/hermes/build_host_hermesc
key: v2-hermesc-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
enableCrossOsArchive: true
@@ -0,0 +1,53 @@
name: build-hermesc-linux
description: This action builds hermesc for linux platforms
inputs:
hermes-version:
required: True
description: The version of Hermes
react-native-version:
required: True
description: The version of React Native
runs:
using: composite
steps:
- name: Install dependencies
shell: bash
run: |
sudo apt update
sudo apt install -y git openssh-client build-essential \
libreadline-dev libicu-dev jq zip python3
# Install cmake 3.28.3-1build7
sudo apt-get install cmake=3.28.3-1build7
sudo ln -sf /usr/bin/cmake /usr/local/bin/cmake
- name: Restore Hermes workspace
uses: ./.github/actions/restore-hermes-workspace
- name: Linux cache
uses: actions/cache@v4
with:
key: v1-hermes-${{ github.job }}-linux-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
path: |
/tmp/hermes/linux64-bin/
/tmp/hermes/hermes/destroot/
- name: Set up workspace
shell: bash
run: |
mkdir -p /tmp/hermes/linux64-bin
- name: Build HermesC for Linux
shell: bash
run: |
if [ -f /tmp/hermes/linux64-bin/hermesc ]; then
echo 'Skipping; Clean "/tmp/hermes/linux64-bin" to rebuild.'
else
cd /tmp/hermes
cmake -S hermes -B build -DHERMES_STATIC_LINK=ON -DCMAKE_BUILD_TYPE=Release -DHERMES_ENABLE_TEST_SUITE=OFF \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=True -DCMAKE_CXX_FLAGS=-s -DCMAKE_C_FLAGS=-s \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,--whole-archive -lpthread -Wl,--no-whole-archive"
cmake --build build --target hermesc -j 4
cp /tmp/hermes/build/bin/hermesc /tmp/hermes/linux64-bin/.
fi
- name: Upload linux artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-linux-bin
path: /tmp/hermes/linux64-bin
@@ -0,0 +1,86 @@
name: build-hermesc-windows
description: This action builds hermesc for Windows platforms
inputs:
hermes-version:
required: True
description: The version of Hermes
react-native-version:
required: True
description: The version of React Native
runs:
using: composite
steps:
- name: Download Previous Artifacts
uses: actions/download-artifact@v4
with:
name: hermes-workspace
path: 'C:\tmp\hermes'
- name: Set up workspace
shell: powershell
run: |
mkdir -p C:\tmp\hermes\osx-bin
mkdir -p .\packages\react-native\sdks\hermes
cp -r -Force C:\tmp\hermes\hermes\* .\packages\react-native\sdks\hermes\.
cp -r -Force .\packages\react-native\sdks\hermes-engine\utils\* .\packages\react-native\sdks\hermes\.
- name: Windows cache
uses: actions/cache@v4
with:
key: v3-hermes-${{ github.job }}-windows-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
path: |
C:\tmp\hermes\win64-bin\
C:\tmp\hermes\hermes\icu\
C:\tmp\hermes\hermes\deps\
C:\tmp\hermes\hermes\build_release\
- name: setup-msbuild
uses: microsoft/setup-msbuild@v1.3.2
- name: Set up workspace
shell: powershell
run: |
New-Item -ItemType Directory -ErrorAction SilentlyContinue $Env:HERMES_WS_DIR\icu
New-Item -ItemType Directory -ErrorAction SilentlyContinue $Env:HERMES_WS_DIR\deps
New-Item -ItemType Directory -ErrorAction SilentlyContinue $Env:HERMES_WS_DIR\win64-bin
- name: Downgrade CMake
shell: powershell
run: choco install cmake --version 3.31.6 --force
- name: Build HermesC for Windows
shell: powershell
run: |
if (-not(Test-Path -Path $Env:HERMES_WS_DIR\win64-bin\hermesc.exe)) {
cd $Env:HERMES_WS_DIR\icu
# If Invoke-WebRequest shows a progress bar, it will fail with
# Win32 internal error "Access is denied" 0x5 occurred [...]
$progressPreference = 'silentlyContinue'
Invoke-WebRequest -Uri "$Env:ICU_URL" -OutFile "icu.zip"
Expand-Archive -Path "icu.zip" -DestinationPath "."
cd $Env:HERMES_WS_DIR
Copy-Item -Path "icu\bin64\icu*.dll" -Destination "deps"
# Include MSVC++ 2015 redistributables
Copy-Item -Path "c:\windows\system32\msvcp140.dll" -Destination "deps"
Copy-Item -Path "c:\windows\system32\vcruntime140.dll" -Destination "deps"
Copy-Item -Path "c:\windows\system32\vcruntime140_1.dll" -Destination "deps"
$Env:PATH += ";$Env:CMAKE_DIR;$Env:MSBUILD_DIR"
$Env:ICU_ROOT = "$Env:HERMES_WS_DIR\icu"
cmake -S hermes -B build_release -G 'Visual Studio 17 2022' -Ax64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=True -DHERMES_ENABLE_WIN10_ICU_FALLBACK=OFF
if (-not $?) { throw "Failed to configure Hermes" }
echo "Running windows build..."
cd build_release
cmake --build . --target hermesc --config Release
if (-not $?) { throw "Failed to build Hermes" }
echo "Copying hermesc.exe to win64-bin"
cd $Env:HERMES_WS_DIR
Copy-Item -Path "build_release\bin\Release\hermesc.exe" -Destination "win64-bin"
# Include Windows runtime dependencies
Copy-Item -Path "deps\*" -Destination "win64-bin"
}
else {
Write-Host "Skipping; Clean c:\tmp\hermes\win64-bin to rebuild."
}
- name: Upload windows artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-win64-bin
path: C:\tmp\hermes\win64-bin\
@@ -4,6 +4,9 @@ inputs:
release-type:
required: true
description: The type of release we are building. It could be nightly, release or dry-run
hermes-ws-dir:
required: 'true'
description: The workspace for hermes
gha-npm-token:
required: false
description: The GHA npm token, required only to publish to npm
@@ -17,6 +20,87 @@ runs:
- name: Setup git safe folders
shell: bash
run: git config --global --add safe.directory '*'
- name: Create /tmp/hermes/osx-bin directory
shell: bash
run: mkdir -p /tmp/hermes/osx-bin
- name: Download osx-bin release artifacts
uses: actions/download-artifact@v4
with:
name: hermes-osx-bin-Release
path: /tmp/hermes/osx-bin/Release
- name: Download osx-bin debug artifacts
uses: actions/download-artifact@v4
with:
name: hermes-osx-bin-Debug
path: /tmp/hermes/osx-bin/Debug
- name: Download darwin-bin release artifacts
uses: actions/download-artifact@v4
with:
name: hermes-darwin-bin-Release
path: /tmp/hermes/hermes-runtime-darwin
- name: Download darwin-bin debug artifacts
uses: actions/download-artifact@v4
with:
name: hermes-darwin-bin-Debug
path: /tmp/hermes/hermes-runtime-darwin
- name: Download hermes dSYM debug artifacts
uses: actions/download-artifact@v4
with:
name: hermes-dSYM-Debug
path: /tmp/hermes/dSYM/Debug
- name: Download hermes dSYM release vartifacts
uses: actions/download-artifact@v4
with:
name: hermes-dSYM-Release
path: /tmp/hermes/dSYM/Release
- name: Download windows-bin artifacts
uses: actions/download-artifact@v4
with:
name: hermes-win64-bin
path: /tmp/hermes/win64-bin
- name: Download linux-bin artifacts
uses: actions/download-artifact@v4
with:
name: hermes-linux-bin
path: /tmp/hermes/linux64-bin
- name: Show /tmp/hermes directory
shell: bash
run: ls -lR /tmp/hermes
- name: Copy Hermes binaries
shell: bash
run: |
mkdir -p ./packages/react-native/sdks/hermesc ./packages/react-native/sdks/hermesc/osx-bin ./packages/react-native/sdks/hermesc/win64-bin ./packages/react-native/sdks/hermesc/linux64-bin
# When build_hermes_macos runs as a matrix, it outputs
if [[ -d ${{ inputs.hermes-ws-dir }}/osx-bin/Release ]]; then
cp -r ${{ inputs.hermes-ws-dir }}/osx-bin/Release/* ./packages/react-native/sdks/hermesc/osx-bin/.
elif [[ -d ${{ inputs.hermes-ws-dir }}/osx-bin/Debug ]]; then
cp -r ${{ inputs.hermes-ws-dir }}/osx-bin/Debug/* ./packages/react-native/sdks/hermesc/osx-bin/.
else
ls ${{ inputs.hermes-ws-dir }}/osx-bin || echo "hermesc macOS artifacts directory missing."
echo "Could not locate macOS hermesc binary."; exit 1;
fi
# Sometimes, GHA creates artifacts with lowercase Debug/Release. Make sure that if it happen, we uppercase them.
if [[ -f "${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-debug.tar.gz" ]]; then
mv "${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-debug.tar.gz" "${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Debug.tar.gz"
fi
if [[ -f "${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-release.tar.gz" ]]; then
mv "${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-release.tar.gz" "${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Release.tar.gz"
fi
cp -r ${{ inputs.hermes-ws-dir }}/win64-bin/* ./packages/react-native/sdks/hermesc/win64-bin/.
cp -r ${{ inputs.hermes-ws-dir }}/linux64-bin/* ./packages/react-native/sdks/hermesc/linux64-bin/.
# Make sure the hermesc files are actually executable.
chmod -R +x packages/react-native/sdks/hermesc/*
mkdir -p ./packages/react-native/ReactAndroid/external-artifacts/artifacts/
cp ${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Debug.tar.gz ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-ios-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Release.tar.gz ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-ios-release.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Debug/hermesvm.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Release/hermesvm.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-release.tar.gz
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
@@ -0,0 +1,99 @@
name: prepare-hermes-workspace
description: This action prepares the hermes workspace with the right hermes and react-native versions.
inputs:
hermes-ws-dir:
required: true
description: The hermes dir we need to use to setup the workspace
hermes-version-file:
required: true
description: the path to the file that will contain the hermes version
outputs:
hermes-version:
description: the version of Hermes tied to this run
value: ${{ steps.hermes-version.outputs.VERSION }}
react-native-version:
description: the version of React Native tied to this run
value: ${{ steps.react-native-version.outputs.VERSION }}
runs:
using: composite
steps:
- name: Setup hermes version
shell: bash
id: hermes-version
run: |
mkdir -p "/tmp/hermes" "/tmp/hermes/download" "/tmp/hermes/hermes"
if [ -f "${{ inputs.hermes-version-file }}" ]; then
echo "Hermes Version file found! Using this version for the build:"
echo "VERSION=$(cat ${{ inputs.hermes-version-file }})" >> "$GITHUB_OUTPUT"
else
echo "Hermes Version file not found!!!"
echo "Using the last commit from main for the build:"
HERMES_TAG_SHA=$(git ls-remote https://github.com/facebook/hermes main | cut -f 1 | tr -d '[:space:]')
echo "VERSION=$HERMES_TAG_SHA" >> "$GITHUB_OUTPUT"
fi
echo "Hermes commit is $HERMES_TAG_SHA"
- name: Get react-native version
shell: bash
id: react-native-version
run: |
VERSION=$(cat packages/react-native/package.json | jq -r '.version')
# Save the react native version we are building in an output variable so we can use that file as part of the cache key.
echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
echo "React Native Version is $VERSION"
- name: Cache hermes workspace
id: restore-hermes
uses: actions/cache/restore@v4
with:
path: |
/tmp/hermes/download/
/tmp/hermes/hermes/
key: v1-hermes-${{ steps.hermes-version.outputs.version }}
enableCrossOsArchive: true
# It happened while testing that a cache was created from the right folders
# but those folders where empty. Thus, the next check ensures that we can work with those caches.
- name: Check if cache was meaningful
id: meaningful-cache
shell: bash
run: |
if [[ -d /tmp/hermes/hermes ]] && [[ -n "$(ls -A /tmp/hermes/hermes)" ]]; then
echo "Found a good hermes cache"
echo "HERMES_CACHED=true" >> "$GITHUB_OUTPUT"
fi
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Yarn- Install Dependencies
if: ${{ steps.meaningful-cache.outputs.HERMES_CACHED != 'true' }}
uses: ./.github/actions/yarn-install
- name: Download Hermes tarball
if: ${{ steps.meaningful-cache.outputs.HERMES_CACHED != 'true' }}
shell: bash
run: |
node packages/react-native/scripts/hermes/prepare-hermes-for-build ${{ github.event.pull_request.html_url }}
cp packages/react-native/sdks/download/* ${{ inputs.hermes-ws-dir }}/download/.
cp -r packages/react-native/sdks/hermes/* ${{ inputs.hermes-ws-dir }}/hermes/.
echo ${{ steps.hermes-version.outputs.version }}
- name: Upload Hermes artifact
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-workspace
path: |
/tmp/hermes/download/
/tmp/hermes/hermes/
- name: Cache hermes workspace
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode.
with:
path: |
/tmp/hermes/download/
/tmp/hermes/hermes/
key: v1-hermes-${{ steps.hermes-version.outputs.version }}
enableCrossOsArchive: true
@@ -0,0 +1,16 @@
name: restore-hermes-workspace
description: "Restore hermes workspace that has been created in Prepare Hermes Workspace"
runs:
using: composite
steps:
- name: Download Previous Artifacts
uses: actions/download-artifact@v4
with:
name: hermes-workspace
path: /tmp/hermes
- name: Set up workspace
shell: bash
run: |
mkdir -p $HERMES_OSXBIN_ARTIFACTS_DIR ./packages/react-native/sdks/hermes
cp -r $HERMES_WS_DIR/hermes/* ./packages/react-native/sdks/hermes/.
cp -r ./packages/react-native/sdks/hermes-engine/utils ./packages/react-native/sdks/hermes/.
-22
View File
@@ -5,10 +5,6 @@ inputs:
description: 'The xcode version to use'
required: false
default: '16.2.0'
platform:
description: 'The platform to use. Valid values are: ios, ios-simulator, macos, mac-catalyst, tvos, tvos-simulator, xros, xros-simulator'
required: false
default: 'macos'
runs:
using: "composite"
steps:
@@ -16,21 +12,3 @@ runs:
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd
with:
xcode-version: ${{ inputs.xcode-version }}
- name: Setup Platform ${{ inputs.platform }}
if: ${{ inputs.platform != 'macos' && inputs.platform != 'mac-catalyst' }}
shell: bash
run: |
# https://github.com/actions/runner-images/issues/12541
sudo xcodebuild -runFirstLaunch
sudo xcrun simctl list
# Install platform based on the platform
if [[ "${{ inputs.platform }}" == "xros" || "${{ inputs.platform }}" == "xros-simulator" ]]; then
sudo xcodebuild -downloadPlatform visionOS
elif [[ "${{ inputs.platform }}" == "tvos" || "${{ inputs.platform }}" == "tvos-simulator" ]]; then
sudo xcodebuild -downloadPlatform tvOS
else
sudo xcodebuild -downloadPlatform iOS
fi
sudo xcodebuild -runFirstLaunch
+31 -8
View File
@@ -10,27 +10,36 @@ inputs:
flavor:
description: The flavor of the build. Must be one of "Debug", "Release".
default: Debug
hermes-version:
description: The version of hermes
required: true
react-native-version:
description: The version of react-native
required: true
runs:
using: composite
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Create Hermes folder
shell: bash
run: mkdir -p "$HERMES_WS_DIR"
- name: Download Hermes
uses: actions/download-artifact@v4
with:
name: hermes-darwin-bin-${{ inputs.flavor }}
path: /tmp/hermes/hermes-runtime-darwin/
- name: Print Downloaded hermes
shell: bash
run: ls -lR "$HERMES_WS_DIR"
- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ inputs.ruby-version }}
- name: Set nightly Hermes versions
shell: bash
run: |
node ./scripts/releases/use-hermes-nightly.js
- name: Run yarn install again, with the correct hermes version
uses: ./.github/actions/yarn-install
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
@@ -57,6 +66,20 @@ runs:
args+=(--frameworks dynamic)
fi
# Tarball is restored with capital flavors suffix, but somehow the tarball name from JS at line 96 returns as lowercased.
# Let's ensure that the tarballs have the right names
if [[ -f "$HERMES_WS_DIR/hermes-runtime-darwin/hermes-ios-Debug.tar.gz" ]]; then
mv "$HERMES_WS_DIR/hermes-runtime-darwin/hermes-ios-Debug.tar.gz" "$HERMES_WS_DIR/hermes-runtime-darwin/hermes-ios-debug.tar.gz"
fi
if [[ -f "$HERMES_WS_DIR/hermes-runtime-darwin/hermes-ios-Release.tar.gz" ]]; then
mv "$HERMES_WS_DIR/hermes-runtime-darwin/hermes-ios-Release.tar.gz" "$HERMES_WS_DIR/hermes-runtime-darwin/hermes-ios-release.tar.gz"
fi
BUILD_TYPE="${{ inputs.flavor }}"
TARBALL_FILENAME=$(node ../../packages/react-native/scripts/hermes/get-tarball-name.js --buildType "$BUILD_TYPE")
export HERMES_ENGINE_TARBALL_PATH="$HERMES_WS_DIR/hermes-runtime-darwin/$TARBALL_FILENAME"
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
+54 -9
View File
@@ -10,9 +10,18 @@ inputs:
run-unit-tests:
description: whether unit tests should run or not.
default: "false"
hermes-tarball-artifacts-dir:
description: The directory where the hermes tarball artifacts are stored
default: /tmp/hermes/hermes-runtime-darwin
flavor:
description: The flavor of the build. Must be one of "Debug", "Release".
default: Debug
hermes-version:
description: The version of hermes
required: true
react-native-version:
description: The version of react-native
required: true
run-e2e-tests:
description: Whether we want to run E2E tests or not
required: false
@@ -23,25 +32,60 @@ runs:
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn
uses: ./.github/actions/yarn-install
- name: Download Hermes
uses: actions/download-artifact@v4
with:
name: hermes-darwin-bin-${{ inputs.flavor }}
path: ${{ inputs.hermes-tarball-artifacts-dir }}
- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ inputs.ruby-version }}
- name: Set nightly Hermes versions
shell: bash
run: |
node ./scripts/releases/use-hermes-nightly.js
- name: Run yarn install again, with the correct hermes version
uses: ./.github/actions/yarn-install
- name: Prepare IOS Tests
if: ${{ inputs.run-unit-tests == 'true' }}
uses: ./.github/actions/prepare-ios-tests
- name: Set HERMES_ENGINE_TARBALL_PATH envvar if Hermes tarball is present
shell: bash
run: |
HERMES_TARBALL_ARTIFACTS_DIR=${{ inputs.hermes-tarball-artifacts-dir }}
if [ ! -d $HERMES_TARBALL_ARTIFACTS_DIR ]; then
echo "Hermes tarball artifacts dir not present ($HERMES_TARBALL_ARTIFACTS_DIR). Build Hermes from source."
exit 0
fi
TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "${{ inputs.flavor }}")
TARBALL_PATH=$HERMES_TARBALL_ARTIFACTS_DIR/$TARBALL_FILENAME
echo "Looking for $TARBALL_FILENAME in $HERMES_TARBALL_ARTIFACTS_DIR"
echo "$TARBALL_PATH"
if [ ! -f $TARBALL_PATH ]; then
echo "Hermes tarball not present ($TARBALL_PATH). Build Hermes from source."
exit 0
fi
echo "Found Hermes tarball at $TARBALL_PATH"
echo "HERMES_ENGINE_TARBALL_PATH=$TARBALL_PATH" >> $GITHUB_ENV
- name: Print Hermes version
shell: bash
run: |
HERMES_TARBALL_ARTIFACTS_DIR=${{ inputs.hermes-tarball-artifacts-dir }}
TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "${{ inputs.flavor }}")
TARBALL_PATH=$HERMES_TARBALL_ARTIFACTS_DIR/$TARBALL_FILENAME
if [[ -e $TARBALL_PATH ]]; then
tar -xf $TARBALL_PATH
echo 'print(HermesInternal?.getRuntimeProperties?.()["OSS Release Version"])' > test.js
chmod +x ./destroot/bin/hermes
./destroot/bin/hermes test.js
rm test.js
rm -rf destroot
else
echo 'No Hermes tarball found.'
fi
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
@@ -61,6 +105,7 @@ runs:
- name: Install CocoaPods dependencies
shell: bash
run: |
export HERMES_ENGINE_TARBALL_PATH=$HERMES_ENGINE_TARBALL_PATH
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
@@ -71,7 +116,7 @@ runs:
cd packages/rn-tester
bundle install
bundle exec pod update hermes-engine --no-repo-update
bundle exec pod install
- name: Build RNTester
shell: bash
run: |
@@ -121,7 +121,7 @@ describe('Create Draft Release', () => {
});
describe('#_computeBody', () => {
it('computes body for release when no hermes versions are passed', async () => {
it('computes body for release', async () => {
const version = '0.77.1';
const changelog = `## v${version}
### Breaking Changes
@@ -134,83 +134,20 @@ describe('Create Draft Release', () => {
#### iOS
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change`;
const body = _computeBody(changelog, version);
const body = _computeBody(version, changelog);
expect(body).toEqual(`${changelog}
---
Hermes dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-release.tar.gz)
Hermes V1 dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-release.tar.gz)
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-release.tar.gz)
ReactNativeDependencies dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
ReactNative Core dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
---
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
---
To help you upgrade to this version, you can use the [Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) ⚛️.
---
View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/react-native/blob/main/CHANGELOG.md).`);
});
it('computes body for release when hermes versions are passed', async () => {
const version = '0.77.1';
const hermesVersion = '0.15.0';
const hermesV1Version = '250829098.0.2';
const changelog = `## v${version}
### Breaking Changes
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
#### Android
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
- [PR #3457](https://github.com/facebook/react-native/pull/3457) - Some other change
#### iOS
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change`;
const body = _computeBody(
changelog,
version,
hermesVersion,
hermesV1Version,
);
expect(body).toEqual(`${changelog}
---
Hermes dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-release.tar.gz)
Hermes V1 dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-release.tar.gz)
ReactNativeDependencies dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
ReactNative Core dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
---
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
+5 -21
View File
@@ -40,29 +40,19 @@ function _extractChangelog(version) {
return changelog.slice(changelogStarts, changelogEnds).join('\n').trim();
}
function _computeBody(changelog, version, hermesVersion, hermesV1Version) {
hermesVersion = hermesVersion ?? version;
hermesV1Version = hermesV1Version ?? version;
function _computeBody(version, changelog) {
return `${changelog}
---
Hermes dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-release.tar.gz)
Hermes V1 dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-release.tar.gz)
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-release.tar.gz)
ReactNativeDependencies dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
ReactNative Core dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
---
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
@@ -123,13 +113,7 @@ function moveToChangelogBranch(version) {
run(`git checkout -b changelog/v${version}`);
}
async function createDraftRelease(
version,
latest,
token,
hermesVersion,
hermesV1Version,
) {
async function createDraftRelease(version, latest, token) {
if (version.startsWith('v')) {
version = version.substring(1);
}
@@ -137,7 +121,7 @@ async function createDraftRelease(
_verifyTagExists(version);
moveToChangelogBranch(version);
const changelog = _extractChangelog(version);
const body = _computeBody(changelog, version, hermesVersion, hermesV1Version);
const body = _computeBody(version, changelog);
const release = await _createDraftReleaseOnGitHub(
version,
body,
+1 -1
View File
@@ -162,7 +162,7 @@ async function main() {
console.info(`WORKING_DIRECTORY: ${WORKING_DIRECTORY}`);
console.info('==============================\n');
const simulatorName = 'iPhone 16 Pro';
const simulatorName = 'iPhone 15 Pro';
launchSimulator(simulatorName);
installAppOnSimulator(APP_PATH);
const udid = extractSimulatorUDID();
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: 'ios'
xcode-version: '16.2.0'
- name: Extract branch name
run: |
TAG="${{ github.ref_name }}";
+1 -10
View File
@@ -2,15 +2,6 @@ name: Create Draft Release
on:
workflow_call:
inputs:
hermesVersion:
required: false
type: string
description: The version of Hermes to use for this release (eg. 0.15.0). If not specified, it will use React Native Version
hermesV1Version:
required: false
type: string
description: The version of Hermes V1 to use for this release (eg. 250829098.0.2). If not specified, it will use React Native Version
jobs:
create-draft-release:
@@ -36,7 +27,7 @@ jobs:
const {createDraftRelease} = require('./.github/workflow-scripts/createDraftRelease.js');
const version = '${{ github.ref_name }}';
const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js');
return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}', ${{ inputs.hermesVersion }}, ${{ inputs.hermesV1Version }})).id;
return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}')).id;
result-encoding: string
- name: Upload release assets for DotSlash
uses: actions/github-script@v6
+121 -3
View File
@@ -21,6 +21,86 @@ jobs:
echo "Setting release type to nightly"
echo "RELEASE_TYPE=nightly" >> $GITHUB_OUTPUT
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
outputs:
react-native-version: ${{ steps.prepare-hermes-workspace.outputs.react-native-version }}
hermes-version: ${{ steps.prepare-hermes-workspace.outputs.hermes-version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Prepare Hermes Workspace
id: prepare-hermes-workspace
uses: ./.github/actions/prepare-hermes-workspace
with:
hermes-ws-dir: ${{ env.HERMES_WS_DIR }}
hermes-version-file: ${{ env.HERMES_VERSION_FILE }}
build_hermesc_apple:
runs-on: macos-14
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: /tmp/hermes
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Apple
uses: ./.github/actions/build-hermesc-apple
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_apple_slices_hermes:
runs-on: macos-14
needs: [build_hermesc_apple, prepare_hermes_workspace]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
HERMES_OSXBIN_ARTIFACTS_DIR: /tmp/hermes/osx-bin
IOS_DEPLOYMENT_TARGET: "15.1"
XROS_DEPLOYMENT_TARGET: "1.0"
MAC_DEPLOYMENT_TARGET: "10.15"
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
slice: [macosx, iphoneos, iphonesimulator, appletvos, appletvsimulator, catalyst, xros, xrsimulator]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Slice
uses: ./.github/actions/build-apple-slices-hermes
with:
flavor: ${{ matrix.flavor }}
slice: ${{ matrix.slice }}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_hermes_macos:
runs-on: macos-14
needs: [build_apple_slices_hermes, prepare_hermes_workspace]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
continue-on-error: true
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Hermes MacOS
uses: ./.github/actions/build-hermes-macos
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
@@ -28,10 +108,42 @@ jobs:
prebuild_react_native_core:
uses: ./.github/workflows/prebuild-ios-core.yml
with:
use-hermes-nightly: true
secrets: inherit
needs: [prebuild_apple_dependencies]
needs: [prebuild_apple_dependencies, build_hermes_macos]
build_hermesc_linux:
runs-on: ubuntu-latest
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Linux
uses: ./.github/actions/build-hermesc-linux
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_hermesc_windows:
runs-on: windows-2025
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: 'C:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
CMAKE_DIR: 'C:\Program Files\CMake\bin'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Windows
uses: ./.github/actions/build-hermesc-windows
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_android:
runs-on: 8-core-ubuntu
@@ -60,6 +172,10 @@ jobs:
needs:
[
set_release_type,
prepare_hermes_workspace,
build_hermes_macos,
build_hermesc_linux,
build_hermesc_windows,
build_android,
prebuild_apple_dependencies,
prebuild_react_native_core,
@@ -72,6 +188,7 @@ jobs:
# By default we only build ARM64 to save time/resources. For release/nightlies, we override this value to build all archs.
ORG_GRADLE_PROJECT_reactNativeArchitectures: "arm64-v8a"
env:
HERMES_WS_DIR: /tmp/hermes
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
@@ -83,6 +200,7 @@ jobs:
- name: Build and Publish NPM Package
uses: ./.github/actions/build-npm-package
with:
hermes-ws-dir: ${{ env.HERMES_WS_DIR }}
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gha-npm-token: ${{ env.GHA_NPM_TOKEN }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
+30 -16
View File
@@ -2,16 +2,11 @@ name: Prebuild iOS Dependencies
on:
workflow_call: # this directive allow us to call this workflow from other workflows
inputs:
use-hermes-nightly:
description: 'Whether to use the hermes nightly build or read the version from the versions.properties file'
type: boolean
required: false
default: false
jobs:
build-rn-slice:
runs-on: macos-15
runs-on: macos-14
strategy:
fail-fast: false
matrix:
@@ -37,20 +32,39 @@ jobs:
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-xcode
with:
platform: ${{ matrix.slice }}
xcode-version: '16.2.0'
- name: Yarn Install
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
uses: ./.github/actions/yarn-install
- name: Set Hermes version
- name: Download Hermes
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
uses: actions/download-artifact@v4
with:
name: hermes-darwin-bin-${{ matrix.flavor }}
path: /tmp/hermes/hermes-runtime-darwin
- name: Extract Hermes
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
shell: bash
run: |
if [ "${{ inputs.use-hermes-nightly }}" == "true" ]; then
HERMES_VERSION="nightly"
else
HERMES_VERSION=$(sed -n 's/^HERMES_VERSION_NAME=//p' packages/react-native/sdks/hermes-engine/version.properties)
HERMES_TARBALL_ARTIFACTS_DIR=/tmp/hermes/hermes-runtime-darwin
if [ ! -d $HERMES_TARBALL_ARTIFACTS_DIR ]; then
echo "Hermes tarball artifacts dir not present ($HERMES_TARBALL_ARTIFACTS_DIR)."
exit 0
fi
echo "Using Hermes version: $HERMES_VERSION"
echo "HERMES_VERSION=$HERMES_VERSION" >> $GITHUB_ENV
TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "${{ matrix.flavor }}")
TARBALL_PATH=$HERMES_TARBALL_ARTIFACTS_DIR/$TARBALL_FILENAME
echo "Looking for $TARBALL_FILENAME in $HERMES_TARBALL_ARTIFACTS_DIR"
echo "$TARBALL_PATH"
if [ ! -f $TARBALL_PATH ]; then
echo "Hermes tarball not present ($TARBALL_PATH). Build Hermes from source."
exit 0
fi
echo "Found Hermes tarball at $TARBALL_PATH"
echo "HERMES_ENGINE_TARBALL_PATH=$TARBALL_PATH" >> $GITHUB_ENV
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
@@ -109,7 +123,7 @@ jobs:
packages/react-native/.build/headers
compose-xcframework:
runs-on: macos-15
runs-on: macos-14
needs: [build-rn-slice]
strategy:
fail-fast: false
+21 -15
View File
@@ -7,7 +7,7 @@ on:
jobs:
prepare_workspace:
name: Prepare workspace
runs-on: macos-15
runs-on: macos-14
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -18,7 +18,7 @@ jobs:
uses: actions/cache/restore@v4
with:
path: packages/react-native/third-party/
key: v3-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
key: v2-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
enableCrossOsArchive: true
- name: Yarn Install
if: steps.restore-ios-prebuilds.outputs.cache-hit != 'true'
@@ -40,13 +40,13 @@ jobs:
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
with:
key: v3-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
key: v2-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
enableCrossOsArchive: true
path: packages/react-native/third-party/
build-apple-slices:
name: Build Apple Slice
runs-on: macos-15
runs-on: macos-14
needs: [prepare_workspace]
strategy:
fail-fast: false
@@ -65,17 +65,16 @@ jobs:
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
xcode-version: '16.1'
- name: Restore slice folder
id: restore-slice-folder
uses: actions/cache/restore@v4
with:
path: packages/react-native/third-party/.build/Build/Products
key: v3-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
- name: Setup xcode
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-xcode
with:
platform: ${{ matrix.slice }}
key: v2-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
- name: Yarn Install
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
uses: ./.github/actions/yarn-install
@@ -86,8 +85,15 @@ jobs:
name: ios-prebuilds-workspace
path: packages/react-native/third-party/
- name: Print third-party folder structure
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
run: ls -lR packages/react-native/third-party
- name: Install VisionOS
if: ${{ steps.restore-slice-folder.outputs.cache-hit != 'true' && (matrix.slice == 'xros' || matrix.slice == 'xros-simulator') }}
run: |
# https://github.com/actions/runner-images/issues/10559
sudo xcodebuild -runFirstLaunch
sudo xcrun simctl list
sudo xcodebuild -downloadPlatform visionOS
sudo xcodebuild -runFirstLaunch
- name: Build slice ${{ matrix.slice }} for ${{ matrix.flavor }}
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
run: node scripts/releases/prepare-ios-prebuilds.js -b -p ${{ matrix.slice }} -r ${{ matrix.flavor }}
@@ -101,14 +107,14 @@ jobs:
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
with:
key: v3-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
key: v2-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
enableCrossOsArchive: true
path: |
packages/react-native/third-party/.build/Build/Products
create-xcframework:
name: Prepare XCFramework
runs-on: macos-15
runs-on: macos-14
needs: [build-apple-slices]
strategy:
fail-fast: false
@@ -132,7 +138,7 @@ jobs:
with:
path: |
packages/react-native/third-party/
key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
key: v2-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
# If cache hit, we already have our binary. We don't need to do anything.
- name: Yarn Install
if: steps.restore-xcframework.outputs.cache-hit != 'true'
@@ -194,4 +200,4 @@ jobs:
path: |
packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
key: v2-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
+113 -19
View File
@@ -19,27 +19,84 @@ jobs:
echo "Setting release type to release"
echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT
set_hermes_versions:
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
outputs:
HERMES_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}
HERMES_V1_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}
react-native-version: ${{ steps.prepare-hermes-workspace.outputs.react-native-version }}
hermes-version: ${{ steps.prepare-hermes-workspace.outputs.hermes-version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- id: set_hermes_versions
run: |
echo "Setting hermes versions to latest"
hermes_version=$(grep -oE 'HERMES_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)
hermes_v1_version=$(grep -oE 'HERMES_V1_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)
- name: Prepare Hermes Workspace
id: prepare-hermes-workspace
uses: ./.github/actions/prepare-hermes-workspace
with:
hermes-ws-dir: ${{ env.HERMES_WS_DIR }}
hermes-version-file: ${{ env.HERMES_VERSION_FILE }}
echo "HERMES_VERSION=$hermes_version" >> $GITHUB_OUTPUT
echo "HERMES_V1_VERSION=$hermes_v1_version" >> $GITHUB_OUTPUT
- name: Print hermes versions
run: |
echo "HERMES_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}"
echo "HERMES_V1_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}"
build_hermesc_apple:
runs-on: macos-14
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: /tmp/hermes
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Apple
uses: ./.github/actions/build-hermesc-apple
with:
hermes-version: ${{ needs.prepare_hermes_workspace.output.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.output.react-native-version }}
build_apple_slices_hermes:
runs-on: macos-14
needs: [build_hermesc_apple, prepare_hermes_workspace]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
HERMES_OSXBIN_ARTIFACTS_DIR: /tmp/hermes/osx-bin
IOS_DEPLOYMENT_TARGET: "15.1"
XROS_DEPLOYMENT_TARGET: "1.0"
MAC_DEPLOYMENT_TARGET: "10.15"
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
slice: [macosx, iphoneos, iphonesimulator, appletvos, appletvsimulator, catalyst, xros, xrsimulator]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Slice
uses: ./.github/actions/build-apple-slices-hermes
with:
flavor: ${{ matrix.flavor }}
slice: ${{ matrix.slice}}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_hermes_macos:
runs-on: macos-14
needs: [build_apple_slices_hermes, prepare_hermes_workspace]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
continue-on-error: true
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Hermes MacOS
uses: ./.github/actions/build-hermes-macos
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
@@ -49,13 +106,51 @@ jobs:
prebuild_react_native_core:
uses: ./.github/workflows/prebuild-ios-core.yml
secrets: inherit
needs: [prebuild_apple_dependencies]
needs: [prebuild_apple_dependencies, build_hermes_macos]
build_hermesc_linux:
runs-on: ubuntu-latest
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Linux
uses: ./.github/actions/build-hermesc-linux
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_hermesc_windows:
runs-on: windows-2025
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: 'C:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
CMAKE_DIR: 'C:\Program Files\CMake\bin'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Windows
uses: ./.github/actions/build-hermesc-windows
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_npm_package:
runs-on: 8-core-ubuntu
needs:
[
set_release_type,
prepare_hermes_workspace,
build_hermes_macos,
build_hermesc_linux,
build_hermesc_windows,
prebuild_apple_dependencies,
prebuild_react_native_core,
]
@@ -67,6 +162,7 @@ jobs:
# By default we only build ARM64 to save time/resources. For release/nightlies, we override this value to build all archs.
ORG_GRADLE_PROJECT_reactNativeArchitectures: "arm64-v8a"
env:
HERMES_WS_DIR: /tmp/hermes
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
@@ -82,6 +178,7 @@ jobs:
- name: Build and Publish NPM Package
uses: ./.github/actions/build-npm-package
with:
hermes-ws-dir: ${{ env.HERMES_WS_DIR }}
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gha-npm-token: ${{ env.GHA_NPM_TOKEN }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
@@ -139,9 +236,6 @@ jobs:
secrets: inherit
create_draft_release:
needs: [generate_changelog, set_hermes_versions]
needs: generate_changelog
uses: ./.github/workflows/create-draft-release.yml
secrets: inherit
with:
hermesVersion: ${{ needs.set_hermes_versions.outputs.HERMES_VERSION }}
hermesV1Version: ${{ needs.set_hermes_versions.outputs.HERMES_V1_VERSION }}
+163 -24
View File
@@ -33,6 +33,86 @@ jobs:
echo "Should I run E2E tests? ${{ inputs.run-e2e-tests }}"
prepare_hermes_workspace:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
outputs:
react-native-version: ${{ steps.prepare-hermes-workspace.outputs.react-native-version }}
hermes-version: ${{ steps.prepare-hermes-workspace.outputs.hermes-version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Prepare Hermes Workspace
id: prepare-hermes-workspace
uses: ./.github/actions/prepare-hermes-workspace
with:
hermes-ws-dir: ${{ env.HERMES_WS_DIR }}
hermes-version-file: ${{ env.HERMES_VERSION_FILE }}
build_hermesc_apple:
runs-on: macos-14
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: /tmp/hermes
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Apple
uses: ./.github/actions/build-hermesc-apple
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_apple_slices_hermes:
runs-on: macos-14
needs: [build_hermesc_apple, prepare_hermes_workspace]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
HERMES_OSXBIN_ARTIFACTS_DIR: /tmp/hermes/osx-bin
IOS_DEPLOYMENT_TARGET: "15.1"
XROS_DEPLOYMENT_TARGET: "1.0"
MAC_DEPLOYMENT_TARGET: "10.15"
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
slice: [macosx, iphoneos, iphonesimulator, appletvos, appletvsimulator, catalyst, xros, xrsimulator]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Slice
uses: ./.github/actions/build-apple-slices-hermes
with:
flavor: ${{ matrix.flavor }}
slice: ${{ matrix.slice}}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_hermes_macos:
runs-on: macos-14
needs: [build_apple_slices_hermes, prepare_hermes_workspace]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
continue-on-error: true
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Hermes MacOS
uses: ./.github/actions/build-hermes-macos
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: ${{ matrix.flavor }}
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
@@ -40,15 +120,16 @@ jobs:
prebuild_react_native_core:
uses: ./.github/workflows/prebuild-ios-core.yml
with:
use-hermes-nightly: ${{ !endsWith(github.ref_name, '-stable') }}
secrets: inherit
needs: [prebuild_apple_dependencies]
needs: [prebuild_apple_dependencies, build_hermes_macos]
test_ios_rntester_ruby_3_2_0:
runs-on: macos-15
runs-on: macos-14
needs:
[prebuild_apple_dependencies, prebuild_react_native_core]
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -56,12 +137,17 @@ jobs:
uses: ./.github/actions/test-ios-rntester
with:
ruby-version: "3.2.0"
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: Debug
test_ios_rntester:
runs-on: macos-15-large
runs-on: macos-14-large
needs:
[prebuild_apple_dependencies, prebuild_react_native_core]
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
continue-on-error: true
strategy:
fail-fast: false
@@ -75,12 +161,17 @@ jobs:
uses: ./.github/actions/test-ios-rntester
with:
use-frameworks: ${{ matrix.frameworks }}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: ${{ matrix.flavor }}
test_e2e_ios_rntester:
runs-on: macos-15-large
runs-on: macos-14-large
needs:
[test_ios_rntester]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
strategy:
fail-fast: false
matrix:
@@ -99,8 +190,6 @@ jobs:
run: ls -lR /tmp/RNTesterBuild
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Run E2E Tests
uses: ./.github/actions/maestro-ios
with:
@@ -110,8 +199,11 @@ jobs:
flavor: ${{ matrix.flavor }}
test_e2e_ios_templateapp:
runs-on: macos-15-large
runs-on: macos-14-large
needs: [build_npm_package, prebuild_apple_dependencies]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
strategy:
fail-fast: false
matrix:
@@ -121,8 +213,6 @@ jobs:
uses: actions/checkout@v4
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn
@@ -131,6 +221,11 @@ jobs:
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6.10
- name: Download Hermes
uses: actions/download-artifact@v4
with:
name: hermes-darwin-bin-${{matrix.flavor}}
path: /tmp/react-native-tmp
- name: Download React Native Package
uses: actions/download-artifact@v4
with:
@@ -164,6 +259,9 @@ jobs:
REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
echo "React Native tgs is $REACT_NATIVE_PKG"
HERMES_PATH=$(find /tmp/react-native-tmp -type f -name "*.tar.gz")
echo "Hermes path is $HERMES_PATH"
# For stable branches, we want to use the stable branch of the template
# In all the other cases, we want to use "main"
BRANCH=${{ github.ref_name }}
@@ -180,7 +278,7 @@ jobs:
export RCT_USE_LOCAL_RN_DEP=/tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
# Disable prebuilds for now, as they are causing issues with E2E tests for 0.82-stable branch
# export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ matrix.flavor }}.xcframework.tar.gz"
RCT_NEW_ARCH_ENABLED=$NEW_ARCH_ENABLED bundle exec pod install
HERMES_ENGINE_TARBALL_PATH=$HERMES_PATH RCT_NEW_ARCH_ENABLED=$NEW_ARCH_ENABLED bundle exec pod install
xcodebuild \
-scheme "RNTestProject" \
@@ -266,6 +364,21 @@ jobs:
flavor: ${{ matrix.flavor }}
working-directory: /tmp/RNTestProject
build_hermesc_linux:
runs-on: ubuntu-latest
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Linux
uses: ./.github/actions/build-hermesc-linux
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
run_fantom_tests:
runs-on: 8-core-ubuntu
needs: [set_release_type]
@@ -285,6 +398,25 @@ jobs:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
build_hermesc_windows:
runs-on: windows-2025
needs: prepare_hermes_workspace
env:
HERMES_WS_DIR: 'C:\tmp\hermes'
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
CMAKE_DIR: 'C:\Program Files\CMake\bin'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build HermesC Windows
uses: ./.github/actions/build-hermesc-windows
with:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
build_android:
runs-on: 8-core-ubuntu
needs: [set_release_type]
@@ -339,6 +471,10 @@ jobs:
needs:
[
set_release_type,
prepare_hermes_workspace,
build_hermes_macos,
build_hermesc_linux,
build_hermesc_windows,
build_android,
prebuild_apple_dependencies,
prebuild_react_native_core,
@@ -348,12 +484,15 @@ jobs:
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
env:
HERMES_WS_DIR: /tmp/hermes
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build NPM Package
uses: ./.github/actions/build-npm-package
with:
hermes-ws-dir: ${{ env.HERMES_WS_DIR }}
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
@@ -396,12 +535,6 @@ jobs:
cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Set nightly Hermes versions
shell: bash
run: |
node ./scripts/releases/use-hermes-nightly.js
- name: Run yarn install again, with the correct hermes version
uses: ./.github/actions/yarn-install
- name: Prepare the Helloworld application
shell: bash
run: node ./scripts/e2e/init-project-e2e.js --useHelloWorld --pathToLocalReactNative "$GITHUB_WORKSPACE/build/$(cat build/react-native-package-version)"
@@ -422,10 +555,11 @@ jobs:
compression-level: 0
test_ios_helloworld_with_ruby_3_2_0:
runs-on: macos-15
needs: [prebuild_apple_dependencies, prebuild_react_native_core]
runs-on: macos-14
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
env:
PROJECT_NAME: iOSTemplateProject
HERMES_WS_DIR: /tmp/hermes
YARN_ENABLE_IMMUTABLE_INSTALLS: false
steps:
- name: Checkout
@@ -434,10 +568,12 @@ jobs:
with:
ruby-version: 3.2.0
flavor: Debug
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
test_ios_helloworld:
runs-on: macos-15
needs: [prebuild_apple_dependencies, prebuild_react_native_core]
runs-on: macos-14
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
strategy:
matrix:
flavor: [Debug, Release]
@@ -448,6 +584,7 @@ jobs:
use_frameworks: StaticLibraries
env:
PROJECT_NAME: iOSTemplateProject
HERMES_WS_DIR: /tmp/hermes
YARN_ENABLE_IMMUTABLE_INSTALLS: false
steps:
- name: Checkout
@@ -456,6 +593,8 @@ jobs:
with:
flavor: ${{ matrix.flavor }}
use-frameworks: ${{ matrix.use_frameworks }}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
test_js:
runs-on: ubuntu-latest
-9
View File
@@ -1,14 +1,5 @@
# Changelog (pre 0.80)
## v0.79.7
### Fixed
#### Android specific
- **Layout:** Make missing parent view state in updateLayout a soft error ([56ad8d9bfd](https://github.com/facebook/react-native/commit/56ad8d9bfd08ea70bc6f5726a2b4a6afb6d2d7c2) by [@javache](https://github.com/javache))
- **Layout:** Make missing parent view state in updateLayout a soft error ([f2e47d8dab](https://github.com/facebook/react-native/commit/f2e47d8dabcd61621ea81c86cd1e2488948c4229) by [@cipolleschi](https://github.com/cipolleschi))
## v0.79.6
### Added
-16
View File
@@ -1,17 +1,5 @@
# Changelog
## v0.82.1
### Fixed
#### Android specific
- Fixed representation of transforms when view is originally zero-sized ([a81e94a40c](https://github.com/facebook/react-native/commit/a81e94a40ca8dca9e57b562db21f8f235c5b25a0) by [@javache](https://github.com/javache))
#### iOS specific
- Fixed issue when using gnu coreutils cp command when using precompiled binaries causing compilation error ([068ec39aea](https://github.com/facebook/react-native/commit/068ec39aea543617e5159fe22274b294bfb29026) by [@chrfalch](https://github.com/chrfalch))
## v0.82.0
### Breaking
@@ -824,10 +812,6 @@
- **Text:** Selection range not respected when changing text or selection when selection is forced ([d32ea66e6a](https://github.com/facebook/react-native/commit/d32ea66e6a945dd84092532401b265b12d482668) by Olivier Bouillet)
- **TextInput:** Fix TextInput `onContentSizeChange` event being dispatched only once on iOS on the new architecture ([5fd5188172](https://github.com/facebook/react-native/commit/5fd51881727b2d86f87abf04db032940ac0ec8c4) by [@j-piasecki](https://github.com/j-piasecki))
## v0.79.7
See [CHANGELOG-0.7x](./CHANGELOG-0.7x.md#v0797)
## v0.79.6
See [CHANGELOG-0.7x](./CHANGELOG-0.7x.md#v0796)
+6 -1
View File
@@ -104,6 +104,10 @@ tasks.register("build") {
tasks.register("publishAllToMavenTempLocal") {
description = "Publish all the artifacts to be available inside a Maven Local repository on /tmp."
dependsOn(":packages:react-native:ReactAndroid:publishAllPublicationsToMavenTempLocalRepository")
// We don't publish the external-artifacts to Maven Local as ci is using it via workspace.
dependsOn(
":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository"
)
}
tasks.register("publishAndroidToSonatype") {
@@ -131,7 +135,8 @@ if (project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoole
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(project(":packages:react-native:ReactAndroid:hermes-engine"))
.using(module("com.facebook.hermes:hermes-android:0.+"))
// TODO: T237406039 update coordinates
.using(module("com.facebook.react:hermes-android:0.+"))
.because("Users opted to use hermes from nightly")
}
}
+2 -1
View File
@@ -86,7 +86,7 @@
"eslint-plugin-relay": "^1.8.3",
"fb-dotslash": "0.5.8",
"flow-api-translator": "0.32.0",
"flow-bin": "^0.289.0",
"flow-bin": "^0.288.0",
"glob": "^7.1.1",
"hermes-eslint": "0.32.0",
"hermes-transform": "0.32.0",
@@ -120,6 +120,7 @@
"ws": "^7.5.10"
},
"resolutions": {
"eslint-plugin-react-hooks": "6.1.0-canary-12bc60f5-20250613",
"react-is": "19.2.0",
"on-headers": "1.1.0",
"compression": "1.8.1"
+2 -2
View File
@@ -1,5 +1,5 @@
@generated SignedSource<<4bb67766e15e25a481c4c38873260a7a>>
Git revision: 7aa57d13e50ce9d74a91c9315c9b0ded00fbc19f
@generated SignedSource<<ec85a720cb9603510d40915ba1410b50>>
Git revision: 54afd8765db32a9640edef3788085b991fe4b88a
Built with --nohooks: false
Is local checkout: false
Remote URL: https://github.com/facebook/react-native-devtools-frontend
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import*as e from"../root/root.js";const t=e.Runtime.RNExperimentName,i={didInitializeExperiments:!1,isReactNativeEntryPoint:!1};class n{name;title;unstable;docLink;feedbackLink;enabledByDefault;constructor(e){this.name=e.name,this.title=e.title,this.unstable=e.unstable,this.docLink=e.docLink,this.feedbackLink=e.feedbackLink,this.enabledByDefault=function(e,t){if(null==e)return()=>t;if("boolean"==typeof e)return()=>e;return e}(e.enabledByDefault,!1)}}const r=new class{#e=new Map;#t=new Set;register(e){if(i.didInitializeExperiments)throw new Error("Experiments must be registered before constructing MainImpl");const{name:t}=e;if(this.#e.has(t))throw new Error(`React Native Experiment ${t} is already registered`);this.#e.set(t,new n(e))}enableExperimentsByDefault(e){if(i.didInitializeExperiments)throw new Error("Experiments must be configured before constructing MainImpl");for(const i of e)if(Object.prototype.hasOwnProperty.call(t,i)){const e=this.#e.get(i);if(!e)throw new Error(`React Native Experiment ${i} is not registered`);e.enabledByDefault=()=>!0}else this.#t.add(i)}copyInto(e,t=""){for(const[n,r]of this.#e)e.register(n,t+r.title,r.unstable,r.docLink,r.feedbackLink),r.enabledByDefault({isReactNativeEntryPoint:i.isReactNativeEntryPoint})&&e.enableExperimentsByDefault([n]);for(const t of this.#t)e.enableExperimentsByDefault([t]);i.didInitializeExperiments=!0}};r.register({name:t.JS_HEAP_PROFILER_ENABLE,title:"Enable Heap Profiler (Memory Panel)",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.REACT_NATIVE_SPECIFIC_UI,title:"Show React Native-specific UI",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>e}),r.register({name:t.ENABLE_NETWORK_PANEL,title:"Enable Network panel",unstable:!0,enabledByDefault:()=>!1});var a=Object.freeze({__proto__:null,Instance:r,RNExperimentName:t,setIsReactNativeEntryPoint:function(e){if(i.didInitializeExperiments)throw new Error("setIsReactNativeEntryPoint must be called before constructing MainImpl");i.isReactNativeEntryPoint=e}});export{a as RNExperimentsImpl};
import*as e from"../root/root.js";const t=e.Runtime.RNExperimentName,n={didInitializeExperiments:!1,isReactNativeEntryPoint:!1};class i{name;title;unstable;docLink;feedbackLink;enabledByDefault;constructor(e){this.name=e.name,this.title=e.title,this.unstable=e.unstable,this.docLink=e.docLink,this.feedbackLink=e.feedbackLink,this.enabledByDefault=function(e,t){if(null==e)return()=>t;if("boolean"==typeof e)return()=>e;return e}(e.enabledByDefault,!1)}}const r=new class{#e=new Map;#t=new Set;register(e){if(n.didInitializeExperiments)throw new Error("Experiments must be registered before constructing MainImpl");const{name:t}=e;if(this.#e.has(t))throw new Error(`React Native Experiment ${t} is already registered`);this.#e.set(t,new i(e))}enableExperimentsByDefault(e){if(n.didInitializeExperiments)throw new Error("Experiments must be configured before constructing MainImpl");for(const n of e)if(Object.prototype.hasOwnProperty.call(t,n)){const e=this.#e.get(n);if(!e)throw new Error(`React Native Experiment ${n} is not registered`);e.enabledByDefault=()=>!0}else this.#t.add(n)}copyInto(e,t=""){for(const[i,r]of this.#e)e.register(i,t+r.title,r.unstable,r.docLink,r.feedbackLink),r.enabledByDefault({isReactNativeEntryPoint:n.isReactNativeEntryPoint})&&e.enableExperimentsByDefault([i]);for(const t of this.#t)e.enableExperimentsByDefault([t]);n.didInitializeExperiments=!0}};r.register({name:t.JS_HEAP_PROFILER_ENABLE,title:"Enable Heap Profiler (Memory Panel)",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.REACT_NATIVE_SPECIFIC_UI,title:"Show React Native-specific UI",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>e}),r.register({name:t.ENABLE_PERFORMANCE_PANEL,title:"Enable Performance panel",unstable:!0,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.ENABLE_NETWORK_PANEL,title:"Enable Network panel",unstable:!0,enabledByDefault:()=>!1});var a=Object.freeze({__proto__:null,Instance:r,RNExperimentName:t,setIsReactNativeEntryPoint:function(e){if(n.didInitializeExperiments)throw new Error("setIsReactNativeEntryPoint must be called before constructing MainImpl");n.isReactNativeEntryPoint=e}});export{a as RNExperimentsImpl};
@@ -1 +1 @@
import*as e from"../platform/platform.js";const t=new URLSearchParams(location.search);let n,r,s="";function a(){return window.location.pathname}function i(e){return["node_app","js_app"].some((t=>e.includes(t)))}class o{constructor(){}static instance(e={forceNew:null}){const{forceNew:t}=e;return n&&!t||(n=new o),n}static removeInstance(){n=void 0}static queryParam(e){return t.get(e)}static setQueryParamForTesting(e,n){t.set(e,n)}static isNode(){return void 0===r&&(r=i(a())),r}static setPlatform(e){s=e}static platform(){return s}static isDescriptorEnabled(e){const{experiment:t}=e;if("*"===t)return!0;if(t&&t.startsWith("!")&&h.isEnabled(t.substring(1)))return!1;if(t&&!t.startsWith("!")&&!h.isEnabled(t))return!1;const{condition:n}=e;return!n||n(_)}loadLegacyModule(e){console.log("Loading legacy module: "+e);return import(`../../${e}`).then((t=>(console.log("Loaded legacy module: "+e),t)))}}class l{#e=[];#t=new Set;#n=new Set;#r=new Set;#s=new Set;#a=new c;allConfigurableExperiments(){const e=[];for(const t of this.#e)this.#n.has(t.name)||e.push(t);return e}register(t,n,r,s,a){if(this.#t.has(t))throw new Error(`Duplicate registration of experiment '${t}'`);this.#t.add(t),this.#e.push(new m(this,t,n,Boolean(r),s??e.DevToolsPath.EmptyUrlString,a??e.DevToolsPath.EmptyUrlString))}isEnabled(e){return this.checkExperiment(e),!1!==this.#a.get(e)&&(!(!this.#n.has(e)&&!this.#r.has(e))||(!!this.#s.has(e)||Boolean(this.#a.get(e))))}setEnabled(e,t){this.checkExperiment(e),this.#a.set(e,t)}enableExperimentsTransiently(e){for(const t of e)this.checkExperiment(t),this.#n.add(t)}enableExperimentsByDefault(e){for(const t of e)this.checkExperiment(t),this.#r.add(t)}setServerEnabledExperiments(e){for(const t of e)this.checkExperiment(t),this.#s.add(t)}enableForTest(e){this.checkExperiment(e),this.#n.add(e)}disableForTest(e){this.checkExperiment(e),this.#n.delete(e)}clearForTest(){this.#e=[],this.#t.clear(),this.#n.clear(),this.#r.clear(),this.#s.clear()}cleanUpStaleExperiments(){this.#a.cleanUpStaleExperiments(this.#t)}checkExperiment(e){if(!this.#t.has(e))throw new Error(`Unknown experiment '${e}'`)}}class c{#e={};constructor(){try{const e=self.localStorage?.getItem("experiments");e&&(this.#e=JSON.parse(e))}catch{console.error("Failed to parse localStorage['experiments']")}}get(e){return this.#e[e]}set(e,t){this.#e[e]=t,this.#i()}cleanUpStaleExperiments(e){for(const[t]of Object.entries(this.#e))e.has(t)||delete this.#e[t];this.#i()}#i(){self.localStorage?.setItem("experiments",JSON.stringify(this.#e))}}class m{name;title;unstable;docLink;feedbackLink;#e;constructor(e,t,n,r,s,a){this.name=t,this.title=n,this.unstable=r,this.docLink=s,this.feedbackLink=a,this.#e=e}isEnabled(){return this.#e.isEnabled(this.name)}setEnabled(e){this.#e.setEnabled(this.name,e)}}const h=new l;var E,p,d,u;!function(e){e.REACT_NATIVE_SPECIFIC_UI="react-native-specific-ui",e.JS_HEAP_PROFILER_ENABLE="js-heap-profiler-enable",e.ENABLE_NETWORK_PANEL="enable-network-panel"}(E||(E={})),function(e){e.NOT_SOURCES_HIDE_ADD_FOLDER="!sources.hide_add_folder",e.REACT_NATIVE_UNSTABLE_NETWORK_PANEL="unstable_enableNetworkPanel"}(p||(p={})),function(e){e[e.ALLOW=0]="ALLOW",e[e.ALLOW_WITHOUT_LOGGING=1]="ALLOW_WITHOUT_LOGGING",e[e.DISABLE=2]="DISABLE"}(d||(d={})),function(e){e.ALL_SCRIPTS="ALL_SCRIPTS",e.SIDE_EFFECT_FREE_SCRIPTS_ONLY="SIDE_EFFECT_FREE_SCRIPTS_ONLY",e.NO_SCRIPTS="NO_SCRIPTS"}(u||(u={}));const _=Object.create(null),f={canDock:()=>Boolean(o.queryParam("can_dock")),notSourcesHideAddFolder:()=>Boolean(o.queryParam(p.NOT_SOURCES_HIDE_ADD_FOLDER)),reactNativeUnstableNetworkPanel:()=>Boolean(o.queryParam(p.REACT_NATIVE_UNSTABLE_NETWORK_PANEL))||h.isEnabled("enable-network-panel")};var x=Object.freeze({__proto__:null,get ConditionName(){return p},Experiment:m,ExperimentsSupport:l,get GenAiEnterprisePolicyValue(){return d},get HostConfigFreestylerExecutionMode(){return u},get RNExperimentName(){return E},Runtime:o,conditions:f,experiments:h,getChromeVersion:()=>{const e=navigator.userAgent.match(/(?:^|\W)(?:Chrome|HeadlessChrome)\/(\S+)/);return e&&e.length>1?e[1]:""},getPathName:a,getRemoteBase:function(e=self.location.toString()){const t=new URL(e).searchParams.get("remoteBase");if(!t)return null;const n=/\/serve_file\/(@[0-9a-zA-Z]+)\/?$/.exec(t);return n?{base:`devtools://devtools/remote/serve_file/${n[1]}/`,version:n[1]}:null},hostConfig:_,isNodeEntry:i});export{x as Runtime};
import*as e from"../platform/platform.js";const t=new URLSearchParams(location.search);let n,r,s="";function a(){return window.location.pathname}function i(e){return["node_app","js_app"].some((t=>e.includes(t)))}class o{constructor(){}static instance(e={forceNew:null}){const{forceNew:t}=e;return n&&!t||(n=new o),n}static removeInstance(){n=void 0}static queryParam(e){return t.get(e)}static setQueryParamForTesting(e,n){t.set(e,n)}static isNode(){return void 0===r&&(r=i(a())),r}static setPlatform(e){s=e}static platform(){return s}static isDescriptorEnabled(e){const{experiment:t}=e;if("*"===t)return!0;if(t&&t.startsWith("!")&&h.isEnabled(t.substring(1)))return!1;if(t&&!t.startsWith("!")&&!h.isEnabled(t))return!1;const{condition:n}=e;return!n||n(_)}loadLegacyModule(e){console.log("Loading legacy module: "+e);return import(`../../${e}`).then((t=>(console.log("Loaded legacy module: "+e),t)))}}class l{#e=[];#t=new Set;#n=new Set;#r=new Set;#s=new Set;#a=new c;allConfigurableExperiments(){const e=[];for(const t of this.#e)this.#n.has(t.name)||e.push(t);return e}register(t,n,r,s,a){if(this.#t.has(t))throw new Error(`Duplicate registration of experiment '${t}'`);this.#t.add(t),this.#e.push(new m(this,t,n,Boolean(r),s??e.DevToolsPath.EmptyUrlString,a??e.DevToolsPath.EmptyUrlString))}isEnabled(e){return this.checkExperiment(e),!1!==this.#a.get(e)&&(!(!this.#n.has(e)&&!this.#r.has(e))||(!!this.#s.has(e)||Boolean(this.#a.get(e))))}setEnabled(e,t){this.checkExperiment(e),this.#a.set(e,t)}enableExperimentsTransiently(e){for(const t of e)this.checkExperiment(t),this.#n.add(t)}enableExperimentsByDefault(e){for(const t of e)this.checkExperiment(t),this.#r.add(t)}setServerEnabledExperiments(e){for(const t of e)this.checkExperiment(t),this.#s.add(t)}enableForTest(e){this.checkExperiment(e),this.#n.add(e)}disableForTest(e){this.checkExperiment(e),this.#n.delete(e)}clearForTest(){this.#e=[],this.#t.clear(),this.#n.clear(),this.#r.clear(),this.#s.clear()}cleanUpStaleExperiments(){this.#a.cleanUpStaleExperiments(this.#t)}checkExperiment(e){if(!this.#t.has(e))throw new Error(`Unknown experiment '${e}'`)}}class c{#e={};constructor(){try{const e=self.localStorage?.getItem("experiments");e&&(this.#e=JSON.parse(e))}catch{console.error("Failed to parse localStorage['experiments']")}}get(e){return this.#e[e]}set(e,t){this.#e[e]=t,this.#i()}cleanUpStaleExperiments(e){for(const[t]of Object.entries(this.#e))e.has(t)||delete this.#e[t];this.#i()}#i(){self.localStorage?.setItem("experiments",JSON.stringify(this.#e))}}class m{name;title;unstable;docLink;feedbackLink;#e;constructor(e,t,n,r,s,a){this.name=t,this.title=n,this.unstable=r,this.docLink=s,this.feedbackLink=a,this.#e=e}isEnabled(){return this.#e.isEnabled(this.name)}setEnabled(e){this.#e.setEnabled(this.name,e)}}const h=new l;var E,p,d,u;!function(e){e.REACT_NATIVE_SPECIFIC_UI="react-native-specific-ui",e.JS_HEAP_PROFILER_ENABLE="js-heap-profiler-enable",e.ENABLE_PERFORMANCE_PANEL="enable-performance-panel",e.ENABLE_NETWORK_PANEL="enable-network-panel"}(E||(E={})),function(e){e.NOT_SOURCES_HIDE_ADD_FOLDER="!sources.hide_add_folder",e.REACT_NATIVE_UNSTABLE_NETWORK_PANEL="unstable_enableNetworkPanel"}(p||(p={})),function(e){e[e.ALLOW=0]="ALLOW",e[e.ALLOW_WITHOUT_LOGGING=1]="ALLOW_WITHOUT_LOGGING",e[e.DISABLE=2]="DISABLE"}(d||(d={})),function(e){e.ALL_SCRIPTS="ALL_SCRIPTS",e.SIDE_EFFECT_FREE_SCRIPTS_ONLY="SIDE_EFFECT_FREE_SCRIPTS_ONLY",e.NO_SCRIPTS="NO_SCRIPTS"}(u||(u={}));const _=Object.create(null),f={canDock:()=>Boolean(o.queryParam("can_dock")),notSourcesHideAddFolder:()=>Boolean(o.queryParam(p.NOT_SOURCES_HIDE_ADD_FOLDER)),reactNativeUnstableNetworkPanel:()=>Boolean(o.queryParam(p.REACT_NATIVE_UNSTABLE_NETWORK_PANEL))||h.isEnabled("enable-network-panel")};var x=Object.freeze({__proto__:null,get ConditionName(){return p},Experiment:m,ExperimentsSupport:l,get GenAiEnterprisePolicyValue(){return d},get HostConfigFreestylerExecutionMode(){return u},get RNExperimentName(){return E},Runtime:o,conditions:f,experiments:h,getChromeVersion:()=>{const e=navigator.userAgent.match(/(?:^|\W)(?:Chrome|HeadlessChrome)\/(\S+)/);return e&&e.length>1?e[1]:""},getPathName:a,getRemoteBase:function(e=self.location.toString()){const t=new URL(e).searchParams.get("remoteBase");if(!t)return null;const n=/\/serve_file\/(@[0-9a-zA-Z]+)\/?$/.exec(t);return n?{base:`devtools://devtools/remote/serve_file/${n[1]}/`,version:n[1]}:null},hostConfig:_,isNodeEntry:i});export{x as Runtime};
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
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
File diff suppressed because one or more lines are too long
@@ -30,7 +30,7 @@
"eslint-plugin-ft-flow": "^2.0.1",
"eslint-plugin-jest": "^29.0.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-native": "^4.0.0"
},
"peerDependencies": {
@@ -14,6 +14,7 @@ import com.facebook.react.utils.KotlinStdlibCompatUtils.capitalizeCompat
import com.facebook.react.utils.NdkConfiguratorUtils.configureJsEnginePackagingOptions
import com.facebook.react.utils.NdkConfiguratorUtils.configureNewArchPackagingOptions
import com.facebook.react.utils.ProjectUtils.isHermesEnabled
import com.facebook.react.utils.ProjectUtils.isHermesV1Enabled
import com.facebook.react.utils.ProjectUtils.useThirdPartyJSC
import com.facebook.react.utils.detectedCliFile
import com.facebook.react.utils.detectedEntryFile
@@ -48,6 +49,7 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio
} else {
isHermesEnabledInProject
}
val isHermesV1Enabled = project.isHermesV1Enabled || rootProject.isHermesV1Enabled
val isDebuggableVariant =
config.debuggableVariants.get().any { it.equals(variant.name, ignoreCase = true) }
val useThirdPartyJSC = project.useThirdPartyJSC
@@ -78,6 +80,7 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio
task.jsBundleDir.set(jsBundleDir)
task.resourcesDir.set(resourcesDir)
task.hermesEnabled.set(isHermesEnabledInThisVariant)
task.hermesV1Enabled.set(isHermesV1Enabled)
task.minifyEnabled.set(!isHermesEnabledInThisVariant)
task.devEnabled.set(false)
task.jsIntermediateSourceMapsDir.set(jsIntermediateSourceMapsDir)
@@ -63,6 +63,8 @@ abstract class BundleHermesCTask : DefaultTask() {
@get:Input abstract val hermesEnabled: Property<Boolean>
@get:Input abstract val hermesV1Enabled: Property<Boolean>
@get:Input abstract val devEnabled: Property<Boolean>
@get:Input abstract val extraPackagerArgs: ListProperty<String>
@@ -94,7 +96,8 @@ abstract class BundleHermesCTask : DefaultTask() {
runCommand(bundleCommand)
if (hermesEnabled.get()) {
val detectedHermesCommand = detectOSAwareHermesCommand(root.get().asFile, hermesCommand.get())
val detectedHermesCommand =
detectOSAwareHermesCommand(root.get().asFile, hermesCommand.get(), hermesV1Enabled.get())
val bytecodeFile = File("${bundleFile}.hbc")
val outputSourceMap = resolveOutputSourceMap(bundleAssetFilename)
val compilerSourceMap = resolveCompilerSourceMap(bundleAssetFilename)
@@ -44,8 +44,12 @@ internal object AgpConfiguratorUtils {
maybeCreate("debugOptimized").apply {
manifestPlaceholders["usesCleartextTraffic"] = "true"
initWith(debug)
matchingFallbacks += listOf("release")
externalNativeBuild { cmake { arguments("-DCMAKE_BUILD_TYPE=Release") } }
externalNativeBuild {
cmake {
arguments("-DCMAKE_BUILD_TYPE=Release")
matchingFallbacks += listOf("release")
}
}
}
}
}
@@ -14,7 +14,6 @@ import com.facebook.react.utils.PropertyUtils.INCLUDE_JITPACK_REPOSITORY
import com.facebook.react.utils.PropertyUtils.INCLUDE_JITPACK_REPOSITORY_DEFAULT
import com.facebook.react.utils.PropertyUtils.INTERNAL_HERMES_PUBLISHING_GROUP
import com.facebook.react.utils.PropertyUtils.INTERNAL_HERMES_V1_VERSION_NAME
import com.facebook.react.utils.PropertyUtils.INTERNAL_HERMES_VERSION_NAME
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_NATIVE_MAVEN_LOCAL_REPO
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_PUBLISHING_GROUP
import com.facebook.react.utils.PropertyUtils.INTERNAL_USE_HERMES_NIGHTLY
@@ -140,7 +139,11 @@ internal object DependencyUtils {
// Contributors only: The hermes-engine version is forced only if the user has
// not opted into using nightlies for local development.
configuration.resolutionStrategy.force(
"${coordinates.hermesGroupString}:hermes-android:${if (hermesV1Enabled) coordinates.hermesV1VersionString else coordinates.hermesVersionString}"
// TODO: T237406039 update coordinates
if (hermesV1Enabled)
"${coordinates.hermesGroupString}:hermes-android:${coordinates.hermesV1VersionString}"
else
"${coordinates.reactGroupString}:hermes-android:${coordinates.hermesVersionString}"
)
}
}
@@ -151,10 +154,13 @@ internal object DependencyUtils {
coordinates: Coordinates,
hermesV1Enabled: Boolean = false,
): List<Triple<String, String, String>> {
// TODO: T231755027 update coordinates and versioning
val dependencySubstitution = mutableListOf<Triple<String, String, String>>()
val hermesVersion =
if (hermesV1Enabled) coordinates.hermesV1VersionString else coordinates.hermesVersionString
val hermesVersionString = "${coordinates.hermesGroupString}:hermes-android:${hermesVersion}"
// TODO: T237406039 update coordinates
val hermesVersionString =
if (hermesV1Enabled)
"${coordinates.hermesGroupString}:hermes-android:${coordinates.hermesV1VersionString}"
else "${coordinates.reactGroupString}:hermes-android:${coordinates.hermesVersionString}"
dependencySubstitution.add(
Triple(
"com.facebook.react:react-native",
@@ -169,13 +175,6 @@ internal object DependencyUtils {
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.",
)
)
dependencySubstitution.add(
Triple(
"com.facebook.react:hermes-android",
hermesVersionString,
"The hermes-android artifact was moved to com.facebook.hermes publishing group.",
)
)
if (coordinates.reactGroupString != DEFAULT_INTERNAL_REACT_PUBLISHING_GROUP) {
dependencySubstitution.add(
Triple(
@@ -184,6 +183,7 @@ internal object DependencyUtils {
"The react-android dependency was modified to use the correct Maven group.",
)
)
// TODO: T237406039 update coordinates
dependencySubstitution.add(
Triple(
"com.facebook.react:hermes-android",
@@ -191,13 +191,12 @@ internal object DependencyUtils {
"The hermes-android dependency was modified to use the correct Maven group.",
)
)
}
if (coordinates.hermesGroupString != DEFAULT_INTERNAL_HERMES_PUBLISHING_GROUP) {
} else if (hermesV1Enabled) {
dependencySubstitution.add(
Triple(
"com.facebook.hermes:hermes-android",
"com.facebook.react:hermes-android",
hermesVersionString,
"The hermes-android dependency was modified to use the correct Maven group.",
"The hermes-android dependency was modified to use Hermes V1.",
)
)
}
@@ -222,19 +221,11 @@ internal object DependencyUtils {
val hermesGroupString =
reactAndroidProperties[INTERNAL_HERMES_PUBLISHING_GROUP] as? String
?: DEFAULT_INTERNAL_HERMES_PUBLISHING_GROUP
// TODO: T237406039 read both versions from the same file
val hermesVersionProperties = Properties()
hermesVersionFile.inputStream().use { hermesVersionProperties.load(it) }
val hermesVersionString =
(hermesVersionProperties[INTERNAL_HERMES_VERSION_NAME] as? String).orEmpty()
val hermesVersion =
if (hermesVersionString.startsWith("0.0.0") || "-commitly-" in hermesVersionString) {
"$hermesVersionString-SNAPSHOT"
} else {
hermesVersionString
}
val hermesVersion = versionString
val hermesV1Version =
(hermesVersionProperties[INTERNAL_HERMES_V1_VERSION_NAME] as? String).orEmpty()
@@ -130,6 +130,7 @@ private fun detectCliFile(reactNativeRoot: File, preconfiguredCliFile: File?): F
internal fun detectOSAwareHermesCommand(
projectRoot: File,
hermesCommand: String,
hermesV1Enabled: Boolean = false,
): String { // 1. If the project specifies a Hermes command, don't second guess it.
if (hermesCommand.isNotBlank()) {
val osSpecificHermesCommand =
@@ -150,9 +151,13 @@ internal fun detectOSAwareHermesCommand(
return builtHermesc.cliPath(projectRoot)
}
// 3. Use hermes-compiler from npm
// 3. If Hermes V1 is enabled, use hermes-compiler from npm, otherwise, if the
// react-native contains a pre-built hermesc, use it.
// TODO: T237406039 use hermes-compiler from npm for both
val hermesCPath = if (hermesV1Enabled) HERMES_COMPILER_NPM_DIR else HERMESC_IN_REACT_NATIVE_DIR
val prebuiltHermesPath =
HERMES_COMPILER_NPM_DIR.plus(getHermesCBin())
hermesCPath
.plus(getHermesCBin())
.replace("%OS-BIN%", getHermesOSBin())
// Execution on Windows fails with / as separator
.replace('/', File.separatorChar)
@@ -238,5 +243,6 @@ internal fun readPackageJsonFile(
}
private const val HERMES_COMPILER_NPM_DIR = "node_modules/hermes-compiler/hermesc/%OS-BIN%/"
private const val HERMESC_IN_REACT_NATIVE_DIR = "node_modules/react-native/sdks/hermesc/%OS-BIN%/"
private const val HERMESC_BUILT_FROM_SOURCE_DIR =
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/"
@@ -81,9 +81,8 @@ object PropertyUtils {
const val INTERNAL_VERSION_NAME = "VERSION_NAME"
/**
* Internal properties, shared with iOS, used to control the version name of Hermes Engine. They
* are stored in sdks/hermes-engine/version.properties
* Internal property, shared with iOS, used to control the version name of Hermes Engine. This is
* stored in sdks/hermes-engine/version.properties
*/
const val INTERNAL_HERMES_VERSION_NAME = "HERMES_VERSION_NAME"
const val INTERNAL_HERMES_V1_VERSION_NAME = "HERMES_V1_VERSION_NAME"
}
@@ -34,9 +34,9 @@ class PreparePrefabHeadersTaskTest {
val project = createProject(projectDir = tempFolder.root)
val task =
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(listOf(PrefabPreprocessingEntry("sample_library", "input/" to "")))
createTestTask<PreparePrefabHeadersTask>(project = project) { prefabTask ->
prefabTask.outputDir.set(outputDir)
prefabTask.input.set(listOf(PrefabPreprocessingEntry("sample_library", "input/" to "")))
}
task.taskAction()
@@ -52,9 +52,9 @@ class PreparePrefabHeadersTaskTest {
val project = createProject(projectDir = tempFolder.root)
val task =
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(
createTestTask<PreparePrefabHeadersTask>(project = project) { headerTask ->
headerTask.outputDir.set(outputDir)
headerTask.input.set(
listOf(PrefabPreprocessingEntry("sample_library", "input/" to expectedPrefix))
)
}
@@ -74,9 +74,9 @@ class PreparePrefabHeadersTaskTest {
val project = createProject(projectDir = tempFolder.root)
val task =
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(
createTestTask<PreparePrefabHeadersTask>(project = project) { ignoreFilesTask ->
ignoreFilesTask.outputDir.set(outputDir)
ignoreFilesTask.input.set(
listOf(PrefabPreprocessingEntry("sample_library", "input/" to expectedPrefix))
)
}
@@ -96,9 +96,9 @@ class PreparePrefabHeadersTaskTest {
val project = createProject(projectDir = tempFolder.root)
val task =
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(
createTestTask<PreparePrefabHeadersTask>(project = project) { multiPathTask ->
multiPathTask.outputDir.set(outputDir)
multiPathTask.input.set(
listOf(
PrefabPreprocessingEntry(
"sample_library",
@@ -122,9 +122,9 @@ class PreparePrefabHeadersTaskTest {
val project = createProject(projectDir = tempFolder.root)
val task =
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(
createTestTask<PreparePrefabHeadersTask>(project = project) { multiEntryTask ->
multiEntryTask.outputDir.set(outputDir)
multiEntryTask.input.set(
listOf(
PrefabPreprocessingEntry("libraryone", "input/lib1/" to ""),
PrefabPreprocessingEntry("librarytwo", "input/lib2/" to ""),
@@ -147,9 +147,9 @@ class PreparePrefabHeadersTaskTest {
val project = createProject(projectDir = tempFolder.root)
val task =
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(
createTestTask<PreparePrefabHeadersTask>(project = project) { sharedHeaderTask ->
sharedHeaderTask.outputDir.set(outputDir)
sharedHeaderTask.input.set(
listOf(
PrefabPreprocessingEntry(
"libraryone",
@@ -289,7 +289,7 @@ class DependencyUtilsTest {
val forcedModules = project.configurations.first().resolutionStrategy.forcedModules
assertThat(forcedModules.any { it.toString() == "com.facebook.react:react-android:1.2.3" })
.isTrue()
assertThat(forcedModules.any { it.toString() == "com.facebook.hermes:hermes-android:4.5.6" })
assertThat(forcedModules.any { it.toString() == "com.facebook.react:hermes-android:4.5.6" })
.isTrue()
}
@@ -324,11 +324,11 @@ class DependencyUtilsTest {
val libForcedModules = libProject.configurations.first().resolutionStrategy.forcedModules
assertThat(appForcedModules.any { it.toString() == "com.facebook.react:react-android:1.2.3" })
.isTrue()
assertThat(appForcedModules.any { it.toString() == "com.facebook.hermes:hermes-android:4.5.6" })
assertThat(appForcedModules.any { it.toString() == "com.facebook.react:hermes-android:4.5.6" })
.isTrue()
assertThat(libForcedModules.any { it.toString() == "com.facebook.react:react-android:1.2.3" })
.isTrue()
assertThat(libForcedModules.any { it.toString() == "com.facebook.hermes:hermes-android:4.5.6" })
assertThat(libForcedModules.any { it.toString() == "com.facebook.react:hermes-android:4.5.6" })
.isTrue()
}
@@ -381,15 +381,11 @@ class DependencyUtilsTest {
val libForcedModules = libProject.configurations.first().resolutionStrategy.forcedModules
assertThat(appForcedModules.any { it.toString() == "io.github.test:react-android:1.2.3" })
.isTrue()
assertThat(
appForcedModules.any { it.toString() == "io.github.test.hermes:hermes-android:4.5.6" }
)
assertThat(appForcedModules.any { it.toString() == "io.github.test:hermes-android:4.5.6" })
.isTrue()
assertThat(libForcedModules.any { it.toString() == "io.github.test:react-android:1.2.3" })
.isTrue()
assertThat(
libForcedModules.any { it.toString() == "io.github.test.hermes:hermes-android:4.5.6" }
)
assertThat(libForcedModules.any { it.toString() == "io.github.test:hermes-android:4.5.6" })
.isTrue()
}
@@ -442,7 +438,7 @@ class DependencyUtilsTest {
)
.isEqualTo(dependencySubstitutions[0].third)
assertThat("com.facebook.react:hermes-engine").isEqualTo(dependencySubstitutions[1].first)
assertThat("com.facebook.hermes:hermes-android:0.42.0")
assertThat("com.facebook.react:hermes-android:0.42.0")
.isEqualTo(dependencySubstitutions[1].second)
assertThat(
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210."
@@ -494,26 +490,19 @@ class DependencyUtilsTest {
)
.isEqualTo(dependencySubstitutions[0].third)
assertThat("com.facebook.react:hermes-engine").isEqualTo(dependencySubstitutions[1].first)
assertThat("io.github.test.hermes:hermes-android:0.42.0")
.isEqualTo(dependencySubstitutions[1].second)
assertThat("io.github.test:hermes-android:0.42.0").isEqualTo(dependencySubstitutions[1].second)
assertThat(
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210."
)
.isEqualTo(dependencySubstitutions[1].third)
assertThat("com.facebook.react:hermes-android").isEqualTo(dependencySubstitutions[2].first)
assertThat("io.github.test.hermes:hermes-android:0.42.0")
.isEqualTo(dependencySubstitutions[2].second)
assertThat("The hermes-android artifact was moved to com.facebook.hermes publishing group.")
.isEqualTo(dependencySubstitutions[2].third)
assertThat("com.facebook.react:react-android").isEqualTo(dependencySubstitutions[3].first)
assertThat("io.github.test:react-android:0.42.0").isEqualTo(dependencySubstitutions[3].second)
assertThat("com.facebook.react:react-android").isEqualTo(dependencySubstitutions[2].first)
assertThat("io.github.test:react-android:0.42.0").isEqualTo(dependencySubstitutions[2].second)
assertThat("The react-android dependency was modified to use the correct Maven group.")
.isEqualTo(dependencySubstitutions[3].third)
assertThat("com.facebook.react:hermes-android").isEqualTo(dependencySubstitutions[4].first)
assertThat("io.github.test.hermes:hermes-android:0.42.0")
.isEqualTo(dependencySubstitutions[4].second)
.isEqualTo(dependencySubstitutions[2].third)
assertThat("com.facebook.react:hermes-android").isEqualTo(dependencySubstitutions[3].first)
assertThat("io.github.test:hermes-android:0.42.0").isEqualTo(dependencySubstitutions[3].second)
assertThat("The hermes-android dependency was modified to use the correct Maven group.")
.isEqualTo(dependencySubstitutions[4].third)
.isEqualTo(dependencySubstitutions[3].third)
}
@Test
@@ -543,20 +532,15 @@ class DependencyUtilsTest {
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210."
)
.isEqualTo(dependencySubstitutions[1].third)
assertThat("com.facebook.react:hermes-android").isEqualTo(dependencySubstitutions[2].first)
assertThat("io.github.test.hermes:hermes-android:0.43.0")
.isEqualTo(dependencySubstitutions[2].second)
assertThat("The hermes-android artifact was moved to com.facebook.hermes publishing group.")
.isEqualTo(dependencySubstitutions[2].third)
assertThat("com.facebook.react:react-android").isEqualTo(dependencySubstitutions[3].first)
assertThat("io.github.test:react-android:0.42.0").isEqualTo(dependencySubstitutions[3].second)
assertThat("com.facebook.react:react-android").isEqualTo(dependencySubstitutions[2].first)
assertThat("io.github.test:react-android:0.42.0").isEqualTo(dependencySubstitutions[2].second)
assertThat("The react-android dependency was modified to use the correct Maven group.")
.isEqualTo(dependencySubstitutions[3].third)
assertThat("com.facebook.react:hermes-android").isEqualTo(dependencySubstitutions[4].first)
.isEqualTo(dependencySubstitutions[2].third)
assertThat("com.facebook.react:hermes-android").isEqualTo(dependencySubstitutions[3].first)
assertThat("io.github.test.hermes:hermes-android:0.43.0")
.isEqualTo(dependencySubstitutions[4].second)
.isEqualTo(dependencySubstitutions[3].second)
assertThat("The hermes-android dependency was modified to use the correct Maven group.")
.isEqualTo(dependencySubstitutions[4].third)
.isEqualTo(dependencySubstitutions[3].third)
}
@Test
@@ -576,7 +560,6 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_VERSION_NAME=1000.0.0
HERMES_V1_VERSION_NAME=1000.0.0
ANOTHER_PROPERTY=true
"""
@@ -613,7 +596,6 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_VERSION_NAME=0.14.0
HERMES_V1_VERSION_NAME=250829098.0.0-stable
ANOTHER_PROPERTY=true
"""
@@ -627,7 +609,7 @@ class DependencyUtilsTest {
val hermesV1VersionString = strings.hermesV1VersionString
assertThat(versionString).isEqualTo("0.0.0-20221101-2019-cfe811ab1-SNAPSHOT")
assertThat(hermesVersionString).isEqualTo("0.14.0")
assertThat(hermesVersionString).isEqualTo("0.0.0-20221101-2019-cfe811ab1-SNAPSHOT")
assertThat(hermesV1VersionString).isEqualTo("250829098.0.0-stable")
}
@@ -679,7 +661,6 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_VERSION_NAME=
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
@@ -714,7 +695,6 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_VERSION_NAME=
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
@@ -746,7 +726,6 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_VERSION_NAME=
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
@@ -155,11 +155,21 @@ class PathUtilsTest {
@Test
@WithOs(OS.MAC)
fun detectOSAwareHermesCommand_withHermescFromNPM() {
fun detectOSAwareHermesCommand_withBundledHermescInsideRN() {
tempFolder.newFolder("node_modules/react-native/sdks/hermesc/osx-bin/")
val expected = tempFolder.newFile("node_modules/react-native/sdks/hermesc/osx-bin/hermesc")
assertThat(detectOSAwareHermesCommand(tempFolder.root, "")).isEqualTo(expected.toString())
}
@Test
@WithOs(OS.MAC)
fun detectOSAwareHermesCommand_withHermesV1Enabled() {
tempFolder.newFolder("node_modules/hermes-compiler/hermesc/osx-bin/")
val expected = tempFolder.newFile("node_modules/hermes-compiler/hermesc/osx-bin/hermesc")
assertThat(detectOSAwareHermesCommand(tempFolder.root, "")).isEqualTo(expected.toString())
assertThat(detectOSAwareHermesCommand(tempFolder.root, "", hermesV1Enabled = true))
.isEqualTo(expected.toString())
}
@Test(expected = IllegalStateException::class)
+1 -2
View File
@@ -123,8 +123,7 @@ function getHermesLabel(): React.Node {
return (
<ThemedText color="secondary" style={styles.label}>
JS Engine: Hermes (
{global.HermesInternal.getRuntimeProperties?.()['OSS Release Version']})
JS Engine: Hermes
</ThemedText>
);
}
@@ -26,9 +26,7 @@ describe('console.timeStamp()', () => {
it("doesn't throw when additional arguments are specified", () => {
expect(() =>
console.timeStamp('label', 100, 500, 'Track', 'Group', 'error', {
tooltipText: 'Image processing failed',
}),
console.timeStamp('label', 100, 500, 'Track', 'Group', 'error'),
).not.toThrow();
});
@@ -24,9 +24,11 @@ RCT_EXPORT_MODULE(FileReaderModule)
@synthesize moduleRegistry = _moduleRegistry;
RCT_EXPORT_METHOD(
readAsText : (NSDictionary<NSString *, id> *)blob encoding : (NSString *)encoding resolve : (RCTPromiseResolveBlock)
resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(readAsText
: (NSDictionary<NSString *, id> *)blob encoding
: (NSString *)encoding resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
@@ -54,9 +56,10 @@ RCT_EXPORT_METHOD(
});
}
RCT_EXPORT_METHOD(
readAsDataURL : (NSDictionary<NSString *, id> *)blob resolve : (RCTPromiseResolveBlock)
resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(readAsDataURL
: (NSDictionary<NSString *, id> *)blob resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
@@ -99,7 +99,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(new Error('NativeAccessibilityManagerIOS is not available'));
reject(null);
}
});
}
@@ -119,11 +119,7 @@ const AccessibilityInfo = {
if (NativeAccessibilityInfoAndroid?.isGrayscaleEnabled != null) {
NativeAccessibilityInfoAndroid.isGrayscaleEnabled(resolve);
} else {
reject(
new Error(
'NativeAccessibilityInfoAndroid.isGrayscaleEnabled is not available',
),
);
reject(null);
}
});
} else {
@@ -134,7 +130,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(new Error('AccessibilityInfo native module is not available'));
reject(null);
}
});
}
@@ -154,11 +150,7 @@ const AccessibilityInfo = {
if (NativeAccessibilityInfoAndroid?.isInvertColorsEnabled != null) {
NativeAccessibilityInfoAndroid.isInvertColorsEnabled(resolve);
} else {
reject(
new Error(
'NativeAccessibilityInfoAndroid.isInvertColorsEnabled is not available',
),
);
reject(null);
}
});
} else {
@@ -169,7 +161,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(new Error('AccessibilityInfo native module is not available'));
reject(null);
}
});
}
@@ -189,7 +181,7 @@ const AccessibilityInfo = {
if (NativeAccessibilityInfoAndroid != null) {
NativeAccessibilityInfoAndroid.isReduceMotionEnabled(resolve);
} else {
reject(new Error('AccessibilityInfo native module is not available'));
reject(null);
}
} else {
if (NativeAccessibilityManagerIOS != null) {
@@ -198,7 +190,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(new Error('NativeAccessibilityManagerIOS is not available'));
reject(null);
}
}
});
@@ -216,11 +208,7 @@ const AccessibilityInfo = {
if (NativeAccessibilityInfoAndroid?.isHighTextContrastEnabled != null) {
NativeAccessibilityInfoAndroid.isHighTextContrastEnabled(resolve);
} else {
reject(
new Error(
'NativeAccessibilityInfoAndroid.isHighTextContrastEnabled is not available',
),
);
reject(null);
}
} else {
return Promise.resolve(false);
@@ -248,11 +236,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(
new Error(
'NativeAccessibilityManagerIOS.getCurrentDarkerSystemColorsState is not available',
),
);
reject(null);
}
}
});
@@ -280,11 +264,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(
new Error(
'NativeAccessibilityManagerIOS.getCurrentPrefersCrossFadeTransitionsState is not available',
),
);
reject(null);
}
}
});
@@ -309,7 +289,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(new Error('NativeAccessibilityManagerIOS is not available'));
reject(null);
}
});
}
@@ -329,7 +309,7 @@ const AccessibilityInfo = {
if (NativeAccessibilityInfoAndroid != null) {
NativeAccessibilityInfoAndroid.isTouchExplorationEnabled(resolve);
} else {
reject(new Error('NativeAccessibilityInfoAndroid is not available'));
reject(null);
}
} else {
if (NativeAccessibilityManagerIOS != null) {
@@ -338,7 +318,7 @@ const AccessibilityInfo = {
reject,
);
} else {
reject(new Error('NativeAccessibilityManagerIOS is not available'));
reject(null);
}
}
});
@@ -363,18 +343,10 @@ const AccessibilityInfo = {
) {
NativeAccessibilityInfoAndroid.isAccessibilityServiceEnabled(resolve);
} else {
reject(
new Error(
'NativeAccessibilityInfoAndroid.isAccessibilityServiceEnabled is not available',
),
);
reject(null);
}
} else {
reject(
new Error(
'isAccessibilityServiceEnabled is only available on Android',
),
);
reject(null);
}
});
},
@@ -9,7 +9,7 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet';
import {ViewStyle} from '../../StyleSheet/StyleSheetTypes';
import {LayoutChangeEvent} from '../../Types/CoreEventTypes';
@@ -46,7 +46,7 @@ export interface ActivityIndicatorProps extends ViewProps {
}
declare class ActivityIndicatorComponent extends React.Component<ActivityIndicatorProps> {}
declare const ActivityIndicatorBase: Constructor<HostInstance> &
declare const ActivityIndicatorBase: Constructor<NativeMethods> &
typeof ActivityIndicatorComponent;
export class ActivityIndicator extends ActivityIndicatorBase {}
@@ -9,7 +9,7 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
import {ColorValue} from '../../StyleSheet/StyleSheet';
import {
NativeSyntheticEvent,
@@ -121,7 +121,7 @@ interface DrawerPosition {
}
declare class DrawerLayoutAndroidComponent extends React.Component<DrawerLayoutAndroidProps> {}
declare const DrawerLayoutAndroidBase: Constructor<HostInstance> &
declare const DrawerLayoutAndroidBase: Constructor<NativeMethods> &
typeof DrawerLayoutAndroidComponent;
export class DrawerLayoutAndroid extends DrawerLayoutAndroidBase {
/**
@@ -9,7 +9,7 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
import {ColorValue} from '../../StyleSheet/StyleSheet';
import {ViewProps} from '../View/ViewPropTypes';
@@ -72,7 +72,7 @@ export interface ProgressBarAndroidProps extends ViewProps {
* that the app is loading or there is some activity in the app.
*/
declare class ProgressBarAndroidComponent extends React.Component<ProgressBarAndroidProps> {}
declare const ProgressBarAndroidBase: Constructor<HostInstance> &
declare const ProgressBarAndroidBase: Constructor<NativeMethods> &
typeof ProgressBarAndroidComponent;
/**
* ProgressBarAndroid has been extracted from react-native core and will be removed in a future release.
@@ -9,7 +9,7 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
import {ColorValue} from '../../StyleSheet/StyleSheet';
import {ViewProps} from '../View/ViewPropTypes';
@@ -80,7 +80,7 @@ export interface RefreshControlProps
* in the `onRefresh` function otherwise the refresh indicator will stop immediately.
*/
declare class RefreshControlComponent extends React.Component<RefreshControlProps> {}
declare const RefreshControlBase: Constructor<HostInstance> &
declare const RefreshControlBase: Constructor<NativeMethods> &
typeof RefreshControlComponent;
export class RefreshControl extends RefreshControlBase {
static SIZE: Object; // Undocumented
@@ -9,7 +9,7 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
import {ViewProps} from '../View/ViewPropTypes';
/**
@@ -23,7 +23,7 @@ import {ViewProps} from '../View/ViewPropTypes';
*/
declare class SafeAreaViewComponent extends React.Component<ViewProps> {}
declare const SafeAreaViewBase: Constructor<HostInstance> &
declare const SafeAreaViewBase: Constructor<NativeMethods> &
typeof SafeAreaViewComponent;
/**
@@ -12,10 +12,12 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
import {createRef} from 'react';
import {ScrollView} from 'react-native';
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
describe('onScroll', () => {
it('delivers onScroll event', () => {
@@ -34,9 +36,11 @@ describe('onScroll', () => {
);
});
const element = ensureInstance(scrollViewRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(
scrollViewRef,
element,
'scroll',
{
contentOffset: {
@@ -76,9 +80,11 @@ describe('onScroll', () => {
);
});
const element = ensureInstance(scrollViewRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(
scrollViewRef,
element,
'scroll',
{
contentOffset: {
@@ -91,7 +97,7 @@ describe('onScroll', () => {
},
);
Fantom.enqueueNativeEvent(
scrollViewRef,
element,
'scroll',
{
contentOffset: {
@@ -13,11 +13,13 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import type {HostInstance} from 'react-native';
import ensureInstance from '../../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import nullthrows from 'nullthrows';
import * as React from 'react';
import {createRef, useState} from 'react';
import {FlatList, Modal, ScrollView, View} from 'react-native';
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
test('basic culling', () => {
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
@@ -44,7 +46,9 @@ test('basic culling', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 60,
});
@@ -57,7 +61,7 @@ test('basic culling', () => {
'Update {type: "ScrollView", nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 0,
});
@@ -114,8 +118,10 @@ test('recursive culling', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// === Scroll down to the edge of child AA ===
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 30,
});
@@ -126,7 +132,7 @@ test('recursive culling', () => {
// === Scroll down past child AA ===
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 36,
});
@@ -138,7 +144,7 @@ test('recursive culling', () => {
]);
// === Scroll down past child AB ===
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 51,
});
@@ -150,7 +156,7 @@ test('recursive culling', () => {
]);
// === Scroll down past element A ===
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 56,
});
@@ -162,7 +168,7 @@ test('recursive culling', () => {
]);
// Scroll element B into viewport. Just child BA should be created.
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 155,
});
@@ -176,7 +182,7 @@ test('recursive culling', () => {
]);
// Scroll child BA into viewport.
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 165,
});
@@ -188,7 +194,7 @@ test('recursive culling', () => {
]);
// Scroll back to start
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 0,
});
@@ -210,7 +216,7 @@ test('recursive culling', () => {
]);
// Scroll past element A
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 85,
});
@@ -259,7 +265,9 @@ test('recursive culling when initial offset is negative', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 0,
});
@@ -320,7 +328,9 @@ test('deep nesting', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 40,
});
@@ -335,7 +345,7 @@ test('deep nesting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 1, nativeID: "element B"}',
]);
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 150,
});
@@ -479,7 +489,9 @@ test('initial render', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 100,
});
@@ -549,7 +561,9 @@ test('basic culling smaller ScrollView', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 11,
});
@@ -610,7 +624,9 @@ test('culling with transform move', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 1,
});
@@ -653,7 +669,9 @@ test('culling with recursive transform move', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 1,
});
@@ -695,7 +713,9 @@ test('culling with transform scale', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 121,
});
@@ -754,8 +774,10 @@ test('culling inside of Modal', () => {
);
});
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueModalSizeUpdate(nodeRef, {
Fantom.enqueueModalSizeUpdate(element, {
width: 100,
height: 100,
});
@@ -878,7 +900,9 @@ describe('reparenting', () => {
'Insert {type: "ScrollView", parentNativeID: (root), index: 0, nativeID: (N/A)}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 60,
});
@@ -1554,8 +1578,10 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
]);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// Scroll down to see the grandchild.
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 115,
});
@@ -1643,8 +1669,10 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
]);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// Scroll down to see the grandchild.
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 118,
});
@@ -1883,8 +1911,10 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// Scroll to reveal grandchild.
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 70,
});
@@ -1971,8 +2001,10 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: (N/A)}',
]);
const element = ensureInstance(nodeRef.current, ReactNativeElement);
// Scroll to reveal grandchild.
Fantom.scrollTo(nodeRef, {
Fantom.scrollTo(element, {
x: 0,
y: 70,
});
@@ -2182,7 +2214,9 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: "unflattened", index: 0, nativeID: "child"}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 50,
});
@@ -2278,7 +2312,9 @@ describe('reparenting', () => {
'Insert {type: "View", parentNativeID: "unflattened", index: 0, nativeID: "child"}',
]);
Fantom.scrollTo(nodeRef, {
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.scrollTo(element, {
x: 0,
y: 50,
});
@@ -2427,9 +2463,10 @@ describe('opt out mechanism - Unstable_uncullableView & Unstable_uncullableTrace
</ScrollView>,
);
});
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueModalSizeUpdate(nodeRef, {
Fantom.enqueueModalSizeUpdate(element, {
width: 100,
height: 100,
});
@@ -2480,8 +2517,10 @@ describe('opt out mechanism - Unstable_uncullableView & Unstable_uncullableTrace
);
});
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueModalSizeUpdate(nodeRef, {
Fantom.enqueueModalSizeUpdate(element, {
width: 100,
height: 100,
});
@@ -9,7 +9,7 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet';
import {ViewStyle} from '../../StyleSheet/StyleSheetTypes';
import {ViewProps} from '../View/ViewPropTypes';
@@ -114,5 +114,5 @@ export interface SwitchProps extends SwitchPropsIOS {
* the supplied `value` prop instead of the expected result of any user actions.
*/
declare class SwitchComponent extends React.Component<SwitchProps> {}
declare const SwitchBase: Constructor<HostInstance> & typeof SwitchComponent;
declare const SwitchBase: Constructor<NativeMethods> & typeof SwitchComponent;
export class Switch extends SwitchBase {}
@@ -10,7 +10,10 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {TimerMixin} from '../../../types/private/TimerMixin';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {
HostInstance,
NativeMethods,
} from '../../../types/public/ReactNativeTypes';
import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet';
import {TextStyle} from '../../StyleSheet/StyleSheetTypes';
import {
@@ -1026,7 +1029,7 @@ interface TextInputState {
* @see https://reactnative.dev/docs/textinput#methods
*/
declare class TextInputComponent extends React.Component<TextInputProps> {}
declare const TextInputBase: Constructor<HostInstance> &
declare const TextInputBase: Constructor<NativeMethods> &
Constructor<TimerMixin> &
typeof TextInputComponent;
export class TextInput extends TextInputBase {
@@ -12,6 +12,7 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import type {TextInputInstance} from '../TextInput.flow';
import ensureInstance from '../../../../src/private/__tests__/utilities/ensureInstance';
import * as Fantom from '@react-native/fantom';
import nullthrows from 'nullthrows';
import * as React from 'react';
@@ -59,8 +60,10 @@ describe('<TextInput>', () => {
);
});
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(nodeRef, 'change', {
Fantom.enqueueNativeEvent(element, 'change', {
text: 'Hello World',
});
});
@@ -83,8 +86,10 @@ describe('<TextInput>', () => {
root.render(<TextInput onChangeText={onChangeText} ref={nodeRef} />);
});
const element = ensureInstance(nodeRef.current, ReactNativeElement);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(nodeRef, 'change', {
Fantom.enqueueNativeEvent(element, 'change', {
text: 'Hello World',
});
});
@@ -108,10 +113,12 @@ describe('<TextInput>', () => {
root.render(<TextInput onFocus={focusEvent} ref={nodeRef} />);
});
const element = ensureInstance(nodeRef.current, ReactNativeElement);
expect(focusEvent).toHaveBeenCalledTimes(0);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(nodeRef, 'focus');
Fantom.enqueueNativeEvent(element, 'focus');
});
// The tasks have not run.
@@ -134,10 +141,12 @@ describe('<TextInput>', () => {
root.render(<TextInput onBlur={blurEvent} ref={nodeRef} />);
});
const element = ensureInstance(nodeRef.current, ReactNativeElement);
expect(blurEvent).toHaveBeenCalledTimes(0);
Fantom.runOnUIThread(() => {
Fantom.enqueueNativeEvent(nodeRef, 'blur');
Fantom.enqueueNativeEvent(element, 'blur');
});
// The tasks have not run.
@@ -13,9 +13,6 @@ import type {AnyAttributeType} from '../../Renderer/shims/ReactNativeTypes';
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
import processAspectRatio from '../../StyleSheet/processAspectRatio';
import processBackgroundImage from '../../StyleSheet/processBackgroundImage';
import processBackgroundPosition from '../../StyleSheet/processBackgroundPosition';
import processBackgroundRepeat from '../../StyleSheet/processBackgroundRepeat';
import processBackgroundSize from '../../StyleSheet/processBackgroundSize';
import processBoxShadow from '../../StyleSheet/processBoxShadow';
import processColor from '../../StyleSheet/processColor';
import processFilter from '../../StyleSheet/processFilter';
@@ -147,25 +144,10 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
: {process: processBoxShadow},
/**
* BackgroundImage
* Linear Gradient
*/
experimental_backgroundImage: {process: processBackgroundImage},
/**
* BackgroundSize
*/
experimental_backgroundSize: {process: processBackgroundSize},
/**
* BackgroundPosition
*/
experimental_backgroundPosition: {process: processBackgroundPosition},
/**
* BackgroundRepeat
*/
experimental_backgroundRepeat: {process: processBackgroundRepeat},
/**
* View
*/
+2 -2
View File
@@ -10,7 +10,7 @@
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {ViewProps} from './ViewPropTypes';
import {HostInstance} from '../../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
/**
* The most fundamental component for building UI, View is a container that supports layout with flexbox, style, some touch handling,
@@ -19,7 +19,7 @@ import {HostInstance} from '../../../types/public/ReactNativeTypes';
* whether that is a UIView, <div>, android.view, etc.
*/
declare class ViewComponent extends React.Component<ViewProps> {}
declare const ViewBase: Constructor<HostInstance> & typeof ViewComponent;
declare const ViewBase: Constructor<NativeMethods> & typeof ViewComponent;
export class View extends ViewBase {
/**
* Is 3D Touch / Force Touch available (i.e. will touch events include `force`)
@@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @fantom_flags enableNativeCSSParsing:*
* @format
*/
@@ -230,56 +229,6 @@ describe('<View>', () => {
});
});
});
describe('background-image', () => {
it('it parses CSS and object syntax', () => {
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(
<>
<View
style={{
experimental_backgroundImage:
'radial-gradient(#e66465, #9198e5)',
}}
/>
<View
style={{
experimental_backgroundImage: [
{
type: 'radial-gradient',
shape: 'ellipse',
position: {top: '50%', right: '50%'},
size: 'farthest-corner',
colorStops: [{color: '#e66465'}, {color: '#9198e5'}],
},
],
}}
/>
</>,
);
});
const expectedProps = {
backgroundImage:
'[radial-gradient(ellipse farthest-corner at 50% 50% , rgba(230, 100, 101, 1), rgba(145, 152, 229, 1))]',
};
expect(root.getRenderedOutput().toJSON()).toEqual([
{
children: [],
props: expectedProps,
type: 'View',
},
{
children: [],
props: expectedProps,
type: 'View',
},
]);
});
});
});
describe('pointerEvents', () => {
@@ -20,9 +20,7 @@ if (NativePerformance) {
// $FlowExpectedError[cannot-write]
global.performance = {
mark: () => {},
clearMarks: () => {},
measure: () => {},
clearMeasures: () => {},
now: () => {
const performanceNow = global.nativePerformanceNow || Date.now;
return performanceNow();
@@ -332,9 +332,7 @@ class DebuggingOverlayRegistry {
instance.measure((x, y, width, height, left, top) => {
// measure can execute callback without any values provided to signal error.
if (left == null || top == null || width == null || height == null) {
reject(
new Error('Unexpectedly failed to call measure on an instance.'),
);
reject('Unexpectedly failed to call measure on an instance.');
}
resolve({
@@ -482,11 +480,7 @@ class DebuggingOverlayRegistry {
width == null ||
height == null
) {
reject(
new Error(
'Unexpectedly failed to call measure on an instance.',
),
);
reject('Unexpectedly failed to call measure on an instance.');
}
resolve({x: left, y: top, width, height});
@@ -30,11 +30,8 @@ class RCTDeviceEventEmitterImpl extends EventEmitter<RCTDeviceEventDefinitions>
...args: RCTDeviceEventDefinitions[TEvent]
): void {
beginEvent(() => `RCTDeviceEventEmitter.emit#${eventType}`);
try {
super.emit(eventType, ...args);
} finally {
endEvent();
}
super.emit(eventType, ...args);
endEvent();
}
}
const RCTDeviceEventEmitter: IEventEmitter<RCTDeviceEventDefinitions> =
@@ -26,81 +26,68 @@ class LazyIterator {
public:
LazyIterator() = default;
LazyIterator(U vector, convert_type convert, size_type i) : _v(vector), _i(i), _convert(std::move(convert)) {}
LazyIterator(U vector, convert_type convert, size_type i)
: _v(vector), _i(i), _convert(std::move(convert)) {}
bool operator==(const LazyIterator &other) const
{
bool operator==(const LazyIterator& other) const {
return _i == other._i && _v == other._v;
}
bool operator<(const LazyIterator &b) const
{
bool operator<(const LazyIterator& b) const {
return _i < b._i;
}
value_type operator*() const
{
value_type operator*() const {
return _convert(_v[_i]);
}
std::unique_ptr<value_type> operator->() const
{
std::unique_ptr<value_type> operator->() const {
return std::make_unique<value_type>(*this);
}
LazyIterator operator+(difference_type n) const
{
LazyIterator operator+(difference_type n) const {
return LazyIterator(_v, _convert, _i + n);
}
LazyIterator &operator+=(difference_type n)
{
LazyIterator& operator+=(difference_type n) {
_i += n;
return *this;
}
LazyIterator &operator-=(difference_type n)
{
LazyIterator& operator-=(difference_type n) {
_i -= n;
return *this;
}
LazyIterator operator-(difference_type n) const
{
LazyIterator operator-(difference_type n) const {
return LazyIterator(_v, _i - n);
}
difference_type operator-(const LazyIterator &a) const
{
difference_type operator-(const LazyIterator& a) const {
return _i - a._i;
}
LazyIterator &operator++()
{
LazyIterator& operator++() {
return *this += 1;
}
LazyIterator operator++(int)
{
LazyIterator operator++(int) {
auto tmp = *this;
++*this;
return tmp;
}
LazyIterator &operator--()
{
LazyIterator& operator--() {
return *this -= 1;
}
LazyIterator operator--(int)
{
LazyIterator operator--(int) {
auto tmp = *this;
--*this;
return tmp;
}
value_type operator[](difference_type n) const
{
value_type operator[](difference_type n) const {
return _convert(_v[_i + n]);
}
@@ -111,32 +98,29 @@ class LazyIterator {
};
template <typename T, typename U>
LazyIterator<T, U> operator+(typename LazyIterator<T, U>::difference_type n, const LazyIterator<T, U> &i)
{
LazyIterator<T, U> operator+(
typename LazyIterator<T, U>::difference_type n,
const LazyIterator<T, U>& i) {
return i + n;
}
template <typename T, typename U>
bool operator!=(const LazyIterator<T, U> &a, const LazyIterator<T, U> &b)
{
bool operator!=(const LazyIterator<T, U>& a, const LazyIterator<T, U>& b) {
return !(a == b);
}
template <typename T, typename U>
bool operator<=(const LazyIterator<T, U> &a, const LazyIterator<T, U> &b)
{
bool operator<=(const LazyIterator<T, U>& a, const LazyIterator<T, U>& b) {
return a < b || a == b;
}
template <typename T, typename U>
bool operator>(const LazyIterator<T, U> &a, const LazyIterator<T, U> &b)
{
bool operator>(const LazyIterator<T, U>& a, const LazyIterator<T, U>& b) {
return b < a;
}
template <typename T, typename U>
bool operator>=(const LazyIterator<T, U> &a, const LazyIterator<T, U> &b)
{
bool operator>=(const LazyIterator<T, U>& a, const LazyIterator<T, U>& b) {
return a > b || a == b;
}
@@ -31,28 +31,24 @@ class LazyVector {
using size_type = std::int32_t;
using convert_type = std::function<T(U)>;
static LazyVector<T, U> fromUnsafeRawValue(U v, size_type size, convert_type convert)
{
static LazyVector<T, U>
fromUnsafeRawValue(U v, size_type size, convert_type convert) {
return {v, size, convert};
}
U unsafeRawValue() const
{
U unsafeRawValue() const {
return _v;
}
bool empty() const
{
bool empty() const {
return _size == 0;
}
size_type size() const
{
size_type size() const {
return _size;
}
const_reference at(size_type pos) const
{
const_reference at(size_type pos) const {
#ifndef _LIBCPP_NO_EXCEPTIONS
if (!(pos < _size)) {
throw std::out_of_range("out of range");
@@ -63,47 +59,41 @@ class LazyVector {
return _convert(_v[pos]);
}
const_reference operator[](size_type pos) const
{
const_reference operator[](size_type pos) const {
assert(pos < _size);
return _convert(_v[pos]);
}
const_reference front() const
{
const_reference front() const {
assert(_size);
return (*this)[0];
}
const_reference back() const
{
const_reference back() const {
assert(_size);
return (*this)[_size - 1];
}
const_iterator begin() const
{
const_iterator begin() const {
return const_iterator(_v, _convert, 0);
}
const_iterator cbegin() const
{
const_iterator cbegin() const {
return begin();
}
const_iterator end() const
{
const_iterator end() const {
return const_iterator(_v, _convert, _size);
}
const_iterator cend() const
{
const_iterator cend() const {
return end();
}
private:
/** Wrapped vector */
LazyVector(U vector, size_type size, convert_type convert) : _v(vector), _size(size), _convert(convert) {}
LazyVector(U vector, size_type size, convert_type convert)
: _v(vector), _size(size), _convert(convert) {}
U _v;
size_type _size;
+3 -3
View File
@@ -11,7 +11,7 @@ import * as React from 'react';
import {Constructor} from '../../types/private/Utilities';
import {AccessibilityProps} from '../Components/View/ViewAccessibility';
import {Insets} from '../../types/public/Insets';
import {HostInstance} from '../../types/public/ReactNativeTypes';
import {NativeMethods} from '../../types/public/ReactNativeTypes';
import {ColorValue, StyleProp} from '../StyleSheet/StyleSheet';
import {ImageStyle, ViewStyle} from '../StyleSheet/StyleSheetTypes';
import {LayoutChangeEvent, NativeSyntheticEvent} from '../Types/CoreEventTypes';
@@ -338,7 +338,7 @@ export interface ImageSize {
}
declare class ImageComponent extends React.Component<ImageProps> {}
declare const ImageBase: Constructor<HostInstance> & typeof ImageComponent;
declare const ImageBase: Constructor<NativeMethods> & typeof ImageComponent;
export class Image extends ImageBase {
static getSize(uri: string): Promise<ImageSize>;
static getSize(
@@ -384,6 +384,6 @@ export interface ImageBackgroundProps extends ImagePropsBase {
}
declare class ImageBackgroundComponent extends React.Component<ImageBackgroundProps> {}
declare const ImageBackgroundBase: Constructor<HostInstance> &
declare const ImageBackgroundBase: Constructor<NativeMethods> &
typeof ImageBackgroundComponent;
export class ImageBackground extends ImageBackgroundBase {}
@@ -38,9 +38,11 @@ RCT_EXPORT_MODULE()
* be scaled down to `displaySize` rather than `size`.
* All units are in px (not points).
*/
RCT_EXPORT_METHOD(
cropImage : (NSURLRequest *)imageRequest cropData : (JS::NativeImageEditor::Options &)cropData successCallback : (
RCTResponseSenderBlock)successCallback errorCallback : (RCTResponseSenderBlock)errorCallback)
RCT_EXPORT_METHOD(cropImage
: (NSURLRequest *)imageRequest cropData
: (JS::NativeImageEditor::Options &)cropData successCallback
: (RCTResponseSenderBlock)successCallback errorCallback
: (RCTResponseSenderBlock)errorCallback)
{
CGRect rect = {
[RCTConvert CGPoint:@{
@@ -331,9 +331,9 @@ static RCTImageLoaderCancellationBlock RCTLoadImageURLFromLoader(
RCTImageLoaderPartialLoadBlock partialLoadHandler,
RCTImageLoaderCompletionBlockWithMetadata completionHandler)
{
if ([loadHandler
respondsToSelector:@selector
(loadImageForURL:size:scale:resizeMode:progressHandler:partialLoadHandler:completionHandlerWithMetadata:)]) {
if ([loadHandler respondsToSelector:@selector(loadImageForURL:
size:scale:resizeMode:progressHandler:partialLoadHandler
:completionHandlerWithMetadata:)]) {
return [loadHandler loadImageForURL:imageURL
size:size
scale:scale
@@ -410,17 +410,17 @@ static RCTImageLoaderCancellationBlock RCTLoadImageURLFromLoader(
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
{
RCTImageURLLoaderRequest *request = [self loadImageWithURLRequest:imageURLRequest
size:size
scale:scale
clipped:clipped
resizeMode:resizeMode
priority:priority
attribution:{}
progressBlock:progressBlock
partialLoadBlock:partialLoadBlock
completionBlock:^(NSError *error, UIImage *image, id metadata) {
completionBlock(error, image);
}];
size:size
scale:scale
clipped:clipped
resizeMode:resizeMode
priority:priority
attribution:{}
progressBlock:progressBlock
partialLoadBlock:partialLoadBlock
completionBlock:^(NSError *error, UIImage *image, id metadata) {
completionBlock(error, image);
}];
return ^{
[request cancel];
};
@@ -1229,8 +1229,10 @@ static RCTImageLoaderCancellationBlock RCTLoadImageURLFromLoader(
return std::make_shared<facebook::react::NativeImageLoaderIOSSpecJSI>(params);
}
RCT_EXPORT_METHOD(
getSize : (NSString *)uri resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(getSize
: (NSString *)uri resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
NSURLRequest *request = [RCTConvert NSURLRequest:uri];
[self getImageSizeForURLRequest:request
@@ -1246,9 +1248,11 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
getSizeWithHeaders : (NSString *)uri headers : (NSDictionary *)headers resolve : (RCTPromiseResolveBlock)
resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(getSizeWithHeaders
: (NSString *)uri headers
: (NSDictionary *)headers resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
NSURL *URL = [RCTConvert NSURL:uri];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
@@ -1265,15 +1269,20 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
prefetchImage : (NSString *)uri resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(prefetchImage
: (NSString *)uri resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
[self prefetchImageWithMetadata:uri queryRootName:nil rootTag:0 resolve:resolve reject:reject];
}
RCT_EXPORT_METHOD(
prefetchImageWithMetadata : (NSString *)uri queryRootName : (NSString *)queryRootName rootTag : (double)
rootTag resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(prefetchImageWithMetadata
: (NSString *)uri queryRootName
: (NSString *)queryRootName rootTag
: (double)rootTag resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
NSURLRequest *request = [RCTConvert NSURLRequest:uri];
[self loadImageWithURLRequest:request
@@ -1297,8 +1306,10 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
queryCache : (NSArray *)uris resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(queryCache
: (NSArray *)uris resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
resolve([self getImageCacheStatus:uris]);
}
@@ -106,9 +106,10 @@ RCT_EXPORT_METHOD(hasImageForTag : (NSString *)imageTag callback : (RCTResponseS
}
// TODO (#5906496): Name could be more explicit - something like getBase64EncodedDataForTag:?
RCT_EXPORT_METHOD(
getBase64ForTag : (NSString *)imageTag successCallback : (RCTResponseSenderBlock)
successCallback errorCallback : (RCTResponseSenderBlock)errorCallback)
RCT_EXPORT_METHOD(getBase64ForTag
: (NSString *)imageTag successCallback
: (RCTResponseSenderBlock)successCallback errorCallback
: (RCTResponseSenderBlock)errorCallback)
{
NSData *imageData = _store[imageTag];
if (imageData == nullptr) {
@@ -122,9 +123,10 @@ RCT_EXPORT_METHOD(
});
}
RCT_EXPORT_METHOD(
addImageFromBase64 : (NSString *)base64String successCallback : (RCTResponseSenderBlock)
successCallback errorCallback : (RCTResponseSenderBlock)errorCallback)
RCT_EXPORT_METHOD(addImageFromBase64
: (NSString *)base64String successCallback
: (RCTResponseSenderBlock)successCallback errorCallback
: (RCTResponseSenderBlock)errorCallback)
{
// Dispatching to a background thread to perform base64 decoding
@@ -101,11 +101,12 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, CGFloat destScale, RCTR
sourceSize.height = destSize.height;
sourceSize.width = sourceSize.height * aspect;
}
return (CGRect){{
RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale),
RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale),
},
RCTCeilSize(sourceSize, destScale)};
return (CGRect){
{
RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale),
RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale),
},
RCTCeilSize(sourceSize, destScale)};
case RCTResizeModeCover:
@@ -114,16 +115,17 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, CGFloat destScale, RCTR
sourceSize.height = destSize.height;
sourceSize.width = sourceSize.height * aspect;
destSize.width = destSize.height * targetAspect;
return (CGRect){{RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale), 0},
RCTCeilSize(sourceSize, destScale)};
return (CGRect){
{RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale), 0}, RCTCeilSize(sourceSize, destScale)};
} else { // target is wider than content
sourceSize.width = destSize.width;
sourceSize.height = sourceSize.width / aspect;
destSize.height = destSize.width / targetAspect;
return (CGRect){{0, RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale)},
RCTCeilSize(sourceSize, destScale)};
return (CGRect){
{0, RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale)},
RCTCeilSize(sourceSize, destScale)};
}
case RCTResizeModeCenter:
@@ -138,11 +140,12 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, CGFloat destScale, RCTR
sourceSize.width = sourceSize.height * aspect;
}
return (CGRect){{
RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale),
RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale),
},
RCTCeilSize(sourceSize, destScale)};
return (CGRect){
{
RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale),
RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale),
},
RCTCeilSize(sourceSize, destScale)};
}
}
@@ -290,31 +293,18 @@ UIImage *__nullable RCTDecodeImageWithData(NSData *data, CGSize destSize, CGFloa
// Calculate target size
CGSize targetSize = RCTTargetSize(sourceSize, 1, destSize, destScale, resizeMode, NO);
CGSize targetPixelSize = RCTSizeInPixels(targetSize, destScale);
CGImageRef imageRef;
BOOL createThumbnail = targetPixelSize.width != 0 && targetPixelSize.height != 0 &&
(sourceSize.width > targetPixelSize.width || sourceSize.height > targetPixelSize.height);
CGFloat maxPixelSize =
fmax(fmin(sourceSize.width, targetPixelSize.width), fmin(sourceSize.height, targetPixelSize.height));
if (createThumbnail) {
CGFloat maxPixelSize = fmax(targetPixelSize.width, targetPixelSize.height);
// Get a thumbnail of the source image. This is usually slower than creating a full-sized image,
// but takes up less memory once it's done.
imageRef = CGImageSourceCreateThumbnailAtIndex(
sourceRef, 0, (__bridge CFDictionaryRef) @{
(id)kCGImageSourceShouldAllowFloat : @YES,
(id)kCGImageSourceCreateThumbnailWithTransform : @YES,
(id)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
(id)kCGImageSourceThumbnailMaxPixelSize : @(maxPixelSize),
});
} else {
// Get an image in full size. This is faster than `CGImageSourceCreateThumbnailAtIndex`
// and consumes less memory if only the target size doesn't require downscaling.
imageRef = CGImageSourceCreateImageAtIndex(
sourceRef, 0, (__bridge CFDictionaryRef) @{
(id)kCGImageSourceShouldAllowFloat : @YES,
});
}
NSDictionary<NSString *, NSNumber *> *options = @{
(id)kCGImageSourceShouldAllowFloat : @YES,
(id)kCGImageSourceCreateThumbnailWithTransform : @YES,
(id)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
(id)kCGImageSourceThumbnailMaxPixelSize : @(maxPixelSize),
};
// Get thumbnail
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
CFRelease(sourceRef);
if (!imageRef) {
return nil;
@@ -53,9 +53,10 @@ RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTImageView)
view.renderingMode = json ? UIImageRenderingModeAlwaysTemplate : defaultView.renderingMode;
}
RCT_EXPORT_METHOD(
getSize : (NSURLRequest *)request successBlock : (RCTResponseSenderBlock)
successBlock errorBlock : (RCTResponseErrorBlock)errorBlock)
RCT_EXPORT_METHOD(getSize
: (NSURLRequest *)request successBlock
: (RCTResponseSenderBlock)successBlock errorBlock
: (RCTResponseErrorBlock)errorBlock)
{
[[self.bridge moduleForName:@"ImageLoader"
lazilyLoadIfNecessary:YES] getImageSizeForURLRequest:request
@@ -68,9 +69,10 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
getSizeWithHeaders : (RCTImageSource *)source resolve : (RCTPromiseResolveBlock)
resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(getSizeWithHeaders
: (RCTImageSource *)source resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
[[self.bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES]
getImageSizeForURLRequest:source.request
@@ -83,9 +85,10 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
prefetchImage : (NSURLRequest *)request resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)
reject)
RCT_EXPORT_METHOD(prefetchImage
: (NSURLRequest *)request resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
if (!request) {
reject(@"E_INVALID_URI", @"Cannot prefetch an image for an empty URI", nil);
@@ -104,8 +107,10 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
queryCache : (NSArray *)requests resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(queryCache
: (NSArray *)requests resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
resolve([[self.bridge moduleForName:@"ImageLoader"] getImageCacheStatus:requests]);
}
@@ -87,8 +87,10 @@ RCT_EXPORT_MODULE()
[self sendEventWithName:@"url" body:notification.userInfo];
}
RCT_EXPORT_METHOD(
openURL : (NSURL *)URL resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(openURL
: (NSURL *)URL resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
[RCTSharedApplication() openURL:URL
options:@{}
@@ -112,8 +114,10 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
canOpenURL : (NSURL *)URL resolve : (RCTPromiseResolveBlock)resolve reject : (__unused RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(canOpenURL
: (NSURL *)URL resolve
: (RCTPromiseResolveBlock)resolve reject
: (__unused RCTPromiseRejectBlock)reject)
{
if (RCTRunningInAppExtension()) {
// Technically Today widgets can open urls, but supporting that would require
@@ -177,9 +181,11 @@ RCT_EXPORT_METHOD(openSettings : (RCTPromiseResolveBlock)resolve reject : (__unu
}];
}
RCT_EXPORT_METHOD(
sendIntent : (NSString *)action extras : (NSArray *_Nullable)extras resolve : (RCTPromiseResolveBlock)
resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(sendIntent
: (NSString *)action extras
: (NSArray *_Nullable)extras resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
RCTLogError(@"Not implemented: %@", NSStringFromSelector(_cmd));
}
+1 -4
View File
@@ -87,7 +87,7 @@ export default function Ansi({
<View style={styles.container}>
{parsedLines.map((items, i) => (
<View style={styles.line} key={i}>
<Text style={styles.text}>
<Text>
{items.map((bundle, key) => {
const textStyle =
bundle.fg && COLORS[bundle.fg]
@@ -122,7 +122,4 @@ const styles = StyleSheet.create({
line: {
flexDirection: 'row',
},
text: {
flexGrow: 1,
},
});
@@ -118,9 +118,11 @@ RCT_EXPORT_METHOD(disconnectAnimatedNodes : (double)parentTag childTag : (double
}];
}
RCT_EXPORT_METHOD(
startAnimatingNode : (double)animationId nodeTag : (double)nodeTag config : (NSDictionary<NSString *, id> *)
config endCallback : (RCTResponseSenderBlock)callBack)
RCT_EXPORT_METHOD(startAnimatingNode
: (double)animationId nodeTag
: (double)nodeTag config
: (NSDictionary<NSString *, id> *)config endCallback
: (RCTResponseSenderBlock)callBack)
{
[self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
[nodesManager startAnimatingNode:[NSNumber numberWithDouble:animationId]
@@ -226,9 +228,10 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue : (double)tag)
}];
}
RCT_EXPORT_METHOD(
addAnimatedEventToView : (double)viewTag eventName : (nonnull NSString *)
eventName eventMapping : (JS::NativeAnimatedModule::EventMapping &)eventMapping)
RCT_EXPORT_METHOD(addAnimatedEventToView
: (double)viewTag eventName
: (nonnull NSString *)eventName eventMapping
: (JS::NativeAnimatedModule::EventMapping &)eventMapping)
{
NSMutableDictionary *eventMappingDict = [NSMutableDictionary new];
eventMappingDict[@"nativeEventPath"] = RCTConvertVecToArray(eventMapping.nativeEventPath());
@@ -244,9 +247,10 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
removeAnimatedEventFromView : (double)viewTag eventName : (nonnull NSString *)eventName animatedNodeTag : (double)
animatedNodeTag)
RCT_EXPORT_METHOD(removeAnimatedEventFromView
: (double)viewTag eventName
: (nonnull NSString *)eventName animatedNodeTag
: (double)animatedNodeTag)
{
[self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
[nodesManager removeAnimatedEventFromView:[NSNumber numberWithDouble:viewTag]
@@ -108,9 +108,11 @@ RCT_EXPORT_METHOD(disconnectAnimatedNodes : (double)parentTag childTag : (double
}];
}
RCT_EXPORT_METHOD(
startAnimatingNode : (double)animationId nodeTag : (double)nodeTag config : (NSDictionary<NSString *, id> *)
config endCallback : (RCTResponseSenderBlock)callBack)
RCT_EXPORT_METHOD(startAnimatingNode
: (double)animationId nodeTag
: (double)nodeTag config
: (NSDictionary<NSString *, id> *)config endCallback
: (RCTResponseSenderBlock)callBack)
{
[self queueFlushedOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
[nodesManager startAnimatingNode:[NSNumber numberWithDouble:animationId]
@@ -202,9 +204,10 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue : (double)tag)
}];
}
RCT_EXPORT_METHOD(
addAnimatedEventToView : (double)viewTag eventName : (nonnull NSString *)
eventName eventMapping : (JS::NativeAnimatedModule::EventMapping &)eventMapping)
RCT_EXPORT_METHOD(addAnimatedEventToView
: (double)viewTag eventName
: (nonnull NSString *)eventName eventMapping
: (JS::NativeAnimatedModule::EventMapping &)eventMapping)
{
NSMutableDictionary *eventMappingDict = [NSMutableDictionary new];
eventMappingDict[@"nativeEventPath"] = RCTConvertVecToArray(eventMapping.nativeEventPath());
@@ -220,9 +223,10 @@ RCT_EXPORT_METHOD(
}];
}
RCT_EXPORT_METHOD(
removeAnimatedEventFromView : (double)viewTag eventName : (nonnull NSString *)eventName animatedNodeTag : (double)
animatedNodeTag)
RCT_EXPORT_METHOD(removeAnimatedEventFromView
: (double)viewTag eventName
: (nonnull NSString *)eventName animatedNodeTag
: (double)animatedNodeTag)
{
[self queueOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
[nodesManager removeAnimatedEventFromView:[NSNumber numberWithDouble:viewTag]
@@ -179,17 +179,8 @@ const validAttributesForNonEventProps = {
backgroundColor: {process: require('../StyleSheet/processColor').default},
transform: true,
transformOrigin: true,
experimental_backgroundImage: ReactNativeFeatureFlags.enableNativeCSSParsing()
? (true as const)
: {process: require('../StyleSheet/processBackgroundImage').default},
experimental_backgroundSize: {
process: require('../StyleSheet/processBackgroundSize').default,
},
experimental_backgroundPosition: {
process: require('../StyleSheet/processBackgroundPosition').default,
},
experimental_backgroundRepeat: {
process: require('../StyleSheet/processBackgroundRepeat').default,
experimental_backgroundImage: {
process: require('../StyleSheet/processBackgroundImage').default,
},
boxShadow: ReactNativeFeatureFlags.enableNativeCSSParsing()
? (true as const)
@@ -23,9 +23,7 @@ export function unstable_hasComponent(name: string): boolean {
hasNativeComponent = global.__nativeComponentRegistry__hasComponent(name);
componentNameToExists.set(name, hasNativeComponent);
} else {
throw new Error(
`unstable_hasComponent('${name}'): Global function is not registered`,
);
throw `unstable_hasComponent('${name}'): Global function is not registered`;
}
}
return hasNativeComponent;
@@ -797,9 +797,9 @@ RCT_EXPORT_MODULE()
#pragma mark - JS API
RCT_EXPORT_METHOD(
sendRequest : (JS::NativeNetworkingIOS::SpecSendRequestQuery &)query callback : (RCTResponseSenderBlock)
responseSender)
RCT_EXPORT_METHOD(sendRequest
: (JS::NativeNetworkingIOS::SpecSendRequestQuery &)query callback
: (RCTResponseSenderBlock)responseSender)
{
NSString *method = query.method();
NSString *url = query.url();
+39 -1
View File
@@ -14,6 +14,7 @@ import type {
EventCallback,
EventListener,
} from '../../src/private/webapis/dom/events/EventTarget';
import type Performance from '../../src/private/webapis/performance/Performance';
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
import Event from '../../src/private/webapis/dom/events/Event';
@@ -33,7 +34,13 @@ const RCTNetworking = require('./RCTNetworking').default;
const base64 = require('base64-js');
const invariant = require('invariant');
const PERFORMANCE_TRACK_NAME = 'Network (JS-initiated only)';
const PERFORMANCE_TRACK_GROUP = 'Chrome DevTools Temp Compat';
declare var performance: Performance;
const DEBUG_NETWORK_SEND_DELAY: false = false; // Set to a number of milliseconds when debugging
const LABEL_FOR_MISSING_URL_FOR_PROFILING = 'Unknown URL';
export type NativeResponseType = 'base64' | 'blob' | 'text';
export type ResponseType =
@@ -134,6 +141,7 @@ class XMLHttpRequest extends EventTarget {
static DONE: number = DONE;
static _interceptor: ?XHRInterceptor = null;
static _profiling: boolean = false;
UNSENT: number = UNSENT;
OPENED: number = OPENED;
@@ -174,6 +182,10 @@ class XMLHttpRequest extends EventTarget {
XMLHttpRequest._interceptor = interceptor;
}
static enableProfiling(enableProfiling: boolean): void {
XMLHttpRequest._profiling = enableProfiling;
}
constructor() {
super();
this._reset();
@@ -377,12 +389,23 @@ class XMLHttpRequest extends EventTarget {
return;
}
const start = XMLHttpRequest._profiling ? performance.now() : undefined;
if (!this._response) {
this._response = responseText;
} else {
this._response += responseText;
}
if (XMLHttpRequest._profiling) {
console.timeStamp(
'Incremental Data: ' + this._getMeasureURL(),
start,
undefined,
PERFORMANCE_TRACK_NAME,
PERFORMANCE_TRACK_GROUP,
);
}
XMLHttpRequest._interceptor &&
XMLHttpRequest._interceptor.dataReceived(requestId, responseText);
@@ -427,7 +450,16 @@ class XMLHttpRequest extends EventTarget {
this._clearSubscriptions();
this._requestId = null;
this.setReadyState(this.DONE);
if (XMLHttpRequest._profiling && this._startTime != null) {
const start = this._startTime;
console.timeStamp(
this._getMeasureURL(),
start,
undefined,
PERFORMANCE_TRACK_NAME,
PERFORMANCE_TRACK_GROUP,
);
}
if (error) {
XMLHttpRequest._interceptor &&
XMLHttpRequest._interceptor.loadingFailed(requestId, error);
@@ -697,6 +729,12 @@ class XMLHttpRequest extends EventTarget {
super.addEventListener(type, listener);
}
_getMeasureURL(): string {
return (
this._trackingName ?? this._url ?? LABEL_FOR_MISSING_URL_FOR_PROFILING
);
}
/*
* `on<event>` event handling (without JS prototype magic).
*/
@@ -8,26 +8,15 @@
* @format
*/
import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
import Pressability, {
type EventHandlers,
type PressabilityConfig,
} from './Pressability';
import {useEffect, useInsertionEffect, useRef} from 'react';
import {useEffect, useRef} from 'react';
declare function usePressability(config: PressabilityConfig): EventHandlers;
declare function usePressability(config: null | void): null | EventHandlers;
// Experiments with using `useInsertionEffect` instead of `useEffect`, which
// changes whether `Pressability` is configured or reset when inm a hidden
// Activity. With `useInsertionEffect`, `Pressability` behaves more like a
// platform control (e.g. Pointer Events), especially with respect to events
// like focus and blur.
const useConfigurationEffect =
ReactNativeFeatureFlags.configurePressabilityDuringInsertion()
? useInsertionEffect
: useEffect;
/**
* Creates a persistent instance of `Pressability` that automatically configures
* itself and resets. Accepts null `config` to support lazy initialization. Once
@@ -51,7 +40,7 @@ export default function usePressability(
// On the initial mount, this is a no-op. On updates, `pressability` will be
// re-configured to use the new configuration.
useConfigurationEffect(() => {
useEffect(() => {
if (config != null && pressability != null) {
pressability.configure(config);
}
@@ -59,7 +48,7 @@ export default function usePressability(
// On unmount, reset pending state and timers inside `pressability`. This is
// a separate effect because we do not want to reset when `config` changes.
useConfigurationEffect(() => {
useEffect(() => {
if (pressability != null) {
return () => {
pressability.reset();
@@ -327,9 +327,10 @@ RCT_EXPORT_METHOD(getApplicationIconBadgeNumber : (RCTResponseSenderBlock)callba
callback(@[ @(RCTSharedApplication().applicationIconBadgeNumber) ]);
}
RCT_EXPORT_METHOD(
requestPermissions : (JS::NativePushNotificationManagerIOS::SpecRequestPermissionsPermission &)
permissions resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(requestPermissions
: (JS::NativePushNotificationManagerIOS::SpecRequestPermissionsPermission &)permissions resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
if (RCTRunningInAppExtension()) {
reject(
@@ -505,8 +506,9 @@ RCT_EXPORT_METHOD(cancelLocalNotifications : (NSDictionary<NSString *, id> *)use
}];
}
RCT_EXPORT_METHOD(
getInitialNotification : (RCTPromiseResolveBlock)resolve reject : (__unused RCTPromiseRejectBlock)reject)
RCT_EXPORT_METHOD(getInitialNotification
: (RCTPromiseResolveBlock)resolve reject
: (__unused RCTPromiseRejectBlock)reject)
{
// The user actioned a local or remote notification to launch the app. Notification is represented by UNNotification.
// Set this property in the implementation of
@@ -0,0 +1,152 @@
/**
* 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
*/
import type {
HostInstance,
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
NativeMethods,
} from '../../../src/private/types/HostInstance';
import type {
InternalInstanceHandle,
ViewConfig,
} from '../../Renderer/shims/ReactNativeTypes';
import TextInputState from '../../Components/TextInput/TextInputState';
import {getNodeFromInternalInstanceHandle} from '../../ReactNative/RendererProxy';
import {getFabricUIManager} from '../FabricUIManager';
import {create} from './ReactNativeAttributePayload';
import warnForStyleProps from './warnForStyleProps';
import nullthrows from 'nullthrows';
const {
measure: fabricMeasure,
measureInWindow: fabricMeasureInWindow,
measureLayout: fabricMeasureLayout,
getBoundingClientRect: fabricGetBoundingClientRect,
setNativeProps,
} = nullthrows(getFabricUIManager());
const noop = () => {};
/**
* This is used for refs on host components.
*/
export default class ReactFabricHostComponent implements NativeMethods {
// These need to be accessible from `ReactFabricPublicInstanceUtils`.
__nativeTag: number;
__internalInstanceHandle: InternalInstanceHandle;
_viewConfig: ViewConfig;
constructor(
tag: number,
viewConfig: ViewConfig,
internalInstanceHandle: InternalInstanceHandle,
) {
this.__nativeTag = tag;
this._viewConfig = viewConfig;
this.__internalInstanceHandle = internalInstanceHandle;
}
blur() {
// $FlowFixMe[incompatible-type] - Error supressed during the migration of HostInstance to ReactNativeElement
TextInputState.blurTextInput(this);
}
focus() {
// $FlowFixMe[incompatible-type] - Error supressed during the migration of HostInstance to ReactNativeElement
TextInputState.focusTextInput(this);
}
measure(callback: MeasureOnSuccessCallback) {
const node = getNodeFromInternalInstanceHandle(
this.__internalInstanceHandle,
);
if (node != null) {
fabricMeasure(node, callback);
}
}
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
const node = getNodeFromInternalInstanceHandle(
this.__internalInstanceHandle,
);
if (node != null) {
fabricMeasureInWindow(node, callback);
}
}
measureLayout(
relativeToNativeNode: number | HostInstance,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void /* currently unused */,
) {
if (
typeof relativeToNativeNode === 'number' ||
!(relativeToNativeNode instanceof ReactFabricHostComponent)
) {
if (__DEV__) {
console.error(
'Warning: ref.measureLayout must be called with a ref to a native component.',
);
}
return;
}
const toStateNode = getNodeFromInternalInstanceHandle(
this.__internalInstanceHandle,
);
const fromStateNode = getNodeFromInternalInstanceHandle(
relativeToNativeNode.__internalInstanceHandle,
);
if (toStateNode != null && fromStateNode != null) {
fabricMeasureLayout(
toStateNode,
fromStateNode,
onFail != null ? onFail : noop,
onSuccess != null ? onSuccess : noop,
);
}
}
unstable_getBoundingClientRect(): DOMRect {
const node = getNodeFromInternalInstanceHandle(
this.__internalInstanceHandle,
);
if (node != null) {
const rect = fabricGetBoundingClientRect(node, true);
if (rect) {
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
}
}
// Empty rect if any of the above failed
return new DOMRect(0, 0, 0, 0);
}
setNativeProps(nativeProps: {...}): void {
if (__DEV__) {
warnForStyleProps(nativeProps, this._viewConfig.validAttributes);
}
const updatePayload = create(nativeProps, this._viewConfig.validAttributes);
const node = getNodeFromInternalInstanceHandle(
this.__internalInstanceHandle,
);
if (node != null && updatePayload != null) {
setNativeProps(node, updatePayload);
}
}
}
@@ -13,62 +13,124 @@
* instances and get some data from them (like their instance handle / fiber).
*/
import type ReactNativeDocumentT from '../../../src/private/webapis/dom/nodes/ReactNativeDocument';
import typeof * as ReactNativeDocumentModuleT from '../../../src/private/webapis/dom/nodes/ReactNativeDocument';
import type ReactNativeElementT from '../../../src/private/webapis/dom/nodes/ReactNativeElement';
import type ReadOnlyTextT from '../../../src/private/webapis/dom/nodes/ReadOnlyText';
import typeof * as RendererProxyT from '../../ReactNative/RendererProxy';
import type {
InternalInstanceHandle,
Node,
ViewConfig,
} from '../../Renderer/shims/ReactNativeTypes';
import type {RootTag} from '../RootTag';
import type ReactFabricHostComponentT from './ReactFabricHostComponent';
import ReactNativeDocument, {
createReactNativeDocument,
} from '../../../src/private/webapis/dom/nodes/ReactNativeDocument';
import ReactNativeElement from '../../../src/private/webapis/dom/nodes/ReactNativeElement';
import ReadOnlyText from '../../../src/private/webapis/dom/nodes/ReadOnlyText';
import * as RendererProxy from '../../ReactNative/RendererProxy';
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
export opaque type PublicRootInstance = mixed;
// Lazy loaded to avoid evaluating the module when using the legacy renderer.
let ReactNativeDocumentModuleObject: ?ReactNativeDocumentModuleT;
let ReactFabricHostComponentClass: Class<ReactFabricHostComponentT>;
let ReactNativeElementClass: Class<ReactNativeElementT>;
let ReadOnlyTextClass: Class<ReadOnlyTextT>;
let RendererProxy: RendererProxyT;
function getReactNativeDocumentModule(): ReactNativeDocumentModuleT {
if (ReactNativeDocumentModuleObject == null) {
// We initialize this lazily to avoid a require cycle.
ReactNativeDocumentModuleObject = require('../../../src/private/webapis/dom/nodes/ReactNativeDocument');
}
return ReactNativeDocumentModuleObject;
}
function getReactNativeElementClass(): Class<ReactNativeElementT> {
if (ReactNativeElementClass == null) {
ReactNativeElementClass =
require('../../../src/private/webapis/dom/nodes/ReactNativeElement').default;
}
return ReactNativeElementClass;
}
function getReactFabricHostComponentClass(): Class<ReactFabricHostComponentT> {
if (ReactFabricHostComponentClass == null) {
ReactFabricHostComponentClass =
require('./ReactFabricHostComponent').default;
}
return ReactFabricHostComponentClass;
}
function getReadOnlyTextClass(): Class<ReadOnlyTextT> {
if (ReadOnlyTextClass == null) {
ReadOnlyTextClass =
require('../../../src/private/webapis/dom/nodes/ReadOnlyText').default;
}
return ReadOnlyTextClass;
}
export function createPublicRootInstance(rootTag: RootTag): PublicRootInstance {
if (ReactNativeFeatureFlags.enableAccessToHostTreeInFabric()) {
const ReactNativeDocumentModule = getReactNativeDocumentModule();
// $FlowExpectedError[incompatible-return]
return ReactNativeDocumentModule.createReactNativeDocument(rootTag);
}
// $FlowExpectedError[incompatible-return]
return createReactNativeDocument(rootTag);
return null;
}
export function createPublicInstance(
tag: number,
viewConfig: ViewConfig,
internalInstanceHandle: InternalInstanceHandle,
ownerDocument: ReactNativeDocument,
): ReactNativeElement {
return new ReactNativeElement(
tag,
viewConfig,
internalInstanceHandle,
ownerDocument,
);
ownerDocument: ReactNativeDocumentT,
): ReactFabricHostComponentT | ReactNativeElementT {
if (ReactNativeFeatureFlags.enableAccessToHostTreeInFabric()) {
const ReactNativeElement = getReactNativeElementClass();
return new ReactNativeElement(
tag,
viewConfig,
internalInstanceHandle,
ownerDocument,
);
} else {
const ReactFabricHostComponent = getReactFabricHostComponentClass();
return new ReactFabricHostComponent(
tag,
viewConfig,
internalInstanceHandle,
);
}
}
export function createPublicTextInstance(
internalInstanceHandle: InternalInstanceHandle,
ownerDocument: ReactNativeDocument,
): ReadOnlyText {
ownerDocument: ReactNativeDocumentT,
): ReadOnlyTextT {
const ReadOnlyText = getReadOnlyTextClass();
return new ReadOnlyText(internalInstanceHandle, ownerDocument);
}
export function getNativeTagFromPublicInstance(
publicInstance: ReactNativeElement,
publicInstance: ReactFabricHostComponentT | ReactNativeElementT,
): number {
return publicInstance.__nativeTag;
}
export function getNodeFromPublicInstance(
publicInstance: ReactNativeElement,
publicInstance: ReactFabricHostComponentT | ReactNativeElementT,
): ?Node {
// Avoid loading ReactFabric if using an instance from the legacy renderer.
if (publicInstance.__internalInstanceHandle == null) {
return null;
}
if (RendererProxy == null) {
RendererProxy = require('../../ReactNative/RendererProxy');
}
return RendererProxy.getNodeFromInternalInstanceHandle(
// $FlowExpectedError[incompatible-type] __internalInstanceHandle is always an InternalInstanceHandle from React when we get here.
publicInstance.__internalInstanceHandle,
@@ -76,7 +138,7 @@ export function getNodeFromPublicInstance(
}
export function getInternalInstanceHandleFromPublicInstance(
publicInstance: ReactNativeElement,
publicInstance: ReactFabricHostComponentT | ReactNativeElementT,
): InternalInstanceHandle {
// TODO(T174762768): Remove this once OSS versions of renderers will be synced.
// $FlowExpectedError[prop-missing] Keeping this for backwards-compatibility with the renderers versions in open source.
@@ -0,0 +1,75 @@
/**
* 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
*/
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import type {
InternalInstanceHandle,
ViewConfig,
} from 'react-native/Libraries/Renderer/shims/ReactNativeTypes';
import type ReactNativeDocument from 'react-native/src/private/webapis/dom/nodes/ReactNativeDocument';
import * as Fantom from '@react-native/fantom';
import ReactFabricHostComponent from 'react-native/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent';
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
// Create fake parameters for the class.
const tag = 11;
const viewConfig: ViewConfig = {
uiViewClassName: 'test',
validAttributes: {
style: {},
},
};
// $FlowExpectedError[incompatible-type]
const internalInstanceHandle: InternalInstanceHandle = {};
// $FlowExpectedError[incompatible-type]
const ownerDocument: ReactNativeDocument = {};
const ITERATIONS = 100;
const now = Fantom.unstable_benchmark.now;
/* eslint-disable no-new */
Fantom.unstable_benchmark
.suite('ReactNativeElement vs. ReactFabricHostComponent', {
minIterations: 50000,
})
.test('ReactNativeElement', () => {
// This logic is very fast and if we only run it once the cost of calling
// the benchmark function itself is significant. Calling it in a loop and
// computing the average is more accurate to account for that.
const start = now();
for (let i = 0; i < ITERATIONS; i++) {
new ReactNativeElement(
tag,
viewConfig,
internalInstanceHandle,
ownerDocument,
);
}
const end = now();
return {
overriddenDuration: (end - start) / ITERATIONS,
};
})
.test('ReactFabricHostComponent', () => {
// This logic is very fast and if we only run it once the cost of calling
// the benchmark function itself is significant. Calling it in a loop and
// computing the average is more accurate to account for that.
const start = now();
for (let i = 0; i < ITERATIONS; i++) {
new ReactFabricHostComponent(tag, viewConfig, internalInstanceHandle);
}
const end = now();
return {
overriddenDuration: (end - start) / ITERATIONS,
};
});
@@ -0,0 +1,353 @@
/**
* 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
* @fantom_flags enableAccessToHostTreeInFabric:*
*/
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import type {HostInstance} from 'react-native';
import ReactNativeElement from '../../../../src/private/webapis/dom/nodes/ReactNativeElement';
import TextInput from '../../../Components/TextInput/TextInput';
import TextInputState from '../../../Components/TextInput/TextInputState';
import View from '../../../Components/View/View';
import ReactFabricHostComponent from '../ReactFabricHostComponent';
import * as Fantom from '@react-native/fantom';
import nullthrows from 'nullthrows';
import * as React from 'react';
import {createRef} from 'react';
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
// TODO: move these tests to the test file for `ReactNativeElement` when the legacy implementation is removed.
describe('ReactFabricPublicInstance', () => {
it('should provide instances of the right class as refs in host components', () => {
const nodeRef = createRef<HostInstance>();
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(<View ref={nodeRef} />);
});
const node = nullthrows(nodeRef.current);
expect(node).toBeInstanceOf(
ReactNativeFeatureFlags.enableAccessToHostTreeInFabric()
? ReactNativeElement
: ReactFabricHostComponent,
);
});
describe('blur', () => {
test('blur() invokes TextInputState', () => {
const root = Fantom.createRoot();
const nodeRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(<TextInput ref={nodeRef} />);
});
const node = nullthrows(nodeRef.current);
const blurTextInput = jest.fn();
// We don't support view commands in Fantom yet, so we have to mock this.
TextInputState.blurTextInput = blurTextInput;
Fantom.runTask(() => {
node.blur();
});
expect(blurTextInput).toHaveBeenCalledTimes(1);
expect(blurTextInput.mock.calls).toEqual([[node]]);
});
});
describe('focus', () => {
test('focus() invokes TextInputState', () => {
const root = Fantom.createRoot();
const ref = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(<TextInput ref={ref} />);
});
const node = nullthrows(ref.current);
const focusTextInput = jest.fn();
// We don't support view commands in Fantom yet, so we have to mock this.
TextInputState.focusTextInput = focusTextInput;
Fantom.runTask(() => {
node.focus();
});
expect(focusTextInput).toHaveBeenCalledTimes(1);
expect(focusTextInput.mock.calls).toEqual([[node]]);
});
});
describe('measure', () => {
it('component.measure(...) invokes callback', () => {
const root = Fantom.createRoot();
const ref = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={ref}
/>,
);
});
const node = nullthrows(ref.current);
const callback = jest.fn();
node.measure(callback);
expect(callback).toHaveBeenCalledTimes(1);
expect(callback.mock.calls).toEqual([[10, 10, 100, 100, 10, 10]]);
});
it('unmounted.measure(...) does nothing', () => {
const root = Fantom.createRoot();
const ref = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={ref}
/>,
);
});
const node = nullthrows(ref.current);
Fantom.runTask(() => {
root.render(<></>);
});
const callback = jest.fn();
node.measure(callback);
expect(callback).not.toHaveBeenCalled();
});
});
describe('measureInWindow', () => {
it('component.measureInWindow(...) invokes callback', () => {
const root = Fantom.createRoot();
const ref = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={ref}
/>,
);
});
const node = nullthrows(ref.current);
const callback = jest.fn();
node.measureInWindow(callback);
expect(callback).toHaveBeenCalledTimes(1);
expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]);
});
it('unmounted.measureInWindow(...) does nothing', () => {
const root = Fantom.createRoot();
const ref = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={ref}
/>,
);
});
const node = nullthrows(ref.current);
Fantom.runTask(() => {
root.render(<></>);
});
const callback = jest.fn();
node.measureInWindow(callback);
expect(callback).not.toHaveBeenCalled();
});
});
describe('measureLayout', () => {
it('component.measureLayout(component, ...) invokes callback', () => {
const root = Fantom.createRoot();
const parentRef = createRef<HostInstance>();
const childRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={parentRef}>
<View
style={{width: 10, height: 10, left: 20, top: 20}}
ref={childRef}
/>
</View>,
);
});
const parentNode = nullthrows(parentRef.current);
const childNode = nullthrows(childRef.current);
const callback = jest.fn();
childNode.measureLayout(parentNode, callback);
expect(callback).toHaveBeenCalledTimes(1);
expect(callback.mock.calls).toEqual([[20, 20, 10, 10]]);
});
it('unmounted.measureLayout(component, ...) does nothing', () => {
const root = Fantom.createRoot();
const parentRef = createRef<HostInstance>();
const childRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={parentRef}>
<View
style={{width: 10, height: 10, left: 20, top: 20}}
ref={childRef}
/>
</View>,
);
});
const parentNode = nullthrows(parentRef.current);
const childNode = nullthrows(childRef.current);
Fantom.runTask(() => {
root.render(
<View style={{width: 100, height: 100, left: 10, top: 10}} />,
);
});
const callback = jest.fn();
childNode.measureLayout(parentNode, callback);
expect(callback).not.toHaveBeenCalled();
});
it('component.measureLayout(unmounted, ...) does nothing', () => {
const root = Fantom.createRoot();
const parentRef = createRef<HostInstance>();
const childRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={parentRef}>
<View
style={{width: 10, height: 10, left: 20, top: 20}}
ref={childRef}
/>
</View>,
);
});
const parentNode = nullthrows(parentRef.current);
const childNode = nullthrows(childRef.current);
Fantom.runTask(() => {
root.render(
<View style={{width: 100, height: 100, left: 10, top: 10}} />,
);
});
const callback = jest.fn();
parentNode.measureLayout(childNode, callback);
expect(callback).not.toHaveBeenCalled();
});
it('unmounted.measureLayout(unmounted, ...) does nothing', () => {
const root = Fantom.createRoot();
const parentRef = createRef<HostInstance>();
const childRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(
<View
style={{width: 100, height: 100, left: 10, top: 10}}
ref={parentRef}>
<View
style={{width: 10, height: 10, left: 20, top: 20}}
ref={childRef}
/>
</View>,
);
});
const parentNode = nullthrows(parentRef.current);
const childNode = nullthrows(childRef.current);
Fantom.runTask(() => {
root.render(<></>);
});
const callback = jest.fn();
childNode.measureLayout(parentNode, callback);
expect(callback).not.toHaveBeenCalled();
});
});
describe('setNativeProps', () => {
it('should propagate changes to the host component', () => {
const root = Fantom.createRoot();
const nodeRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(<View ref={nodeRef} testID="first test id" />);
});
expect(
root
.getRenderedOutput({
props: ['testID'],
})
.toJSX(),
).toEqual(<rn-view testID={'first test id'} />);
const element = nullthrows(nodeRef.current);
Fantom.runTask(() => {
element.setNativeProps({testID: 'second test id'});
});
expect(
root
.getRenderedOutput({
props: ['testID'],
})
.toJSX(),
).toEqual(<rn-view testID={'second test id'} />);
});
});
});
@@ -1,181 +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.
*
* @fantom_flags updateRuntimeShadowNodeReferencesOnCommit:true
* @fantom_react_fb_flags passChildrenWhenCloningPersistedNodes:true
* @flow strict-local
* @format
*/
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import * as Fantom from '@react-native/fantom';
import * as React from 'react';
import {View} from 'react-native';
describe('Render updates with passChildrenWhenCloningPersistedNodes', () => {
it('updates the runtime shadow node reference correctly when using sync on commit', () => {
const root = Fantom.createRoot();
// Initial render setting to row items next to each other
Fantom.runTask(() => {
root.render(
<View nativeID="parent" style={{flex: 1, flexDirection: 'row'}}>
<View
nativeID="initial-child-1"
key="1"
style={{width: 100, height: 32}}
/>
<View
nativeID="initial-child-2"
key="2"
style={{width: 100, height: 32}}>
<View nativeID="sub-child-2-1" key="1" />
</View>
</View>,
);
});
// Insert new items on the row between the previous two items
Fantom.runTask(() => {
root.render(
<View nativeID="parent" style={{flex: 1, flexDirection: 'row'}}>
<View
nativeID="initial-child-1"
key="1"
style={{width: 100, height: 32}}
/>
<View
nativeID="inserted-child-1"
key="3"
style={{width: 100, height: 32}}
/>
<View
nativeID="initial-child-2"
key="2"
style={{width: 100, height: 32}}>
<View nativeID="sub-child-2-1" key="1" />
</View>
<View
nativeID="inserted-child-2"
key="4"
style={{width: 100, height: 32}}
/>
<View
nativeID="inserted-child-3"
key="5"
style={{width: 100, height: 32}}
/>
</View>,
);
});
// Update a prop on the children of the original row item to force a clone
Fantom.runTask(() => {
root.render(
<View nativeID="parent" style={{flex: 1, flexDirection: 'row'}}>
<View
nativeID="initial-child-1"
key="1"
style={{width: 100, height: 32}}
/>
<View
nativeID="inserted-child-1"
key="3"
style={{width: 100, height: 32}}
/>
<View
nativeID="initial-child-2"
key="2"
style={{width: 100, height: 32}}>
<View
nativeID="sub-child-2-1"
key="1"
testID="prop-change-to-force-clone"
/>
</View>
<View
nativeID="inserted-child-2"
key="4"
style={{width: 100, height: 32}}
/>
<View
nativeID="inserted-child-3"
key="5"
style={{width: 100, height: 32}}
/>
</View>,
);
});
// The row items should all be layed out next to each other
expect(
root
.getRenderedOutput({
includeLayoutMetrics: true,
props: ['layoutMetrics-frame', 'nativeID'],
})
.toJSON(),
).toEqual({
type: 'View',
props: {
'layoutMetrics-frame': '{x:0,y:0,width:390,height:844}',
nativeID: 'parent',
},
children: [
{
type: 'View',
props: {
'layoutMetrics-frame': '{x:0,y:0,width:100,height:32}',
nativeID: 'initial-child-1',
},
children: [],
},
{
type: 'View',
props: {
'layoutMetrics-frame': '{x:100,y:0,width:100,height:32}',
nativeID: 'inserted-child-1',
},
children: [],
},
{
type: 'View',
props: {
'layoutMetrics-frame': '{x:200,y:0,width:100,height:32}',
nativeID: 'initial-child-2',
},
children: [
{
type: 'View',
props: {
'layoutMetrics-frame': '{x:0,y:0,width:100,height:0}',
nativeID: 'sub-child-2-1',
},
children: [],
},
],
},
{
type: 'View',
props: {
'layoutMetrics-frame': '{x:300,y:0,width:100,height:32}',
nativeID: 'inserted-child-2',
},
children: [],
},
{
type: 'View',
props: {
'layoutMetrics-frame': '{x:400,y:0,width:100,height:32}',
nativeID: 'inserted-child-3',
},
children: [],
},
],
});
});
});
@@ -17,12 +17,6 @@ const ReactNativeStyleAttributes =
const resolveAssetSource = require('../Image/resolveAssetSource').default;
const processBackgroundImage =
require('../StyleSheet/processBackgroundImage').default;
const processBackgroundPosition =
require('../StyleSheet/processBackgroundPosition').default;
const processBackgroundRepeat =
require('../StyleSheet/processBackgroundRepeat').default;
const processBackgroundSize =
require('../StyleSheet/processBackgroundSize').default;
const processColor = require('../StyleSheet/processColor').default;
const processColorArray = require('../StyleSheet/processColorArray').default;
const processFilter = require('../StyleSheet/processFilter').default;
@@ -209,12 +203,6 @@ function getProcessorForType(typeName: string): ?(nextProp: any) => any {
return processFilter;
case 'BackgroundImage':
return processBackgroundImage;
case 'BackgroundPosition':
return processBackgroundPosition;
case 'BackgroundRepeat':
return processBackgroundRepeat;
case 'BackgroundSize':
return processBackgroundSize;
case 'ImageSource':
return resolveAssetSource;
case 'BoxShadow':
@@ -7,9 +7,9 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<90e5b8f55761c6a4805052d5b49689b8>>
*
* This file is no longer sync'd from the facebook/react repository.
* The version compatability check is removed. Use at your own risk.
* This file was sync'd from the facebook/react repository.
*/
"use strict";
@@ -19455,6 +19455,13 @@ __DEV__ &&
setSuspenseHandler = function (newShouldSuspendImpl) {
shouldSuspendImpl = newShouldSuspendImpl;
};
var isomorphicReactPackageVersion = React.version;
if ("19.2.0" !== isomorphicReactPackageVersion)
throw Error(
'Incompatible React versions: The "react" and "react-native-renderer" packages must have the exact same version. Instead got:\n - react: ' +
(isomorphicReactPackageVersion +
"\n - react-native-renderer: 19.2.0\nLearn more: https://react.dev/warnings/version-mismatch")
);
if (
"function" !==
typeof ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog
@@ -7,9 +7,9 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<14f9eca680f3065d18eda114fb4bea9f>>
*
* This file is no longer sync'd from the facebook/react repository.
* The version compatability check is removed. Use at your own risk.
* This file was sync'd from the facebook/react repository.
*/
"use strict";
@@ -10918,6 +10918,13 @@ function updateContainer(element, container, parentComponent, callback) {
entangleTransitions(element, parentComponent, lane));
return lane;
}
var isomorphicReactPackageVersion = React.version;
if ("19.2.0" !== isomorphicReactPackageVersion)
throw Error(
'Incompatible React versions: The "react" and "react-native-renderer" packages must have the exact same version. Instead got:\n - react: ' +
(isomorphicReactPackageVersion +
"\n - react-native-renderer: 19.2.0\nLearn more: https://react.dev/warnings/version-mismatch")
);
if (
"function" !==
typeof ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog
@@ -7,9 +7,9 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<238b7d9e5ffe0f30b64b3b5c7c156088>>
*
* This file is no longer sync'd from the facebook/react repository.
* The version compatability check is removed. Use at your own risk.
* This file was sync'd from the facebook/react repository.
*/
"use strict";
@@ -12713,6 +12713,13 @@ function updateContainer(element, container, parentComponent, callback) {
entangleTransitions(element, parentComponent, lane));
return lane;
}
var isomorphicReactPackageVersion = React.version;
if ("19.2.0" !== isomorphicReactPackageVersion)
throw Error(
'Incompatible React versions: The "react" and "react-native-renderer" packages must have the exact same version. Instead got:\n - react: ' +
(isomorphicReactPackageVersion +
"\n - react-native-renderer: 19.2.0\nLearn more: https://react.dev/warnings/version-mismatch")
);
if (
"function" !==
typeof ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog
@@ -7,7 +7,9 @@
* @noformat
* @nolint
* @flow
* @generated SignedSource<<cf323fc5ca893bab5669c7d321660412>>
* @generated SignedSource<<16b364e89f43b8a47832b0dfb98af11e>>
*
* This file was sync'd from the facebook/react repository.
*/
'use strict';
@@ -7,7 +7,9 @@
* @noformat
* @nolint
* @flow strict-local
* @generated SignedSource<<908f5fb85384725318e261f40e49d9a6>>
* @generated SignedSource<<1dd9e9c3f20e37ae14e485fc6ee3d9e9>>
*
* This file was sync'd from the facebook/react repository.
*/
'use strict';
@@ -7,9 +7,9 @@
* @noformat
* @nolint
* @flow
* @generated SignedSource<<e2c46705ed927302dbe9332dafba459d>>
*
* This file is no longer sync'd from the facebook/react repository.
* The version compatability check is removed. Use at your own risk.
* This file was sync'd from the facebook/react repository.
*/
'use strict';
@@ -7,7 +7,9 @@
* @noformat
* @nolint
* @flow strict
* @generated SignedSource<<c0e57723772ea5f1aa8c3c897ac3c216>>
* @generated SignedSource<<989e6e2e860dc2af7ba983849111bda8>>
*
* This file was sync'd from the facebook/react repository.
*/
import type {
@@ -7,7 +7,9 @@
* @noformat
* @nolint
* @flow strict-local
* @generated SignedSource<<1f7876c0dc0b05685a730513dc410236>>
* @generated SignedSource<<67d18226984338ab9301147ce0a7d414>>
*
* This file was sync'd from the facebook/react repository.
*/
'use strict';

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