diff --git a/.editorconfig b/.editorconfig
index eeda81f4e0cb..4ac4973fb15f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,12 +9,3 @@ end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
-
-[*.gradle]
-indent_size = 4
-
-[*.kts]
-indent_size = 4
-
-[BUCK]
-indent_size = 4
diff --git a/.eslintignore b/.eslintignore
index e16e0140326a..6109bd95fecd 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -13,6 +13,8 @@ packages/*/dist
packages/*/types_generated
packages/debugger-frontend/dist/**/*
packages/react-native-codegen/lib
+private/react-native-codegen-typescript-test/lib/**/*
**/Pods/*
**/*.macos.js
**/*.windows.js
+**/__fixtures__/**
diff --git a/.eslintrc.js b/.eslintrc.js
index a6d2c177a278..82ef6ae75f76 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -35,6 +35,9 @@ 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',
},
},
{
@@ -95,7 +98,7 @@ module.exports = {
'**/__fixtures__/**/*.js',
'**/__mocks__/**/*.js',
'**/__tests__/**/*.js',
- 'packages/react-native/jest/**/*.js',
+ 'packages/jest-preset/jest/**/*.js',
'packages/rn-tester/**/*.js',
],
globals: {
diff --git a/.flowconfig b/.flowconfig
index 1faa6debeb19..6c657dce6f54 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -8,9 +8,6 @@
; Ignore the codegen e2e tests
/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeEnumTurboModule.js
-; Ignore the Dangerfile
-/private/react-native-bots/dangerfile.js
-
; Ignore "BUCK" generated dirs
/\.buckd/
@@ -69,18 +66,12 @@ munge_underscores=true
module.name_mapper='^react-native$' -> '/packages/react-native/index.js'
module.name_mapper='^react-native/\(.*\)$' -> '/packages/react-native/\1'
module.name_mapper='^@react-native/dev-middleware$' -> '/packages/dev-middleware'
-module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\|xml\)$' -> '/packages/react-native/Libraries/Image/RelativeImageStub'
+module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\|xml\|ktx\|heic\|heif\)$' -> '/packages/react-native/Libraries/Image/RelativeImageStub'
module.system.haste.module_ref_prefix=m#
react.runtime=automatic
-suppress_type=$FlowIssue
-suppress_type=$FlowFixMe
-suppress_type=$FlowFixMeProps
-suppress_type=$FlowFixMeState
-suppress_type=$FlowFixMeEmpty
-
ban_spread_key_props=true
[lints]
@@ -104,4 +95,4 @@ untyped-import
untyped-type-import
[version]
-^0.275.0
+^0.314.0
diff --git a/.github/ISSUE_TEMPLATE/debugger_bug_report.yml b/.github/ISSUE_TEMPLATE/debugger_bug_report.yml
index be4ea9617263..1d7200d2a61d 100644
--- a/.github/ISSUE_TEMPLATE/debugger_bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/debugger_bug_report.yml
@@ -1,6 +1,6 @@
name: 🔍 Debugger - Bug Report
description: Report a bug with React Native DevTools and the New Debugger
-labels: ["Needs: Triage :mag:", "Debugger"]
+labels: ["Needs: Triage :mag:", "Debugging"]
body:
- type: markdown
diff --git a/.github/actions/build-android/action.yml b/.github/actions/build-android/action.yml
index 91f8e25bf1d0..3466b817a382 100644
--- a/.github/actions/build-android/action.yml
+++ b/.github/actions/build-android/action.yml
@@ -4,9 +4,6 @@ inputs:
release-type:
required: true
description: The type of release we are building. It could be nightly, release or dry-run
- run-e2e-tests:
- default: 'false'
- description: If we need to build to run E2E tests. If yes, we need to build also x86.
gradle-cache-encryption-key:
description: "The encryption key needed to store the Gradle Configuration cache"
runs:
@@ -19,7 +16,19 @@ runs:
uses: ./.github/actions/setup-node
- name: Install node dependencies
uses: ./.github/actions/yarn-install
+ - name: Read current RNVersion
+ shell: bash
+ id: read-rn-version
+ run: |
+ echo "rn-version=$(jq -r '.version' packages/react-native/package.json)" >> $GITHUB_OUTPUT
- name: Set React Native Version
+ # We don't want to set the version for stable branches, because this has been
+ # already set from the 'create release' commits on the release branch.
+ # For testing RC.0, though, the version has not been set yet. In that case, we are on Stable branch and
+ # it is the only case when the version is still 1000.0.0
+ # We also skip this when the PR targets a stable branch (github.base_ref ends with '-stable'),
+ # since the version is already set on the stable branch.
+ if: ${{ !endsWith(github.ref_name, '-stable') && !endsWith(github.base_ref || '', '-stable') || endsWith(github.ref_name, '-stable') && steps.read-rn-version.outputs.rn-version == '1000.0.0' }}
shell: bash
run: node ./scripts/releases/set-rn-artifacts-version.js --build-type ${{ inputs.release-type }}
- name: Setup gradle
@@ -28,13 +37,14 @@ runs:
cache-read-only: "false"
cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
- name: Restore Android ccache
- uses: actions/cache/restore@v4
+ uses: actions/cache/restore@v5
with:
path: /github/home/.cache/ccache
- key: v1-ccache-android-${{ github.job }}-${{ github.ref }}
+ key: v2-ccache-android-${{ github.job }}-${{ github.ref }}-${{ hashFiles('packages/react-native/ReactAndroid/**/*.cpp', 'packages/react-native/ReactAndroid/**/*.h', 'packages/react-native/ReactCommon/**/*.cpp', 'packages/react-native/ReactAndroid/**/CMakeLists.txt', 'packages/react-native/ReactCommon/**/CMakeLists.txt') }}
restore-keys: |
- v1-ccache-android-${{ github.job }}-
- v1-ccache-android-
+ v2-ccache-android-${{ github.job }}-${{ github.ref }}-
+ v2-ccache-android-${{ github.job }}-
+ v2-ccache-android-
- name: Show ccache stats
shell: bash
run: ccache -s -v
@@ -43,38 +53,37 @@ runs:
run: |
if [[ "${{ inputs.release-type }}" == "dry-run" ]]; then
# dry-run: we only build ARM64 to save time/resources. For release/nightlies the default is to build all archs.
- if [[ "${{ inputs.run-e2e-tests }}" == 'true' ]]; then
- export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a,x86" # x86 is required for E2E testing
- else
- export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a"
- fi
+ export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a,x86" # x86 is required for E2E testing
+ export HERMES_PREBUILT_FLAG="ORG_GRADLE_PROJECT_react.internal.useHermesNightly=true"
TASKS="publishAllToMavenTempLocal build"
elif [[ "${{ inputs.release-type }}" == "nightly" ]]; then
# nightly: we set isSnapshot to true so artifacts are sent to the right repository on Maven Central.
export ORG_GRADLE_PROJECT_isSnapshot="true"
+ export HERMES_PREBUILT_FLAG="ORG_GRADLE_PROJECT_react.internal.useHermesNightly=true"
TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build"
else
# release: we want to build all archs (default)
+ export HERMES_PREBUILT_FLAG="ORG_GRADLE_PROJECT_react.internal.useHermesStable=true"
TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build"
fi
- ./gradlew $TASKS -PenableWarningsAsErrors=true
+ env "$HERMES_PREBUILT_FLAG" ./gradlew $TASKS -PenableWarningsAsErrors=true
- name: Save Android ccache
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }}
- uses: actions/cache/save@v4
+ uses: actions/cache/save@v5
with:
path: /github/home/.cache/ccache
- key: v1-ccache-android-${{ github.job }}-${{ github.ref }}
+ key: v2-ccache-android-${{ github.job }}-${{ github.ref }}-${{ hashFiles('packages/react-native/ReactAndroid/**/*.cpp', 'packages/react-native/ReactAndroid/**/*.h', 'packages/react-native/ReactCommon/**/*.cpp', 'packages/react-native/ReactAndroid/**/CMakeLists.txt', 'packages/react-native/ReactCommon/**/CMakeLists.txt') }}
- name: Show ccache stats
shell: bash
run: ccache -s -v
- name: Upload Maven Artifacts
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: maven-local
path: /tmp/maven-local
- name: Upload test results
if: ${{ always() }}
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: build-android-results
compression-level: 1
@@ -84,14 +93,14 @@ runs:
packages/react-native/ReactAndroid/build/reports
- name: Upload RNTester APK - hermes-debug
if: ${{ always() }}
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: rntester-debug
path: packages/rn-tester/android/app/build/outputs/apk/debug/
compression-level: 0
- name: Upload RNTester APK - hermes-release
if: ${{ always() }}
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: rntester-release
path: packages/rn-tester/android/app/build/outputs/apk/release/
diff --git a/.github/actions/build-apple-slices-hermes/action.yml b/.github/actions/build-apple-slices-hermes/action.yml
deleted file mode 100644
index 36eda067ef00..000000000000
--- a/.github/actions/build-apple-slices-hermes/action.yml
+++ /dev/null
@@ -1,103 +0,0 @@
-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/API/hermes/hermes.framework" ]]; then
- echo "Successfully built hermes.framework for $SLICE in $FLAVOR"
- else
- echo "Failed to built hermes.framework for $SLICE in $FLAVOR"
- exit 1
- fi
-
- if [[ -d "$FINAL_PATH/API/hermes/hermes.framework.dSYM" ]]; then
- echo "Successfully built hermes.framework.dSYM for $SLICE in $FLAVOR"
- else
- echo "Failed to built hermes.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 }}
diff --git a/.github/actions/build-fantom-runner/action.yml b/.github/actions/build-fantom-runner/action.yml
new file mode 100644
index 000000000000..00ea1d63d2dd
--- /dev/null
+++ b/.github/actions/build-fantom-runner/action.yml
@@ -0,0 +1,84 @@
+name: Build Fantom Runner
+inputs:
+ release-type:
+ required: true
+ description: The type of release we are building. It could be nightly, release or dry-run
+ gradle-cache-encryption-key:
+ description: "The encryption key needed to store the Gradle Configuration cache"
+
+runs:
+ using: composite
+ steps:
+ - name: Install dependencies
+ shell: bash
+ run: |
+ sudo apt update
+ sudo apt install -y git cmake openssl libssl-dev clang
+ - name: Setup git safe folders
+ shell: bash
+ run: git config --global --add safe.directory '*'
+ - name: Setup node.js
+ uses: ./.github/actions/setup-node
+ - name: Install node dependencies
+ uses: ./.github/actions/yarn-install
+ - name: Setup gradle
+ uses: ./.github/actions/setup-gradle
+ with:
+ cache-read-only: "false"
+ cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
+ - name: Restore Fantom ccache
+ uses: actions/cache/restore@v5
+ with:
+ path: /github/home/.cache/ccache
+ key: v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-${{ hashFiles(
+ 'packages/react-native/ReactAndroid/**/*.cpp',
+ 'packages/react-native/ReactAndroid/**/*.h',
+ 'packages/react-native/ReactAndroid/**/CMakeLists.txt',
+ 'packages/react-native/ReactCommon/**/*.cpp',
+ 'packages/react-native/ReactCommon/**/*.h',
+ 'packages/react-native/ReactCommon/**/CMakeLists.txt',
+ 'private/react-native-fantom/tester/**/*.cpp',
+ 'private/react-native-fantom/tester/**/*.h',
+ 'private/react-native-fantom/tester/**/CMakeLists.txt'
+ ) }}
+ restore-keys: |
+ v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-
+ v2-ccache-fantom-${{ github.job }}-
+ v2-ccache-fantom-
+ - name: Show ccache stats (before)
+ shell: bash
+ run: ccache -s -v
+ - name: Build Fantom Runner
+ shell: bash
+ run: yarn workspace @react-native/fantom build
+ env:
+ CC: clang
+ CXX: clang++
+ - name: Save Fantom ccache
+ if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }}
+ uses: actions/cache/save@v5
+ with:
+ path: /github/home/.cache/ccache
+ key: v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-${{ hashFiles(
+ 'packages/react-native/ReactAndroid/**/*.cpp',
+ 'packages/react-native/ReactAndroid/**/*.h',
+ 'packages/react-native/ReactAndroid/**/CMakeLists.txt',
+ 'packages/react-native/ReactCommon/**/*.cpp',
+ 'packages/react-native/ReactCommon/**/*.h',
+ 'packages/react-native/ReactCommon/**/CMakeLists.txt',
+ 'private/react-native-fantom/tester/**/*.cpp',
+ 'private/react-native-fantom/tester/**/*.h',
+ 'private/react-native-fantom/tester/**/CMakeLists.txt'
+ ) }}
+ - name: Show ccache stats (after)
+ shell: bash
+ run: ccache -s -v
+ - name: Copy shared libraries
+ shell: bash
+ run: cp packages/react-native/ReactAndroid/hermes-engine/build/hermes/lib/libhermesvm.so private/react-native-fantom/build/tester/
+ - name: Upload Fantom Runner binary
+ uses: actions/upload-artifact@v6
+ with:
+ name: fantom-runner-binary
+ compression-level: 1
+ path: private/react-native-fantom/build/tester/
diff --git a/.github/actions/build-hermes-macos/action.yml b/.github/actions/build-hermes-macos/action.yml
deleted file mode 100644
index 41c7e6e869c8..000000000000
--- a/.github/actions/build-hermes-macos/action.yml
+++ /dev/null
@@ -1,227 +0,0 @@
-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: Setup node.js
- uses: ./.github/actions/setup-node
- - 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: 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=API/hermes/hermes.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 "hermes.framework.dSYM" .
-
- mkdir -p "$DEST_DIR"
- mv "hermes.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
diff --git a/.github/actions/build-hermesc-apple/action.yml b/.github/actions/build-hermesc-apple/action.yml
deleted file mode 100644
index c4fefdce9e17..000000000000
--- a/.github/actions/build-hermesc-apple/action.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-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
diff --git a/.github/actions/build-hermesc-linux/action.yml b/.github/actions/build-hermesc-linux/action.yml
deleted file mode 100644
index 0c90739d0a72..000000000000
--- a/.github/actions/build-hermesc-linux/action.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-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
diff --git a/.github/actions/build-hermesc-windows/action.yml b/.github/actions/build-hermesc-windows/action.yml
deleted file mode 100644
index 7b80fbc99296..000000000000
--- a/.github/actions/build-hermesc-windows/action.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-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: 'D:\tmp\hermes'
- - name: Set up workspace
- shell: powershell
- run: |
- mkdir -p D:\tmp\hermes\osx-bin
- mkdir -p .\packages\react-native\sdks\hermes
- cp -r -Force D:\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: |
- D:\tmp\hermes\win64-bin\
- D:\tmp\hermes\hermes\icu\
- D:\tmp\hermes\hermes\deps\
- D:\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: D:\tmp\hermes\win64-bin\
diff --git a/.github/actions/build-npm-package/action.yml b/.github/actions/build-npm-package/action.yml
index 807e03a742cf..6bacb3d29dde 100644
--- a/.github/actions/build-npm-package/action.yml
+++ b/.github/actions/build-npm-package/action.yml
@@ -4,9 +4,6 @@ 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
@@ -20,95 +17,14 @@ 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/hermes.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-debug.tar.gz
- cp ${{ inputs.hermes-ws-dir }}/dSYM/Release/hermes.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-release.tar.gz
- name: Download ReactNativeDependencies
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@v7
with:
pattern: ReactNativeDependencies*
path: ./packages/react-native/ReactAndroid/external-artifacts/artifacts
merge-multiple: true
- name: Download ReactCore artifacts
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@v7
with:
pattern: ReactCore*
path: ./packages/react-native/ReactAndroid/external-artifacts/artifacts
@@ -116,12 +32,12 @@ runs:
- name: Print Artifacts Directory
shell: bash
run: ls -lR ./packages/react-native/ReactAndroid/external-artifacts/artifacts/
- - name: Setup node.js
- uses: ./.github/actions/setup-node
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
+ - name: Setup node.js
+ uses: ./.github/actions/setup-node
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Build packages
@@ -149,7 +65,7 @@ runs:
fi
node ./scripts/releases-ci/publish-npm.js -t ${{ inputs.release-type }}
- name: Upload npm logs
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: npm-logs
path: ~/.npm/_logs
@@ -164,7 +80,7 @@ runs:
echo "$FILENAME" > build/react-native-package-version
- name: Upload release package
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
if: ${{ inputs.release-type == 'dry-run' }}
with:
name: react-native-package
diff --git a/.github/actions/create-release/action.yml b/.github/actions/create-release/action.yml
index ff22a0cb3a09..1d26e17e8fcc 100644
--- a/.github/actions/create-release/action.yml
+++ b/.github/actions/create-release/action.yml
@@ -14,6 +14,8 @@ inputs:
runs:
using: composite
steps:
+ - name: Setup node.js
+ uses: ./.github/actions/setup-node
- name: Yarn install
uses: ./.github/actions/yarn-install
- name: Configure Git
diff --git a/.github/actions/diff-js-api-breaking-changes/action.yml b/.github/actions/diff-js-api-breaking-changes/action.yml
deleted file mode 100644
index 25ec197ab022..000000000000
--- a/.github/actions/diff-js-api-breaking-changes/action.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: diff-js-api-breaking-changes
-description: Check for breaking changes in the public React Native JS API
-runs:
- using: composite
- steps:
- - name: Fetch snapshot from PR head
- shell: bash
- env:
- SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes
- run: |
- mkdir $SCRATCH_DIR
- git fetch --depth=1 origin ${{ github.event.pull_request.head.sha }}
- git show ${{ github.event.pull_request.head.sha }}:packages/react-native/ReactNativeApi.d.ts > $SCRATCH_DIR/ReactNativeApi-after.d.ts \
- || echo "" > $SCRATCH_DIR/ReactNativeApi.d.ts
- - name: Run breaking change detection
- shell: bash
- env:
- SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes
- run: |
- node ./scripts/diff-api-snapshot \
- ${{ github.workspace }}/packages/react-native/ReactNativeApi.d.ts \
- $SCRATCH_DIR/ReactNativeApi-after.d.ts \
- > $SCRATCH_DIR/output.json
diff --git a/.github/actions/diff-js-api-changes/action.yml b/.github/actions/diff-js-api-changes/action.yml
new file mode 100644
index 000000000000..cd6a780505ea
--- /dev/null
+++ b/.github/actions/diff-js-api-changes/action.yml
@@ -0,0 +1,73 @@
+name: diff-js-api-changes
+description: Check for breaking changes in the public React Native JS API
+outputs:
+ message:
+ description: Formatted markdown message describing API changes, or empty if no changes
+ value: ${{ steps.format_output.outputs.message }}
+runs:
+ using: composite
+ steps:
+ - name: Fetch PR and main, compute merge base
+ id: merge_base
+ shell: bash
+ env:
+ PR_SHA: ${{ github.event.pull_request.head.sha }}
+ run: |
+ git fetch origin main
+ git fetch origin "$PR_SHA" --depth=500
+ echo "merge_base=$(git merge-base "$PR_SHA" origin/main)" >> $GITHUB_OUTPUT
+
+ - name: Extract before and after API snapshots
+ shell: bash
+ env:
+ SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-changes
+ MERGE_BASE: ${{ steps.merge_base.outputs.merge_base }}
+ PR_SHA: ${{ github.event.pull_request.head.sha }}
+ run: |
+ mkdir -p $SCRATCH_DIR
+ git show "$MERGE_BASE":packages/react-native/ReactNativeApi.d.ts > $SCRATCH_DIR/ReactNativeApi-before.d.ts \
+ || echo "" > $SCRATCH_DIR/ReactNativeApi-before.d.ts
+ git show "$PR_SHA":packages/react-native/ReactNativeApi.d.ts > $SCRATCH_DIR/ReactNativeApi-after.d.ts \
+ || echo "" > $SCRATCH_DIR/ReactNativeApi-after.d.ts
+
+ - name: Run breaking change detection
+ shell: bash
+ env:
+ SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-changes
+ run: |
+ node ./scripts/js-api/diff-api-snapshot \
+ $SCRATCH_DIR/ReactNativeApi-before.d.ts \
+ $SCRATCH_DIR/ReactNativeApi-after.d.ts \
+ > $SCRATCH_DIR/output.json
+
+ - name: Format output message
+ id: format_output
+ shell: bash
+ env:
+ SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-changes
+ run: |
+ if [ ! -f "$SCRATCH_DIR/output.json" ]; then
+ echo "message=" >> $GITHUB_OUTPUT
+ exit 0
+ fi
+
+ RESULT=$(cat $SCRATCH_DIR/output.json | jq -r '.result // empty')
+ if [ -z "$RESULT" ] || [ "$RESULT" = "NON_BREAKING" ]; then
+ echo "message=" >> $GITHUB_OUTPUT
+ exit 0
+ fi
+
+ # Use delimiter for multiline output
+ {
+ echo "message< [!WARNING]"
+ echo "> **JavaScript API change detected**"
+ echo ">"
+ echo "> This PR commits an update to \`ReactNativeApi.d.ts\`, indicating a change to React Native's public JavaScript API."
+ echo ">"
+ echo "> - Please include a **clear changelog message**."
+ echo "> - This change will be subject to additional review."
+ echo ">"
+ echo "> This change was flagged as: \`${RESULT}\`"
+ echo "EOF"
+ } >> $GITHUB_OUTPUT
diff --git a/.github/actions/lint/action.yml b/.github/actions/lint/action.yml
deleted file mode 100644
index 236b07006dc2..000000000000
--- a/.github/actions/lint/action.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-name: lint
-description: Runs all the linters in the codebase
-inputs:
- node-version:
- description: "The node.js version to use"
- required: false
- default: "22"
- github-token:
- description: "The GitHub token used by pull-bot"
- required: true
-runs:
- using: composite
- steps:
- - name: Setup node.js
- uses: ./.github/actions/setup-node
- with:
- node-version: ${{ inputs.node-version }}
- - name: Run yarn install
- uses: ./.github/actions/yarn-install
- - name: Run linters against modified files (analysis-bot)
- shell: bash
- run: yarn lint-ci
- env:
- GITHUB_TOKEN: ${{ inputs.github-token }}
- GITHUB_PR_NUMBER: ${{ github.event.number }}
- - name: Lint code
- shell: bash
- run: ./.github/workflow-scripts/exec_swallow_error.sh yarn lint --format junit -o ./reports/junit/eslint/results.xml
- - name: Lint file structure
- shell: bash
- run: ./.github/workflow-scripts/lint_files.sh
- - name: Verify not committing repo after running build
- shell: bash
- run: yarn run build --validate
- - name: Run flowcheck
- shell: bash
- run: yarn flow-check
- - name: Run typescript check
- shell: bash
- run: yarn test-typescript
- - name: Check license
- shell: bash
- run: ./.github/workflow-scripts/check_license.sh
- - name: Check formatting
- shell: bash
- run: yarn run format-check
- - name: Lint markdown
- shell: bash
- run: yarn run lint-markdown
- - name: Build types
- shell: bash
- run: yarn build-types --skip-snapshot
- - name: Run typescript check of generated types
- shell: bash
- run: yarn test-generated-typescript
diff --git a/.github/actions/maestro-android/action.yml b/.github/actions/maestro-android/action.yml
index 4a24e2c0231e..cbc5ef1b96bc 100644
--- a/.github/actions/maestro-android/action.yml
+++ b/.github/actions/maestro-android/action.yml
@@ -22,6 +22,10 @@ inputs:
required: false
default: "."
description: The directory from which metro should be started
+ emulator-arch:
+ required: false
+ default: x86
+ description: The architecture of the emulator to run
runs:
using: composite
@@ -31,7 +35,7 @@ runs:
run: export MAESTRO_VERSION=1.40.0; curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Set up JDK 17
if: ${{ inputs.install-java == 'true' }}
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'zulu'
@@ -53,7 +57,7 @@ runs:
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 24
- arch: x86
+ arch: ${{ inputs.emulator-arch }}
ram-size: '8192M'
heap-size: '4096M'
disk-size: '10G'
@@ -69,16 +73,18 @@ runs:
NORM_APP_ID=$(echo "${{ inputs.app-id }}" | tr '.' '-')
echo "app-id=$NORM_APP_ID" >> $GITHUB_OUTPUT
- name: Store tests result
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
if: always()
with:
- name: e2e_android_${{ steps.normalize-app-id.outputs.app-id }}_report_${{ inputs.flavor }}_NewArch
+ name: e2e_android_${{ steps.normalize-app-id.outputs.app-id }}_report_${{ inputs.flavor }}_${{ inputs.emulator-arch }}_NewArch
+ overwrite: true
path: |
report.xml
screen.mp4
- name: Store Logs
if: steps.run-tests.outcome == 'failure'
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
- name: maestro-logs-android-${{ steps.normalize-app-id.outputs.app-id }}-${{ inputs.flavor }}-NewArch
+ name: maestro-logs-android-${{ steps.normalize-app-id.outputs.app-id }}-${{ inputs.flavor }}-${{ inputs.emulator-arch }}-NewArch
+ overwrite: true
path: /tmp/MaestroLogs
diff --git a/.github/actions/maestro-ios/action.yml b/.github/actions/maestro-ios/action.yml
index 5ba4f8dc2aaa..4720d1ad5d8d 100644
--- a/.github/actions/maestro-ios/action.yml
+++ b/.github/actions/maestro-ios/action.yml
@@ -30,11 +30,13 @@ runs:
run: |
brew tap facebook/fb
brew install facebook/fb/idb-companion
- - name: Set up JDK 11
- uses: actions/setup-java@v2
+ - name: Set up JDK 17
+ uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'zulu'
+ - name: Setup node.js
+ uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Start Metro in Debug
@@ -64,9 +66,10 @@ runs:
"${{ inputs.working-directory }}"
- name: Store video record
if: always()
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: e2e_ios_${{ inputs.app-id }}_report_${{ inputs.flavor }}_NewArch
+ overwrite: true
path: |
video_record_1.mov
video_record_2.mov
@@ -76,7 +79,8 @@ runs:
report.xml
- name: Store Logs
if: failure() && steps.run-tests.outcome == 'failure'
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: maestro-logs-${{ inputs.app-id }}-${{ inputs.flavor }}-NewArch
+ overwrite: true
path: /tmp/MaestroLogs
diff --git a/.github/actions/post-pr-comment/action.yml b/.github/actions/post-pr-comment/action.yml
new file mode 100644
index 000000000000..e289df1c48a7
--- /dev/null
+++ b/.github/actions/post-pr-comment/action.yml
@@ -0,0 +1,55 @@
+name: post-pr-comment
+description: Post or update a PR comment, or delete if no sections
+inputs:
+ sections:
+ description: 'JSON array of markdown sections to include in comment'
+ required: false
+ default: '[]'
+ header:
+ description: 'Optional header text to display at the top of the comment'
+ required: false
+ default: ''
+ marker:
+ description: 'HTML comment marker to identify this comment'
+ required: true
+runs:
+ using: composite
+ steps:
+ - name: Create, update, or delete comment
+ uses: actions/github-script@v8
+ env:
+ SECTIONS_INPUT: ${{ inputs.sections }}
+ MARKER_INPUT: ${{ inputs.marker }}
+ HEADER_INPUT: ${{ inputs.header }}
+ with:
+ script: |
+ const marker = process.env.MARKER_INPUT;
+ const header = process.env.HEADER_INPUT;
+ const sections = JSON.parse(process.env.SECTIONS_INPUT)
+ .filter(Boolean)
+ .filter(s => s.trim());
+
+ const {owner, repo} = context.repo;
+ const issue_number = context.issue.number;
+
+ const {data: comments} = await github.rest.issues.listComments({
+ owner, repo, issue_number,
+ });
+
+ const existing = comments.find(c => c.body?.includes(marker));
+
+ if (!sections.length) {
+ if (existing) {
+ await github.rest.issues.deleteComment({owner, repo, comment_id: existing.id});
+ }
+ return;
+ }
+
+ const content = sections.join('\n\n');
+ const body = header ? `${marker}\n## ${header}\n\n${content}` : `${marker}\n${content}`;
+
+ if (existing) {
+ await github.rest.issues.updateComment({owner, repo, comment_id: existing.id, body});
+ } else {
+ await github.rest.issues.createComment({owner, repo, issue_number, body});
+ }
diff --git a/.github/actions/prepare-hermes-workspace/action.yml b/.github/actions/prepare-hermes-workspace/action.yml
deleted file mode 100644
index 22dbe356ee58..000000000000
--- a/.github/actions/prepare-hermes-workspace/action.yml
+++ /dev/null
@@ -1,100 +0,0 @@
-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 node.js
- uses: ./.github/actions/setup-node
-
- - 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: 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
diff --git a/.github/actions/restore-hermes-workspace/action.yml b/.github/actions/restore-hermes-workspace/action.yml
deleted file mode 100644
index 0b1cb2594357..000000000000
--- a/.github/actions/restore-hermes-workspace/action.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-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/.
diff --git a/.github/actions/run-fantom-tests/action.yml b/.github/actions/run-fantom-tests/action.yml
new file mode 100644
index 000000000000..8a6fdcd832ac
--- /dev/null
+++ b/.github/actions/run-fantom-tests/action.yml
@@ -0,0 +1,54 @@
+name: Run Fantom Tests
+runs:
+ using: composite
+ steps:
+ - name: Install runtime dependencies
+ shell: bash
+ run: |
+ sudo apt update
+ sudo apt install -y openssl libssl-dev
+ - name: Setup git safe folders
+ shell: bash
+ run: git config --global --add safe.directory '*'
+ - name: Setup node.js
+ uses: ./.github/actions/setup-node
+ - name: Install node dependencies
+ uses: ./.github/actions/yarn-install
+ - name: Download Fantom Runner binary
+ uses: actions/download-artifact@v7
+ with:
+ name: fantom-runner-binary
+ path: private/react-native-fantom/build/tester
+ - name: Make binary executable
+ shell: bash
+ run: chmod +x private/react-native-fantom/build/tester/fantom_tester
+ - name: Run Fantom Tests
+ shell: bash
+ run: |
+ for attempt in 1 2 3; do
+ echo "Attempt $attempt of 3"
+ if [ "$attempt" -eq 1 ]; then
+ if yarn fantom; then
+ exit 0
+ fi
+ else
+ if yarn fantom --onlyFailures; then
+ exit 0
+ fi
+ fi
+ if [ "$attempt" -lt 3 ]; then
+ echo "Attempt $attempt failed. Retrying only failed tests..."
+ fi
+ done
+ echo "All 3 attempts failed."
+ exit 1
+ env:
+ LD_LIBRARY_PATH: ${{ github.workspace }}/private/react-native-fantom/build/tester
+ - name: Upload test results
+ if: ${{ always() }}
+ uses: actions/upload-artifact@v6
+ with:
+ name: run-fantom-tests-results
+ compression-level: 1
+ path: |
+ private/react-native-fantom/build/reports
diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml
index b22fb3e822db..7b5aa82470a4 100644
--- a/.github/actions/setup-node/action.yml
+++ b/.github/actions/setup-node/action.yml
@@ -4,12 +4,12 @@ inputs:
node-version:
description: 'The node.js version to use'
required: false
- default: '22'
+ default: '22.14.0'
runs:
using: "composite"
steps:
- name: Setup node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node-version }}
cache: yarn
diff --git a/.github/actions/setup-xcode-build-cache/action.yml b/.github/actions/setup-xcode-build-cache/action.yml
deleted file mode 100644
index 5d2187b06942..000000000000
--- a/.github/actions/setup-xcode-build-cache/action.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: setup-xcode-build-cache
-description: Add caching to iOS jobs to speed up builds
-inputs:
- hermes-version:
- description: The version of hermes
- required: true
- flavor:
- description: The flavor that is going to be built
- default: Debug
- use-frameworks:
- description: Whether we are bulding with DynamicFrameworks or StaticLibraries
- default: StaticLibraries
- ruby-version:
- description: The ruby version we are going to use
- default: 2.6.10
-
-runs:
- using: composite
- steps:
- - name: See commands.yml with_xcodebuild_cache
- shell: bash
- run: echo "See commands.yml with_xcodebuild_cache"
- - name: Cache podfile lock
- uses: actions/cache@v4
- with:
- path: packages/rn-tester/Podfile.lock
- key: v13-podfilelock-${{ github.job }}-NewArch-${{ inputs.flavor }}-${{ inputs.use-frameworks }}-${{ inputs.ruby-version }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ inputs.hermes-version }}
- - name: Cache cocoapods
- uses: actions/cache@v4
- with:
- path: packages/rn-tester/Pods
- key: v15-cocoapods-${{ github.job }}-NewArch-${{ inputs.flavor }}-${{ inputs.use-frameworks }}-${{ inputs.ruby-version }}-${{ hashfiles('packages/rn-tester/Podfile.lock') }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ inputs.hermes-version}}
diff --git a/.github/actions/setup-xcode/action.yml b/.github/actions/setup-xcode/action.yml
index c0ae6ceccea7..19e3f3e6f06e 100644
--- a/.github/actions/setup-xcode/action.yml
+++ b/.github/actions/setup-xcode/action.yml
@@ -4,7 +4,7 @@ inputs:
xcode-version:
description: 'The xcode version to use'
required: false
- default: '16.2.0'
+ default: '16.4.0'
runs:
using: "composite"
steps:
diff --git a/.github/actions/test-ios-helloworld/action.yml b/.github/actions/test-ios-helloworld/action.yml
index 137efb0a08b2..b325a061d929 100644
--- a/.github/actions/test-ios-helloworld/action.yml
+++ b/.github/actions/test-ios-helloworld/action.yml
@@ -10,12 +10,6 @@ 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:
@@ -23,31 +17,34 @@ runs:
uses: ./.github/actions/setup-xcode
- name: Setup node.js
uses: ./.github/actions/setup-node
- - 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: Run yarn
+ - name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ inputs.ruby-version }}
+ - name: Set Hermes prebuilt version
+ shell: bash
+ run: |
+ node ./scripts/releases/use-hermes-prebuilt.js
+ - name: Run yarn install again, with the correct hermes version
+ uses: ./.github/actions/yarn-install
- name: Download ReactNativeDependencies
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@v7
with:
name: ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/third-party
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
+ - name: Download React Native Prebuilds
+ uses: actions/download-artifact@v7
+ with:
+ name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
+ path: /tmp/ReactCore
+ - name: Print ReactCore folder
+ shell: bash
+ run: ls -lR /tmp/ReactCore
- name: Install iOS dependencies - Configuration ${{ inputs.flavor }};
shell: bash
run: |
@@ -58,21 +55,8 @@ 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"
yarn bootstrap ios "${args[@]}" | cat
diff --git a/.github/actions/test-ios-rntester/action.yml b/.github/actions/test-ios-rntester/action.yml
index 79f820dd34e5..08e355e76858 100644
--- a/.github/actions/test-ios-rntester/action.yml
+++ b/.github/actions/test-ios-rntester/action.yml
@@ -1,31 +1,23 @@
name: test-ios-rntester
description: Test iOS RNTester
inputs:
- use-frameworks:
- description: The dependency building and linking strategy to use. Must be one of "StaticLibraries", "DynamicFrameworks"
- default: StaticLibraries
ruby-version:
description: The version of ruby that must be used
default: 2.6.10
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
+ default: false
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
default: false
+ use-frameworks:
+ description: Whether we have to build with Dynamic Frameworks. If this is set to true, it builds from source
+ required: false
+ default: false
runs:
using: composite
@@ -36,85 +28,54 @@ runs:
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 Hermes prebuilt version
+ shell: bash
+ run: |
+ node ./scripts/releases/use-hermes-prebuilt.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
+ if: ${{ inputs.use-frameworks == 'false' }}
+ uses: actions/download-artifact@v7
with:
name: ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/third-party/
- name: Print third-party folder
+ if: ${{ inputs.use-frameworks == 'false' }}
shell: bash
run: ls -lR /tmp/third-party
- - name: Setup xcode build cache
- uses: ./.github/actions/setup-xcode-build-cache
+ - name: Download React Native Prebuilds
+ if: ${{ inputs.use-frameworks == 'false' }}
+ uses: actions/download-artifact@v7
with:
- hermes-version: ${{ inputs.hermes-version }}
- use-frameworks: ${{ inputs.use-frameworks }}
- flavor: ${{ inputs.flavor }}
- ruby-version: ${{ inputs.ruby-version }}
+ name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
+ path: /tmp/ReactCore
+ - name: Print ReactCore folder
+ if: ${{ inputs.use-frameworks == 'false' }}
+ shell: bash
+ run: ls -lR /tmp/ReactCore
- name: Install CocoaPods dependencies
shell: bash
run: |
- export HERMES_ENGINE_TARBALL_PATH=$HERMES_ENGINE_TARBALL_PATH
-
- if [[ ${{ inputs.use-frameworks }} == "DynamicFrameworks" ]]; then
+ if [[ ${{ inputs.use-frameworks }} == "true" ]]; then
export USE_FRAMEWORKS=dynamic
+ else
+ # If use-frameworks is false, let's use prebuilds
+ 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"
fi
- export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
cd packages/rn-tester
bundle install
- bundle exec pod install
+ bundle exec pod update hermes-engine --no-repo-update
- name: Build RNTester
shell: bash
run: |
@@ -141,24 +102,23 @@ runs:
shell: bash
run: |
echo "zipping tests results"
- cd /Users/distiller/Library/Developer/Xcode
- XCRESULT_PATH=$(find . -name '*.xcresult')
- tar -zcvf xcresults.tar.gz $XCRESULT_PATH
+ cd /Users/runner/Library/Developer/Xcode
+ tar -zcvf xcresults.tar.gz "/tmp/RNTesterTestResults"
- name: Upload artifact
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
if: ${{ inputs.run-unit-tests == 'true' }}
with:
- name: xcresults
- path: /Users/distiller/Library/Developer/Xcode/xcresults.tar.gz
+ name: xcresults-${{ inputs.flavor }}-${{ inputs.use-frameworks == 'true' && 'dynamic-frameworks' || 'static-libraries' }}-Ruby${{ inputs.ruby-version }}
+ path: /Users/runner/Library/Developer/Xcode/xcresults.tar.gz
- name: Upload RNTester App
- if: ${{ inputs.use-frameworks == 'StaticLibraries' && inputs.ruby-version == '2.6.10' }} # This is needed to avoid conflicts with the artifacts
- uses: actions/upload-artifact@v4.3.4
+ if: ${{ inputs.use-frameworks == 'false' && inputs.ruby-version == '2.6.10' }} # This is needed to avoid conflicts with the artifacts
+ uses: actions/upload-artifact@v6
with:
name: RNTesterApp-NewArch-${{ inputs.flavor }}
path: ${{ env.app-path }}
- name: Store test results
if: ${{ inputs.run-unit-tests == 'true' }}
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
- name: test-results
+ name: test-results-${{ inputs.flavor }}-${{ inputs.use-frameworks == 'true' && 'dynamic-frameworks' || 'static-libraries' }}-Ruby${{ inputs.ruby-version }}
path: ./reports/junit
diff --git a/.github/actions/test-js/action.yml b/.github/actions/test-js/action.yml
index 2528973d6e4a..2b5c97a009a0 100644
--- a/.github/actions/test-js/action.yml
+++ b/.github/actions/test-js/action.yml
@@ -19,7 +19,7 @@ runs:
run: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
- name: Upload test results
if: ${{ always() }}
- uses: actions/upload-artifact@v4.3.4
+ uses: actions/upload-artifact@v6
with:
name: test-js-results
compression-level: 1
diff --git a/.github/actions/test-library-on-nightly/action.yml b/.github/actions/test-library-on-nightly/action.yml
deleted file mode 100644
index 5310dae7059f..000000000000
--- a/.github/actions/test-library-on-nightly/action.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-name: test-library-on-nightly
-description: Tests a library on a nightly
-inputs:
- library-npm-package:
- description: The library npm package to add
- required: true
- platform:
- description: whether we want to build for iOS or Android
- required: true
-runs:
- using: composite
- steps:
- - name: Create new app
- shell: bash
- run: |
- cd /tmp
- npx @react-native-community/cli init RNApp --skip-install --version nightly
- - name: Add library
- shell: bash
- run: |
- cd /tmp/RNApp
- yarn add ${{ inputs.library-npm-package }}
-
- # iOS
- - name: Setup xcode
- if: ${{ inputs.platform == 'ios' }}
- uses: ./.github/actions/setup-xcode
- - name: Build iOS
- shell: bash
- if: ${{ inputs.platform == 'ios' }}
- run: |
- cd /tmp/RNApp/ios
- bundle install
- bundle exec pod install
- xcodebuild build \
- -workspace RNApp.xcworkspace \
- -scheme RNApp \
- -sdk iphonesimulator
-
- # Android
- - name: Setup Java for Android
- if: ${{ inputs.platform == 'android' }}
- uses: actions/setup-java@v2
- with:
- java-version: '17'
- distribution: 'zulu'
- - name: Build Android
- shell: bash
- if: ${{ inputs.platform == 'android' }}
- run: |
- cd /tmp/RNApp/android
- ./gradlew assembleDebug
diff --git a/.github/workflow-scripts/__tests__/createDraftRelease-test.js b/.github/workflow-scripts/__tests__/createDraftRelease-test.js
index 77901d4df099..55b73771424a 100644
--- a/.github/workflow-scripts/__tests__/createDraftRelease-test.js
+++ b/.github/workflow-scripts/__tests__/createDraftRelease-test.js
@@ -121,8 +121,57 @@ describe('Create Draft Release', () => {
});
describe('#_computeBody', () => {
- it('computes body for release', async () => {
+ it('falls back to HERMES_VERSION_NAME from version.properties when no hermes version is passed', async () => {
const version = '0.77.1';
+ const hermesVersion = '250829098.0.13';
+ jest.spyOn(fs, 'readFileSync').mockImplementationOnce(() => {
+ return `HERMES_VERSION_NAME=${hermesVersion}\n`;
+ });
+ 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);
+
+ expect(body).toEqual(`${changelog}
+
+---
+
+Hermes V1 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)
+
+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 changelog = `## v${version}
### Breaking Changes
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
@@ -134,20 +183,24 @@ 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(version, changelog);
+ const body = _computeBody(changelog, version, hermesVersion);
expect(body).toEqual(`${changelog}
---
-Hermes dSYMS:
-- [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)
+Hermes V1 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)
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).
@@ -188,6 +241,7 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
status: 201,
json: () =>
Promise.resolve({
+ id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
}),
@@ -208,9 +262,11 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
body: fetchBody,
},
);
- expect(response).toEqual(
- 'https://github.com/facebook/react-native/releases/tag/v0.77.1',
- );
+ expect(response).toEqual({
+ id: 1,
+ html_url:
+ 'https://github.com/facebook/react-native/releases/tag/v0.77.1',
+ });
});
it('creates a draft release for prerelease on GitHub', async () => {
@@ -238,6 +294,7 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
status: 201,
json: () =>
Promise.resolve({
+ id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
}),
@@ -258,9 +315,11 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/
body: fetchBody,
},
);
- expect(response).toEqual(
- 'https://github.com/facebook/react-native/releases/tag/v0.77.1',
- );
+ expect(response).toEqual({
+ id: 1,
+ html_url:
+ 'https://github.com/facebook/react-native/releases/tag/v0.77.1',
+ });
});
it('throws if the post failes', async () => {
diff --git a/.github/workflow-scripts/__tests__/notifyDiscord-test.js b/.github/workflow-scripts/__tests__/notifyDiscord-test.js
deleted file mode 100644
index c87a293e20ce..000000000000
--- a/.github/workflow-scripts/__tests__/notifyDiscord-test.js
+++ /dev/null
@@ -1,189 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-'use strict';
-
-const {
- prepareFailurePayload,
- sendMessageToDiscord,
-} = require('../notifyDiscord');
-
-describe('prepareFailurePayload', () => {
- it('should handle undefined failures', () => {
- const message = prepareFailurePayload(undefined);
- expect(message).toEqual({
- content:
- '⚠️ **React Native Nightly Integration Failures** ⚠️\n\nNo failures to report.',
- });
- });
-
- it('should handle empty failures array', () => {
- const message = prepareFailurePayload([]);
- expect(message).toEqual({
- content:
- '⚠️ **React Native Nightly Integration Failures** ⚠️\n\nNo failures to report.',
- });
- });
-
- it('should format a single failure correctly', () => {
- const failures = [
- {
- library: 'react-native-reanimated',
- platform: 'iOS',
- },
- ];
-
- const message = prepareFailurePayload(failures);
- expect(message).toEqual({
- content:
- '⚠️ **React Native Nightly Integration Failures** ⚠️\n\nThe integration of libraries with React Native nightly failed for the following libraries:\n\n❌ [iOS] react-native-reanimated',
- });
- });
-
- it('should sort multiple failures by platform and library name', () => {
- const failures = [
- {
- library: 'react-native-reanimated',
- platform: 'iOS',
- },
- {
- library: 'react-native-gesture-handler',
- platform: 'Android',
- },
- {
- library: 'react-native-screens',
- platform: 'iOS',
- },
- {
- library: 'react-native-svg',
- platform: 'Android',
- },
- ];
-
- const message = prepareFailurePayload(failures);
-
- // The failures should be sorted: first Android (alphabetically), then iOS
- // Within each platform, libraries should be sorted alphabetically
- expect(message).toEqual({
- content:
- '⚠️ **React Native Nightly Integration Failures** ⚠️\n\nThe integration of libraries with React Native nightly failed for the following libraries:\n\n❌ [Android] react-native-gesture-handler\n❌ [Android] react-native-svg\n❌ [iOS] react-native-reanimated\n❌ [iOS] react-native-screens',
- });
- });
-
- it('should handle failures with missing properties', () => {
- const failures = [
- {
- // Missing library
- platform: 'iOS',
- },
- {
- library: 'react-native-gesture-handler',
- // Missing platform
- },
- {
- // Both missing
- },
- ];
-
- const message = prepareFailurePayload(failures);
-
- expect(message).toEqual({
- content:
- '⚠️ **React Native Nightly Integration Failures** ⚠️\n\nThe integration of libraries with React Native nightly failed for the following libraries:\n\n❌ [iOS] Unknown\n❌ [Unknown] react-native-gesture-handler\n❌ [Unknown] Unknown',
- });
- });
-});
-
-describe('sendMessageToDiscord', () => {
- // Store the original fetch function
- const originalFetch = global.fetch;
-
- // Setup and teardown for each test
- beforeEach(() => {
- // Mock the global fetch function
- global.fetch = jest.fn();
- // Silence console logs during tests
- jest.spyOn(console, 'log').mockImplementation(() => {});
- jest.spyOn(console, 'error').mockImplementation(() => {});
- });
-
- afterEach(() => {
- // Restore the original fetch function
- global.fetch = originalFetch;
- // Restore console functions
- jest.restoreAllMocks();
- });
-
- it('should throw an error if webhook URL is missing', async () => {
- await expect(sendMessageToDiscord(null, {})).rejects.toThrow(
- 'Discord webhook URL is missing',
- );
- });
-
- it('should send a message successfully', async () => {
- // Mock a successful response
- global.fetch.mockResolvedValueOnce({
- ok: true,
- status: 200,
- });
-
- const webhook = 'https://discord.com/api/webhooks/123/abc';
- const message = {content: 'Test message'};
-
- await expect(sendMessageToDiscord(webhook, message)).resolves.not.toThrow();
-
- // Verify fetch was called with the right arguments
- expect(global.fetch).toHaveBeenCalledWith(webhook, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(message),
- });
-
- // Verify console.log was called
- expect(console.log).toHaveBeenCalledWith(
- 'Successfully sent message to Discord',
- );
- });
-
- it('should throw an error if the response is not ok', async () => {
- // Mock a failed response
- global.fetch.mockResolvedValueOnce({
- ok: false,
- status: 400,
- text: jest.fn().mockResolvedValueOnce('Bad Request'),
- });
-
- const webhook = 'https://discord.com/api/webhooks/123/abc';
- const message = {content: 'Test message'};
-
- await expect(sendMessageToDiscord(webhook, message)).rejects.toThrow(
- 'HTTP status code: 400',
- );
-
- // Verify console.error was called
- expect(console.error).toHaveBeenCalledWith(
- 'Failed to send message to Discord: 400 Bad Request',
- );
- });
-
- it('should throw an error if fetch fails', async () => {
- // Mock a network error
- const networkError = new Error('Network error');
- global.fetch.mockRejectedValueOnce(networkError);
-
- const webhook = 'https://discord.com/api/webhooks/123/abc';
- const message = {content: 'Test message'};
-
- await expect(sendMessageToDiscord(webhook, message)).rejects.toThrow(
- 'Network error',
- );
- });
-});
diff --git a/.github/workflow-scripts/__tests__/publishTemplate-test.js b/.github/workflow-scripts/__tests__/publishTemplate-test.js
index 9ddc60016806..9f735a633977 100644
--- a/.github/workflow-scripts/__tests__/publishTemplate-test.js
+++ b/.github/workflow-scripts/__tests__/publishTemplate-test.js
@@ -117,13 +117,13 @@ describe('#verifyPublishedTemplate', () => {
it('will timeout if npm does not update package version after a set number of retries', async () => {
const RETRIES = 2;
- await verifyPublishedTemplate('0.77.0', true, RETRIES),
+ (await verifyPublishedTemplate('0.77.0', true, RETRIES),
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'@react-native-community/template',
'0.77.0',
'latest',
2,
- );
+ ));
});
});
});
diff --git a/.github/workflow-scripts/__tests__/verifyArtifactsAreOnMaven-test.js b/.github/workflow-scripts/__tests__/verifyArtifactsAreOnMaven-test.js
index df1a332ac22f..e77e7c4e2e49 100644
--- a/.github/workflow-scripts/__tests__/verifyArtifactsAreOnMaven-test.js
+++ b/.github/workflow-scripts/__tests__/verifyArtifactsAreOnMaven-test.js
@@ -38,7 +38,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
- 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
+ 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
@@ -55,7 +55,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
- 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
+ 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
@@ -67,7 +67,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(0);
expect(mockFetch).toHaveBeenCalledWith(
- 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
+ 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
@@ -81,7 +81,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockSleep).toHaveBeenCalledTimes(90);
expect(mockExit).toHaveBeenCalledWith(1);
expect(mockFetch).toHaveBeenCalledWith(
- 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1',
+ 'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
});
diff --git a/.github/workflow-scripts/__tests__/verifyReleaseOnNpm-test.js b/.github/workflow-scripts/__tests__/verifyReleaseOnNpm-test.js
index 4850e256b5ab..761c4352b408 100644
--- a/.github/workflow-scripts/__tests__/verifyReleaseOnNpm-test.js
+++ b/.github/workflow-scripts/__tests__/verifyReleaseOnNpm-test.js
@@ -83,13 +83,13 @@ describe('#verifyReleaseOnNPM', () => {
it('will timeout if npm does not update package version after a set number of retries', async () => {
const RETRIES = 2;
- await verifyReleaseOnNpm('0.77.0', true, RETRIES),
+ (await verifyReleaseOnNpm('0.77.0', true, RETRIES),
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'react-native',
'0.77.0',
'latest',
2,
- );
+ ));
});
it('will timeout if npm does not update latest tag after a set number of retries', async () => {
diff --git a/.github/workflow-scripts/analyze_code.sh b/.github/workflow-scripts/analyze_code.sh
deleted file mode 100755
index 8ea078174c1f..000000000000
--- a/.github/workflow-scripts/analyze_code.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-# 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.
-
-export GITHUB_OWNER=-facebook
-export GITHUB_REPO=-react-native
-
-{
- echo eslint
- npm run lint --silent -- --format=json
-
- echo flow
- npm run flow-check --silent --json
-} | node private/react-native-bots/code-analysis-bot.js
-
-STATUS=$?
-if [ $STATUS == 0 ]; then
- echo "Code analyzed successfully."
-else
- echo "Code analysis failed, error status $STATUS."
-fi
-exit $STATUS
diff --git a/.github/workflow-scripts/analyze_scripts.sh b/.github/workflow-scripts/analyze_scripts.sh
index 5f9bcfadee49..cdf280636b2b 100755
--- a/.github/workflow-scripts/analyze_scripts.sh
+++ b/.github/workflow-scripts/analyze_scripts.sh
@@ -16,6 +16,7 @@ if [ -x "$(command -v shellcheck)" ]; then
-type f \
-not -path "*node_modules*" \
-not -path "*third-party*" \
+ -not -path "*vendor*" \
-name '*.sh' \
-exec sh -c 'shellcheck "$1"' -- {} \;
diff --git a/.github/workflow-scripts/checkBranchTarget.js b/.github/workflow-scripts/checkBranchTarget.js
new file mode 100644
index 000000000000..78e95a5e8142
--- /dev/null
+++ b/.github/workflow-scripts/checkBranchTarget.js
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @format
+ */
+
+'use strict';
+
+/**
+ * Validates that the PR targets an appropriate base branch.
+ *
+ * @param {string} baseRef - The base branch ref (e.g., 'main', '0.76-stable')
+ * @returns {{message: string, status: 'PASS'|'FAIL', shouldAddPickLabel: boolean}}
+ */
+function checkBranchTarget(baseRef) {
+ const isMain = baseRef === 'main';
+ const isStable = baseRef.endsWith('-stable');
+
+ let message = '';
+ let status = 'PASS';
+ if (!isMain && !isStable) {
+ status = 'FAIL';
+ message = `> [!CAUTION]
+> **Invalid Base Branch**
+>
+> The base branch for this PR is \`${baseRef}\`, which is not \`main\` or a \`-stable\` branch.
+> [Are you sure you want to target this branch?](https://reactnative.dev/docs/contributing#pull-requests)`;
+ }
+
+ return {
+ message,
+ status,
+ shouldAddPickLabel: isStable,
+ };
+}
+
+module.exports = checkBranchTarget;
diff --git a/.github/workflow-scripts/check_license.sh b/.github/workflow-scripts/check_license.sh
deleted file mode 100755
index 53b9dddcbe60..000000000000
--- a/.github/workflow-scripts/check_license.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-# Make sure we don't introduce accidental references to PATENTS.
-EXPECTED='.github/workflow-scripts/check_license.sh'
-ACTUAL=$(git grep -l PATENTS)
-
-if [ "$EXPECTED" != "$ACTUAL" ]; then
- echo "PATENTS crept into some new files?"
- diff -u <(echo "$EXPECTED") <(echo "$ACTUAL") || true
- exit 1
-fi
diff --git a/.github/workflow-scripts/collectNightlyOutcomes.js b/.github/workflow-scripts/collectNightlyOutcomes.js
deleted file mode 100644
index 1c811c1c1ed7..000000000000
--- a/.github/workflow-scripts/collectNightlyOutcomes.js
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
-
-const fs = require('fs');
-const path = require('path');
-const {
- prepareFailurePayload,
- sendMessageToDiscord,
-} = require('./notifyDiscord');
-
-function readOutcomes() {
- const baseDir = '/tmp';
- let outcomes = [];
- fs.readdirSync(baseDir).forEach(file => {
- const fullPath = path.join(baseDir, file);
- if (fullPath.endsWith('outcome') && fs.statSync(fullPath).isDirectory) {
- fs.readdirSync(fullPath).forEach(subFile => {
- const subFullPath = path.join(fullPath, subFile);
- if (subFullPath.endsWith('outcome')) {
- const [library, status] = String(fs.readFileSync(subFullPath, 'utf8'))
- .trim()
- .split(':');
- const platform = subFile.includes('android') ? 'Android' : 'iOS';
- console.log(
- `[${platform}] ${library} completed with status ${status}`,
- );
- outcomes.push({
- library: library.trim(),
- platform,
- status: status.trim(),
- });
- }
- });
- } else if (fullPath.endsWith('outcome')) {
- const [library, status] = String(fs.readFileSync(fullPath, 'utf8'))
- .trim()
- .split(':');
- const platform = file.includes('android') ? 'Android' : 'iOS';
- console.log(`[${platform}] ${library} completed with status ${status}`);
- outcomes.push({
- library: library.trim(),
- platform,
- status: status.trim(),
- });
- }
- });
- return outcomes;
-}
-
-function printFailures(outcomes) {
- console.log('Printing failures...');
- let failedLibraries = [];
- outcomes.forEach(entry => {
- if (entry.status !== 'success') {
- console.log(
- `❌ [${entry.platform}] ${entry.library} failed with status ${entry.status}`,
- );
- failedLibraries.push({
- library: entry.library,
- platform: entry.platform,
- });
- }
- });
- return failedLibraries;
-}
-
-/**
- * Sends a message to Discord with the list of failures.
- * @param {string} webHook - The Discord webhook URL
- * @param {Array
diff --git a/__docs__/README.md b/__docs__/README.md
index 9f5195a9f81b..dd25a3fd248d 100644
--- a/__docs__/README.md
+++ b/__docs__/README.md
@@ -49,13 +49,16 @@ TODO: Explain the different components of React Native at a high level.
- [passChildrenWhenCloningPersistedNodes](../packages/react-native/ReactCommon/react/renderer/core/__docs__/passChildrenWhenCloning.md)
- Layout
- Mounting
+ - [Animation Backend](../packages/react-native/ReactCommon/react/renderer/animationbackend/__docs__/AnimationBackend.md)
- Native Modules / TurboModules
- JS Runtime
- [Event Loop](../packages/react-native/ReactCommon/react/renderer/runtimescheduler/__docs__/README.md)
- Globals and environment setup
- Error handling
- Developer Tools
- - React DevTools
+ - React Native DevTools
+ - Infrastructure
+ - [Inspector proxy protocol](../packages/dev-middleware/src/inspector-proxy/__docs__/README.md)
- LogBox
- Misc
- Web APIs
@@ -91,8 +94,6 @@ TODO: Explain the different components of React Native at a high level.
- ESLint
- Integration / E2E
- [Fantom](../private/react-native-fantom/__docs__/README.md)
-- Tooling
- - React Native DevTools
### Used by this
diff --git a/build.gradle.kts b/build.gradle.kts
index 4ed9ea7dc9a2..d23181ed7ce7 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,6 +13,7 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.binary.compatibility.validator) apply true
alias(libs.plugins.android.test) apply false
+ alias(libs.plugins.ktfmt) apply true
}
val reactAndroidProperties = java.util.Properties()
@@ -25,10 +26,12 @@ fun getListReactAndroidProperty(name: String) = reactAndroidProperties.getProper
apiValidation {
ignoredPackages.addAll(
- getListReactAndroidProperty("binaryCompatibilityValidator.ignoredPackages"))
+ getListReactAndroidProperty("binaryCompatibilityValidator.ignoredPackages")
+ )
ignoredClasses.addAll(getListReactAndroidProperty("binaryCompatibilityValidator.ignoredClasses"))
nonPublicMarkers.addAll(
- getListReactAndroidProperty("binaryCompatibilityValidator.nonPublicMarkers"))
+ getListReactAndroidProperty("binaryCompatibilityValidator.nonPublicMarkers")
+ )
validationDisabled =
reactAndroidProperties
.getProperty("binaryCompatibilityValidator.validationDisabled")
@@ -36,8 +39,9 @@ apiValidation {
}
version =
- if (project.hasProperty("isSnapshot") &&
- (project.property("isSnapshot") as? String).toBoolean()) {
+ if (
+ project.hasProperty("isSnapshot") && (project.property("isSnapshot") as? String).toBoolean()
+ ) {
"${reactAndroidProperties.getProperty("VERSION_NAME")}-SNAPSHOT"
} else {
reactAndroidProperties.getProperty("VERSION_NAME")
@@ -65,8 +69,10 @@ tasks.register("clean", Delete::class.java) {
description = "Remove all the build files and intermediate build outputs"
dependsOn(gradle.includedBuild("gradle-plugin").task(":clean"))
subprojects.forEach {
- if (it.project.plugins.hasPlugin("com.android.library") ||
- it.project.plugins.hasPlugin("com.android.application")) {
+ if (
+ it.project.plugins.hasPlugin("com.android.library") ||
+ it.project.plugins.hasPlugin("com.android.application")
+ ) {
dependsOn(it.tasks.named("clean"))
}
}
@@ -76,10 +82,13 @@ tasks.register("clean", Delete::class.java) {
delete(rootProject.file("./packages/react-native/sdks/download/"))
delete(rootProject.file("./packages/react-native/sdks/hermes/"))
delete(
- rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/arm64-v8a/"))
+ rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/arm64-v8a/")
+ )
delete(
rootProject.file(
- "./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/"))
+ "./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/"
+ )
+ )
delete(rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/x86/"))
delete(rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/x86_64/"))
delete(rootProject.file("./packages/react-native-codegen/lib"))
@@ -95,38 +104,111 @@ 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") {
description = "Publish the Android artifacts to Sonatype (Maven Central or Snapshot repository)"
dependsOn(":packages:react-native:ReactAndroid:publishToSonatype")
- dependsOn(":packages:react-native:ReactAndroid:hermes-engine:publishToSonatype")
}
-if (project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoolean() == true) {
+var hermesSubstitution: Pair? = null
+
+if (project.findProperty("react.internal.useHermesStable")?.toString()?.toBoolean() == true) {
+ val hermesVersions = java.util.Properties()
+ val hermesVersionPropertiesFile =
+ rootProject.file("./packages/react-native/sdks/hermes-engine/version.properties")
+ hermesVersionPropertiesFile.inputStream().use { hermesVersions.load(it) }
+ val selectedHermesVersion = hermesVersions["HERMES_VERSION_NAME"] as String
+
+ hermesSubstitution = selectedHermesVersion to "Users opted to use stable hermes release"
+} else if (
+ project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoolean() == true
+) {
+ val reactNativePackageJson = rootProject.file("./packages/react-native/package.json")
+ val reactNativePackageJsonContent = reactNativePackageJson.readText()
+ val packageJson = groovy.json.JsonSlurper().parseText(reactNativePackageJsonContent) as Map<*, *>
+
+ val hermesCompilerVersion =
+ (packageJson["dependencies"] as Map<*, *>)["hermes-compiler"] as String
+
+ if (hermesCompilerVersion == "0.0.0") {
+ throw RuntimeException(
+ "Trying to use Hermes Nightly but hermes-compiler version is not specified"
+ )
+ }
+
+ hermesSubstitution = hermesCompilerVersion to "Users opted to use Hermes V1 prebuilt"
+} else {
logger.warn(
"""
********************************************************************************
- INFO: You're using Hermes from nightly as you set
+ INFO: You're building Hermes from source as you set
- react.internal.useHermesNightly=true
+ react.internal.useHermesStable=false
+ react.internal.useHermesNightly=false
in the ./gradle.properties file.
That's fine for local development, but you should not commit this change.
********************************************************************************
- """
- .trimIndent())
+ """
+ .trimIndent()
+ )
+}
+
+if (hermesSubstitution != null) {
+ val (hermesVersion, reason) = hermesSubstitution!!
+ project(":packages:react-native:ReactAndroid:hermes-engine") {
+ tasks.configureEach { enabled = false }
+ }
+
allprojects {
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(project(":packages:react-native:ReactAndroid:hermes-engine"))
- .using(module("com.facebook.react:hermes-android:0.+"))
- .because("Users opted to use hermes from nightly")
+ .using(module("com.facebook.hermes:hermes-android:$hermesVersion"))
+ .because(reason)
}
}
}
}
+
+ktfmt {
+ blockIndent.set(2)
+ continuationIndent.set(4)
+ maxWidth.set(100)
+ removeUnusedImports.set(false)
+ manageTrailingCommas.set(false)
+}
+
+// Configure ktfmt tasks to include gradle-plugin
+listOf("ktfmtCheck", "ktfmtFormat").forEach { taskName ->
+ tasks.named(taskName) { dependsOn(gradle.includedBuild("gradle-plugin").task(":$taskName")) }
+}
+
+allprojects {
+ // Apply exclusions for specific files that should not be formatted
+ val excludePatterns =
+ listOf(
+ "**/build/**",
+ "**/hermes-engine/**",
+ "**/internal/featureflags/**",
+ "**/systeminfo/ReactNativeVersion.kt",
+ )
+ listOf(
+ com.ncorti.ktfmt.gradle.tasks.KtfmtCheckTask::class,
+ com.ncorti.ktfmt.gradle.tasks.KtfmtFormatTask::class,
+ )
+ .forEach { tasks.withType(it) { exclude(excludePatterns) } }
+
+ // Disable the problematic ktfmt script tasks due to symbolic link issues in subprojects
+ afterEvaluate {
+ listOf("ktfmtCheckScripts", "ktfmtFormatScripts").forEach {
+ tasks.findByName(it)?.enabled = false
+ }
+ }
+}
+
+// We intentionally disable the `ktfmtCheck` tasks as the formatting is primarly handled inside
+// fbsource
+allprojects { tasks.withType() { enabled = false } }
diff --git a/flow-typed/environment/node.js b/flow-typed/environment/node.js
index 7969e444e116..1a99ec0dcbd2 100644
--- a/flow-typed/environment/node.js
+++ b/flow-typed/environment/node.js
@@ -21,6 +21,12 @@ interface ErrnoError extends Error {
syscall?: string;
}
+type Node$Conditional = T extends true
+ ? IfTrue
+ : T extends false
+ ? IfFalse
+ : IfTrue | IfFalse;
+
type buffer$NonBufferEncoding =
| 'hex'
| 'HEX'
@@ -192,18 +198,33 @@ declare type Node$Buffer = typeof Buffer;
declare module 'buffer' {
declare var kMaxLength: number;
declare var INSPECT_MAX_BYTES: number;
+
+ declare var constants: Readonly<{
+ MAX_LENGTH: number,
+ MAX_STRING_LENGTH: number,
+ }>;
+
declare function transcode(
source: Node$Buffer,
fromEnc: buffer$Encoding,
toEnc: buffer$Encoding,
): Node$Buffer;
+
+ declare function isUtf8(input: Buffer | ArrayBuffer | $TypedArray): boolean;
+
+ declare function isAscii(input: Buffer | ArrayBuffer | $TypedArray): boolean;
+
+ declare function resolveObjectURL(id: string): Blob | void;
+
declare var Buffer: Node$Buffer;
+ declare var Blob: typeof globalThis.Blob;
+ declare var File: typeof globalThis.File;
}
-type child_process$execOpts = {
+type child_process$execOpts = Readonly<{
cwd?: string,
- env?: Object,
- encoding?: string,
+ env?: Readonly<{[key: string]: string | number | void}>,
+ encoding?: buffer$NonBufferEncoding | 'buffer' | string,
shell?: string,
timeout?: number,
maxBuffer?: number,
@@ -211,8 +232,8 @@ type child_process$execOpts = {
uid?: number,
gid?: number,
windowsHide?: boolean,
- ...
-};
+ signal?: AbortSignal,
+}>;
declare class child_process$Error extends Error {
code: number | string | null;
@@ -225,32 +246,31 @@ declare class child_process$Error extends Error {
cmd: string;
}
-type child_process$execCallback = (
+type child_process$execCallback = (
error: ?child_process$Error,
- stdout: string | Buffer,
- stderr: string | Buffer,
+ stdout: T,
+ stderr: T,
) => void;
-type child_process$execSyncOpts = {
+type child_process$execSyncOpts = Readonly<{
cwd?: string,
input?: string | Buffer | $TypedArray | DataView,
stdio?: string | Array,
- env?: Object,
+ env?: Readonly<{[key: string]: string | number | void}>,
shell?: string,
uid?: number,
gid?: number,
timeout?: number,
killSignal?: string | number,
maxBuffer?: number,
- encoding?: string,
+ encoding?: buffer$NonBufferEncoding | 'buffer' | string,
windowsHide?: boolean,
- ...
-};
+}>;
-type child_process$execFileOpts = {
+type child_process$execFileOpts = Readonly<{
cwd?: string,
- env?: Object,
- encoding?: string,
+ env?: Readonly<{[key: string]: string | number | void}>,
+ encoding?: buffer$NonBufferEncoding | 'buffer' | string,
timeout?: number,
maxBuffer?: number,
killSignal?: string | number,
@@ -259,168 +279,418 @@ type child_process$execFileOpts = {
windowsHide?: boolean,
windowsVerbatimArguments?: boolean,
shell?: boolean | string,
- ...
-};
+ signal?: AbortSignal,
+}>;
-type child_process$execFileCallback = (
- error: ?child_process$Error,
- stdout: string | Buffer,
- stderr: string | Buffer,
-) => void;
+type child_process$execFileCallback =
+ child_process$execCallback;
-type child_process$execFileSyncOpts = {
+type child_process$execFileSyncOpts = Readonly<{
cwd?: string,
input?: string | Buffer | $TypedArray | DataView,
stdio?: string | Array,
- env?: Object,
+ env?: {[key: string]: string | number | void},
uid?: number,
gid?: number,
timeout?: number,
killSignal?: string | number,
maxBuffer?: number,
- encoding?: string,
+ encoding?: buffer$NonBufferEncoding | 'buffer' | string,
windowsHide?: boolean,
shell?: boolean | string,
- ...
-};
+}>;
-type child_process$forkOpts = {
+type child_process$forkOpts = Readonly<{
cwd?: string,
- env?: Object,
+ env?: Readonly<{[key: string]: string | number | void}>,
execPath?: string,
- execArgv?: Array,
+ execArgv?: ReadonlyArray,
silent?: boolean,
- stdio?: Array | string,
+ stdio?:
+ | child_process$StdioPipe
+ | string
+ | Readonly<
+ [
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ ...
+ ],
+ >
+ | Readonly<
+ [
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ string | number,
+ ...
+ ],
+ >
+ | Readonly<
+ [
+ child_process$StdioPipe,
+ string | number,
+ child_process$StdioPipe,
+ ...
+ ],
+ >
+ | Readonly<
+ [
+ string | number,
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ ...
+ ],
+ >
+ | Readonly<[child_process$StdioPipe, string | number, string | number, ...]>
+ | Readonly<[string | number, child_process$StdioPipe, string | number, ...]>
+ | Readonly<[string | number, string | number, child_process$StdioPipe, ...]>
+ | Readonly<[string | number, string | number, string | number, ...]>,
windowsVerbatimArguments?: boolean,
uid?: number,
gid?: number,
- ...
-};
+ serialization?: 'json' | 'advanced',
+ killSignal?: string | number,
+ timeout?: number,
+ signal?: AbortSignal,
+}>;
type child_process$Handle = any; // TODO
-type child_process$spawnOpts = {
+type child_process$StdioPipe = 'pipe' | 'overlapped';
+
+type child_process$spawnOpts = Readonly<{
cwd?: string,
- env?: Object,
+ env?: Readonly<{[key: string]: string | number | void}>,
+ encoding?: buffer$NonBufferEncoding | 'buffer' | string,
argv0?: string,
- stdio?: string | Array,
+ stdio?:
+ | child_process$StdioPipe
+ | string
+ | Readonly<
+ [
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ ...
+ ],
+ >
+ | Readonly<
+ [
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ string | number,
+ ...
+ ],
+ >
+ | Readonly<
+ [
+ child_process$StdioPipe,
+ string | number,
+ child_process$StdioPipe,
+ ...
+ ],
+ >
+ | Readonly<
+ [
+ string | number,
+ child_process$StdioPipe,
+ child_process$StdioPipe,
+ ...
+ ],
+ >
+ | Readonly<[child_process$StdioPipe, string | number, string | number, ...]>
+ | Readonly<[string | number, child_process$StdioPipe, string | number, ...]>
+ | Readonly<[string | number, string | number, child_process$StdioPipe, ...]>
+ | Readonly<[string | number, string | number, string | number, ...]>,
detached?: boolean,
uid?: number,
gid?: number,
shell?: boolean | string,
windowsVerbatimArguments?: boolean,
windowsHide?: boolean,
- ...
-};
+ signal?: AbortSignal,
+ killSignal?: string | number,
+ timeout?: number,
+ serialization?: 'json' | 'advanced',
+}>;
-type child_process$spawnRet = {
+type child_process$spawnSyncRet = Readonly<{
pid: number,
output: Array,
- stdout: Buffer | string,
- stderr: Buffer | string,
+ // TODO: subprocess.stdout may be null in case of error
+ stdout: T,
+ // TODO: subprocess.stderr may be null in case of error
+ stderr: T,
+ // TODO: subprocess.status may be null in case of error or signal
status: number,
- signal: string,
- error: Error,
- ...
-};
+ signal: string | null,
+ error: Error | void,
+}>;
-type child_process$spawnSyncOpts = {
+type child_process$spawnSyncOpts = Readonly<{
cwd?: string,
input?: string | Buffer,
- stdio?: string | Array,
- env?: Object,
+ stdio?: string | ReadonlyArray,
+ env?: Readonly<{[key: string]: string | number | void}>,
uid?: number,
gid?: number,
timeout?: number,
- killSignal?: string,
+ killSignal?: string | number,
maxBuffer?: number,
- encoding?: string,
+ encoding?: buffer$NonBufferEncoding | 'buffer' | string,
shell?: boolean | string,
- ...
-};
-
-type child_process$spawnSyncRet = child_process$spawnRet;
-
-declare class child_process$ChildProcess extends events$EventEmitter {
- channel: Object;
- connected: boolean;
- killed: boolean;
- pid: number;
- exitCode: number | null;
- stderr: stream$Readable;
- stdin: stream$Writable;
- stdio: Array;
- stdout: stream$Readable;
+ windowsHide?: boolean,
+ windowsVerbatimArguments?: boolean,
+}>;
+type child_process$Serializable =
+ | string
+ | number
+ | boolean
+ | bigint
+ | {[key: string]: child_process$Serializable}
+ | Array;
+
+type child_process$SendHandle = net$Server | net$Socket;
+
+declare class child_process$ChildProcessTyped<
+ TStdin extends stream$Writable | null,
+ TStdout extends stream$Readable | null,
+ TStderr extends stream$Readable | null,
+> extends events$EventEmitter
+{
+ +stdin: TStdin;
+ +stdout: TStdout;
+ +stderr: TStderr;
+ +channel: unknown;
+ +stdio: [TStdin, TStdout, TStderr, ...];
+ +killed: boolean;
+ +pid: number;
+ +connected: boolean;
+ +exitCode: number | null;
+ +signalCode: string | null;
+ +spawnargs: Array;
+ +spawnfile: string;
disconnect(): void;
- kill(signal?: string): void;
+ kill(signal?: string | number): boolean;
send(
- message: Object,
- sendHandleOrCallback?: child_process$Handle,
- optionsOrCallback?: Object | Function,
- callback?: Function,
+ message: child_process$Serializable,
+ callback?: (error: Error | null) => void,
+ ): boolean;
+ send(
+ message: child_process$Serializable,
+ sendHandle: child_process$SendHandle,
+ callback?: (error: Error | null) => void,
+ ): boolean;
+ send(
+ message: child_process$Serializable,
+ sendHandle: child_process$SendHandle,
+ options: Readonly<{keepOpen?: boolean}>,
+ callback?: (error: Error | null) => void,
): boolean;
unref(): void;
ref(): void;
}
+/**
+ * @deprecated - Unsafely assumes stdio is piped
+ */
+declare type child_process$ChildProcess = child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+>;
+
declare module 'child_process' {
- declare var ChildProcess: typeof child_process$ChildProcess;
+ declare type ExecOptions = child_process$execOpts;
+ declare type ExecFileOptions = child_process$execFileOpts;
+ declare type ExecSyncOptions = child_process$execSyncOpts;
+ declare type ForkOptions = child_process$forkOpts;
+ declare type SpawnOptions = child_process$spawnOpts;
+ declare type SpawnSyncOptions = child_process$spawnSyncOpts;
+
+ declare var ChildProcess: typeof child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+ >;
+
+ type StringOrBuffer =
+ Opts extends Readonly<{encoding: infer E, ...}>
+ ? E extends buffer$NonBufferEncoding
+ ? string
+ : E extends 'buffer'
+ ? Buffer
+ : string | Buffer
+ : Default;
+
+ type StreamForChannel = Channel extends 0
+ ? stream$Writable
+ : stream$Readable;
+
+ type MaybeStream<
+ Opts,
+ FD extends 0 | 1 | 2,
+ PipeByDefault extends true | false = true,
+ > =
+ Opts extends Readonly<{stdio: infer E, ...}>
+ ? E extends child_process$StdioPipe
+ ? StreamForChannel
+ : E extends string
+ ? null
+ : E[FD] extends child_process$StdioPipe
+ ? StreamForChannel
+ : E[FD] extends string | number
+ ? null
+ : null | StreamForChannel
+ : PipeByDefault extends true
+ ? StreamForChannel
+ : null;
declare function exec(
command: string,
- optionsOrCallback?: child_process$execOpts | child_process$execCallback,
- callback?: child_process$execCallback,
- ): child_process$ChildProcess;
-
- declare function execSync(
+ callback?: child_process$execCallback,
+ ): child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+ >;
+
+ declare function exec(
command: string,
- options: {
- encoding: buffer$NonBufferEncoding,
- ...
- } & child_process$execSyncOpts,
- ): string;
-
- declare function execSync(
+ options: Opts,
+ callback?: child_process$execCallback>,
+ ): child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+ >;
+
+ declare function execSync(
command: string,
- options?: child_process$execSyncOpts,
): Buffer;
+ declare function execSync(
+ command: string,
+ options: Opts,
+ ): StringOrBuffer;
+
declare function execFile(
file: string,
- argsOrOptionsOrCallback?:
- | Array
- | child_process$execFileOpts
- | child_process$execFileCallback,
- optionsOrCallback?:
- | child_process$execFileOpts
- | child_process$execFileCallback,
- callback?: child_process$execFileCallback,
- ): child_process$ChildProcess;
+ argsOrCallback?:
+ | ReadonlyArray
+ | child_process$execFileCallback,
+ callback?: child_process$execFileCallback,
+ ): child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+ >;
+
+ declare function execFile(
+ file: string,
+ args: ReadonlyArray,
+ options: Opts,
+ callback?: child_process$execFileCallback>,
+ ): child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+ >;
+
+ declare function execFile(
+ file: string,
+ options: Opts,
+ callback?: child_process$execFileCallback>,
+ ): child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+ >;
declare function execFileSync(
command: string,
- argsOrOptions?: Array | child_process$execFileSyncOpts,
- options?: child_process$execFileSyncOpts,
- ): Buffer | string;
+ args?: ReadonlyArray,
+ ): Buffer;
+
+ declare function execFileSync(
+ command: string,
+ args: ReadonlyArray,
+ options: Opts,
+ ): StringOrBuffer;
+
+ declare function execFileSync(
+ command: string,
+ options: Opts,
+ ): StringOrBuffer;
declare function fork(
modulePath: string,
- argsOrOptions?: Array | child_process$forkOpts,
- options?: child_process$forkOpts,
- ): child_process$ChildProcess;
+ args?: ReadonlyArray,
+ ): child_process$ChildProcessTyped;
+
+ declare function fork(
+ modulePath: string,
+ args: ReadonlyArray,
+ options: Opts,
+ ): child_process$ChildProcessTyped<
+ MaybeStream,
+ MaybeStream,
+ MaybeStream,
+ >;
+
+ declare function fork(
+ modulePath: string,
+ options: Opts,
+ ): child_process$ChildProcessTyped<
+ MaybeStream,
+ MaybeStream,
+ MaybeStream,
+ >;
declare function spawn(
command: string,
- argsOrOptions?: Array | child_process$spawnOpts,
- options?: child_process$spawnOpts,
- ): child_process$ChildProcess;
+ args?: ReadonlyArray,
+ ): child_process$ChildProcessTyped<
+ stream$Writable,
+ stream$Readable,
+ stream$Readable,
+ >;
+
+ declare function spawn(
+ command: string,
+ args: ReadonlyArray,
+ options: Opts,
+ ): child_process$ChildProcessTyped<
+ MaybeStream,
+ MaybeStream,
+ MaybeStream,
+ >;
+
+ declare function spawn(
+ command: string,
+ options: Opts,
+ ): child_process$ChildProcessTyped<
+ MaybeStream,
+ MaybeStream,
+ MaybeStream,
+ >;
declare function spawnSync(
command: string,
- argsOrOptions?: Array | child_process$spawnSyncOpts,
- options?: child_process$spawnSyncOpts,
- ): child_process$spawnSyncRet;
+ args?: ReadonlyArray,
+ ): child_process$spawnSyncRet;
+
+ declare function spawnSync(
+ command: string,
+ args: ReadonlyArray,
+ options: Opts,
+ ): child_process$spawnSyncRet>;
+
+ declare function spawnSync(
+ command: string,
+ options: Opts,
+ ): child_process$spawnSyncRet>;
}
declare module 'cluster' {
@@ -597,6 +867,7 @@ declare class crypto$Hash extends stream$Duplex {
data: string | Buffer,
input_encoding?: 'utf8' | 'ascii' | 'latin1' | 'binary',
): crypto$Hash;
+ copy(options?: unknown): crypto$Hash;
}
declare class crypto$Hmac extends stream$Duplex {
@@ -655,6 +926,83 @@ type crypto$key =
...
};
+declare class crypto$KeyObject {
+ +asymmetricKeyType?:
+ | 'rsa'
+ | 'rsa-pss'
+ | 'dsa'
+ | 'ec'
+ | 'ed25519'
+ | 'ed448'
+ | 'x25519'
+ | 'x448';
+ +asymmetricKeySize?: number;
+ +symmetricKeySize?: number;
+ +type: 'secret' | 'public' | 'private';
+
+ export(
+ options: Readonly<{
+ type: 'pkcs1' | 'spki' | 'pkcs8' | 'sec1',
+ format: 'pem',
+ }>,
+ ): string;
+ export(
+ options: Readonly<{
+ type: 'pkcs1' | 'spki' | 'pkcs8' | 'sec1',
+ format: 'der',
+ }>,
+ ): Buffer;
+ export(options: Readonly<{format: 'jwk'}>): unknown;
+ equals(otherKeyObject: crypto$KeyObject): boolean;
+}
+
+declare class crypto$X509Certificate {
+ constructor(buffer: string | Buffer | $TypedArray | DataView): void;
+
+ +ca: boolean;
+ +fingerprint: string;
+ +fingerprint256: string;
+ +fingerprint512: string;
+ +issuer: string;
+ +issuerCertificate?: crypto$X509Certificate;
+ +keyUsage: Array;
+ +publicKey: crypto$KeyObject;
+ +raw: Buffer;
+ +serialNumber: string;
+ +subject: string;
+ +subjectAltName: string;
+ +validFrom: string;
+ +validTo: string;
+ +validFromDate: Date;
+ +validToDate: Date;
+
+ checkEmail(
+ email: string,
+ options?: Readonly<{subject?: 'always' | 'default' | 'never'}>,
+ ): string | void;
+ checkHost(
+ name: string,
+ options?: Readonly<{subject?: 'always' | 'default' | 'never'}>,
+ ): string | void;
+ checkIP(ip: string): string | void;
+ checkIssued(otherCert: crypto$X509Certificate): boolean;
+ checkPrivateKey(privateKey: crypto$KeyObject): boolean;
+ toJSON(): string;
+ toLegacyObject(): unknown;
+ toString(): string;
+ verify(publicKey: crypto$KeyObject): boolean;
+}
+
+declare class crypto$Certificate {
+ static exportChallenge(
+ spkac: string | Buffer | $TypedArray | DataView,
+ ): Buffer;
+ static exportPublicKey(
+ spkac: string | Buffer | $TypedArray | DataView,
+ ): Buffer;
+ static verifySpkac(spkac: Buffer | $TypedArray | DataView): boolean;
+}
+
declare module 'crypto' {
declare var DEFAULT_ENCODING: string;
@@ -808,12 +1156,85 @@ declare module 'crypto' {
callback: (err: ?Error, buffer: Buffer) => void,
): void;
declare function randomUUID(
- options?: $ReadOnly<{|disableEntropyCache?: boolean|}>,
+ options?: Readonly<{disableEntropyCache?: boolean}>,
): string;
declare function timingSafeEqual(
a: Buffer | $TypedArray | DataView,
b: Buffer | $TypedArray | DataView,
): boolean;
+ declare function hash(
+ algorithm: string,
+ data: string | Buffer | $TypedArray | DataView,
+ ): Buffer;
+ declare function hash(
+ algorithm: string,
+ data: string | Buffer | $TypedArray | DataView,
+ outputEncoding: buffer$Encoding,
+ ): string;
+ declare function createSecretKey(
+ key: Buffer | $TypedArray | DataView,
+ ): crypto$KeyObject;
+ declare function createSecretKey(
+ key: string,
+ encoding: buffer$Encoding,
+ ): crypto$KeyObject;
+ declare function createPublicKey(
+ key: string | Buffer | crypto$KeyObject | unknown,
+ ): crypto$KeyObject;
+ declare function createPrivateKey(
+ key: string | Buffer | unknown,
+ ): crypto$KeyObject;
+ declare function generateKeyPair(
+ type:
+ | 'rsa'
+ | 'rsa-pss'
+ | 'dsa'
+ | 'ec'
+ | 'ed25519'
+ | 'ed448'
+ | 'x25519'
+ | 'x448',
+ options: unknown,
+ callback: (
+ err: ?Error,
+ publicKey: crypto$KeyObject,
+ privateKey: crypto$KeyObject,
+ ) => void,
+ ): void;
+ declare function generateKeyPairSync(
+ type:
+ | 'rsa'
+ | 'rsa-pss'
+ | 'dsa'
+ | 'ec'
+ | 'ed25519'
+ | 'ed448'
+ | 'x25519'
+ | 'x448',
+ options: unknown,
+ ): {publicKey: crypto$KeyObject, privateKey: crypto$KeyObject, ...};
+ declare function generateKey(
+ type: 'hmac' | 'aes',
+ options: Readonly<{length: number}>,
+ callback: (err: ?Error, key: crypto$KeyObject) => void,
+ ): void;
+ declare function generateKeySync(
+ type: 'hmac' | 'aes',
+ options: Readonly<{length: number}>,
+ ): crypto$KeyObject;
+ declare function checkPrime(
+ candidate: Buffer | $TypedArray | DataView | bigint,
+ options?: Readonly<{checks?: number}>,
+ callback: (err: ?Error, result: boolean) => void,
+ ): void;
+ declare function checkPrimeSync(
+ candidate: Buffer | $TypedArray | DataView | bigint,
+ options?: Readonly<{checks?: number}>,
+ ): boolean;
+ declare class Certificate extends crypto$Certificate {}
+ declare class X509Certificate extends crypto$X509Certificate {}
+ declare class KeyObject extends crypto$KeyObject {}
+ declare var webcrypto: unknown;
}
type net$Socket$address = {
@@ -841,7 +1262,7 @@ declare class dgram$Socket extends events$EventEmitter {
msg: Buffer,
port: number,
address: string,
- callback?: (err: ?Error, bytes: any) => mixed,
+ callback?: (err: ?Error, bytes: any) => unknown,
): void;
send(
msg: Buffer,
@@ -849,7 +1270,7 @@ declare class dgram$Socket extends events$EventEmitter {
length: number,
port: number,
address: string,
- callback?: (err: ?Error, bytes: any) => mixed,
+ callback?: (err: ?Error, bytes: any) => unknown,
): void;
setBroadcast(flag: boolean): void;
setMulticastLoopback(flag: boolean): void;
@@ -1044,6 +1465,8 @@ declare module 'fs' {
declare class FSWatcher extends events$EventEmitter {
close(): void;
+ ref(): this;
+ unref(): this;
}
declare class ReadStream extends stream$Readable {
@@ -1057,6 +1480,7 @@ declare module 'fs' {
declare class Dirent {
name: string | Buffer;
+ parentPath: string;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
@@ -1290,12 +1714,24 @@ declare module 'fs' {
declare function mkdtempSync(prefix: string): string;
declare function readdir(
path: string,
- options: string | {encoding?: string, withFileTypes?: false, ...},
+ options:
+ | string
+ | Readonly<{
+ encoding?: string,
+ recursive?: boolean,
+ withFileTypes?: false,
+ ...
+ }>,
callback: (err: ?ErrnoError, files: Array) => void,
): void;
declare function readdir(
path: string,
- options: {encoding?: string, withFileTypes: true, ...},
+ options: Readonly<{
+ encoding?: string,
+ recursive?: boolean,
+ withFileTypes: true,
+ ...
+ }>,
callback: (err: ?ErrnoError, files: Array) => void,
): void;
declare function readdir(
@@ -1304,11 +1740,23 @@ declare module 'fs' {
): void;
declare function readdirSync(
path: string,
- options?: string | {encoding?: string, withFileTypes?: false, ...},
+ options?:
+ | string
+ | Readonly<{
+ encoding?: string,
+ recursive?: boolean,
+ withFileTypes?: false,
+ }>,
): Array;
declare function readdirSync(
path: string,
- options?: string | {encoding?: string, withFileTypes: true, ...},
+ options?:
+ | string
+ | Readonly<{
+ encoding?: string,
+ recursive?: boolean,
+ withFileTypes: true,
+ }>,
): Array;
declare function close(
fd: number,
@@ -1326,6 +1774,29 @@ declare module 'fs' {
flags: string | number,
callback: (err: ?ErrnoError, fd: number) => void,
): void;
+ declare function openAsBlob(
+ path: string | Buffer | URL,
+ options?: Readonly<{
+ type?: string, // Optional MIME type hint
+ }>,
+ ): Promise;
+ declare function opendir(
+ path: string,
+ options?: Readonly<{
+ encoding?: string,
+ bufferSize?: number,
+ recursive?: boolean,
+ }>,
+ callback: (err: ?ErrnoError, dir: Dir) => void,
+ ): void;
+ declare function opendirSync(
+ path: string,
+ options?: Readonly<{
+ encoding?: string,
+ bufferSize?: number,
+ recursive?: boolean,
+ }>,
+ ): Dir;
declare function openSync(
path: string | Buffer,
flags: string | number,
@@ -1544,7 +2015,15 @@ declare module 'fs' {
): void;
declare function watchFile(
filename: string,
- options?: Object,
+ listener?: (curr: Stats, prev: Stats) => void,
+ ): void;
+ declare function watchFile(
+ filename: string,
+ options?: Readonly<{
+ bigint?: boolean,
+ persistent?: boolean,
+ interval?: number,
+ }>,
listener?: (curr: Stats, prev: Stats) => void,
): void;
declare function unwatchFile(
@@ -1553,7 +2032,16 @@ declare module 'fs' {
): void;
declare function watch(
filename: string,
- options?: Object,
+ listener?: (event: string, filename: string) => void,
+ ): FSWatcher;
+ declare function watch(
+ filename: string,
+ options?: Readonly<{
+ persistent?: boolean,
+ recursive?: boolean,
+ encoding?: string,
+ signal?: AbortSignal,
+ }>,
listener?: (event: string, filename: string) => void,
): FSWatcher;
declare function exists(
@@ -1593,6 +2081,105 @@ declare module 'fs' {
dest: string,
flags?: number,
): void;
+ declare function cp(
+ src: string | URL,
+ dest: string | URL,
+ options: Readonly<{
+ dereference?: boolean,
+ errorOnExist?: boolean,
+ filter?: (src: string, dest: string) => boolean | Promise,
+ force?: boolean,
+ mode?: number,
+ preserveTimestamps?: boolean,
+ recursive?: boolean,
+ verbatimSymlinks?: boolean,
+ }>,
+ callback: (err: ?Error) => void,
+ ): void;
+ declare function cp(
+ src: string | URL,
+ dest: string | URL,
+ callback: (err: ?Error) => void,
+ ): void;
+ declare function cpSync(
+ src: string | URL,
+ dest: string | URL,
+ options?: Readonly<{
+ dereference?: boolean,
+ errorOnExist?: boolean,
+ filter?: (src: string, dest: string) => boolean,
+ force?: boolean,
+ mode?: number,
+ preserveTimestamps?: boolean,
+ recursive?: boolean,
+ verbatimSymlinks?: boolean,
+ }>,
+ ): void;
+
+ declare type GlobOptions = Readonly<{
+ /**
+ * Current working directory.
+ * @default process.cwd()
+ */
+ cwd?: string | void,
+ /**
+ * `true` if the glob should return paths as `Dirent`s, `false` otherwise.
+ * @default false
+ * @since v22.2.0
+ */
+ withFileTypes?: WithFileTypes,
+ /**
+ * Function to filter out files/directories or a
+ * list of glob patterns to be excluded. If a function is provided, return
+ * `true` to exclude the item, `false` to include it.
+ * @default undefined
+ */
+ exclude?:
+ | ((fileName: Node$Conditional) => boolean)
+ | ReadonlyArray,
+ ...
+ }>;
+
+ /**
+ * Retrieves the files matching the specified pattern.
+ *
+ * ```js
+ * import { glob } from 'node:fs';
+ *
+ * glob('*.js', (err, matches) => {
+ * if (err) throw err;
+ * console.log(matches);
+ * });
+ * ```
+ * @since v22.0.0
+ */
+ declare function glob(
+ pattern: string | ReadonlyArray,
+ callback: (err: ?ErrnoError, matches: Array) => void,
+ ): void;
+
+ declare function glob(
+ pattern: string | ReadonlyArray,
+ options: GlobOptions,
+ callback: (
+ err: ?ErrnoError,
+ matches: Node$Conditional, Array>,
+ ) => void,
+ ): void;
+
+ /**
+ * ```js
+ * import { globSync } from 'node:fs';
+ *
+ * console.log(globSync('*.js'));
+ * ```
+ * @since v22.0.0
+ * @returns paths of files that match the pattern.
+ */
+ declare function globSync(
+ pattern: string | ReadonlyArray,
+ options?: GlobOptions,
+ ): Node$Conditional, Array>;
declare var F_OK: number;
declare var R_OK: number;
@@ -1658,17 +2245,55 @@ declare module 'fs' {
retryDelay?: number,
...
};
+ declare class Dir {
+ +path: string;
+ close(): Promise;
+ closeSync(): void;
+ read(): Promise;
+ read(cb: (err?: Error, dirent: ?Dirent) => void): void;
+ readSync(): ?Dirent;
+ @@asyncIterator(): AsyncIterator;
+ }
+ type AppendOrWriteToFileHandle = (
+ data:
+ | string
+ | Buffer
+ | Uint8Array
+ | DataView
+ | AsyncIterable
+ | Iterable
+ | stream$Readable,
+ options: WriteOptions | string,
+ ) => Promise;
declare class FileHandle {
- appendFile(
- data: string | Buffer,
- options: WriteOptions | string,
- ): Promise;
+ appendFile: AppendOrWriteToFileHandle;
chmod(mode: number): Promise;
chown(uid: number, guid: number): Promise;
close(): Promise;
+ createReadStream(
+ options?: Readonly<{
+ encoding?: string,
+ autoClose?: boolean,
+ emitClose?: boolean,
+ start?: number,
+ end?: number,
+ highWaterMark?: number,
+ signal?: AbortSignal,
+ }>,
+ ): ReadStream;
+ createWriteStream(
+ options?: Readonly<{
+ encoding?: string,
+ autoClose?: boolean,
+ emitClose?: boolean,
+ start?: number,
+ highWaterMark?: number,
+ flush?: boolean,
+ }>,
+ ): WriteStream;
datasync(): Promise;
fd: number;
- read(
+ read(
buffer: T,
offset: number,
length: number,
@@ -1678,8 +2303,25 @@ declare module 'fs' {
buffer: T,
...
}>;
+ readableWebStream(
+ options?: Readonly<{autoClose?: boolean}>,
+ ): ReadableStream;
readFile(options: EncodingFlag): Promise;
readFile(options: string): Promise;
+ readLines(
+ options?: Readonly<{
+ encoding?: string,
+ autoClose?: boolean,
+ emitClose?: boolean,
+ start?: number,
+ end?: number,
+ highWaterMark?: number,
+ }>,
+ ): readline$Interface;
+ readv | Array | Array>(
+ buffers: T,
+ position?: number | null,
+ ): Promise<{buffers: T, bytesRead: number}>;
stat(): Promise;
sync(): Promise;
truncate(len?: number): Promise;
@@ -1688,15 +2330,24 @@ declare module 'fs' {
mtime: number | string | Date,
): Promise;
write(
- buffer: Buffer | Uint8Array,
+ buffer: Buffer | Uint8Array | DataView,
offset: number,
length: number,
position: number,
): Promise;
- writeFile(
- data: string | Buffer | Uint8Array,
- options: WriteOptions | string,
+ write(
+ buffer: Buffer | Uint8Array | DataView,
+ options?: Readonly<{
+ offset?: number,
+ length?: number,
+ position?: number,
+ }>,
): Promise;
+ writeFile: AppendOrWriteToFileHandle;
+ writev | Array | Array>(
+ buffers: T,
+ position?: number | null,
+ ): Promise<{buffers: T, bytesWritten: number}>;
}
declare type FSPromisePath = string | Buffer | URL;
@@ -1714,6 +2365,20 @@ declare module 'fs' {
dest: FSPromisePath,
flags?: number,
): Promise,
+ cp(
+ src: string | URL,
+ dest: string | URL,
+ options?: Readonly<{
+ dereference?: boolean,
+ errorOnExist?: boolean,
+ filter?: (src: string, dest: string) => boolean | Promise,
+ force?: boolean,
+ mode?: number,
+ preserveTimestamps?: boolean,
+ recursive?: boolean,
+ verbatimSymlinks?: boolean,
+ }>,
+ ): Promise,
fchmod(filehandle: FileHandle, mode: number): Promise,
fchown(filehandle: FileHandle, uid: number, guid: number): Promise,
fdatasync(filehandle: FileHandle): Promise,
@@ -1725,6 +2390,14 @@ declare module 'fs' {
atime: number | string | Date,
mtime: number | string | Date,
): Promise,
+ glob(
+ pattern: string | ReadonlyArray,
+ options?: GlobOptions,
+ ): Node$Conditional<
+ WithFileTypes,
+ AsyncIterator,
+ AsyncIterator,
+ >,
lchmod(path: FSPromisePath, mode: number): Promise,
lchown(path: FSPromisePath, uid: number, guid: number): Promise,
link(existingPath: FSPromisePath, newPath: FSPromisePath): Promise,
@@ -1745,7 +2418,15 @@ declare module 'fs' {
flags?: string | number,
mode?: number,
): Promise,
- read(
+ opendir(
+ path: string,
+ options?: Readonly<{
+ encoding?: string,
+ bufferSize?: number,
+ recursive?: boolean,
+ }>,
+ ): Promise,
+ read(
filehandle: FileHandle,
buffer: T,
offset: number,
@@ -1758,11 +2439,21 @@ declare module 'fs' {
}>,
readdir: ((
path: FSPromisePath,
- options: string | {encoding?: string, withFileTypes?: false, ...},
+ options:
+ | string
+ | Readonly<{
+ encoding?: string,
+ recursive?: boolean,
+ withFileTypes?: false,
+ }>,
) => Promise>) &
((
path: FSPromisePath,
- options: {encoding?: string, withFileTypes: true, ...},
+ options: Readonly<{
+ encoding?: string,
+ recursive?: boolean,
+ withFileTypes: true,
+ }>,
) => Promise>) &
((path: FSPromisePath) => Promise>),
readFile: ((
@@ -1805,7 +2496,18 @@ declare module 'fs' {
atime: number | string | Date,
mtime: number | string | Date,
): Promise,
- write(
+ watch(
+ filename: FSPromisePath,
+ options?: Readonly<{
+ persistent?: boolean,
+ recursive?: boolean,
+ encoding?: string,
+ signal?: AbortSignal,
+ maxQueue?: number,
+ overflow?: 'ignore' | 'throw',
+ }>,
+ ): AsyncIterator<{eventType: string, filename: ?string}>,
+ write(
filehandle: FileHandle,
buffer: T,
offset: number,
@@ -1827,6 +2529,10 @@ declare module 'fs' {
declare var promises: FSPromise;
}
+declare module 'fs/promises' {
+ declare module.exports: $Exports<'fs'>['promises'];
+}
+
type http$agentOptions = {
keepAlive?: boolean,
keepAliveMsecs?: number,
@@ -1838,7 +2544,8 @@ type http$agentOptions = {
declare class http$Agent<+SocketT = net$Socket> {
constructor(options: http$agentOptions): void;
destroy(): void;
- freeSockets: {[name: string]: $ReadOnlyArray, ...};
+ // $FlowFixMe[incompatible-variance]
+ freeSockets: {[name: string]: ReadonlyArray, ...};
getName(options: {
host: string,
port: number,
@@ -1847,8 +2554,10 @@ declare class http$Agent<+SocketT = net$Socket> {
}): string;
maxFreeSockets: number;
maxSockets: number;
- requests: {[name: string]: $ReadOnlyArray>, ...};
- sockets: {[name: string]: $ReadOnlyArray, ...};
+ // $FlowFixMe[incompatible-variance]
+ requests: {[name: string]: ReadonlyArray>, ...};
+ // $FlowFixMe[incompatible-variance]
+ sockets: {[name: string]: ReadonlyArray, ...};
}
declare class http$IncomingMessage
@@ -1939,7 +2648,7 @@ declare class http$Server extends net$Server {
callback?: Function,
): this;
listening: boolean;
- close(callback?: (error: ?Error) => mixed): this;
+ close(callback?: (error: ?Error) => unknown): this;
closeAllConnections(): void;
closeIdleConnections(): void;
maxHeadersCount: number;
@@ -1975,7 +2684,7 @@ declare class https$Server extends tls$Server {
},
callback?: Function,
): this;
- close(callback?: (error: ?Error) => mixed): this;
+ close(callback?: (error: ?Error) => unknown): this;
closeAllConnections(): void;
closeIdleConnections(): void;
keepAliveTimeout: number;
@@ -1988,7 +2697,7 @@ type requestOptions = {|
auth?: string,
defaultPort?: number,
family?: number,
- headers?: {[key: string]: mixed, ...},
+ headers?: {[key: string]: unknown, ...},
host?: string,
hostname?: string,
localAddress?: string,
@@ -2011,7 +2720,25 @@ type http$requestOptions = {
...
};
+type http$createServerOptions = Readonly<{
+ ...net$createServerOptions,
+ connectionsCheckingInterval?: number,
+ headersTimeout?: number,
+ insecureHTTPParser?: boolean,
+ IncomingMessage?: Class>,
+ joinDuplicateHeaders?: boolean,
+ keepAliveTimeout?: number,
+ maxHeaderSize?: number,
+ requestTimeout?: number,
+ requireHostHeader?: boolean,
+ rejectNonStandardBodyWrites?: boolean,
+ ServerResponse?: Class,
+ uniqueHeaders?: ReadonlyArray>,
+}>;
+
declare module 'http' {
+ export type ServerOptions = http$createServerOptions;
+
declare class Server extends http$Server {}
declare class Agent extends http$Agent {
createConnection(
@@ -2023,6 +2750,13 @@ declare module 'http' {
declare class IncomingMessage extends http$IncomingMessage {}
declare class ServerResponse extends http$ServerResponse {}
+ declare function createServer(
+ options: http$createServerOptions,
+ requestListener?: (
+ request: IncomingMessage,
+ response: ServerResponse,
+ ) => void,
+ ): Server;
declare function createServer(
requestListener?: (
request: IncomingMessage,
@@ -2053,6 +2787,11 @@ declare module 'http' {
declare var globalAgent: Agent;
}
+type https$createServerOptions = Readonly<{
+ ...http$createServerOptions,
+ ...tls$createServerOptions,
+}>;
+
type https$requestOptions = {
...requestOptions,
agent?: boolean | http$Agent,
@@ -2064,6 +2803,8 @@ type https$requestOptions = {
};
declare module 'https' {
+ export type ServerOptions = https$createServerOptions;
+
declare class Server extends https$Server {}
declare class Agent extends http$Agent {
createConnection(
@@ -2080,7 +2821,7 @@ declare module 'https' {
declare class ServerResponse extends http$ServerResponse {}
declare function createServer(
- options: Object,
+ options: https$createServerOptions,
requestListener?: (
request: IncomingMessage,
response: ServerResponse,
@@ -2126,14 +2867,14 @@ declare class net$Socket extends stream$Duplex {
bufferSize: number;
bytesRead: number;
bytesWritten: number;
- connect(path: string, connectListener?: () => mixed): net$Socket;
+ connect(path: string, connectListener?: () => unknown): net$Socket;
connect(
port: number,
host?: string,
- connectListener?: () => mixed,
+ connectListener?: () => unknown,
): net$Socket;
- connect(port: number, connectListener?: () => mixed): net$Socket;
- connect(options: Object, connectListener?: () => mixed): net$Socket;
+ connect(port: number, connectListener?: () => unknown): net$Socket;
+ connect(options: Object, connectListener?: () => unknown): net$Socket;
destroyed: boolean;
end(
chunkOrEncodingOrCallback?:
@@ -2193,12 +2934,23 @@ type net$connectOptions = {
domain: string,
options?: ?number | ?Object,
callback?: (err: ?Error, address: string, family: number) => void,
- ) => mixed,
+ ) => unknown,
path?: string,
...
};
+type net$createServerOptions = Readonly<{
+ allowHalfOpen?: boolean,
+ highWaterMark?: number,
+ keepAlive?: boolean,
+ keepAliveInitialDelay?: number,
+ noDelay?: boolean,
+ pauseOnConnect?: boolean,
+}>;
+
declare module 'net' {
+ export type ServerOptions = net$createServerOptions;
+
declare class Server extends net$Server {}
declare class Socket extends net$Socket {}
@@ -2208,13 +2960,10 @@ declare module 'net' {
declare type connectionListener = (socket: Socket) => any;
declare function createServer(
- options?:
- | {
- allowHalfOpen?: boolean,
- pauseOnConnect?: boolean,
- ...
- }
- | connectionListener,
+ options: net$createServerOptions,
+ connectionListener?: connectionListener,
+ ): Server;
+ declare function createServer(
connectionListener?: connectionListener,
): Server;
@@ -2241,9 +2990,7 @@ type os$CPU = {
nice: number,
sys: number,
user: number,
- ...
},
- ...
};
type os$NetIFAddr = {
@@ -2252,7 +2999,8 @@ type os$NetIFAddr = {
internal: boolean,
mac: string,
netmask: string,
- ...
+ scopeid?: number,
+ cidr: ?string,
};
type os$UserInfo$buffer = {
@@ -2261,7 +3009,6 @@ type os$UserInfo$buffer = {
username: Buffer,
homedir: Buffer,
shell: ?Buffer,
- ...
};
type os$UserInfo$string = {
@@ -2270,43 +3017,117 @@ type os$UserInfo$string = {
username: string,
homedir: string,
shell: ?string,
- ...
};
declare module 'os' {
- declare function arch(): 'x64' | 'arm' | 'ia32';
+ declare function arch():
+ | 'arm'
+ | 'arm64'
+ | 'ia32'
+ | 'loong64'
+ | 'mips'
+ | 'mipsel'
+ | 'ppc64'
+ | 'riscv64'
+ | 's390x'
+ | 'x64';
declare function availableParallelism(): number;
declare function cpus(): Array;
declare function endianness(): 'BE' | 'LE';
declare function freemem(): number;
+ declare function getPriority(pid?: number): number;
declare function homedir(): string;
declare function hostname(): string;
declare function loadavg(): [number, number, number];
+ declare function machine(): string;
declare function networkInterfaces(): {
[ifName: string]: Array,
- ...
};
- declare function platform(): string;
+ declare function platform():
+ | 'aix'
+ | 'android'
+ | 'darwin'
+ | 'freebsd'
+ | 'haiku'
+ | 'linux'
+ | 'openbsd'
+ | 'sunos'
+ | 'win32'
+ | 'cygwin';
declare function release(): string;
+ declare function setPriority(priority: number): void;
+ declare function setPriority(pid: number, priority: number): void;
declare function tmpdir(): string;
declare function totalmem(): number;
declare function type(): string;
declare function uptime(): number;
- declare function userInfo(options: {
- encoding: 'buffer',
- ...
- }): os$UserInfo$buffer;
- declare function userInfo(options?: {
- encoding: 'utf8',
- ...
- }): os$UserInfo$string;
+ declare function userInfo(
+ options: Readonly<{
+ encoding: 'buffer',
+ }>,
+ ): os$UserInfo$buffer;
+ declare function userInfo(
+ options?: Readonly<{
+ encoding: 'utf8',
+ }>,
+ ): os$UserInfo$string;
+ declare function version(): string;
declare var EOL: string;
+ declare var devNull: string;
+ declare var constants: Readonly<{
+ signals: {[key: string]: number, ...},
+ errno: {[key: string]: number, ...},
+ priority: Readonly<{
+ PRIORITY_LOW: number,
+ PRIORITY_BELOW_NORMAL: number,
+ PRIORITY_NORMAL: number,
+ PRIORITY_ABOVE_NORMAL: number,
+ PRIORITY_HIGH: number,
+ PRIORITY_HIGHEST: number,
+ }>,
+ dlopen: {[key: string]: number, ...},
+ }>;
}
+type path$PlatformPath = {
+ normalize(path: string): string,
+ join(...parts: Array): string,
+ resolve(...parts: Array): string,
+ matchesGlob(path: string, pattern: string): boolean,
+ isAbsolute(path: string): boolean,
+ relative(from: string, to: string): string,
+ dirname(path: string): string,
+ basename(path: string, ext?: string): string,
+ extname(path: string): string,
+ sep: string,
+ delimiter: string,
+ parse(pathString: string): Readonly<{
+ root: string,
+ dir: string,
+ base: string,
+ ext: string,
+ name: string,
+ }>,
+ format(
+ pathObject: Readonly<{
+ root?: string,
+ dir?: string,
+ base?: string,
+ ext?: string,
+ name?: string,
+ }>,
+ ): string,
+ toNamespacedPath(path: string): string,
+ posix: path$PlatformPath,
+ win32: path$PlatformPath,
+ ...
+};
+
declare module 'path' {
declare function normalize(path: string): string;
declare function join(...parts: Array): string;
declare function resolve(...parts: Array): string;
+ declare function matchesGlob(path: string, pattern: string): boolean;
declare function isAbsolute(path: string): boolean;
declare function relative(from: string, to: string): string;
declare function dirname(path: string): string;
@@ -2320,41 +3141,244 @@ declare module 'path' {
base: string,
ext: string,
name: string,
- ...
};
- declare function format(pathObject: {
- root?: string,
- dir?: string,
- base?: string,
- ext?: string,
- name?: string,
- ...
- }): string;
- declare var posix: any;
- declare var win32: any;
+ declare function format(
+ pathObject: Readonly<{
+ root?: string,
+ dir?: string,
+ base?: string,
+ ext?: string,
+ name?: string,
+ }>,
+ ): string;
+ declare function toNamespacedPath(path: string): string;
+ declare var posix: path$PlatformPath;
+ declare var win32: path$PlatformPath;
}
-declare module 'punycode' {
- declare function decode(string: string): string;
- declare function encode(string: string): string;
- declare function toASCII(domain: string): string;
- declare function toUnicode(domain: string): string;
- declare var ucs2: {
- decode: (str: string) => Array,
- encode: (codePoints: Array) => string,
- ...
- };
- declare var version: string;
-}
+declare module 'perf_hooks' {
+ declare export type EntryType =
+ | 'function'
+ | 'gc'
+ | 'http'
+ | 'http2'
+ | 'mark'
+ | 'measure'
+ | 'navigation'
+ | 'node'
+ | 'resource';
+
+ declare export interface Histogram {
+ +count: number;
+ +countBigInt: bigint;
+ +exceeds: number;
+ +exceedsBigInt: bigint;
+ +max: number;
+ +maxBigInt: bigint;
+ +mean: number;
+ +min: number;
+ +minBigInt: bigint;
+ +stddev: number;
+ +percentiles: Map;
+ +percentilesBigInt: Map;
+ percentile(percentile: number): number;
+ percentileBigInt(percentile: number): bigint;
+ reset(): void;
+ }
-declare module 'querystring' {
- declare function stringify(
- obj: Object,
- separator?: string,
- equal?: string,
- options?: {encodeURIComponent?: (str: string) => string, ...},
- ): string;
- declare function parse(
+ declare export interface IntervalHistogram extends Histogram {
+ enable(): boolean;
+ disable(): boolean;
+ }
+
+ declare export interface RecordableHistogram extends Histogram {
+ record(val: number | bigint): void;
+ recordDelta(): void;
+ }
+
+ declare export class PerformanceEntry {
+ +duration: number;
+ +entryType: EntryType;
+ +name: string;
+ +startTime: number;
+ +detail?: unknown;
+ toJSON(): unknown;
+ }
+
+ declare export class PerformanceMark extends PerformanceEntry {
+ +entryType: 'mark';
+ +duration: 0;
+ +detail?: T;
+ }
+
+ declare export class PerformanceMeasure
+ extends PerformanceEntry
+ {
+ +entryType: 'measure';
+ +detail?: T;
+ }
+
+ declare export class PerformanceNodeEntry extends PerformanceEntry {
+ +entryType: 'node';
+ }
+
+ declare export class PerformanceNodeTiming extends PerformanceEntry {
+ +entryType: 'node';
+ +bootstrapComplete: number;
+ +environment: number;
+ +idleTime: number;
+ +loopExit: number;
+ +loopStart: number;
+ +nodeStart: number;
+ +v8Start: number;
+ }
+
+ declare export class PerformanceResourceTiming extends PerformanceEntry {
+ +entryType: 'resource';
+ +connectEnd: number;
+ +connectStart: number;
+ +decodedBodySize: number;
+ +domainLookupEnd: number;
+ +domainLookupStart: number;
+ +encodedBodySize: number;
+ +fetchStart: number;
+ +redirectEnd: number;
+ +redirectStart: number;
+ +requestStart: number;
+ +responseEnd: number;
+ +secureConnectionStart: number;
+ +transferSize: number;
+ +workerStart: number;
+ }
+
+ declare export class PerformanceObserverEntryList {
+ getEntries(): Array;
+ getEntriesByName(name: string, type?: EntryType): Array;
+ getEntriesByType(type: EntryType): Array;
+ }
+
+ declare export type PerformanceObserverCallback = (
+ list: PerformanceObserverEntryList,
+ observer: PerformanceObserver,
+ ) => void;
+
+ declare export class PerformanceObserver {
+ static supportedEntryTypes: ReadonlyArray;
+ constructor(callback: PerformanceObserverCallback): this;
+ observe(
+ options: Readonly<{
+ entryTypes?: ReadonlyArray,
+ type?: EntryType,
+ buffered?: boolean,
+ }>,
+ ): void;
+ disconnect(): void;
+ takeRecords(): Array;
+ }
+
+ declare export type EventLoopUtilization = {
+ +utilization: number,
+ +idle: number,
+ +active: number,
+ };
+
+ declare export type PerformanceMarkOptions = Readonly<{
+ detail?: T,
+ startTime?: number,
+ }>;
+
+ declare export type PerformanceMeasureOptions = Readonly<{
+ detail?: T,
+ duration?: number,
+ end?: number | string,
+ start?: number | string,
+ }>;
+
+ declare class Performance {
+ clearMarks(name?: string): void;
+ clearMeasures(name?: string): void;
+ clearResourceTimings(name?: string): void;
+ eventLoopUtilization(
+ elu1?: EventLoopUtilization,
+ elu2?: EventLoopUtilization,
+ ): EventLoopUtilization;
+ getEntries(): Array;
+ getEntriesByName(name: string, type?: EntryType): Array;
+ getEntriesByType(type: EntryType): Array;
+ mark(
+ name: string,
+ options?: PerformanceMarkOptions,
+ ): PerformanceMark;
+ measure(
+ name: string,
+ startMarkOrOptions?: string | PerformanceMeasureOptions,
+ endMark?: string,
+ ): PerformanceMeasure;
+ +nodeTiming: PerformanceNodeTiming;
+ now(): number;
+ setResourceTimingBufferSize(maxSize: number): void;
+ +timeOrigin: number;
+ timerify, TReturn>(
+ fn: (...TArgs) => TReturn,
+ options?: Readonly<{histogram?: RecordableHistogram}>,
+ ): (...TArgs) => TReturn;
+ toJSON(): unknown;
+ }
+
+ declare export var performance: Performance;
+
+ declare export var constants: Readonly<{
+ NODE_PERFORMANCE_GC_MAJOR: number,
+ NODE_PERFORMANCE_GC_MINOR: number,
+ NODE_PERFORMANCE_GC_INCREMENTAL: number,
+ NODE_PERFORMANCE_GC_WEAKCB: number,
+ NODE_PERFORMANCE_GC_FLAGS_NO: number,
+ NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED: number,
+ NODE_PERFORMANCE_GC_FLAGS_FORCED: number,
+ NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING: number,
+ NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE: number,
+ NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY: number,
+ NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE: number,
+ }>;
+
+ declare export function monitorEventLoopDelay(
+ options?: Readonly<{resolution?: number}>,
+ ): IntervalHistogram;
+
+ declare export function createHistogram(
+ options?: Readonly<{
+ lowest?: number | bigint,
+ highest?: number | bigint,
+ figures?: number,
+ }>,
+ ): RecordableHistogram;
+}
+
+declare module 'process' {
+ declare module.exports: Process;
+}
+
+declare module 'punycode' {
+ declare function decode(string: string): string;
+ declare function encode(string: string): string;
+ declare function toASCII(domain: string): string;
+ declare function toUnicode(domain: string): string;
+ declare var ucs2: {
+ decode: (str: string) => Array,
+ encode: (codePoints: Array) => string,
+ ...
+ };
+ declare var version: string;
+}
+
+declare module 'querystring' {
+ declare function stringify(
+ obj: Object,
+ separator?: string,
+ equal?: string,
+ options?: {encodeURIComponent?: (str: string) => string, ...},
+ ): string;
+ declare function parse(
str: string,
separator: ?string,
equal: ?string,
@@ -2368,6 +3392,125 @@ declare module 'querystring' {
declare function unescape(str: string, decodeSpaces?: boolean): string;
}
+/**
+ * Node.js sqlite module (only available with node: prefix)
+ * @since v22.5.0
+ */
+declare module 'node:sqlite' {
+ declare export type SupportedValueType =
+ | null
+ | number
+ | bigint
+ | string
+ | Uint8Array;
+
+ declare export type DatabaseSyncOptions = Readonly<{
+ open?: boolean,
+ enableForeignKeyConstraints?: boolean,
+ enableDoubleQuotedStringLiterals?: boolean,
+ readOnly?: boolean,
+ allowExtension?: boolean,
+ }>;
+
+ declare export type CreateSessionOptions = Readonly<{
+ table?: string,
+ db?: string,
+ }>;
+
+ declare export type ApplyChangesetOptions = Readonly<{
+ filter?: (tableName: string) => boolean,
+ onConflict?: number,
+ }>;
+
+ declare export type FunctionOptions = Readonly<{
+ deterministic?: boolean,
+ directOnly?: boolean,
+ useBigIntArguments?: boolean,
+ varargs?: boolean,
+ }>;
+
+ declare export type StatementResultingChanges = {
+ changes: number | bigint,
+ lastInsertRowid: number | bigint,
+ };
+
+ declare export interface Session {
+ changeset(): Uint8Array;
+ patchset(): Uint8Array;
+ close(): void;
+ }
+
+ declare export class StatementSync {
+ all(...anonymousParameters: ReadonlyArray): Array;
+ all(
+ namedParameters: {[key: string]: SupportedValueType, ...},
+ ...anonymousParameters: ReadonlyArray
+ ): Array;
+
+ +expandedSQL: string;
+
+ get(...anonymousParameters: ReadonlyArray): any;
+ get(
+ namedParameters: {[key: string]: SupportedValueType, ...},
+ ...anonymousParameters: ReadonlyArray
+ ): any;
+
+ iterate(
+ ...anonymousParameters: ReadonlyArray
+ ): Iterator;
+ iterate(
+ namedParameters: {[key: string]: SupportedValueType, ...},
+ ...anonymousParameters: ReadonlyArray
+ ): Iterator;
+
+ run(
+ ...anonymousParameters: ReadonlyArray
+ ): StatementResultingChanges;
+ run(
+ namedParameters: {[key: string]: SupportedValueType, ...},
+ ...anonymousParameters: ReadonlyArray
+ ): StatementResultingChanges;
+
+ setAllowBareNamedParameters(enabled: boolean): void;
+ setReadBigInts(enabled: boolean): void;
+
+ +sourceSQL: string;
+ }
+
+ declare export class DatabaseSync {
+ constructor(location: string, options?: DatabaseSyncOptions): void;
+
+ close(): void;
+ loadExtension(path: string): void;
+ enableLoadExtension(allow: boolean): void;
+ exec(sql: string): void;
+
+ function(
+ name: string,
+ options: FunctionOptions,
+ func: (...args: ReadonlyArray) => SupportedValueType,
+ ): void;
+ function(
+ name: string,
+ func: (...args: ReadonlyArray) => SupportedValueType,
+ ): void;
+
+ open(): void;
+ prepare(sql: string): StatementSync;
+ createSession(options?: CreateSessionOptions): Session;
+ applyChangeset(
+ changeset: Uint8Array,
+ options?: ApplyChangesetOptions,
+ ): boolean;
+ }
+
+ declare export var constants: {|
+ +SQLITE_CHANGESET_OMIT: number,
+ +SQLITE_CHANGESET_REPLACE: number,
+ +SQLITE_CHANGESET_ABORT: number,
+ |};
+}
+
type readline$InterfaceCompleter = (
line: string,
) =>
@@ -2457,17 +3600,32 @@ declare class stream$Readable extends stream$Stream {
static from(
iterable: Iterable | AsyncIterable,
options?: readableStreamOptions,
- ): stream$Readable;
+ ): this;
+
+ static fromWeb(
+ readableStream: ReadableStream,
+ options?: readableStreamOptions,
+ ): this;
+
+ static toWeb(streamReadable: stream$Readable): ReadableStream;
constructor(options?: readableStreamOptions): void;
+ closed: boolean;
destroy(error?: Error): this;
+ destroyed: boolean;
+ errored: ?Error;
isPaused(): boolean;
pause(): this;
- pipe(dest: T, options?: {end?: boolean, ...}): T;
+ pipe(dest: T, options?: {end?: boolean, ...}): T;
read(size?: number): ?(string | Buffer);
readable: boolean;
+ readableAborted: boolean;
+ readableDidRead: boolean;
+ readableEnded: boolean;
+ readableFlowing: boolean | null;
readableHighWaterMark: number;
readableLength: number;
+ readableObjectMode: boolean;
resume(): this;
setEncoding(encoding: string): this;
unpipe(dest?: stream$Writable): this;
@@ -2504,9 +3662,18 @@ type writableStreamOptions = {
...
};
declare class stream$Writable extends stream$Stream {
+ static fromWeb(
+ writableStream: WritableStream,
+ options?: writableStreamOptions,
+ ): this;
+
+ static toWeb(streamWritable: stream$Writable): WritableStream;
+
constructor(options?: writableStreamOptions): void;
+ closed: boolean;
cork(): void;
destroy(error?: Error): this;
+ destroyed: boolean;
end(callback?: () => void): this;
end(chunk?: string | Buffer | Uint8Array, callback?: () => void): this;
end(
@@ -2514,11 +3681,17 @@ declare class stream$Writable extends stream$Stream {
encoding?: string,
callback?: () => void,
): this;
+ errored: ?Error;
setDefaultEncoding(encoding: string): this;
uncork(): void;
writable: boolean;
+ writableAborted: boolean;
+ writableEnded: boolean;
+ writableFinished: boolean;
writableHighWaterMark: number;
writableLength: number;
+ writableNeedDrain: boolean;
+ writableObjectMode: boolean;
write(
chunk: string | Buffer | Uint8Array,
callback?: (error?: Error) => void,
@@ -2545,10 +3718,6 @@ declare class stream$Writable extends stream$Stream {
_final(callback: (error?: Error) => void): void;
}
-//According to the NodeJS docs:
-//"Since JavaScript doesn't have multiple prototypal inheritance, this class
-//prototypally inherits from Readable, and then parasitically from Writable."
-//Source: ,
+ options?: duplexStreamOptions,
+ ): this;
+
+ // $FlowFixMe[incompatible-type] See above
+ static toWeb(streamDuplex: stream$Duplex): {
+ readable: ReadableStream,
+ writable: WritableStream,
+ ...
+ };
+
constructor(options?: duplexStreamOptions): void;
}
type transformStreamOptions = duplexStreamOptions & {
@@ -2602,25 +3793,25 @@ declare module 'stream' {
},
callback: (error?: Error) => void,
): () => void;
- declare function pipeline(
+ declare function pipeline(
s1: stream$Readable,
last: T,
cb: (error?: Error) => void,
): T;
- declare function pipeline(
+ declare function pipeline(
s1: stream$Readable,
s2: stream$Duplex,
last: T,
cb: (error?: Error) => void,
): T;
- declare function pipeline(
+ declare function pipeline(
s1: stream$Readable,
s2: stream$Duplex,
s3: stream$Duplex,
last: T,
cb: (error?: Error) => void,
): T;
- declare function pipeline(
+ declare function pipeline(
s1: stream$Readable,
s2: stream$Duplex,
s3: stream$Duplex,
@@ -2628,7 +3819,7 @@ declare module 'stream' {
last: T,
cb: (error?: Error) => void,
): T;
- declare function pipeline(
+ declare function pipeline(
s1: stream$Readable,
s2: stream$Duplex,
s3: stream$Duplex,
@@ -2637,7 +3828,7 @@ declare module 'stream' {
last: T,
cb: (error?: Error) => void,
): T;
- declare function pipeline(
+ declare function pipeline(
s1: stream$Readable,
s2: stream$Duplex,
s3: stream$Duplex,
@@ -2704,7 +3895,7 @@ declare module 'stream' {
options?: StreamPipelineOptions,
): Promise,
pipeline(
- streams: $ReadOnlyArray,
+ streams: ReadonlyArray,
options?: StreamPipelineOptions,
): Promise,
...
@@ -2811,11 +4002,63 @@ type tls$connectOptions = {
domain: string,
options?: ?number | ?Object,
callback?: (err: ?Error, address: string, family: number) => void,
- ) => mixed,
+ ) => unknown,
requestOCSP?: boolean,
...
};
+type tls$SecureContext = interface {};
+
+type tls$createServerOptions = Readonly<{
+ ALPNProtocols?: ReadonlyArray | Uint8Array,
+ ca?: string | Buffer | ReadonlyArray,
+ cert?: string | Buffer | ReadonlyArray,
+ ciphers?: string,
+ clientCertEngine?: string,
+ crl?: string | Buffer | ReadonlyArray,
+ dhparam?: string | Buffer,
+ ecdhCurve?: string,
+ enableTrace?: boolean,
+ handshakeTimeout?: number,
+ honorCipherOrder?: boolean,
+ key?:
+ | string
+ | Buffer
+ | ReadonlyArray<
+ | string
+ | Buffer
+ | Readonly<{pem: string | Buffer, passphrase?: string, ...}>,
+ >,
+ maxVersion?: 'TLSv1.3' | 'TLSv1.2' | 'TLSv1.1' | 'TLSv1',
+ minVersion?: 'TLSv1.3' | 'TLSv1.2' | 'TLSv1.1' | 'TLSv1',
+ passphrase?: string,
+ pfx?:
+ | string
+ | Buffer
+ | ReadonlyArray<
+ | string
+ | Buffer
+ | Readonly<{buf: string | Buffer, passphrase?: string, ...}>,
+ >,
+ privateKeyIdentifier?: string,
+ privateKeyEngine?: string,
+ pskCallback?: (socket: tls$TLSSocket, identity: string) => Buffer | null,
+ pskIdentityHint?: string,
+ rejectUnauthorized?: boolean,
+ requestCert?: boolean,
+ secureContext?: tls$SecureContext,
+ secureOptions?: number,
+ secureProtocol?: string,
+ sessionIdContext?: string,
+ sessionTimeout?: number,
+ sigalgs?: string,
+ SNICallback?: (
+ servername: string,
+ callback: (err: Error | null, ctx?: tls$SecureContext) => void,
+ ) => void,
+ ticketKeys?: Buffer,
+}>;
+
type tls$Certificate$Subject = {
C?: string,
ST?: string,
@@ -2888,6 +4131,8 @@ declare class tls$Server extends net$Server {
}
declare module 'tls' {
+ export type ServerOptions = tls$createServerOptions;
+
declare var CLIENT_RENEG_LIMIT: number;
declare var CLIENT_RENEG_WINDOW: number;
declare var SLAB_BUFFER_SIZE: number;
@@ -2904,12 +4149,15 @@ declare module 'tls' {
): Error | void;
declare function parseCertString(s: string): Object;
declare function createSecureContext(details: Object): Object;
- declare var SecureContext: Object;
+ declare var SecureContext: tls$SecureContext;
declare var TLSSocket: typeof tls$TLSSocket;
declare var Server: typeof tls$Server;
declare function createServer(
- options: Object,
- secureConnectionListener?: Function,
+ options: tls$createServerOptions,
+ secureConnectionListener?: (socket: tls$TLSSocket) => void,
+ ): tls$Server;
+ declare function createServer(
+ secureConnectionListener?: (socket: tls$TLSSocket) => void,
): tls$Server;
declare function connect(
options: tls$connectOptions,
@@ -2945,6 +4193,75 @@ type url$urlObject = {
...
};
+declare module 'timers' {
+ declare export class Timeout {
+ close(): this;
+ hasRef(): boolean;
+ ref(): this;
+ refresh(): this;
+ unref(): this;
+ [key: $SymbolToPrimitive]: () => number;
+ // [key: $SymbolDispose]: () => void;
+ }
+
+ declare export class Immediate {
+ hasRef(): boolean;
+ ref(): this;
+ unref(): this;
+ // [key: $SymbolDispose]: () => void;
+ }
+
+ declare export function setTimeout>(
+ callback: (...args: TArgs) => unknown,
+ delay?: number,
+ ...args: TArgs
+ ): Timeout;
+
+ declare export function setInterval>(
+ callback: (...args: TArgs) => unknown,
+ delay?: number,
+ ...args: TArgs
+ ): Timeout;
+
+ declare export function setImmediate>(
+ callback: (...args: TArgs) => unknown,
+ ...args: TArgs
+ ): Immediate;
+
+ declare export function clearTimeout(timeout?: Timeout | number): void;
+ declare export function clearInterval(timeout?: Timeout | number): void;
+ declare export function clearImmediate(immediate?: Immediate | number): void;
+}
+
+declare module 'timers/promises' {
+ declare export type TimerOptions = Readonly<{
+ ref?: boolean,
+ signal?: AbortSignal,
+ }>;
+
+ declare export function setTimeout(
+ delay?: number,
+ value?: T,
+ options?: TimerOptions,
+ ): Promise;
+
+ declare export function setImmediate(
+ value?: T,
+ options?: TimerOptions,
+ ): Promise;
+
+ declare export function setInterval(
+ delay?: number,
+ value?: T,
+ options?: TimerOptions,
+ ): AsyncIterator;
+
+ declare export var scheduler: Readonly<{
+ wait(delay: number, options?: TimerOptions): Promise,
+ yield(): Promise,
+ }>;
+}
+
declare module 'url' {
declare type Url = {|
protocol: string | null,
@@ -2990,8 +4307,16 @@ declare module 'url' {
declare function resolve(from: string, to: string): string;
declare function domainToASCII(domain: string): string;
declare function domainToUnicode(domain: string): string;
- declare function pathToFileURL(path: string): url$urlObject;
- declare function fileURLToPath(path: url$urlObject | string): string;
+
+ declare function pathToFileURL(
+ path: string,
+ options?: Readonly<{windows?: boolean}>,
+ ): url$urlObject;
+
+ declare function fileURLToPath(
+ path: url$urlObject | string,
+ options?: Readonly<{windows?: boolean}>,
+ ): string;
declare class URLSearchParams {
@@iterator(): Iterator<[string, string]>;
@@ -3013,7 +4338,7 @@ declare module 'url' {
value: string,
name: string,
searchParams: URLSearchParams,
- ) => mixed,
+ ) => unknown,
thisArg?: This,
): void;
get(name: string): string | null;
@@ -3027,6 +4352,7 @@ declare module 'url' {
}
declare class URL {
static canParse(url: string, base?: string): boolean;
+ static parse(input: string, base?: string): URL | null;
static createObjectURL(blob: Blob): string;
static createObjectURL(mediaSource: MediaSource): string;
static revokeObjectURL(url: string): void;
@@ -3046,6 +4372,63 @@ declare module 'url' {
toString(): string;
toJSON(): string;
}
+
+ declare type url$URLPatternInit = {
+ protocol?: string,
+ username?: string,
+ password?: string,
+ hostname?: string,
+ port?: string,
+ pathname?: string,
+ search?: string,
+ hash?: string,
+ baseURL?: string,
+ };
+
+ declare type url$URLPatternComponentResult = {
+ input: string,
+ groups: {[key: string]: string | void},
+ };
+
+ declare type url$URLPatternResult = {
+ inputs: ReadonlyArray,
+ protocol: url$URLPatternComponentResult,
+ username: url$URLPatternComponentResult,
+ password: url$URLPatternComponentResult,
+ hostname: url$URLPatternComponentResult,
+ port: url$URLPatternComponentResult,
+ pathname: url$URLPatternComponentResult,
+ search: url$URLPatternComponentResult,
+ hash: url$URLPatternComponentResult,
+ };
+
+ declare class URLPattern {
+ constructor(
+ input?: string | url$URLPatternInit,
+ options?: Readonly<{ignoreCase?: boolean}>,
+ ): void;
+ constructor(
+ input: string | url$URLPatternInit,
+ baseURL: string,
+ options?: Readonly<{ignoreCase?: boolean}>,
+ ): void;
+
+ +hasRegExpGroups: boolean;
+ +hash: string;
+ +hostname: string;
+ +password: string;
+ +pathname: string;
+ +port: string;
+ +protocol: string;
+ +search: string;
+ +username: string;
+
+ exec(
+ input?: string | url$URLPatternInit,
+ baseURL?: string,
+ ): url$URLPatternResult | null;
+ test(input?: string | url$URLPatternInit, baseURL?: string): boolean;
+ }
}
type util$InspectOptions = {
@@ -3057,30 +4440,30 @@ type util$InspectOptions = {
};
declare type util$ParseArgsOption =
- | {|
+ | Readonly<{
type: 'boolean',
multiple?: false,
short?: string,
default?: boolean,
- |}
- | {|
+ }>
+ | Readonly<{
type: 'boolean',
multiple: true,
short?: string,
default?: Array,
- |}
- | {|
+ }>
+ | Readonly<{
type: 'string',
multiple?: false,
short?: string,
default?: string,
- |}
- | {|
+ }>
+ | Readonly<{
type: 'string',
multiple: true,
short?: string,
default?: Array,
- |};
+ }>;
type util$ParseArgsOptionToValue = TOption['type'] extends 'boolean'
? TOption['multiple'] extends true
@@ -3137,31 +4520,33 @@ declare module 'util' {
declare function stripVTControlCharacters(str: string): string;
declare function parseArgs<
- TOptions: {[string]: util$ParseArgsOption} = {||},
- >(config: {|
+ TOptions extends {+[string]: util$ParseArgsOption} = {},
+ >(config: {
args?: Array,
options?: TOptions,
strict?: boolean,
allowPositionals?: boolean,
+ allowNegative?: boolean,
tokens?: false,
- |}): {|
+ }): {
values: util$ParseArgsOptionsToValues,
positionals: Array