Compare commits

...
Author SHA1 Message Date
CodemodService Bot 86c67a0e70 Fix CQS signal performance-faster-string-find in xplat/js/react-native-github/packages/react-native/ReactCommon/react/runtime
Reviewed By: dtolnay

Differential Revision: D78146248
2025-07-11 09:05:09 -07:00
Rubén Norte 9747c955ac Migrate network profiling to console.timeStamp (#52560)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52560

Changelog: [internal]

This migrates the profiling logic for `XMLHttpRequest` from `performance.measure` to `console.timeStamp` with built-in support for tracks.

Reviewed By: hoxyq

Differential Revision: D78157407

fbshipit-source-id: 0ef060557a00e7973ef7f0478b26b81471d38226
2025-07-11 08:41:01 -07:00
Rubén Norte 6f6945e64f Propagate console.timeStamp entries to Perfetto (#52542)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52542

Changelog: [internal]

This adds support to propagate performance entries logged to `console.timeStamp` to Perfetto, if enabled. It also modifies the Perfetto integration to support track groups, in addition to track names.

Reviewed By: hoxyq

Differential Revision: D78092596

fbshipit-source-id: 76b0fe2738d856fd75ee941de223d6a6a73d8e1c
2025-07-11 08:41:01 -07:00
Nicola Corti 0021dafc51 Remove deprecated constructors for TextInput *Event classes (#52535)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52535

Those constructors are no longer necessary. They're deprecated + the class is internal so they're not breaking changes.
I'm just cleaning them up as they're not needed anymore.

Changelog:
[Internal] [Changed] - Remove deprecated constructors for TextInput *Event classes

Reviewed By: javache

Differential Revision: D78095748

fbshipit-source-id: 2dc6c750f8470a88918d8a69b68364f38251d79e
2025-07-11 08:15:42 -07:00
Riccardo Cipolleschi e69777d258 Connect prebuilds with CI (#52562)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52562

This change use the prebuilds we build in CI i other iOS jobs to speed-up the iOS CI

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D78159367

fbshipit-source-id: 64486c99fdbc54487dbcff786209cacac304b9b7
2025-07-11 07:15:35 -07:00
Riccardo Cipolleschi dc5110a8f2 Unify test_ios_rntester_dynamic_frameworks with test_ios_rntester (#52563)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52563

The test_ios_rntester_dynamic_frameworks is identical to the test_ios_rntester but for the framework parameter.

This change unifies the two, using a matrix to test all the configurations:
- Debug / Static Libraries
- Release / Static Libraries
- Debug / Dynamic Frameworks
- Release / Dynamic Frameworks

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D78159366

fbshipit-source-id: b321f295477fe3ae6e43c7518d47afb0714bddb8
2025-07-11 07:15:35 -07:00
Riccardo Cipolleschi 3de1dc0fd1 Fix RCTPushNotification podspec to work with prebuilds (#52531)
Summary:
This change tries to use the prebuilds we build in CI i other iOS jobs to speed-up the iOS CI

bypass-github-export-checks

## Changelog:
[Internal] -

Pull Request resolved: https://github.com/facebook/react-native/pull/52531

Test Plan:
Build rntester using prebuilds:

```
# after downloading the prebuilds from CI and unzipping them
export HERMES_ENGINE_TARBALL_PATH=~/Downloads/hermes-ios-Debug.tar.gz
export RCT_USE_LOCAL_RN_DEP=~/Downloads/reactnative-dependencies-debug.tar.gz
export RCT_TESTONLY_RNCORE_TARBALL_PATH=~/Downloads/React.xcframework.tar.gz

USE_FRAMEWORKS=dynamic bundle exec pod install
open RNTesterPods.xcworkspace
```
And then build from Xcode.

Reviewed By: rshest

Differential Revision: D78158734

Pulled By: cipolleschi

fbshipit-source-id: 43cbb66bd44fa621292b69de0dadde5ed20c4574
2025-07-11 07:15:35 -07:00
Christoph Purrer 88cb7832ea Remove unused Color/Transform #includes and use enum class for TransformOperationType (#52549)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52549

Changelog: [Internal]

- The #includes are not used
- `enum class` is C++, (enum is C)

Reviewed By: rshest

Differential Revision: D78135339

fbshipit-source-id: 1a35301ea063ce17c195be7dc373132d342f111a
2025-07-11 06:51:49 -07:00
Zeya Peng aa2a5a682f Animated.sequence (#52547)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52547

## Changelog:

[Internal] [Added] - add fantom test for Animated.sequence

Reviewed By: christophpurrer

Differential Revision: D78107756

fbshipit-source-id: c3a7bc2d487cc0ae7316a26dc10b01dcf54dbd37
2025-07-11 06:40:03 -07:00
Zeya Peng a0543b773c AnimatedValue.interpolate (#52546)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52546

## Changelog:

[Internal] [Added] - add fantom test for AnimatedValue.interpolate

Reviewed By: christophpurrer

Differential Revision: D78032554

fbshipit-source-id: 0100a510cb0ad5c8e1886c309fab91ee9e017769
2025-07-11 06:40:03 -07:00
Rubén Norte f5abce0932 Micro-optimize performance methods (#52555)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52555

Changelog: [internal]

Applied several micro-optimizations to methods in the `performance` object:
- Cached property access
- Avoided unnecessary function calls
- Avoided unnecessary object allocations
- Use strict comparisons with `undefined` instead of loose comparisons with `null` whenever possible.

This yields wins from 5 to 15% depending on the method and args.

## Before

| (index) | Task name                                                 | Latency average (ns) | Latency median (ns) | Throughput average (ops/s) | Throughput median (ops/s) | Samples |
| ------- | --------------------------------------------------------- | -------------------- | ------------------- | -------------------------- | ------------------------- | ------- |
| 0       | 'mark (default)'                                          | '1728.19 ± 0.81%'    | '1682.00'           | '592249 ± 0.01%'           | '594530'                  | 578640  |
| 1       | 'mark (with custom startTime)'                            | '2008.33 ± 1.32%'    | '1933.00'           | '514326 ± 0.01%'           | '517331'                  | 497927  |
| 2       | 'measure (default)'                                       | '2568.90 ± 1.48%'    | '2484.00'           | '400362 ± 0.02%'           | '402576'                  | 389272  |
| 3       | 'measure (with start and end timestamps)'                 | '2806.21 ± 0.69%'    | '2744.00'           | '362439 ± 0.02%'           | '364431'                  | 356353  |
| 4       | 'measure (with mark names)'                               | '2860.82 ± 0.23%'    | '2824.00'           | '352145 ± 0.02%'           | '354108'                  | 349551  |
| 5       | 'clearMarks'                                              | '763.05 ± 0.03%'     | '751.00'            | '1320377 ± 0.01%'          | '1331558'                 | 1310524 |
| 6       | 'clearMeasures'                                           | '788.10 ± 0.05%'     | '781.00'            | '1281839 ± 0.01%'          | '1280410'                 | 1268875 |
| 7       | 'mark + clearMarks'                                       | '2129.03 ± 1.04%'    | '2053.00'           | '484778 ± 0.01%'           | '487092'                  | 469698  |
| 8       | 'measure + clearMeasures (with start and end timestamps)' | '3176.38 ± 0.67%'    | '3105.00'           | '320111 ± 0.02%'           | '322061'                  | 314825  |
| 9       | 'measure + clearMeasures (with mark names)'               | '3229.33 ± 0.60%'    | '3145.00'           | '316463 ± 0.02%'           | '317965'                  | 309662  |

## After

| (index) | Task name                                                 | Latency average (ns) | Latency median (ns) | Throughput average (ops/s) | Throughput median (ops/s) | Samples |
| ------- | --------------------------------------------------------- | -------------------- | ------------------- | -------------------------- | ------------------------- | ------- |
| 0       | 'mark (default)'                                          | '1598.54 ± 0.93%'    | '1553.00'           | '639076 ± 0.01%'           | '643915'                  | 625572  |
| 1       | 'mark (with custom startTime)'                            | '1772.07 ± 1.24%'    | '1713.00'           | '579523 ± 0.01%'           | '583771'                  | 564314  |
| 2       | 'measure (default)'                                       | '2349.32 ± 0.81%'    | '2284.00'           | '434149 ± 0.01%'           | '437828'                  | 425656  |
| 3       | 'measure (with start and end timestamps)'                 | '2609.11 ± 1.06%'    | '2534.00'           | '391950 ± 0.02%'           | '394633'                  | 383273  |
| 4       | 'measure (with mark names)'                               | '2656.46 ± 0.42%'    | '2614.00'           | '380128 ± 0.01%'           | '382555'                  | 376442  |
| 5       | 'clearMarks'                                              | '666.38 ± 0.03%'     | '661.00'            | '1511649 ± 0.01%'          | '1512859'                 | 1500641 |
| 6       | 'clearMeasures'                                           | '718.62 ± 0.03%'     | '711.00'            | '1401526 ± 0.01%'          | '1406470'                 | 1391563 |
| 7       | 'mark + clearMarks'                                       | '2027.47 ± 1.29%'    | '1953.00'           | '509105 ± 0.01%'           | '512033'                  | 493227  |
| 8       | 'measure + clearMeasures (with start and end timestamps)' | '3030.83 ± 0.98%'    | '2915.00'           | '340624 ± 0.02%'           | '343053'                  | 329943  |
| 9       | 'measure + clearMeasures (with mark names)'               | '2915.76 ± 0.59%'    | '2844.00'           | '349120 ± 0.02%'           | '351617'                  | 342964  |

Reviewed By: hoxyq

Differential Revision: D78013565

fbshipit-source-id: ddd02d887b228debd58805406c1395b9179dd804
2025-07-11 05:37:31 -07:00
Rubén Norte 38cf247c63 Add more benchmarks for performance.measure (#52556)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52556

Changelog: [internal]

This adds a new benchmark for `performance.measure` to measure the performance of calling it without arguments.

Reviewed By: hoxyq

Differential Revision: D78013563

fbshipit-source-id: 84e2151d9d91cfc2e85d310f42010483e7304648
2025-07-11 05:37:31 -07:00
Rubén Norte 1fc168f005 Handle nullability of detail correctly in performance.mark and performance.measure (#52557)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52557

Changelog: [internal]

`PerformanceEntry.detail` should be `null` if not defined, not undefined as it is currently. This fixes that.

Reviewed By: hoxyq

Differential Revision: D78013568

fbshipit-source-id: b22dfdd8d582594fc1e5199264e8af92c26bb0ea
2025-07-11 05:37:31 -07:00
Rubén Norte 5e0eb0a17c Small refactor of performance API (#52558)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52558

Changelog: [internal]

Small refactors for `$ReadOnly`, move `getCurrentTimeStamp` to utils so it can be reused, etc.

Reviewed By: hoxyq

Differential Revision: D78013570

fbshipit-source-id: f73d119f22dd4dc9aaa5efef76a1156821ecd8de
2025-07-11 05:37:31 -07:00
Rubén Norte acd07c7e1c Handle casting to string in performance.mark and performance.measure correctly (#52559)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52559

Changelog: [internal]

Making `performance.mark` and `performance.measure` slightly more spec-compliant.

Reviewed By: hoxyq

Differential Revision: D78013571

fbshipit-source-id: 4881b674f7cded5045b9f464ca7442a186c39048
2025-07-11 05:37:31 -07:00
Harini Malothu ff38d59cff # Fixed Type Conversion Error in DynamicEventPayload (#52525)
Summary:
Resolves https://github.com/microsoft/react-native-windows/issues/14797
We were facing a type conversion error in the DynamicEventPayload::extractValue() method. The function signature declares a return type of std::optional<double>, but when handling INT64 values, but when handling `INT64` values, the code was directly returning `dynamic.asInt()` without proper type conversion
We faced the issue while integrating https://github.com/microsoft/react-native-windows/pull/14791
## Changelog:
[General][Fixed]

Pull Request resolved: https://github.com/facebook/react-native/pull/52525

Test Plan:
The fix involved wrapping the dynamic.asInt() call with static_cast<double>(), creating the corrected line: return static_cast<double>(dynamic.asInt())

Tested E2E in RNW

Reviewed By: andrewdacenko

Differential Revision: D78083842

Pulled By: rshest

fbshipit-source-id: 8dbedd67fa7c21e89b863d8b1bc7b9e0d7978b9f
2025-07-11 03:13:30 -07:00
Riccardo Cipolleschi 7bbb13c9be Fix ENTERPRISE_REPOSITORY usage (#52553)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52553

This change fixes the usage of `ENTERPRISE_REPOSITORY` in Ruby

## Changelog
[Internal] -

Reviewed By: cortinico

Differential Revision: D78152641

fbshipit-source-id: e4ace014f1b7cbeb1ec5a0dea955d1fc2bae5b67
2025-07-11 03:01:30 -07:00
Jakub Piasecki d4b36b0300 Fix display: contents nodes not being cloned with the wrong owner (#52530)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52530

This PR fixes two issues with `display: contents` implementation:
1. When a node with `display: contents` set is a leaf, it won't be cloned after the initial tree is built. The added test case covers this scenario.
2. It was possible for the subtree of `display: contents` nodes not to be cloned during layout. I don't have a minimal reproduction for this one, unfortunately. It was discovered in the Expensify app: https://github.com/Expensify/App/issues/65268, along with a consistent reproduction. In that specific case, it seems to be heavily tied to `react-native-onyx`, which is a state management library.

Changelog: [GENERAL][FIXED] - Fixed nodes with `display: contents` set being cloned with the wrong owner

X-link: https://github.com/facebook/yoga/pull/1826

Reviewed By: adityasharat, NickGerleman

Differential Revision: D78084270

Pulled By: j-piasecki

fbshipit-source-id: eb81f6d7dcd1665974d07261ba693e2abea239bb
2025-07-11 02:16:35 -07:00
Vitali Zaidman 84a2765c2a renamed release testing scripts (#52541)
Summary:
Use a more suitable name for the [scripts used in the release process](https://github.com/reactwg/react-native-releases/blob/main/docs/guide-release-testing.md) to generate a testing project to test a new React Native release against.
```diff
- test-e2e-local
+ test-release-local
```
## Changelog:
[INTERNAL]

Pull Request resolved: https://github.com/facebook/react-native/pull/52541

Test Plan:
`yarn test-release-local-clean` works the same way:
<img width="1177" height="161" alt="Screenshot 2025-07-10 at 17 54 50" src="https://github.com/user-attachments/assets/5efe30c6-a738-476e-a670-696959e9a0fc" />

`yarn test-release-local` works the same way:
<img width="1077" height="395" alt="Screenshot 2025-07-10 at 17 59 29" src="https://github.com/user-attachments/assets/fe6c6443-9316-4ed0-b6dc-51de5ffb109c" />

Reviewed By: cipolleschi

Differential Revision: D78150648

Pulled By: vzaidman

fbshipit-source-id: 471715da271d03bc2a35afbda02074bf71f62734
2025-07-11 01:57:14 -07:00
Nick Lefever 6b8bc5a1d0 Move toDynamic conversion for FilterFunction (#52537)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52537

See title

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D78088447

fbshipit-source-id: 3f3a1e82e527cfe83de7a798b8b9ea2996dc8de1
2025-07-10 12:35:18 -07:00
Nick Lefever 0144798e25 Move toDynamic conversion for BoxShadow (#52536)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52536

See title

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D78005880

fbshipit-source-id: 5a4b7ff3c4d9c6ece17759926ee80aec80d3cde0
2025-07-10 12:35:18 -07:00
generatedunixname89002005287564 263ccad3c5 Fix CQS signal modernize-use-using in xplat/js/react-native-github/packages/react-native/React/CoreModules [B] (#52539)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52539

Reviewed By: dtolnay

Differential Revision: D78062538

fbshipit-source-id: 610505b5bfd78798b09970194f3b95aaefb08920
2025-07-10 12:16:40 -07:00
Devan Buggay c2a3e4420e HWInput: Add Channel Up/Down Support (#52540)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52540

Adds Channel Up/Down events to HWInput.

Changelog:
[Android][Added] - Channel up/down hardware events.

Reviewed By: Abbondanzo

Differential Revision: D78099245

fbshipit-source-id: 133d5c835f3862feba641354cb1164eefeafed9f
2025-07-10 12:04:00 -07:00
Rob Hogan 5d4c22b4a7 Update @typescript-eslint (#52532)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52532

Since we updated TypeScript in https://github.com/facebook/react-native/pull/51831, ESLint has printed a warning that `typescript/eslint` doesn't support our TS version.

This updates it to fix the warning.

Changelog: [Internal]

Reviewed By: vzaidman

Differential Revision: D77833826

fbshipit-source-id: 29a5179c4f223a8cc0ab2c8071f0a5efa09e5edc
2025-07-10 10:10:09 -07:00
Nicola Corti b0606ba041 Correctly mark as deprecated the ReactActivityDelegate.getReactInstanceManager (#52533)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52533

This method is deprecated in the JavaDoc but not correctly annotated as Deprecated, let's fix it.

Changelog:
[Internal] [Changed] -

Reviewed By: cipolleschi

Differential Revision: D78092468

fbshipit-source-id: 31e4cb958a51b20f5105a4bec3366d67402e5419
2025-07-10 10:00:32 -07:00
44 changed files with 701 additions and 342 deletions
@@ -48,6 +48,14 @@ runs:
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
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: |
@@ -73,6 +81,7 @@ runs:
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
+10 -1
View File
@@ -94,6 +94,14 @@ runs:
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
with:
name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Setup xcode build cache
uses: ./.github/actions/setup-xcode-build-cache
with:
@@ -105,12 +113,13 @@ runs:
shell: bash
run: |
export HERMES_ENGINE_TARBALL_PATH=$HERMES_ENGINE_TARBALL_PATH
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
if [[ ${{ inputs.use-frameworks }} == "DynamicFrameworks" ]]; then
export USE_FRAMEWORKS=dynamic
fi
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
cd packages/rn-tester
bundle install
+16 -26
View File
@@ -128,7 +128,7 @@ jobs:
test_ios_rntester_ruby_3_2_0:
runs-on: macos-14
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies]
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
@@ -141,31 +141,12 @@ jobs:
ruby-version: "3.2.0"
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
test_ios_rntester_dynamic_frameworks:
runs-on: macos-14
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
continue-on-error: true
strategy:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run it
uses: ./.github/actions/test-ios-rntester
with:
use-frameworks: DynamicFrameworks
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: Debug
test_ios_rntester:
runs-on: macos-14-large
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies]
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
@@ -174,14 +155,14 @@ jobs:
fail-fast: false
matrix:
flavor: [Debug, Release]
frameworks: [StaticLibraries, DynamicFrameworks]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run it
uses: ./.github/actions/test-ios-rntester
with:
run-unit-tests: "false"
use-frameworks: StaticLibraries
use-frameworks: ${{ matrix.frameworks }}
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
flavor: ${{ matrix.flavor }}
@@ -264,6 +245,14 @@ jobs:
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
with:
name: ReactCore${{ matrix.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Prepare artifacts
run: |
REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
@@ -286,6 +275,7 @@ jobs:
NEW_ARCH_ENABLED=1
export RCT_USE_LOCAL_RN_DEP=/tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ matrix.flavor }}.xcframework.tar.gz"
HERMES_ENGINE_TARBALL_PATH=$HERMES_PATH RCT_NEW_ARCH_ENABLED=$NEW_ARCH_ENABLED bundle exec pod install
xcodebuild \
@@ -548,7 +538,7 @@ jobs:
test_ios_helloworld_with_ruby_3_2_0:
runs-on: macos-14
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
env:
PROJECT_NAME: iOSTemplateProject
HERMES_WS_DIR: /tmp/hermes
@@ -565,7 +555,7 @@ jobs:
test_ios_helloworld:
runs-on: macos-14
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
needs: [prepare_hermes_workspace, build_hermes_macos, prebuild_apple_dependencies, prebuild_react_native_core] # prepare_hermes_workspace must be there because we need its reference to retrieve a couple of outputs
strategy:
matrix:
flavor: [Debug, Release]
+3 -3
View File
@@ -28,8 +28,8 @@
"set-version": "node ./scripts/releases/set-version.js",
"test-android": "./gradlew :packages:react-native:ReactAndroid:test",
"test-ci": "jest --maxWorkers=2 --ci --reporters=\"default\" --reporters=\"jest-junit\"",
"test-e2e-local-clean": "node ./scripts/release-testing/test-e2e-local-clean.js",
"test-e2e-local": "node ./scripts/release-testing/test-e2e-local.js",
"test-release-local-clean": "node ./scripts/release-testing/test-release-local-clean.js",
"test-release-local": "node ./scripts/release-testing/test-release-local.js",
"test-ios": "./scripts/objc-test.sh test",
"test-typescript": "tsc -p packages/react-native/types/tsconfig.json",
"test-generated-typescript": "tsc -p packages/react-native/types_generated/tsconfig.test.json",
@@ -58,7 +58,7 @@
"@react-native/metro-config": "0.81.0-main",
"@tsconfig/node22": "22.0.2",
"@types/react": "^19.1.0",
"@typescript-eslint/parser": "^7.1.1",
"@typescript-eslint/parser": "^8.36.0",
"ansi-styles": "^4.2.1",
"babel-plugin-minify-dead-code-elimination": "^0.5.2",
"babel-plugin-syntax-hermes-parser": "0.29.1",
@@ -23,8 +23,8 @@
"@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.25.1",
"@react-native/eslint-plugin": "0.81.0-main",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"@typescript-eslint/eslint-plugin": "^8.36.0",
"@typescript-eslint/parser": "^8.36.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-ft-flow": "^2.0.1",
@@ -537,3 +537,160 @@ test('animate layout props', () => {
<rn-view height="100.000000" />,
);
});
test('AnimatedValue.interpolate', () => {
let _valueX;
let _interpolatedValueX;
const viewRef = createRef<HostInstance>();
function MyApp({outputRangeX}: $ReadOnly<{outputRangeX: number}>) {
const valueX = useAnimatedValue(0.5, {useNativeDriver: true});
_valueX = valueX;
const offset = outputRangeX - 1;
const interpolatedValueX = valueX.interpolate({
inputRange: [0, 1],
outputRange: [offset, 100],
});
_interpolatedValueX = interpolatedValueX;
return (
<Animated.View
ref={viewRef}
style={[
{
width: 100,
height: 100,
},
{transform: [{translateX: valueX}, {translateY: interpolatedValueX}]},
]}
/>
);
}
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(<MyApp outputRangeX={1} />);
});
const viewElement = ensureInstance(viewRef.current, ReactNativeElement);
expect(_valueX?.__getValue()).toBe(0.5);
expect(_interpolatedValueX?.__getValue()).toBe(50);
expect(
JSON.stringify(
Fantom.unstable_getDirectManipulationProps(viewElement).transform,
),
).toBe('[{"translateX":0.5},{"translateY":50}]');
expect(viewElement.getBoundingClientRect().x).toBe(0.5);
expect(viewElement.getBoundingClientRect().y).toBe(50);
Fantom.runTask(() => {
root.render(<MyApp outputRangeX={51} />);
});
expect(_valueX?.__getValue()).toBe(0.5);
expect(_interpolatedValueX?.__getValue()).toBe(75);
expect(
JSON.stringify(
Fantom.unstable_getDirectManipulationProps(viewElement).transform,
),
).toBe('[{"translateX":0.5},{"translateY":75}]');
expect(viewElement.getBoundingClientRect().x).toBe(0.5);
expect(viewElement.getBoundingClientRect().y).toBe(75);
});
test('Animated.sequence', () => {
let _translateY;
let _isSequenceFinished = false;
const elementRef = createRef<HostInstance>();
function MyApp() {
const translateY = useAnimatedValue(0, {useNativeDriver: true});
_translateY = translateY;
return (
<View>
<Animated.View
ref={elementRef}
style={[
{
position: 'absolute',
width: 100,
height: 100,
},
{
transform: [
{
translateY: translateY.interpolate({
inputRange: [0, 1],
outputRange: [0, -16],
}),
},
],
},
]}
/>
</View>
);
}
const root = Fantom.createRoot();
Fantom.runTask(() => {
root.render(<MyApp />);
});
const element = ensureInstance(elementRef.current, ReactNativeElement);
expect(element.getBoundingClientRect().y).toBe(0);
Fantom.runTask(() => {
Animated.sequence([
Animated.timing(_translateY, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}),
Animated.timing(_translateY, {
toValue: 0,
duration: 0,
useNativeDriver: true,
}),
]).start(({finished}) => {
if (finished) {
_isSequenceFinished = true;
}
});
});
Fantom.unstable_produceFramesForDuration(500);
expect(
// $FlowFixMe[incompatible-use]
Fantom.unstable_getDirectManipulationProps(element).transform[0].translateY,
).toBeCloseTo(-16, 0.001);
if (!ReactNativeFeatureFlags.cxxNativeAnimatedRemoveJsSync()) {
Fantom.runWorkLoop(); // React update to sync end state of 1st timing animation in sequence
}
expect(_isSequenceFinished).toBe(false);
expect(element.getBoundingClientRect().y).toBe(-16);
Fantom.runWorkLoop(); // React render
expect(
// $FlowFixMe[incompatible-use]
Fantom.unstable_getDirectManipulationProps(element).transform[0].translateY,
).toBeCloseTo(0, 0.001);
if (!ReactNativeFeatureFlags.cxxNativeAnimatedRemoveJsSync()) {
Fantom.runWorkLoop(); // React update to sync end state of 2nd timing animation in sequence
}
expect(element.getBoundingClientRect().y).toBe(0);
if (ReactNativeFeatureFlags.cxxNativeAnimatedRemoveJsSync()) {
expect(_isSequenceFinished).toBe(false);
Fantom.runWorkLoop();
}
expect(_isSequenceFinished).toBe(true);
});
+20 -5
View File
@@ -34,6 +34,9 @@ const RCTNetworking = require('./RCTNetworking').default;
const base64 = require('base64-js');
const invariant = require('invariant');
const PERFORMANCE_TRACK_NAME = 'Network (JS-initiated only)';
const PERFORMANCE_TRACK_GROUP = 'Chrome DevTools Temp Compat';
declare var performance: Performance;
const DEBUG_NETWORK_SEND_DELAY: false = false; // Set to a number of milliseconds when debugging
@@ -385,6 +388,9 @@ class XMLHttpRequest extends EventTarget {
if (requestId !== this._requestId) {
return;
}
const start = XMLHttpRequest._profiling ? performance.now() : undefined;
if (!this._response) {
this._response = responseText;
} else {
@@ -392,8 +398,13 @@ class XMLHttpRequest extends EventTarget {
}
if (XMLHttpRequest._profiling) {
performance.mark(
'Track:XMLHttpRequest:Incremental Data: ' + this._getMeasureURL(),
console.timeStamp(
'Incremental Data: ' + this._getMeasureURL(),
// $FlowFixMe[extra-arg] Add correct typing for `console.timeStamp`
start,
undefined,
PERFORMANCE_TRACK_NAME,
PERFORMANCE_TRACK_GROUP,
);
}
XMLHttpRequest._interceptor &&
@@ -442,10 +453,14 @@ class XMLHttpRequest extends EventTarget {
this.setReadyState(this.DONE);
if (XMLHttpRequest._profiling && this._startTime != null) {
const start = this._startTime;
performance.measure('Track:XMLHttpRequest:' + this._getMeasureURL(), {
console.timeStamp(
this._getMeasureURL(),
// $FlowFixMe[extra-arg] Add correct typing for `console.timeStamp`
start,
end: performance.now(),
});
undefined,
PERFORMANCE_TRACK_NAME,
PERFORMANCE_TRACK_GROUP,
);
}
if (error) {
XMLHttpRequest._interceptor &&
@@ -18,6 +18,7 @@ end
header_search_paths = [
"\"${PODS_ROOT}/Headers/Public/ReactCodegen/react/renderer/components\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTFBReactNativeSpec/FBReactNativeSpec\"",
]
Pod::Spec.new do |s|
@@ -45,7 +46,9 @@ Pod::Spec.new do |s|
s.dependency "React-Core/RCTPushNotificationHeaders"
s.dependency "React-jsi"
add_dependency(s, "React-RCTFBReactNativeSpec")
add_dependency(s, "React-RCTFBReactNativeSpec", :additional_framework_paths => ['FBReactNativeSpec'])
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
add_dependency(s, "React-NativeModulesApple")
add_rncore_dependency(s)
end
+1 -1
View File
@@ -166,7 +166,7 @@ let reactJsInspector = RNTarget(
name: .reactJsInspector,
path: "ReactCommon/jsinspector-modern",
excludedPaths: ["tracing", "network", "tests"],
dependencies: [.reactNativeDependencies, .reactFeatureFlags, .jsi, .reactJsInspectorTracing, .reactJsInspectorNetwork, .reactRuntimeExecutor],
dependencies: [.reactNativeDependencies, .reactFeatureFlags, .jsi, .reactJsInspectorTracing, .reactJsInspectorNetwork, .reactRuntimeExecutor, .reactPerfLogger],
defines: [
CXXSetting.define("REACT_NATIVE_DEBUGGER_ENABLED", to: "1", .when(configuration: BuildConfiguration.debug)),
CXXSetting.define("REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY", to: "1", .when(configuration: BuildConfiguration.debug)),
@@ -39,7 +39,7 @@ static NSString *const RCTPerfMonitorCellIdentifier = @"RCTPerfMonitorCellIdenti
static const CGFloat RCTPerfMonitorBarHeight = 50;
static const CGFloat RCTPerfMonitorExpandHeight = 250;
typedef BOOL (*RCTJSCSetOptionType)(const char *);
using RCTJSCSetOptionType = BOOL (*)(const char *);
NSArray<NSString *> *LabelsForRCTPerformanceLoggerTags();
@@ -117,6 +117,7 @@ public class ReactActivityDelegate {
* going away in the New Architecture. You should access {@link ReactHost} instead."
* @noinspection deprecation
*/
@Deprecated
public ReactInstanceManager getReactInstanceManager() {
return Objects.requireNonNull(mReactDelegate).getReactInstanceManager();
}
@@ -83,6 +83,9 @@ internal class ReactAndroidHWInputDeviceHelper(private val reactRootView: ReactR
KeyEvent.KEYCODE_DPAD_DOWN to "down",
KeyEvent.KEYCODE_DPAD_LEFT to "left",
KeyEvent.KEYCODE_INFO to "info",
KeyEvent.KEYCODE_MENU to "menu")
KeyEvent.KEYCODE_MENU to "menu",
KeyEvent.KEYCODE_CHANNEL_UP to "channelUp",
KeyEvent.KEYCODE_CHANNEL_DOWN to "channelDown",
)
}
}
@@ -10,26 +10,16 @@ package com.facebook.react.views.textinput
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.buildReadableMap
import com.facebook.react.uimanager.common.ViewUtil
import com.facebook.react.uimanager.events.Event
/** Event emitted by EditText native view when content size changes. */
internal class ReactContentSizeChangedEvent(
internal class ReactContentSizeChangedEvent
constructor(
surfaceId: Int,
viewId: Int,
private val contentWidth: Float,
private val contentHeight: Float
) : Event<ReactTextChangedEvent>(surfaceId, viewId) {
@Deprecated(
"Use the constructor with surfaceId instead",
ReplaceWith(
"ReactContentSizeChangedEvent(surfaceId, viewId, contentSizeWidth, contentSizeHeight)"))
constructor(
viewId: Int,
contentSizeWidth: Float,
contentSizeHeight: Float
) : this(ViewUtil.NO_SURFACE_ID, viewId, contentSizeWidth, contentSizeHeight)
override fun getEventName(): String = EVENT_NAME
override fun getEventData(): WritableMap {
@@ -9,7 +9,6 @@ package com.facebook.react.views.textinput
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.common.ViewUtil
import com.facebook.react.uimanager.events.Event
/** Event emitted by EditText native view when text changes. */
@@ -19,15 +18,6 @@ internal class ReactTextChangedEvent(
private val text: String,
private val eventCount: Int
) : Event<ReactTextChangedEvent>(surfaceId, viewId) {
@Deprecated(
"Use the constructor with surfaceId instead",
ReplaceWith("ReactTextChangedEvent(surfaceId, viewId, text, eventCount)"))
constructor(
viewId: Int,
text: String,
eventCount: Int
) : this(ViewUtil.NO_SURFACE_ID, viewId, text, eventCount)
override fun getEventName(): String = EVENT_NAME
override fun getEventData(): WritableMap {
@@ -9,7 +9,6 @@ package com.facebook.react.views.textinput
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.common.ViewUtil
import com.facebook.react.uimanager.events.Event
/**
@@ -21,11 +20,6 @@ internal class ReactTextInputEndEditingEvent(
viewId: Int,
private val text: String
) : Event<ReactTextInputEndEditingEvent>(surfaceId, viewId) {
@Deprecated(
"Use the constructor with surfaceId instead",
ReplaceWith("ReactTextInputEndEditingEvent(surfaceId, viewId, text)"))
constructor(viewId: Int, text: String) : this(ViewUtil.NO_SURFACE_ID, viewId, text)
override fun getEventName(): String = EVENT_NAME
override fun canCoalesce(): Boolean = false
@@ -9,17 +9,11 @@ package com.facebook.react.views.textinput
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.common.ViewUtil
import com.facebook.react.uimanager.events.Event
/** Event emitted by EditText native view when key pressed. */
internal class ReactTextInputKeyPressEvent(surfaceId: Int, viewId: Int, private val key: String) :
Event<ReactTextInputKeyPressEvent>(surfaceId, viewId) {
@Deprecated(
"Use the constructor with surfaceId instead",
ReplaceWith("ReactTextInputKeyPressEvent(surfaceId, viewId, key)"))
constructor(viewId: Int, key: String) : this(ViewUtil.NO_SURFACE_ID, viewId, key)
override fun getEventName(): String = EVENT_NAME
override fun getEventData(): WritableMap {
@@ -10,7 +10,6 @@ package com.facebook.react.views.textinput
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.buildReadableMap
import com.facebook.react.uimanager.common.ViewUtil
import com.facebook.react.uimanager.events.Event
/** Event emitted by EditText native view when the text selection changes. */
@@ -20,15 +19,6 @@ internal class ReactTextInputSelectionEvent(
private val selectionStart: Int,
private val selectionEnd: Int
) : Event<ReactTextInputSelectionEvent>(surfaceId, viewId) {
@Deprecated(
"Use the constructor with surfaceId instead",
ReplaceWith("ReactTextInputSelectionEvent(surfaceId, viewId, selectionStart, selectionEnd)"))
constructor(
viewId: Int,
selectionStart: Int,
selectionEnd: Int
) : this(ViewUtil.NO_SURFACE_ID, viewId, selectionStart, selectionEnd)
override fun getEventName(): String = EVENT_NAME
override fun getEventData(): WritableMap {
@@ -9,7 +9,6 @@ package com.facebook.react.views.textinput
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.common.ViewUtil
import com.facebook.react.uimanager.events.Event
/** Event emitted by EditText native view when the user submits the text. */
@@ -18,11 +17,6 @@ internal class ReactTextInputSubmitEditingEvent(
viewId: Int,
private val text: String
) : Event<ReactTextInputSubmitEditingEvent>(surfaceId, viewId) {
@Deprecated(
"Use the constructor with surfaceId instead",
ReplaceWith("ReactTextInputSubmitEditingEvent(surfaceId, viewId, text)"))
constructor(viewId: Int, text: String) : this(ViewUtil.NO_SURFACE_ID, viewId, text)
override fun getEventName(): String = EVENT_NAME
override fun getEventData(): WritableMap {
@@ -25,6 +25,7 @@ target_link_libraries(jsinspector
jsinspector_tracing
react_featureflags
runtimeexecutor
reactperflogger
)
target_compile_reactnative_options(jsinspector PRIVATE)
target_compile_options(jsinspector PRIVATE
@@ -8,6 +8,7 @@
#include <jsinspector-modern/RuntimeTarget.h>
#include <jsinspector-modern/tracing/PerformanceTracer.h>
#include <reactperflogger/ReactPerfettoLogger.h>
#include <concepts>
#include <deque>
#include <string>
@@ -19,6 +20,20 @@ namespace facebook::react::jsinspector_modern {
namespace {
inline std::optional<HighResTimeStamp> getTimeStampForPerfetto(
const std::optional<tracing::ConsoleTimeStampEntry>& consoleTimeStampEntry,
const HighResTimeStamp now) {
if (consoleTimeStampEntry) {
if (std::holds_alternative<HighResTimeStamp>(*consoleTimeStampEntry)) {
return std::get<HighResTimeStamp>(*consoleTimeStampEntry);
} else {
return std::nullopt;
}
} else {
return now;
}
}
struct ConsoleState {
/**
* https://console.spec.whatwg.org/#counting
@@ -376,7 +391,8 @@ void consoleTimeStamp(
const jsi::Value* arguments,
size_t argumentsCount) {
auto& performanceTracer = tracing::PerformanceTracer::getInstance();
if (!performanceTracer.isTracing() || argumentsCount == 0) {
if ((!performanceTracer.isTracing() && !ReactPerfettoLogger::isTracing()) ||
argumentsCount == 0) {
// If not tracing, just early return to avoid the cost of parsing.
return;
}
@@ -444,8 +460,22 @@ void consoleTimeStamp(
}
}
performanceTracer.reportTimeStamp(
label, start, end, trackName, trackGroup, color);
if (performanceTracer.isTracing()) {
performanceTracer.reportTimeStamp(
label, start, end, trackName, trackGroup, color);
}
if (ReactPerfettoLogger::isTracing()) {
std::optional<HighResTimeStamp> perfettoStart =
getTimeStampForPerfetto(start, now);
std::optional<HighResTimeStamp> perfettoEnd =
getTimeStampForPerfetto(end, now);
if (perfettoStart && perfettoEnd) {
ReactPerfettoLogger::measure(
label, *perfettoStart, *perfettoEnd, trackName, trackGroup);
}
}
}
/*
@@ -491,45 +491,6 @@ inline static void updateAccessibilityStateProp(
result["accessibilityState"] = resultState;
}
static folly::dynamic toDynamic(const std::vector<BoxShadow>& boxShadow) {
folly::dynamic boxShadowResult = folly::dynamic::array();
for (const auto& boxShadowValue : boxShadow) {
folly::dynamic boxShadowValueResult = folly::dynamic::object();
boxShadowValueResult["offsetX"] = boxShadowValue.offsetX;
boxShadowValueResult["offsetY"] = boxShadowValue.offsetY;
boxShadowValueResult["blurRadius"] = boxShadowValue.blurRadius;
boxShadowValueResult["spreadDistance"] = boxShadowValue.spreadDistance;
boxShadowValueResult["color"] = *boxShadowValue.color;
boxShadowValueResult["inset"] = boxShadowValue.inset;
boxShadowResult.push_back(boxShadowValueResult);
}
return boxShadowResult;
}
static folly::dynamic toDynamic(const std::vector<FilterFunction>& filter) {
folly::dynamic filterResult = folly::dynamic::array();
for (const auto& filterFunction : filter) {
folly::dynamic filterFunctionResult = folly::dynamic::object();
std::string typeKey = toString(filterFunction.type);
if (std::holds_alternative<Float>(filterFunction.parameters)) {
filterFunctionResult[typeKey] =
std::get<Float>(filterFunction.parameters);
} else if (std::holds_alternative<DropShadowParams>(
filterFunction.parameters)) {
const auto& parameters =
std::get<DropShadowParams>(filterFunction.parameters);
folly::dynamic parametersResult = folly::dynamic::object();
parametersResult["offsetX"] = parameters.offsetX;
parametersResult["offsetY"] = parameters.offsetY;
parametersResult["standardDeviation"] = parameters.standardDeviation;
parametersResult["color"] = *parameters.color;
filterFunctionResult[typeKey] = parametersResult;
}
filterResult.push_back(filterFunctionResult);
}
return filterResult;
}
ComponentName HostPlatformViewProps::getDiffPropsImplementationTarget() const {
return "View";
}
@@ -36,7 +36,7 @@ std::optional<double> DynamicEventPayload::extractValue(
if (dynamic.type() == folly::dynamic::Type::DOUBLE) {
return dynamic.asDouble();
} else if (dynamic.type() == folly::dynamic::Type::INT64) {
return dynamic.asInt();
return static_cast<double>(dynamic.asInt());
}
return std::nullopt;
}
@@ -21,5 +21,25 @@ struct BoxShadow {
Float spreadDistance{};
SharedColor color{};
bool inset{};
#ifdef RN_SERIALIZABLE_STATE
folly::dynamic toDynamic() const {
folly::dynamic result = folly::dynamic::object();
result["offsetX"] = offsetX;
result["offsetY"] = offsetY;
result["blurRadius"] = blurRadius;
result["spreadDistance"] = spreadDistance;
result["color"] = *color;
result["inset"] = inset;
return result;
}
#endif
};
#ifdef RN_SERIALIZABLE_STATE
inline folly::dynamic toDynamic(const BoxShadow& boxShadow) {
return boxShadow.toDynamic();
}
#endif
} // namespace facebook::react
@@ -8,7 +8,6 @@
#pragma once
#include <functional>
#include <limits>
#include <react/renderer/graphics/ColorComponents.h>
#include <react/renderer/graphics/HostPlatformColor.h>
@@ -29,22 +29,6 @@ enum class FilterType {
DropShadow
};
struct DropShadowParams {
bool operator==(const DropShadowParams& other) const = default;
Float offsetX{};
Float offsetY{};
Float standardDeviation{};
SharedColor color{};
};
struct FilterFunction {
bool operator==(const FilterFunction& other) const = default;
FilterType type{};
std::variant<Float, DropShadowParams> parameters{};
};
inline FilterType filterTypeFromString(std::string_view filterName) {
if (filterName == "blur") {
return FilterType::Blur;
@@ -96,4 +80,51 @@ inline std::string toString(const FilterType& filterType) {
}
}
struct DropShadowParams {
bool operator==(const DropShadowParams& other) const = default;
Float offsetX{};
Float offsetY{};
Float standardDeviation{};
SharedColor color{};
#ifdef RN_SERIALIZABLE_STATE
folly::dynamic toDynamic() const {
folly::dynamic result = folly::dynamic::object();
result["offsetX"] = offsetX;
result["offsetY"] = offsetY;
result["standardDeviation"] = standardDeviation;
result["color"] = *color;
return result;
}
#endif
};
struct FilterFunction {
bool operator==(const FilterFunction& other) const = default;
FilterType type{};
std::variant<Float, DropShadowParams> parameters{};
#ifdef RN_SERIALIZABLE_STATE
folly::dynamic toDynamic() const {
folly::dynamic result = folly::dynamic::object();
std::string typeKey = toString(type);
if (std::holds_alternative<Float>(parameters)) {
result[typeKey] = std::get<Float>(parameters);
} else if (std::holds_alternative<DropShadowParams>(parameters)) {
const auto& dropShadowParams = std::get<DropShadowParams>(parameters);
result[typeKey] = dropShadowParams.toDynamic();
}
return result;
}
#endif
};
#ifdef RN_SERIALIZABLE_STATE
inline folly::dynamic toDynamic(const FilterFunction& filterFunction) {
return filterFunction.toDynamic();
}
#endif
} // namespace facebook::react
@@ -8,7 +8,6 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include <react/renderer/debug/flags.h>
@@ -37,7 +36,7 @@ inline bool isZero(Float n) {
* An "Arbitrary" operation means that the transform was seeded with some
* arbitrary initial result.
*/
enum class TransformOperationType {
enum class TransformOperationType : uint8_t {
Arbitrary,
Identity,
Perspective,
@@ -200,7 +200,7 @@ namespace {
// Copied from JSIExecutor.cpp
// basename_r isn't in all iOS SDKs, so use this simple version instead.
std::string simpleBasename(const std::string& path) {
size_t pos = path.rfind("/");
size_t pos = path.rfind('/');
return (pos != std::string::npos) ? path.substr(pos) : path;
}
@@ -22,10 +22,26 @@ const std::string PERFETTO_DEFAULT_TRACK_NAME = "# Web Performance";
const std::string PERFETTO_TRACK_NAME_PREFIX = "# Web Performance: ";
std::string toPerfettoTrackName(
const std::optional<std::string_view>& trackName) {
return trackName.has_value()
? PERFETTO_TRACK_NAME_PREFIX + std::string(trackName.value())
: PERFETTO_DEFAULT_TRACK_NAME;
const std::optional<std::string_view>& trackName,
const std::optional<std::string_view>& trackGroup) {
std::string perfettoTrackName = PERFETTO_DEFAULT_TRACK_NAME;
if (trackName || trackGroup) {
perfettoTrackName += ": ";
if (trackGroup) {
perfettoTrackName += *trackGroup;
if (trackName) {
perfettoTrackName += " | ";
}
}
if (trackName) {
perfettoTrackName += *trackName;
}
}
return perfettoTrackName;
}
#elif defined(WITH_FBSYSTRACE)
int64_t getDeltaNanos(HighResTimeStamp jsTime) {
@@ -50,10 +66,12 @@ int64_t getDeltaNanos(HighResTimeStamp jsTime) {
const std::string_view& eventName,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
const std::optional<std::string_view>& trackName) {
const std::optional<std::string_view>& trackName,
const std::optional<std::string_view>& trackGroup) {
#if defined(WITH_PERFETTO)
if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) {
auto track = getPerfettoWebPerfTrackAsync(toPerfettoTrackName(trackName));
auto track = getPerfettoWebPerfTrackAsync(
toPerfettoTrackName(trackName, trackGroup));
TRACE_EVENT_BEGIN(
"react-native",
perfetto::DynamicString(eventName.data(), eventName.size()),
@@ -75,13 +93,14 @@ int64_t getDeltaNanos(HighResTimeStamp jsTime) {
/* static */ void ReactPerfettoLogger::mark(
const std::string_view& eventName,
HighResTimeStamp startTime,
const std::optional<std::string_view>& trackName) {
const std::optional<std::string_view>& trackName,
const std::optional<std::string_view>& trackGroup) {
#if defined(WITH_PERFETTO)
if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) {
TRACE_EVENT_INSTANT(
"react-native",
perfetto::DynamicString(eventName.data(), eventName.size()),
getPerfettoWebPerfTrackSync(toPerfettoTrackName(trackName)),
getPerfettoWebPerfTrackSync(toPerfettoTrackName(trackName, trackGroup)),
highResTimeStampToPerfettoTraceTime(startTime));
}
#elif defined(WITH_FBSYSTRACE)
@@ -11,7 +11,7 @@
#include <reactperflogger/ReactPerfettoCategories.h>
#include <optional>
#include <string>
#include <string_view>
namespace facebook::react {
@@ -26,13 +26,15 @@ class ReactPerfettoLogger {
static void mark(
const std::string_view& eventName,
HighResTimeStamp startTime,
const std::optional<std::string_view>& trackName);
const std::optional<std::string_view>& trackName = std::nullopt,
const std::optional<std::string_view>& trackGroup = std::nullopt);
static void measure(
const std::string_view& eventName,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
const std::optional<std::string_view>& trackName);
const std::optional<std::string_view>& trackName = std::nullopt,
const std::optional<std::string_view>& trackGroup = std::nullopt);
};
} // namespace facebook::react
@@ -478,16 +478,19 @@ static void zeroOutLayoutRecursively(yoga::Node* const node) {
}
static void cleanupContentsNodesRecursively(yoga::Node* const node) {
for (auto child : node->getChildren()) {
if (child->style().display() == Display::Contents) {
child->getLayout() = {};
child->setLayoutDimension(0, Dimension::Width);
child->setLayoutDimension(0, Dimension::Height);
child->setHasNewLayout(true);
child->setDirty(false);
child->cloneChildrenIfNeeded();
if (node->hasContentsChildren()) [[unlikely]] {
node->cloneContentsChildrenIfNeeded();
for (auto child : node->getChildren()) {
if (child->style().display() == Display::Contents) {
child->getLayout() = {};
child->setLayoutDimension(0, Dimension::Width);
child->setLayoutDimension(0, Dimension::Height);
child->setHasNewLayout(true);
child->setDirty(false);
child->cloneChildrenIfNeeded();
cleanupContentsNodesRecursively(child);
cleanupContentsNodesRecursively(child);
}
}
}
}
@@ -181,6 +181,17 @@ void Node::setDirty(bool isDirty) {
}
}
void Node::setChildren(const std::vector<Node*>& children) {
children_ = children;
contentsChildrenCount_ = 0;
for (const auto& child : children) {
if (child->style().display() == Display::Contents) {
contentsChildrenCount_++;
}
}
}
bool Node::removeChild(Node* child) {
auto p = std::find(children_.begin(), children_.end(), child);
if (p != children_.end()) {
@@ -380,6 +391,23 @@ void Node::cloneChildrenIfNeeded() {
if (child->getOwner() != this) {
child = resolveRef(config_->cloneNode(child, this, i));
child->setOwner(this);
if (child->hasContentsChildren()) [[unlikely]] {
child->cloneContentsChildrenIfNeeded();
}
}
i += 1;
}
}
void Node::cloneContentsChildrenIfNeeded() {
size_t i = 0;
for (Node*& child : children_) {
if (child->style().display() == Display::Contents &&
child->getOwner() != this) {
child = resolveRef(config_->cloneNode(child, this, i));
child->setOwner(this);
child->cloneChildrenIfNeeded();
}
i += 1;
}
@@ -96,6 +96,10 @@ class YG_EXPORT Node : public ::YGNode {
return config_->hasErrata(errata);
}
bool hasContentsChildren() const {
return contentsChildrenCount_ != 0;
}
YGDirtiedFunc getDirtiedFunc() const {
return dirtiedFunc_;
}
@@ -244,15 +248,12 @@ class YG_EXPORT Node : public ::YGNode {
owner_ = owner;
}
void setChildren(const std::vector<Node*>& children) {
children_ = children;
}
// TODO: rvalue override for setChildren
void setConfig(Config* config);
void setDirty(bool isDirty);
void setChildren(const std::vector<Node*>& children);
void setLayoutLastOwnerDirection(Direction direction);
void setLayoutComputedFlexBasis(FloatOptional computedFlexBasis);
void setLayoutComputedFlexBasisGeneration(
@@ -286,6 +287,7 @@ class YG_EXPORT Node : public ::YGNode {
void removeChild(size_t index);
void cloneChildrenIfNeeded();
void cloneContentsChildrenIfNeeded();
void markDirtyAndPropagate();
float resolveFlexGrow() const;
float resolveFlexShrink() const;
@@ -134,8 +134,8 @@ class ReactNativeCoreUtils
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
maven_repo_url =
ENV[ENTERPRISE_REPOSITORY] != nil && ENV[ENTERPRISE_REPOSITORY] != "" ?
ENV[ENTERPRISE_REPOSITORY] :
ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != "" ?
ENV['ENTERPRISE_REPOSITORY'] :
"https://repo1.maven.org/maven2"
group = "com/facebook/react"
# Sample url from Maven:
@@ -169,8 +169,8 @@ class ReactNativeDependenciesUtils
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
maven_repo_url =
ENV[ENTERPRISE_REPOSITORY] != nil && ENV[ENTERPRISE_REPOSITORY] != "" ?
ENV[ENTERPRISE_REPOSITORY] :
ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != "" ?
ENV['ENTERPRISE_REPOSITORY'] :
"https://repo1.maven.org/maven2"
group = "com/facebook/react"
# Sample url from Maven:
@@ -207,8 +207,8 @@ def release_tarball_url(version, build_type)
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
maven_repo_url =
ENV[ENTERPRISE_REPOSITORY] != nil && ENV[ENTERPRISE_REPOSITORY] != "" ?
ENV[ENTERPRISE_REPOSITORY] :
ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != "" ?
ENV['ENTERPRISE_REPOSITORY'] :
"https://repo1.maven.org/maven2"
namespace = "com/facebook/react"
# Sample url from Maven:
@@ -15,7 +15,11 @@ import type {
PerformanceEntryList,
PerformanceEntryType,
} from './PerformanceEntry';
import type {DetailType, PerformanceMarkOptions} from './UserTiming';
import type {
DetailType,
PerformanceMarkOptions,
PerformanceMeasureInit,
} from './UserTiming';
import DOMException from '../errors/DOMException';
import structuredClone from '../structuredClone/structuredClone';
@@ -25,35 +29,46 @@ import {
performanceEntryTypeToRaw,
rawToPerformanceEntry,
} from './internals/RawPerformanceEntry';
import {warnNoNativePerformance} from './internals/Utilities';
import {
getCurrentTimeStamp,
warnNoNativePerformance,
} from './internals/Utilities';
import MemoryInfo from './MemoryInfo';
import ReactNativeStartupTiming from './ReactNativeStartupTiming';
import NativePerformance from './specs/NativePerformance';
import {PerformanceMark, PerformanceMeasure} from './UserTiming';
declare var global: {
// This value is defined directly via JSI, if available.
+nativePerformanceNow?: ?() => number,
};
const getCurrentTimeStamp: () => DOMHighResTimeStamp =
NativePerformance?.now ?? global.nativePerformanceNow ?? (() => Date.now());
export type PerformanceMeasureOptions =
| {
| $ReadOnly<{
detail?: DetailType,
start?: DOMHighResTimeStamp | string,
duration?: DOMHighResTimeStamp,
}
| {
}>
| $ReadOnly<{
detail?: DetailType,
start?: DOMHighResTimeStamp | string,
end?: DOMHighResTimeStamp | string,
};
}>;
const ENTRY_TYPES_AVAILABLE_FROM_TIMELINE: $ReadOnlyArray<PerformanceEntryType> =
['mark', 'measure'];
const cachedNativeMark = NativePerformance?.markWithResult;
const cachedNativeMeasure = NativePerformance?.measure;
const cachedNativeClearMarks = NativePerformance?.clearMarks;
const cachedNativeClearMeasures = NativePerformance?.clearMeasures;
const MARK_OPTIONS_REUSABLE_OBJECT: {...PerformanceMarkOptions} = {
startTime: 0,
detail: undefined,
};
const MEASURE_OPTIONS_REUSABLE_OBJECT: {...PerformanceMeasureInit} = {
startTime: 0,
duration: 0,
detail: undefined,
};
/**
* Partial implementation of the Performance interface for RN,
* corresponding to the standard in
@@ -117,58 +132,68 @@ export default class Performance {
markName: string,
markOptions?: PerformanceMarkOptions,
): PerformanceMark {
if (markName == null) {
// IMPORTANT: this method has been micro-optimized.
// Please run the benchmarks in `Performance-benchmarks-itest` to ensure
// changes do not regress performance.
if (markName === undefined) {
throw new TypeError(
`Failed to execute 'mark' on 'Performance': 1 argument required, but only 0 present.`,
);
}
const resolvedMarkName =
typeof markName === 'string' ? markName : String(markName);
let resolvedDetail;
if (markOptions?.detail != null) {
resolvedDetail = structuredClone(markOptions.detail);
const detail = markOptions?.detail;
if (detail !== undefined) {
resolvedDetail = structuredClone(detail);
}
let computedStartTime;
if (NativePerformance?.markWithResult) {
if (cachedNativeMark) {
let resolvedStartTime;
const startTime = markOptions?.startTime;
if (startTime !== undefined) {
resolvedStartTime = Number(startTime);
resolvedStartTime =
typeof startTime === 'number' ? startTime : Number(startTime);
if (resolvedStartTime < 0) {
throw new TypeError(
`Failed to execute 'mark' on 'Performance': '${markName}' cannot have a negative start time.`,
`Failed to execute 'mark' on 'Performance': '${resolvedMarkName}' cannot have a negative start time.`,
);
} else if (!Number.isFinite(resolvedStartTime)) {
} else if (
// This is faster than calling Number.isFinite()
// eslint-disable-next-line no-self-compare
resolvedStartTime !== resolvedStartTime ||
resolvedStartTime === Infinity
) {
throw new TypeError(
`Failed to execute 'mark' on 'Performance': Failed to read the 'startTime' property from 'PerformanceMarkOptions': The provided double value is non-finite.`,
);
}
}
// $FlowExpectedError[not-a-function]
computedStartTime = NativePerformance.markWithResult(
markName,
resolvedStartTime,
);
computedStartTime = cachedNativeMark(resolvedMarkName, resolvedStartTime);
} else {
warnNoNativePerformance();
computedStartTime = performance.now();
computedStartTime = getCurrentTimeStamp();
}
return new PerformanceMark(markName, {
startTime: computedStartTime,
detail: resolvedDetail,
});
MARK_OPTIONS_REUSABLE_OBJECT.startTime = computedStartTime;
MARK_OPTIONS_REUSABLE_OBJECT.detail = resolvedDetail;
return new PerformanceMark(resolvedMarkName, MARK_OPTIONS_REUSABLE_OBJECT);
}
clearMarks(markName?: string): void {
if (!NativePerformance?.clearMarks) {
if (!cachedNativeClearMarks) {
warnNoNativePerformance();
return;
}
NativePerformance.clearMarks(markName);
cachedNativeClearMarks(markName);
}
measure(
@@ -176,6 +201,18 @@ export default class Performance {
startMarkOrOptions?: string | PerformanceMeasureOptions,
endMark?: string,
): PerformanceMeasure {
// IMPORTANT: this method has been micro-optimized.
// Please run the benchmarks in `Performance-benchmarks-itest` to ensure
// changes do not regress performance.
if (measureName === undefined) {
throw new TypeError(
`Failed to execute 'measure' on 'Performance': 1 argument required, but only 0 present.`,
);
}
let resolvedMeasureName =
typeof measureName === 'string' ? measureName : String(measureName);
let resolvedStartTime: number | void;
let resolvedStartMark: string | void;
let resolvedEndTime: number | void;
@@ -186,7 +223,7 @@ export default class Performance {
if (startMarkOrOptions != null) {
switch (typeof startMarkOrOptions) {
case 'object': {
if (endMark != null) {
if (endMark !== undefined) {
throw new TypeError(
`Failed to execute 'measure' on 'Performance': If a non-empty PerformanceMeasureOptions object was passed, |end_mark| must not be passed.`,
);
@@ -247,8 +284,8 @@ export default class Performance {
}
if (
resolvedDuration != null &&
(resolvedEndMark != null || resolvedEndTime != null)
resolvedDuration !== undefined &&
(resolvedEndMark !== undefined || resolvedEndTime !== undefined)
) {
throw new TypeError(
`Failed to execute 'measure' on 'Performance': If a non-empty PerformanceMeasureOptions object was passed, it must not have all of its 'start', 'duration', and 'end' properties defined`,
@@ -256,7 +293,7 @@ export default class Performance {
}
const detail = startMarkOrOptions.detail;
if (detail != null) {
if (detail !== undefined) {
resolvedDetail = structuredClone(detail);
}
@@ -279,10 +316,10 @@ export default class Performance {
let computedStartTime = 0;
let computedDuration = 0;
if (NativePerformance?.measure) {
if (cachedNativeMeasure) {
try {
[computedStartTime, computedDuration] = NativePerformance.measure(
measureName,
[computedStartTime, computedDuration] = cachedNativeMeasure(
resolvedMeasureName,
resolvedStartTime,
resolvedEndTime,
resolvedDuration,
@@ -299,7 +336,7 @@ export default class Performance {
try {
[computedStartTime, computedDuration] =
NativePerformance.measureWithResult(
measureName,
resolvedMeasureName,
resolvedStartTime ?? 0,
resolvedEndTime ?? 0,
resolvedDuration,
@@ -316,22 +353,23 @@ export default class Performance {
warnNoNativePerformance();
}
const measure = new PerformanceMeasure(measureName, {
startTime: computedStartTime,
duration: computedDuration ?? 0,
detail: resolvedDetail,
});
MEASURE_OPTIONS_REUSABLE_OBJECT.startTime = computedStartTime;
MEASURE_OPTIONS_REUSABLE_OBJECT.duration = computedDuration ?? 0;
MEASURE_OPTIONS_REUSABLE_OBJECT.detail = resolvedDetail;
return measure;
return new PerformanceMeasure(
resolvedMeasureName,
MEASURE_OPTIONS_REUSABLE_OBJECT,
);
}
clearMeasures(measureName?: string): void {
if (!NativePerformance?.clearMeasures) {
if (!cachedNativeClearMeasures) {
warnNoNativePerformance();
return;
}
NativePerformance?.clearMeasures(measureName);
cachedNativeClearMeasures(measureName);
}
/**
@@ -12,44 +12,43 @@
import type {DOMHighResTimeStamp} from './PerformanceEntry';
import {getCurrentTimeStamp} from './internals/Utilities';
import {PerformanceEntry} from './PerformanceEntry';
export type DetailType = mixed;
export type PerformanceMarkOptions = {
export type PerformanceMarkOptions = $ReadOnly<{
detail?: DetailType,
startTime?: DOMHighResTimeStamp,
};
}>;
export type TimeStampOrName = DOMHighResTimeStamp | string;
export type PerformanceMeasureInit = {
export type PerformanceMeasureInit = $ReadOnly<{
detail?: DetailType,
startTime: DOMHighResTimeStamp,
duration: DOMHighResTimeStamp,
};
}>;
class PerformanceMarkTemplate extends PerformanceEntry {
// We don't use private fields because they're significantly slower to
// initialize on construction and to access.
_detail: DetailType;
__detail: DetailType;
// This constructor isn't really used. See `PerformanceMark` below.
constructor(markName: string, markOptions?: PerformanceMarkOptions) {
super({
name: markName,
entryType: 'mark',
startTime: markOptions?.startTime ?? performance.now(),
startTime: markOptions?.startTime ?? getCurrentTimeStamp(),
duration: 0,
});
if (markOptions) {
this._detail = markOptions.detail;
}
this.__detail = markOptions?.detail ?? null;
}
get detail(): DetailType {
return this._detail;
return this.__detail;
}
}
@@ -67,12 +66,10 @@ export const PerformanceMark: typeof PerformanceMarkTemplate =
) {
this.__name = markName;
this.__entryType = 'mark';
this.__startTime = markOptions?.startTime ?? performance.now();
this.__startTime = markOptions?.startTime ?? getCurrentTimeStamp();
this.__duration = 0;
if (markOptions) {
this._detail = markOptions.detail;
}
this.__detail = markOptions?.detail ?? null;
};
// $FlowExpectedError[prop-missing]
@@ -81,7 +78,7 @@ PerformanceMark.prototype = PerformanceMarkTemplate.prototype;
class PerformanceMeasureTemplate extends PerformanceEntry {
// We don't use private fields because they're significantly slower to
// initialize on construction and to access.
_detail: DetailType;
__detail: DetailType;
// This constructor isn't really used. See `PerformanceMeasure` below.
constructor(measureName: string, measureOptions: PerformanceMeasureInit) {
@@ -92,13 +89,11 @@ class PerformanceMeasureTemplate extends PerformanceEntry {
duration: measureOptions.duration,
});
if (measureOptions) {
this._detail = measureOptions.detail;
}
this.__detail = measureOptions?.detail ?? null;
}
get detail(): DetailType {
return this._detail;
return this.__detail;
}
}
@@ -115,9 +110,7 @@ export const PerformanceMeasure: typeof PerformanceMeasureTemplate =
this.__startTime = measureOptions.startTime;
this.__duration = measureOptions.duration;
if (measureOptions) {
this._detail = measureOptions.detail;
}
this.__detail = measureOptions.detail ?? null;
};
// $FlowExpectedError[prop-missing]
@@ -44,6 +44,15 @@ Fantom.unstable_benchmark
afterEach: clearMarksAndMeasures,
},
)
.test(
'measure (default)',
() => {
performance.measure('measure');
},
{
afterEach: clearMarksAndMeasures,
},
)
.test(
'measure (with start and end timestamps)',
() => {
@@ -53,7 +53,7 @@ describe('Performance', () => {
expect(mark.name).toBe('mark-now');
expect(mark.startTime).toBe(25);
expect(mark.duration).toBe(0);
expect(mark.detail).toBeUndefined();
expect(mark.detail).toBe(null);
});
it('works with custom timestamp', () => {
@@ -64,7 +64,7 @@ describe('Performance', () => {
expect(mark.name).toBe('mark-custom');
expect(mark.startTime).toBe(10);
expect(mark.duration).toBe(0);
expect(mark.detail).toBeUndefined();
expect(mark.detail).toBe(null);
});
it('provides detail', () => {
@@ -78,6 +78,13 @@ describe('Performance', () => {
expect(mark.detail).not.toBe(originalDetail);
});
it('provides a null detail if it is not provided or is undefined', () => {
expect(performance.mark('mark-without-detail').detail).toBe(null);
expect(
performance.mark('mark-without-detail', {detail: undefined}).detail,
).toBe(null);
});
it('throws if no name is provided', () => {
expect(() => {
// $FlowExpectedError[incompatible-call]
@@ -87,6 +94,13 @@ describe('Performance', () => {
);
});
it('casts mark name to a string', () => {
// $FlowExpectedError[incompatible-call]
const mark = performance.mark(10);
expect(mark.name).toBe('10');
});
it('casts startTime to a number', () => {
const mark = performance.mark('some-mark', {
// $FlowExpectedError[incompatible-call]
@@ -139,7 +153,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-defaults');
expect(measure.startTime).toBe(0);
expect(measure.duration).toBe(25);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with a start timestamp', () => {
@@ -154,7 +168,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-start-timestamp');
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(15);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with start mark', () => {
@@ -173,7 +187,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-start-mark');
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(15);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with end mark', () => {
@@ -192,7 +206,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-end-mark');
expect(measure.startTime).toBe(0);
expect(measure.duration).toBe(50);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with start mark and end mark', () => {
@@ -219,7 +233,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-start-mark-and-end-mark');
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(40);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with a start timestamp and an end timestamp', () => {
@@ -238,7 +252,7 @@ describe('Performance', () => {
);
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(15);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with a start timestamp and a duration', () => {
@@ -255,7 +269,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-start-timestamp-and-duration');
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(30);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with a start mark and a duration', () => {
@@ -276,7 +290,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-start-mark-and-duration');
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(30);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('throws if the specified mark does NOT exist', () => {
@@ -332,7 +346,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-defaults');
expect(measure.startTime).toBe(0);
expect(measure.duration).toBe(25);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with startMark', () => {
@@ -352,7 +366,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-start-mark');
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(15);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('works with startMark and endMark', () => {
@@ -376,7 +390,7 @@ describe('Performance', () => {
expect(measure.name).toBe('measure-with-start-mark-and-end-mark');
expect(measure.startTime).toBe(10);
expect(measure.duration).toBe(15);
expect(measure.detail).toBeUndefined();
expect(measure.detail).toBe(null);
});
it('throws if the specified marks do NOT exist', () => {
@@ -424,6 +438,30 @@ describe('Performance', () => {
expect(measure.detail).toEqual(originalDetail);
expect(measure.detail).not.toBe(originalDetail);
});
it('provides a null detail if it is not provided or is undefined', () => {
expect(performance.measure('measure-without-detail').detail).toBe(null);
expect(
performance.measure('measure-without-detail', {detail: undefined})
.detail,
).toBe(null);
});
it('casts measure name to a string', () => {
// $FlowExpectedError[incompatible-call]
const measure = performance.measure(10);
expect(measure.name).toBe('10');
});
it('throws if no name is provided', () => {
expect(() => {
// $FlowExpectedError[incompatible-call]
performance.measure();
}).toThrow(
`Failed to execute 'measure' on 'Performance': 1 argument required, but only 0 present.`,
);
});
});
describe('getting and clearing marks and measures', () => {
@@ -9,6 +9,7 @@
*/
import warnOnce from '../../../../../Libraries/Utilities/warnOnce';
import NativePerformance from '../specs/NativePerformance';
export function warnNoNativePerformance() {
warnOnce(
@@ -16,3 +17,11 @@ export function warnNoNativePerformance() {
'Missing native implementation of Performance',
);
}
declare var global: {
// This value is defined directly via JSI, if available.
+nativePerformanceNow?: ?() => number,
};
export const getCurrentTimeStamp: () => DOMHighResTimeStamp =
NativePerformance?.now ?? global.nativePerformanceNow ?? (() => Date.now());
+2 -2
View File
@@ -6,10 +6,10 @@ Scripts supporting local manual release testing. See also [How to Test a Release
For information on command arguments, run `node <command> --help`.
### `test-e2e-local`
### `test-release-local`
Set up, build, and install a given test app configuration.
### `test-e2e-local-clean`
### `test-release-local-clean`
Clean up all file system and cache state between tests.
@@ -11,7 +11,7 @@
'use strict';
/*
* This script, paired with test-e2e-local.js, is the full suite of
* This script, paired with test-release-local.js, is the full suite of
* tooling needed for a successful local testing experience.
* This script is an helper to clean up the environment fully
* before running the test suite.
+109 -71
View File
@@ -1359,13 +1359,20 @@
minimist "^1.2.8"
postject "^1.0.0-alpha.6"
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
"@eslint-community/eslint-utils@^4.7.0":
version "4.7.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a"
integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==
dependencies:
eslint-visitor-keys "^3.4.3"
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae"
@@ -2495,20 +2502,20 @@
dependencies:
"@types/node" "*"
"@typescript-eslint/eslint-plugin@^7.1.1":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3"
integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==
"@typescript-eslint/eslint-plugin@^8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.36.0.tgz#880ce277f8a30ccf539ec027acac157088f131ae"
integrity sha512-lZNihHUVB6ZZiPBNgOQGSxUASI7UJWhT8nHyUGCnaQ28XFCw98IfrMCG3rUl1uwUWoAvodJQby2KTs79UTcrAg==
dependencies:
"@eslint-community/regexpp" "^4.10.0"
"@typescript-eslint/scope-manager" "7.18.0"
"@typescript-eslint/type-utils" "7.18.0"
"@typescript-eslint/utils" "7.18.0"
"@typescript-eslint/visitor-keys" "7.18.0"
"@typescript-eslint/scope-manager" "8.36.0"
"@typescript-eslint/type-utils" "8.36.0"
"@typescript-eslint/utils" "8.36.0"
"@typescript-eslint/visitor-keys" "8.36.0"
graphemer "^1.4.0"
ignore "^5.3.1"
ignore "^7.0.0"
natural-compare "^1.4.0"
ts-api-utils "^1.3.0"
ts-api-utils "^2.1.0"
"@typescript-eslint/parser@7.2.0":
version "7.2.0"
@@ -2521,15 +2528,24 @@
"@typescript-eslint/visitor-keys" "7.2.0"
debug "^4.3.4"
"@typescript-eslint/parser@^7.1.1":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.18.0.tgz#83928d0f1b7f4afa974098c64b5ce6f9051f96a0"
integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==
"@typescript-eslint/parser@^8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.36.0.tgz#003007fe2030013936b6634b9cf52c457d36ed42"
integrity sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==
dependencies:
"@typescript-eslint/scope-manager" "7.18.0"
"@typescript-eslint/types" "7.18.0"
"@typescript-eslint/typescript-estree" "7.18.0"
"@typescript-eslint/visitor-keys" "7.18.0"
"@typescript-eslint/scope-manager" "8.36.0"
"@typescript-eslint/types" "8.36.0"
"@typescript-eslint/typescript-estree" "8.36.0"
"@typescript-eslint/visitor-keys" "8.36.0"
debug "^4.3.4"
"@typescript-eslint/project-service@8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.36.0.tgz#0c4acdcbe56476a43cdabaac1f08819424a379fd"
integrity sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==
dependencies:
"@typescript-eslint/tsconfig-utils" "^8.36.0"
"@typescript-eslint/types" "^8.36.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.62.0":
@@ -2540,14 +2556,6 @@
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/visitor-keys" "5.62.0"
"@typescript-eslint/scope-manager@7.18.0":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83"
integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==
dependencies:
"@typescript-eslint/types" "7.18.0"
"@typescript-eslint/visitor-keys" "7.18.0"
"@typescript-eslint/scope-manager@7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz#cfb437b09a84f95a0930a76b066e89e35d94e3da"
@@ -2556,31 +2564,44 @@
"@typescript-eslint/types" "7.2.0"
"@typescript-eslint/visitor-keys" "7.2.0"
"@typescript-eslint/type-utils@7.18.0":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b"
integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==
"@typescript-eslint/scope-manager@8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz#23e4196ed07d7ea3737a584fbebc9a79c3835168"
integrity sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==
dependencies:
"@typescript-eslint/typescript-estree" "7.18.0"
"@typescript-eslint/utils" "7.18.0"
"@typescript-eslint/types" "8.36.0"
"@typescript-eslint/visitor-keys" "8.36.0"
"@typescript-eslint/tsconfig-utils@8.36.0", "@typescript-eslint/tsconfig-utils@^8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz#63ef8a20ae9b5754c6ceacbe87b2fe1aab12ba13"
integrity sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==
"@typescript-eslint/type-utils@8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.36.0.tgz#16b092c2cbbb5549f6a4df1382a481586850502f"
integrity sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==
dependencies:
"@typescript-eslint/typescript-estree" "8.36.0"
"@typescript-eslint/utils" "8.36.0"
debug "^4.3.4"
ts-api-utils "^1.3.0"
ts-api-utils "^2.1.0"
"@typescript-eslint/types@5.62.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
"@typescript-eslint/types@7.18.0":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9"
integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==
"@typescript-eslint/types@7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.2.0.tgz#0feb685f16de320e8520f13cca30779c8b7c403f"
integrity sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==
"@typescript-eslint/types@8.36.0", "@typescript-eslint/types@^8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.36.0.tgz#d3d184adc2899e2912c13b17c1590486ef37c7ac"
integrity sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==
"@typescript-eslint/typescript-estree@5.62.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
@@ -2594,20 +2615,6 @@
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@7.18.0":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931"
integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==
dependencies:
"@typescript-eslint/types" "7.18.0"
"@typescript-eslint/visitor-keys" "7.18.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
minimatch "^9.0.4"
semver "^7.6.0"
ts-api-utils "^1.3.0"
"@typescript-eslint/typescript-estree@7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz#5beda2876c4137f8440c5a84b4f0370828682556"
@@ -2622,15 +2629,31 @@
semver "^7.5.4"
ts-api-utils "^1.0.1"
"@typescript-eslint/utils@7.18.0":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f"
integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==
"@typescript-eslint/typescript-estree@8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz#344857fa79f71715369554a3cbb6b4ff8695a7bc"
integrity sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
"@typescript-eslint/scope-manager" "7.18.0"
"@typescript-eslint/types" "7.18.0"
"@typescript-eslint/typescript-estree" "7.18.0"
"@typescript-eslint/project-service" "8.36.0"
"@typescript-eslint/tsconfig-utils" "8.36.0"
"@typescript-eslint/types" "8.36.0"
"@typescript-eslint/visitor-keys" "8.36.0"
debug "^4.3.4"
fast-glob "^3.3.2"
is-glob "^4.0.3"
minimatch "^9.0.4"
semver "^7.6.0"
ts-api-utils "^2.1.0"
"@typescript-eslint/utils@8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.36.0.tgz#2c9af5292f14e0aa4b0e9c7ac0406afafb299acf"
integrity sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==
dependencies:
"@eslint-community/eslint-utils" "^4.7.0"
"@typescript-eslint/scope-manager" "8.36.0"
"@typescript-eslint/types" "8.36.0"
"@typescript-eslint/typescript-estree" "8.36.0"
"@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.47.1":
version "5.62.0"
@@ -2654,14 +2677,6 @@
"@typescript-eslint/types" "5.62.0"
eslint-visitor-keys "^3.3.0"
"@typescript-eslint/visitor-keys@7.18.0":
version "7.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7"
integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==
dependencies:
"@typescript-eslint/types" "7.18.0"
eslint-visitor-keys "^3.4.3"
"@typescript-eslint/visitor-keys@7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz#5035f177752538a5750cca1af6044b633610bf9e"
@@ -2670,6 +2685,14 @@
"@typescript-eslint/types" "7.2.0"
eslint-visitor-keys "^3.4.1"
"@typescript-eslint/visitor-keys@8.36.0":
version "8.36.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz#7dc6ba4dd037979eb3a3bdd2093aa3604bb73674"
integrity sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==
dependencies:
"@typescript-eslint/types" "8.36.0"
eslint-visitor-keys "^4.2.1"
"@ungap/structured-clone@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
@@ -4501,6 +4524,11 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
eslint-visitor-keys@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1"
integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
eslint@^8.19.0, eslint@^8.57.0:
version "8.57.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668"
@@ -5359,11 +5387,16 @@ ieee754@^1.1.13:
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore@^5.0.5, ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1:
ignore@^5.0.5, ignore@^5.2.0, ignore@^5.2.4:
version "5.3.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
ignore@^7.0.0:
version "7.0.5"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9"
integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==
image-size@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.1.1.tgz#ddd67d4dc340e52ac29ce5f546a09f4e29e840ac"
@@ -9143,11 +9176,16 @@ trim-repeated@^1.0.0:
dependencies:
escape-string-regexp "^1.0.2"
ts-api-utils@^1.0.1, ts-api-utils@^1.3.0:
ts-api-utils@^1.0.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
ts-api-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91"
integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"