Compare commits

..
Author SHA1 Message Date
Simek 04ae39e603 fix C++ in-code docs comments to silence warnings 2025-09-18 10:50:03 +02:00
429 changed files with 3769 additions and 5875 deletions
+1 -1
View File
@@ -98,4 +98,4 @@ untyped-import
untyped-type-import
[version]
^0.286.0
^0.281.0
-3
View File
@@ -17,9 +17,6 @@ runs:
- name: Install node dependencies
uses: ./.github/actions/yarn-install
- 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.
if: ${{ !endsWith(github.ref_name, '-stable') }}
shell: bash
run: node ./scripts/releases/set-rn-artifacts-version.js --build-type ${{ inputs.release-type }}
- name: Setup gradle
+2 -1
View File
@@ -383,7 +383,8 @@ jobs:
runs-on: 8-core-ubuntu
needs: [set_release_type]
container:
image: reactnativecommunity/react-native-android:latest
# Version is pinned to v18.0 to unblock `run_fantom_tests` - see https://github.com/react-native-community/docker-android/pull/242#issuecomment-3280029122
image: reactnativecommunity/react-native-android:v18.0
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
-1
View File
@@ -133,7 +133,6 @@ vendor/
# Swift Package build folder
/packages/react-native/.build
/packages/react-native/.swiftpm
/packages/react-native/React/includes/
# @react-native/codegen
/packages/react-native/React/FBReactNativeSpec/
+2 -38
View File
@@ -1,40 +1,5 @@
# Changelog
## v0.81.4
### Fixed
#### iOS specific
- Fix regression that skips artifacts code generation ([f6f5ea0b2e](https://github.com/facebook/react-native/commit/f6f5ea0b2eed894725d8f6e8bd045c99c3182026) by [@kitten](https://github.com/kitten))
- Reapplied "Use autolinking-generated react-native-config output in second step of cocoapods linking that generates artifacts and generated source" ([bb73315a3f](https://github.com/facebook/react-native/commit/bb73315a3fd8cd203c4ddb3ffa10bfec307c7e92) by [@kitten](https://github.com/kitten))
## v0.82.0-rc.4
### Fixed
- **Hermes V1:** Fixed coordinates for Hermes V1 artifacts ([674fb77d93](https://github.com/facebook/react-native/commit/674fb77d93dfe67a5fe90449dc71b195b1851e13) by [@j-piasecki](https://github.com/j-piasecki))
#### iOS specific
- **Switch:** Fix Switch layout to work with iOS26 ([91d427fe52](https://github.com/facebook/react-native/commit/91d427fe52a307f9aa8579912ef956d61808dad2) by [@cipolleschi](https://github.com/cipolleschi))
## v0.82.0-rc.3
### Added
- **Hermes V1:** Added a dependency on hermes-compiler ([0caf8e70d5](https://github.com/facebook/react-native/commit/0caf8e70d53f611a73ad9b55879dfe0a5f036371) by [@j-piasecki](https://github.com/j-piasecki))
### Fixed
#### Android specific
- **Hermes V1:** Changed the coordinates of hermes artifacts when using Hermes V1 ([d0fb33822d](https://github.com/facebook/react-native/commit/d0fb33822de38183895c8b3421f46966909beaf3) by [@j-piasecki](https://github.com/j-piasecki))
#### iOS specific
- **Codegen:** Fix regression that skips artifacts code generation ([f6f5ea0b2e](https://github.com/facebook/react-native/commit/f6f5ea0b2eed894725d8f6e8bd045c99c3182026) by [@kitten](https://github.com/kitten))
## v0.81.3
### Fixed
@@ -101,7 +66,6 @@
- **Error Handling:** Unhandled promises are now handled by ExceptionsManager.handleException, instead of being swallowed as Logbox Warnings. ([c4082c9ce2](https://github.com/facebook/react-native/commit/c4082c9ce208a324c2d011823ca2ba432411aafc) by [@krystofwoldrich](https://github.com/krystofwoldrich))
- **`shouldEmitW3CPointerEvents`:** Migrate `shouldPressibilityUseW3CPointerEventsForHover` to common private feature flags and remove `shouldEmitW3CPointerEvents` flag. ([fb4587780e](https://github.com/facebook/react-native/commit/fb4587780e8d6111139d73598a9a26ff392dee28) by [@coado](https://github.com/coado))
- **TurboModuleUtils:** Remove unused ReactCommon/TurboModuleUtils functions #deepCopyJSIObject and #deepCopyJSIArray ([ead669ade3](https://github.com/facebook/react-native/commit/ead669ade31ee703c407f96c0ce98d8f2991bdc8) by [@christophpurrer](https://github.com/christophpurrer))
- **TurboModules:** Delete old location of CallbackWrapper.h / LongLivedObject.h by ([cb94e71](https://github.com/facebook/react-native/commit/cb94e71845259ae7fa823eb4d21cde74fccd7435) [@christophpurrer](https://github.com/christophpurrer))
#### Android specific
@@ -116,7 +80,7 @@
### Added
- **Animated:** `Animated.CompositeAnimation` is now exposed when using `"react-native-strict-api"` ([024d25794a](https://github.com/facebook/react-native/commit/024d25794a51c94c877c1dfa115a82ebbf559614) by [@huntie](https://github.com/huntie))
- **Animated:** `Animated.CompositeAnomation` is now exposed when using `"react-native-strict-api"` ([024d25794a](https://github.com/facebook/react-native/commit/024d25794a51c94c877c1dfa115a82ebbf559614) by [@huntie](https://github.com/huntie))
- **Animated:** Allow calling createAnimatedNode without batching ([d9d9a49e18](https://github.com/facebook/react-native/commit/d9d9a49e18f3c51caa18cf7da0a1fcd62f1ecf18) by [@zeyap](https://github.com/zeyap))
- **Animated:** Allow filter usage with native animated driver. ([138d0eb01d](https://github.com/facebook/react-native/commit/138d0eb01dbe597261459a37d364d1780c3ef228) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
- **API:** Expose NativeComponentRegistry API as JavaScript root export ([f936780cd5](https://github.com/facebook/react-native/commit/f936780cd5c0c17797f9d2bbc8f5cee81c2eefce) by [@zhongwuzw](https://github.com/zhongwuzw))
@@ -153,7 +117,7 @@
- **AGP:** AGP to 8.12.0 ([742ef3d661](https://github.com/facebook/react-native/commit/742ef3d6615c8c1202e9f683e6127ac97d7a9e23) by [@cortinico](https://github.com/cortinico))
- **DevSupportManager:** DevSupport `openDebugger()` methods now accept a `panel: String?` param. Frameworks directly implementing `DevSupportManager` will need to adjust call signatures. ([9dba7112cf](https://github.com/facebook/react-native/commit/9dba7112cfd09b02300869a77dba3dca16f49a28) by [@huntie](https://github.com/huntie))
- **Kotlin:** Migrated TextAttributeProps to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([fa921b3c7b](https://github.com/facebook/react-native/commit/fa921b3c7b289800a79196468f993a0eb0bf693f) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:**Migrated TextAttributeProps to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([fa921b3c7b](https://github.com/facebook/react-native/commit/fa921b3c7b289800a79196468f993a0eb0bf693f) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:** Migrated ReactBaseTextShadowNode to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([8ccfff9a46](https://github.com/facebook/react-native/commit/8ccfff9a46f317fd78f478c8b3f180441535d1ca) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:** Migrated com.facebook.react.bridge.Arguments to Kotlin. ([2534aeaddb](https://github.com/facebook/react-native/commit/2534aeaddb0490b69dfaba6b8d316616c7e10a9c) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:** Migrate `YogaConfig` to Kotlin ([4d5caef76b](https://github.com/facebook/react-native/commit/4d5caef76b83eb7e983364ecc81abb6027e5f98e) by [@mateoguzmana](https://github.com/mateoguzmana))
+16 -19
View File
@@ -3057,30 +3057,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<boolean>,
|}>
| $ReadOnly<{|
|}
| {|
type: 'string',
multiple?: false,
short?: string,
default?: string,
|}>
| $ReadOnly<{|
|}
| {|
type: 'string',
multiple: true,
short?: string,
default?: Array<string>,
|}>;
|};
type util$ParseArgsOptionToValue<TOption> = TOption['type'] extends 'boolean'
? TOption['multiple'] extends true
@@ -3137,7 +3137,7 @@ declare module 'util' {
declare function stripVTControlCharacters(str: string): string;
declare function parseArgs<
TOptions: {+[string]: util$ParseArgsOption} = {||},
TOptions: {[string]: util$ParseArgsOption} = {||},
>(config: {|
args?: Array<string>,
options?: TOptions,
@@ -3995,16 +3995,13 @@ declare class Process extends events$EventEmitter {
initgroups?: (user: number | string, extra_group: number | string) => void;
kill(pid: number, signal?: string | number): void;
mainModule: Object;
memoryUsage: {
(): {
arrayBuffers: number,
rss: number,
heapTotal: number,
heapUsed: number,
external: number,
...
},
rss: () => number,
memoryUsage(): {
arrayBuffers: number,
rss: number,
heapTotal: number,
heapUsed: number,
external: number,
...
};
nextTick: <T>(cb: (...T) => mixed, ...T) => void;
pid: number;
+41
View File
@@ -0,0 +1,41 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
declare module 'electron-store' {
declare export type Schema = any;
declare export type Options = {
+name?: string,
defaults?: Object,
schema?: any,
migrations?: any,
beforeEachMigration?: any,
clearInvalidConfig?: boolean,
serialize?: any,
deserialize?: any,
accessPropertiesByDotNotation?: boolean,
watch?: boolean,
encryptionKey?: string | Buffer | $ReadOnlyArray<number>,
...
};
declare class ElectronStore {
constructor(options?: Options): this;
get(key: string): any;
get(key: string, defaultValue: any): any;
set(key: string, value: any): void;
set(object: Object): void;
has(key: string): boolean;
delete(key: string): void;
clear(): void;
}
declare module.exports: Class<ElectronStore>;
}
+1 -1
View File
@@ -86,7 +86,7 @@
"eslint-plugin-relay": "^1.8.3",
"fb-dotslash": "0.5.8",
"flow-api-translator": "0.32.0",
"flow-bin": "^0.286.0",
"flow-bin": "^0.281.0",
"glob": "^7.1.1",
"hermes-eslint": "0.32.0",
"hermes-transform": "0.32.0",
@@ -119,6 +119,7 @@ async function runServer(
watchFolders,
});
const {middleware, websocketEndpoints} = createDevMiddleware({
projectRoot,
serverBaseUrl: devServerUrl,
logger: createDevMiddlewareLogger(terminalReporter),
});
+2 -2
View File
@@ -1,5 +1,5 @@
@generated SignedSource<<e0cc45c5c3854d0d3013f1c735e804b8>>
Git revision: 8cce39003f66f66a8fb4c0e581a2b5046cf9c1d1
@generated SignedSource<<0b54f75686e4893a5444839bf621a317>>
Git revision: 5a792db1225adda206313e9bf751198a1ca7851a
Built with --nohooks: false
Is local checkout: false
Remote URL: https://github.com/facebook/react-native-devtools-frontend
Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -983,7 +983,7 @@ import*as e from"../../../services/trace_bounds/trace_bounds.js";import*as t fro
<p class="tooltip">${Ai(Oi.feedbackTooltip)}</p>
</div>
`,n=s.Directives.repeat([i],(()=>this.#ve),(e=>e));s.render(n,this.#e,{host:this})}}customElements.define("devtools-performance-sidebar-insights",Ui);var Bi=Object.freeze({__proto__:null,SidebarInsightsTab:Ui});class qi extends Event{removedAnnotation;static eventName="removeannotation";constructor(e){super(qi.eventName,{bubbles:!0,composed:!0}),this.removedAnnotation=e}}class Vi extends Event{annotation;static eventName="revealannotation";constructor(e){super(Vi.eventName,{bubbles:!0,composed:!0}),this.annotation=e}}class ji extends r.Widget.VBox{#ri=new r.TabbedPane.TabbedPane;#tn=new Wi;#in=new Ki;#nn=a.Settings.Settings.instance().createSetting("timeline-user-has-opened-sidebar-once",!1);userHasOpenedSidebarOnce(){return this.#nn.get()}constructor(){super(),this.setMinimumSize(170,0);const e=!S.Runtime.experiments.isEnabled("react-native-specific-ui");e&&this.#ri.appendTab("insights","Insights",this.#tn,void 0,void 0,!1,!1,0,"timeline.insights-tab"),this.#ri.appendTab("annotations","Annotations",this.#in,void 0,void 0,!1,!1,1,"timeline.annotations-tab"),this.#ri.selectTab(e?"insights":"annotations")}wasShown(){this.#nn.set(!0),this.#ri.show(this.element),this.#rn(),"insights"===this.#ri.selectedTabId&&this.#ri.tabIsDisabled("insights")&&this.#ri.selectTab("annotations")}setAnnotations(e,t){this.#in.setAnnotations(e,t),this.#rn()}#rn(){const e=this.#in.deduplicatedAnnotations();this.#ri.setBadge("annotations",e.length>0?e.length.toString():null)}setParsedTrace(e,t){this.#tn.setParsedTrace(e,t)}setInsights(e){this.#tn.setInsights(e),this.#ri.setTabEnabled("insights",null!==e)}setActiveInsight(e){this.#tn.setActiveInsight(e),e&&this.#ri.selectTab("insights")}}class Wi extends r.Widget.VBox{#sn=new Ui;constructor(){super(),this.element.classList.add("sidebar-insights"),this.element.appendChild(this.#sn)}setParsedTrace(e,t){this.#sn.parsedTrace=e,this.#sn.traceMetadata=t}setInsights(e){this.#sn.insights=e}setActiveInsight(e){this.#sn.activeInsight=e}}class Ki extends r.Widget.VBox{#sn=new xi;constructor(){super(),this.element.classList.add("sidebar-annotations"),this.element.appendChild(this.#sn)}setAnnotations(e,t){this.#sn.annotationEntryToColorMap=t,this.#sn.annotations=e}deduplicatedAnnotations(){return this.#sn.deduplicatedAnnotations()}}var Gi=Object.freeze({__proto__:null,DEFAULT_SIDEBAR_TAB:"insights",DEFAULT_SIDEBAR_WIDTH_PX:240,RemoveAnnotation:qi,RevealAnnotation:Vi,SidebarWidget:ji}),Yi={cssText:`:host{max-height:100%;overflow:hidden auto;scrollbar-width:thin}.timeline-summary{font-size:var(--sys-typescale-body4-size);flex-direction:column;padding:0 var(--sys-size-6) var(--sys-size-4) var(--sys-size-8)}.summary-range{font-weight:var(--ref-typeface-weight-medium);height:24.5px;line-height:22px}.category-summary{gap:var(--sys-size-4);display:flex;flex-direction:column}.category-row{min-height:16px;line-height:16px}.category-swatch{display:inline-block;width:var(--sys-size-6);height:var(--sys-size-6);margin-right:var(--sys-size-4);top:var(--sys-size-1);position:relative;border:var(--sys-size-1) solid var(--sys-color-neutral-outline)}.category-name{display:inline;word-break:break-all}.category-value{text-align:right;position:relative;float:right;z-index:0;width:var(--sys-size-19)}.background-bar-container{position:absolute;inset:0 0 0 var(--sys-size-3);z-index:-1}.background-bar{width:100%;float:right;height:var(--sys-size-8);background-color:var(--sys-color-surface-yellow);border-bottom:var(--sys-size-1) solid var(--sys-color-yellow-outline)}\n/*# sourceURL=${import.meta.resolve("./timelineSummary.css")} */\n`};const{render:Xi,html:Ji}=s,Zi={total:"Total",rangeSS:"Range: {PH1} {PH2}"},Qi=t.i18n.registerUIStrings("panels/timeline/components/TimelineSummary.ts",Zi),en=t.i18n.getLocalizedString.bind(void 0,Qi);class tn extends HTMLElement{#e=r.UIUtils.createShadowRootWithCoreStyles(this,{cssFile:Yi,delegatesFocus:void 0});#on=0;#an=0;#ln=0;#dn=[];set data(e){this.#ln=e.total,this.#dn=e.categories,this.#on=e.rangeStart,this.#an=e.rangeEnd,this.#i()}#i(){const e=Ji`
`,n=s.Directives.repeat([i],(()=>this.#ve),(e=>e));s.render(n,this.#e,{host:this})}}customElements.define("devtools-performance-sidebar-insights",Ui);var Bi=Object.freeze({__proto__:null,SidebarInsightsTab:Ui});class qi extends Event{removedAnnotation;static eventName="removeannotation";constructor(e){super(qi.eventName,{bubbles:!0,composed:!0}),this.removedAnnotation=e}}class Vi extends Event{annotation;static eventName="revealannotation";constructor(e){super(Vi.eventName,{bubbles:!0,composed:!0}),this.annotation=e}}class ji extends r.Widget.VBox{#ri=new r.TabbedPane.TabbedPane;#tn=new Wi;#in=new Ki;#nn=a.Settings.Settings.instance().createSetting("timeline-user-has-opened-sidebar-once",!1);userHasOpenedSidebarOnce(){return this.#nn.get()}constructor(){super(),this.setMinimumSize(170,0),this.#ri.appendTab("insights","Insights",this.#tn,void 0,void 0,!1,!1,0,"timeline.insights-tab"),this.#ri.appendTab("annotations","Annotations",this.#in,void 0,void 0,!1,!1,1,"timeline.annotations-tab"),this.#ri.selectTab("insights")}wasShown(){this.#nn.set(!0),this.#ri.show(this.element),this.#rn(),"insights"===this.#ri.selectedTabId&&this.#ri.tabIsDisabled("insights")&&this.#ri.selectTab("annotations")}setAnnotations(e,t){this.#in.setAnnotations(e,t),this.#rn()}#rn(){const e=this.#in.deduplicatedAnnotations();this.#ri.setBadge("annotations",e.length>0?e.length.toString():null)}setParsedTrace(e,t){this.#tn.setParsedTrace(e,t)}setInsights(e){this.#tn.setInsights(e),this.#ri.setTabEnabled("insights",null!==e)}setActiveInsight(e){this.#tn.setActiveInsight(e),e&&this.#ri.selectTab("insights")}}class Wi extends r.Widget.VBox{#sn=new Ui;constructor(){super(),this.element.classList.add("sidebar-insights"),this.element.appendChild(this.#sn)}setParsedTrace(e,t){this.#sn.parsedTrace=e,this.#sn.traceMetadata=t}setInsights(e){this.#sn.insights=e}setActiveInsight(e){this.#sn.activeInsight=e}}class Ki extends r.Widget.VBox{#sn=new xi;constructor(){super(),this.element.classList.add("sidebar-annotations"),this.element.appendChild(this.#sn)}setAnnotations(e,t){this.#sn.annotationEntryToColorMap=t,this.#sn.annotations=e}deduplicatedAnnotations(){return this.#sn.deduplicatedAnnotations()}}var Gi=Object.freeze({__proto__:null,DEFAULT_SIDEBAR_TAB:"insights",DEFAULT_SIDEBAR_WIDTH_PX:240,RemoveAnnotation:qi,RevealAnnotation:Vi,SidebarWidget:ji}),Yi={cssText:`:host{max-height:100%;overflow:hidden auto;scrollbar-width:thin}.timeline-summary{font-size:var(--sys-typescale-body4-size);flex-direction:column;padding:0 var(--sys-size-6) var(--sys-size-4) var(--sys-size-8)}.summary-range{font-weight:var(--ref-typeface-weight-medium);height:24.5px;line-height:22px}.category-summary{gap:var(--sys-size-4);display:flex;flex-direction:column}.category-row{min-height:16px;line-height:16px}.category-swatch{display:inline-block;width:var(--sys-size-6);height:var(--sys-size-6);margin-right:var(--sys-size-4);top:var(--sys-size-1);position:relative;border:var(--sys-size-1) solid var(--sys-color-neutral-outline)}.category-name{display:inline;word-break:break-all}.category-value{text-align:right;position:relative;float:right;z-index:0;width:var(--sys-size-19)}.background-bar-container{position:absolute;inset:0 0 0 var(--sys-size-3);z-index:-1}.background-bar{width:100%;float:right;height:var(--sys-size-8);background-color:var(--sys-color-surface-yellow);border-bottom:var(--sys-size-1) solid var(--sys-color-yellow-outline)}\n/*# sourceURL=${import.meta.resolve("./timelineSummary.css")} */\n`};const{render:Xi,html:Ji}=s,Zi={total:"Total",rangeSS:"Range: {PH1} {PH2}"},Qi=t.i18n.registerUIStrings("panels/timeline/components/TimelineSummary.ts",Zi),en=t.i18n.getLocalizedString.bind(void 0,Qi);class tn extends HTMLElement{#e=r.UIUtils.createShadowRootWithCoreStyles(this,{cssFile:Yi,delegatesFocus:void 0});#on=0;#an=0;#ln=0;#dn=[];set data(e){this.#ln=e.total,this.#dn=e.categories,this.#on=e.rangeStart,this.#an=e.rangeEnd,this.#i()}#i(){const e=Ji`
<div class="timeline-summary">
<div class="summary-range">${en(Zi.rangeSS,{PH1:t.TimeUtilities.millisToString(this.#on),PH2:t.TimeUtilities.millisToString(this.#an)})}</div>
<div class="category-summary">
File diff suppressed because one or more lines are too long
@@ -1,71 +1,71 @@
#!/usr/bin/env dotslash
// @generated SignedSource<<f03dde90e30b4654dc18ba4c688f588e>>
// @generated SignedSource<<9df662721aea6e3774a8677e2a6065e4>>
{
"name": "React Native DevTools",
"platforms": {
"linux-aarch64": {
"size": 116056498,
"size": 116056584,
"hash": "sha256",
"digest": "74ddbe463a81b57533a87f4301c6a6c74323018f70e4f1dbeed0dfbe2ebab257",
"digest": "fac3912f10e3c373c874be6c4696f11e05cbaa754c116db6ea72189afae5efe6",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQNNgo1RofrfkLfx2qh_zLXdyNL54sIiYfd6p9aXIk-1zJ2lV1dpD2p58FTweCN6y3RZcdE_u9U8z16S_xRbtgA0mobHgSK6JASeR3dCLmMAazKXiiSb98rToqI9XAdOc4pJOGhOb2PVQ_c6lzngiOQ0vkyYU7xFENy-7jKKLbqYFSoDgT7RBs4dnbw"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPdlYV_w4y_wxd5Rs8c_F-soLMbY1zwXJjD-JM4TkOtOELyxZGyreTb6dTehp_X6e3qVFZUT05ETRs0MbvqYr4mqdb6dkG9DqNQEVv3TBoHwl7TYSygtHJEs3gXTAtMLYEKW9xXODJlVF-9II7fdTdHU7x7Pyf6NR6S3nv7sKUVD-zKpxF50L2TwUQ"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-arm64/React Native DevTools"
},
"linux-x86_64": {
"size": 115924960,
"size": 115929093,
"hash": "sha256",
"digest": "eba05066886fe6cd88b4123ed423ad301fd35b2f12381627b3b22c7955c73333",
"digest": "06bbaeb62ae2e0081d184eba42b9f15be0d0b3f4901142b08a8a1430ff83e722",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOXAiG9ivBeW9v9jZMpg7nJZRT1SNBjTz8Nc5_SWUPCUf3xDekbhB6w3lWc8JtfklAzOL5TlJOsvIT3eujx2exadBpcS5NiAnq47KYvcgGP9iVxv5NuRwxttCc3Vncl5CLpGA6-Ifkt1g2-MrdM5yiaSaMKOCDQ83C2Fw07zH6tXt28jsZcTaPj"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPENbrxrg0RF_TiyxSY_YVYqC1UfRKj_bMfKb3qHUsIhBlya8n3FkbfJqTXTNdqL4riFRulXS5ecXZprtvk_9kao-zY59r3kiTRwobzF0jnjM507_9UOnEHWzG5ZJYzQyOtS3kQmT0HwZabVj9qw38OB9mk-MPVCZIPZay2PRnIThBzpKDoOOP9"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-x64/React Native DevTools"
},
"macos-aarch64": {
"size": 110890882,
"size": 110891603,
"hash": "sha256",
"digest": "f289b7ae3c300b9d744c729a0024e55a2a8d6953a6a8e834d867f705daad1153",
"digest": "eeb9cc1399c0c38c429848dbf622f1b46e88d7d97788dcdc4c30a9fcce37705c",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQP4xY72fwAGy3-m2Gx7mPodV90K-GbWYYIZ9_xgI89O0rm5GPmXE0u-C18Vq2h6x3zL479nhS7o9_OonWaISxx6TMYZcZsG9nkqTW3-uWcUi6ndzPNQILwryGVg034jrlmjKLB2CiIRoJvdW37wB_1AWFCOKO9gXRozFKV4ndjGDxDC6HJvbfFTacvX"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN9bd7nbXi-uF_MooJEiUL2jJVifMqgQxZ236aqbSdiJe5Uzjud5ANf0LDAl8GDVVRShd6x4B-gsZ-qRowH0qJikoGatQIkBgyzp4i8ors52etGOIIwdAxdNIng5Vtp441j2_N__btkJqlHcMMbbqvO8fg9oeYTlhMpOx3MLLWXIlG7ix5IFUDiYChf"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"macos-x86_64": {
"size": 117778007,
"size": 117770388,
"hash": "sha256",
"digest": "a4698d6c3e2fdfb0c7bafec2130f3701c655468f953af836bf66ce3fe848c6ae",
"digest": "a65e446e526502b267cbe6800ae031e4e1b5b0aca21412152a66ffe1d3a29410",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQMpGXCifWF6VrFwv_jM4lw-E8eFi59l776z1OYrS8u3mLluAyA8bUtscEyLwoMitqyjF7or5lPuW7OFyiyZ00bKFxSC5lH6Xo_Sc41cQN5n5hmXCX7Wpku9ilU39_ZWmI95W3_oAacYXA1l6ZmHX2AWlv3jERpywrP4J_RNFBi5UAvOhPFo4LtRXw"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN29ukKLZS48QcCU-gms06YFnG-fxxDfrWTup-Z6KoIAP-QEu3sFzrpqeZz4g-jFsh3o-IIoHJsdbu4a2U7ROjPfWGguGJrPK8fdc3iV67Qw1_VAPU13dm0dI1DbSY50ah05wh43jdBG3LGCAYYJ-W8_mZMC3HqM2v-8KVd-DoPT4hOh1s9CCFgEQ"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"windows-x86_64": {
"size": 125528869,
"size": 125526370,
"hash": "sha256",
"digest": "95234a13e6ba55556cff46f3da8af9e57ff1010c5483265cbbd444cad01c4216",
"digest": "26b190c0f85249dee91999e020b8fe7ffd5c007458a2103ed3822558861dbe87",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOJdgsL68PBrM0rJk-WOm-re-8uqKfI1FfcTcAr1hiFSQr2bKBOqQNtHLnEA6JlRvKrwlOp4XTB6y9pC1TISeGo2dG_BYwN9jsVRLzcGWvfnpZ6GR7evVe82-XKS3Ya5YpScRdLycRqrhHuACXXbQ0HNvhNJjBWZtnQ8N3vOFJXn5QOGlobXqYp"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQO0mdIJx1eYiSDJNiAZ2soaeECILayWnvOeiey-fpS4ydDTreAMfwL4QZ5GZo4-AsGwOXCSdF3hBMM2ufnvw6BDFg5UEiTc4DALJu7o6YBBG4wlVZbI-2kkaXd7u8RhBQPjmhsdcX3sDmCGmSr3WK9EkTRKStE2lb6ilOn-969h4dYWekwUUCSX"
}
],
"format": "tar.gz",
+1
View File
@@ -35,6 +35,7 @@
},
"devDependencies": {
"electron": "37.2.6",
"electron-store": "^8.2.0",
"semver": "^7.1.3"
},
"files": [
@@ -8,15 +8,13 @@
* @format
*/
import SettingsStore from './SettingsStore.js';
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {BrowserWindow, Menu, app, shell, ipcMain} = require('electron') as any;
const Store = require('electron-store');
const path = require('path');
const util = require('util');
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {BrowserWindow, Menu, app, shell, ipcMain} = require('electron') as any;
const appSettings = new SettingsStore();
const appSettings = new Store();
const windowMetadata = new WeakMap<
typeof BrowserWindow,
$ReadOnly<{
@@ -1,128 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {app} = require('electron') as any;
const fs = require('fs');
const path = require('path');
type Options = $ReadOnly<{
name?: string,
defaults?: Object,
}>;
/**
* A data persistence layer for storing application settings, modelled after
* [`electron-store`](https://www.npmjs.com/package/electron-store).
*
* Values are saved in a `config.json` file in `app.getPath('userData')`.
*
* Compatibility:
* - Maintains API and file format compatibility with `electron-store@8.2.0`.
* - Supports the Electron main process only.
*/
export default class SettingsStore {
#defaultValues: Object = {};
path: string;
constructor(options: Options = {}) {
options = {
name: 'config',
...options,
};
this.#defaultValues = {
...this.#defaultValues,
...options.defaults,
};
this.path = path.resolve(
app.getPath('userData'),
`${options.name ?? 'config'}.json`,
);
}
get(key: string, defaultValue?: any): any {
const store = this.store;
return store[key] !== undefined ? store[key] : defaultValue;
}
set(key: string, value: any): void {
const {store} = this;
if (typeof key === 'object') {
const object = key;
for (const [k, v] of Object.entries(object)) {
store[k] = v;
}
} else {
store[key] = value;
}
this.store = store;
}
has(key: string): boolean {
return key in this.store;
}
reset(...keys: Array<string>): void {
for (const key of keys) {
if (this.#defaultValues[key] != null) {
this.set(key, this.#defaultValues[key]);
}
}
}
delete(key: string): void {
const {store} = this;
delete store[key];
this.store = store;
}
clear(): void {
this.store = {};
for (const key of Object.keys(this.#defaultValues)) {
this.reset(key);
}
}
get store(): {[string]: mixed} {
try {
const data = fs.readFileSync(this.path, 'utf8');
const deserializedData = this._deserialize(data);
return {
...((deserializedData: any): {[string]: mixed}),
};
} catch (error) {
if (error?.code === 'ENOENT') {
this._ensureDirectory();
return {};
}
throw error;
}
}
set store(value: mixed): void {
this._ensureDirectory();
this._write(value);
}
_deserialize = (value: string): mixed => JSON.parse(value);
_serialize = (value: mixed): string =>
JSON.stringify(value, undefined, '\t') ?? '';
_ensureDirectory(): void {
fs.mkdirSync(path.dirname(this.path), {recursive: true});
}
_write(value: mixed): void {
const data = this._serialize(value);
fs.writeFileSync(this.path, data, {mode: 0o666});
}
}
@@ -25,9 +25,7 @@ app.setVersion(pkg.version + '-' + buildInfo.revision);
const {
values: {version = false},
} = util.parseArgs({
options: {
version: {type: 'boolean'},
},
options: {version: {type: 'boolean'}},
args: process.argv.slice(app.isPackaged ? 1 : 2),
strict: false,
});
+5 -18
View File
@@ -30,7 +30,6 @@ async function unstable_spawnDebuggerShellWithArgs(
{
mode = 'detached',
flavor = 'prebuilt',
prebuiltBinaryPath,
}: $ReadOnly<{
// In 'syncAndExit' mode, the current process will block until the spawned process exits, and then it will exit
// with the same exit code as the spawned process.
@@ -38,13 +37,9 @@ async function unstable_spawnDebuggerShellWithArgs(
// continue to run normally.
mode?: 'syncThenExit' | 'detached',
flavor?: DebuggerShellFlavor,
prebuiltBinaryPath?: string,
}> = {},
): Promise<void> {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(
flavor,
prebuiltBinaryPath,
);
const [binaryPath, baseArgs] = getShellBinaryAndArgs(flavor);
return new Promise((resolve, reject) => {
const child = spawn(binaryPath, [...baseArgs, ...args], {
@@ -114,13 +109,14 @@ export type DebuggerShellPreparationResult = $ReadOnly<{
*/
async function unstable_prepareDebuggerShell(
flavor: DebuggerShellFlavor,
{prebuiltBinaryPath}: {prebuiltBinaryPath?: string} = {},
): Promise<DebuggerShellPreparationResult> {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(flavor);
try {
switch (flavor) {
case 'prebuilt':
const prebuiltResult = await prepareDebuggerShellFromDotSlashFile(
prebuiltBinaryPath ?? DEVTOOLS_BINARY_DOTSLASH_FILE,
DEVTOOLS_BINARY_DOTSLASH_FILE,
);
if (prebuiltResult.code !== 'success') {
return prebuiltResult;
@@ -132,11 +128,6 @@ async function unstable_prepareDebuggerShell(
flavor as empty;
throw new Error(`Unknown flavor: ${flavor}`);
}
const [binaryPath, baseArgs] = getShellBinaryAndArgs(
flavor,
prebuiltBinaryPath,
);
const {code, stderr} = await spawnAndGetStderr(binaryPath, [
...baseArgs,
'--version',
@@ -158,14 +149,10 @@ async function unstable_prepareDebuggerShell(
function getShellBinaryAndArgs(
flavor: DebuggerShellFlavor,
prebuiltBinaryPath: ?string,
): [string, Array<string>] {
switch (flavor) {
case 'prebuilt':
return [
require('fb-dotslash'),
[prebuiltBinaryPath ?? DEVTOOLS_BINARY_DOTSLASH_FILE],
];
return [require('fb-dotslash'), [DEVTOOLS_BINARY_DOTSLASH_FILE]];
case 'dev':
return [
// NOTE: Internally at Meta, this is aliased to a workspace that is
@@ -21,6 +21,10 @@ import {
withServerForEachTest,
} from './ServerUtils';
import {createHash} from 'crypto';
import fs from 'fs';
import path from 'path';
const fsPromise = fs.promises;
// WebSocket is unreliable when using fake timers.
jest.useRealTimers();
@@ -43,6 +47,7 @@ describe.each(['HTTP', 'HTTPS'])(
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: __dirname,
secure: protocol === 'HTTPS',
});
@@ -467,7 +472,14 @@ describe.each(['HTTP', 'HTTPS'])(
}
});
test('throws when attempting to pass a filesystem url', async () => {
test('reads source from disk', async () => {
// Should be just 'foo\n', but the newline can get mangled by the OS
// and/or SCM, so let's read the source of truth from disk.
const fileRealContents = await fsPromise.readFile(
path.join(__dirname, '__fixtures__', 'mock-source-file.txt'),
'utf8',
);
const {device, debugger_} = await createAndConnectTarget(
serverRef,
autoCleanup.signal,
@@ -478,7 +490,6 @@ describe.each(['HTTP', 'HTTPS'])(
vm: 'bar-vm',
},
);
try {
await sendFromTargetToDebugger(device, debugger_, 'page1', {
method: 'Debugger.scriptParsed',
@@ -489,7 +500,7 @@ describe.each(['HTTP', 'HTTPS'])(
endLine: 0,
startColumn: 0,
endColumn: 0,
hash: createHash('sha256').update('').digest('hex'),
hash: createHash('sha256').update(fileRealContents).digest('hex'),
},
});
const response = await debugger_.sendAndGetResponse({
@@ -500,15 +511,8 @@ describe.each(['HTTP', 'HTTPS'])(
},
});
expect(response.result).toEqual(
expect.objectContaining({
error: {
message: expect.stringContaining(
'Can\'t parse requested URL "__fixtures__/mock-source-file.txt"',
),
},
}),
expect.objectContaining({scriptSource: fileRealContents}),
);
// The device does not receive the getScriptSource request, since it
// is handled by the proxy.
expect(device.wrappedEventParsed).not.toBeCalledWith({
@@ -33,6 +33,7 @@ describe.each(['HTTP', 'HTTPS'])(
protocol => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
secure: protocol === 'HTTPS',
});
const autoCleanup = withAbortSignalForEachTest();
@@ -39,6 +39,7 @@ describe('inspector proxy device message middleware', () => {
const createCustomMessageHandler = jest.fn().mockImplementation(() => null);
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: createCustomMessageHandler,
});
@@ -82,6 +83,7 @@ describe('inspector proxy device message middleware', () => {
const createCustomMessageHandler = jest.fn().mockImplementation(() => null);
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: createCustomMessageHandler,
});
const {serverBaseUrl, serverBaseWsUrl} = serverRefUrls(server);
@@ -167,6 +169,7 @@ describe('inspector proxy device message middleware', () => {
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: createCustomMessageHandler,
});
@@ -228,6 +231,7 @@ describe('inspector proxy device message middleware', () => {
const handleDeviceMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage,
handleDebuggerMessage() {},
@@ -260,6 +264,7 @@ describe('inspector proxy device message middleware', () => {
const handleDeviceMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage,
handleDebuggerMessage() {},
@@ -299,6 +304,7 @@ describe('inspector proxy device message middleware', () => {
const handleDebuggerMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage() {},
handleDebuggerMessage,
@@ -335,6 +341,7 @@ describe('inspector proxy device message middleware', () => {
const handleDebuggerMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage() {},
handleDebuggerMessage,
@@ -37,6 +37,7 @@ const PAGE_DEFAULTS = {
describe('inspector-proxy device socket handoff', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
const autoCleanup = withAbortSignalForEachTest();
afterEach(() => {
@@ -27,6 +27,7 @@ jest.useFakeTimers();
describe('inspector proxy HTTP API', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
const autoCleanup = withAbortSignalForEachTest();
afterEach(() => {
@@ -260,6 +261,7 @@ describe('inspector proxy HTTP API', () => {
describe('HTTP vs HTTPS', () => {
const secureServerRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
secure: true,
});
@@ -25,6 +25,7 @@ jest.setTimeout(10000);
describe('inspector proxy React Native reloads', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
const autoCleanup = withAbortSignalForEachTest();
afterEach(() => {
@@ -34,6 +34,7 @@ describe('enableStandaloneFuseboxShell experiment', () => {
};
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
unstable_browserLauncher: BrowserLauncherWithFuseboxShell,
unstable_experiments: {
enableStandaloneFuseboxShell: true,
@@ -17,6 +17,7 @@ jest.setTimeout(10000);
describe('embedder script', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
test('is always served', async () => {
@@ -24,6 +24,8 @@ import path from 'path';
import serveStaticMiddleware from 'serve-static';
type Options = $ReadOnly<{
projectRoot: string,
/**
* The base URL to the dev server, as reachable from the machine on which
* dev-middleware is hosted. Typically `http://localhost:${metroPort}`.
@@ -76,6 +78,7 @@ type DevMiddlewareAPI = $ReadOnly<{
}>;
export default function createDevMiddleware({
projectRoot,
serverBaseUrl,
logger,
// $FlowFixMe[incompatible-type]
@@ -93,6 +96,7 @@ export default function createDevMiddleware({
);
const inspectorProxy = new InspectorProxy(
projectRoot,
serverBaseUrl,
eventReporter,
experiments,
@@ -28,7 +28,9 @@ import type {
import CdpDebugLogging from './CdpDebugLogging';
import DeviceEventReporter from './DeviceEventReporter';
import * as fs from 'fs';
import invariant from 'invariant';
import * as path from 'path';
import WS from 'ws';
const debug = require('debug')('Metro:InspectorProxy');
@@ -73,6 +75,7 @@ export type DeviceOptions = $ReadOnly<{
name: string,
app: string,
socket: WS,
projectRoot: string,
eventReporter: ?EventReporter,
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
deviceRelativeBaseUrl: URL,
@@ -117,6 +120,9 @@ export default class Device {
// Mapping built from scriptParsed events and used to fetch file content in `Debugger.getScriptSource`.
#scriptIdToSourcePathMapping: Map<string, string> = new Map();
// Root of the project used for relative to absolute source path conversion.
#projectRoot: string;
#deviceEventReporter: ?DeviceEventReporter;
#pagesPollingIntervalId: ReturnType<typeof setInterval>;
@@ -145,6 +151,7 @@ export default class Device {
name,
app,
socket,
projectRoot,
eventReporter,
createMessageMiddleware,
serverRelativeBaseUrl,
@@ -156,6 +163,7 @@ export default class Device {
this.#name = name;
this.#app = app;
this.#deviceSocket = socket;
this.#projectRoot = projectRoot;
this.#serverRelativeBaseUrl = serverRelativeBaseUrl;
this.#deviceRelativeBaseUrl = deviceRelativeBaseUrl;
this.#deviceEventReporter = eventReporter
@@ -872,7 +880,7 @@ export default class Device {
return this.#processDebuggerSetBreakpointByUrl(req, debuggerInfo);
case 'Debugger.getScriptSource':
// Sends response to debugger via side-effect
void this.#processDebuggerGetScriptSource(req, socket);
this.#processDebuggerGetScriptSource(req, socket);
return null;
case 'Network.loadNetworkResource':
// If we're rewriting URLs (to frontend-relative), we don't want to
@@ -957,10 +965,10 @@ export default class Device {
return processedReq;
}
async #processDebuggerGetScriptSource(
#processDebuggerGetScriptSource(
req: CDPRequest<'Debugger.getScriptSource'>,
socket: WS,
): Promise<void> {
): void {
const sendSuccessResponse = (scriptSource: string) => {
const result: {
scriptSource: string,
@@ -997,23 +1005,33 @@ export default class Device {
const pathToSource = this.#scriptIdToSourcePathMapping.get(
req.params.scriptId,
);
try {
const httpURL =
pathToSource == null ? null : this.#tryParseHTTPURL(pathToSource);
if (!httpURL) {
throw new Error(
`Can't parse requested URL ${pathToSource === undefined ? 'undefined' : JSON.stringify(pathToSource)}`,
if (pathToSource != null) {
const httpURL = this.#tryParseHTTPURL(pathToSource);
if (httpURL) {
// URL is server-relatve, so we should be able to fetch it from here.
this.#fetchText(httpURL).then(
text => sendSuccessResponse(text),
err =>
sendErrorResponse(
`Failed to fetch source url ${pathToSource}: ${err.message}`,
),
);
} else {
let file;
try {
file = fs.readFileSync(
path.resolve(this.#projectRoot, pathToSource),
'utf8',
);
} catch (err) {
sendErrorResponse(
`Failed to fetch source file ${pathToSource}: ${err.message}`,
);
}
if (file != null) {
sendSuccessResponse(file);
}
}
const text = await this.#fetchText(httpURL);
sendSuccessResponse(text);
} catch (err) {
sendErrorResponse(
`Failed to fetch source url ${pathToSource === undefined ? 'undefined' : JSON.stringify(pathToSource)} for scriptId ${req.params.scriptId}: ${err.message}`,
);
}
}
@@ -75,6 +75,9 @@ export interface InspectorProxyQueries {
* Main Inspector Proxy class that connects JavaScript VM inside Android/iOS apps and JS debugger.
*/
export default class InspectorProxy implements InspectorProxyQueries {
// Root of the project used for relative to absolute source path conversion.
#projectRoot: string;
// The base URL to the dev server from the dev-middleware host.
#serverBaseUrl: URL;
@@ -98,6 +101,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
#eventLoopPerfTracker: EventLoopPerfTracker;
constructor(
projectRoot: string,
serverBaseUrl: string,
eventReporter: ?EventReporter,
experiments: Experiments,
@@ -105,6 +109,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
customMessageHandler: ?CreateCustomMessageHandlerFn,
trackEventLoopPerf?: boolean = false,
) {
this.#projectRoot = projectRoot;
this.#serverBaseUrl = new URL(serverBaseUrl);
this.#devices = new Map();
this.#eventReporter = eventReporter;
@@ -350,6 +355,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
name: deviceName,
app: appName,
socket,
projectRoot: this.#projectRoot,
eventReporter: this.#eventReporter,
createMessageMiddleware: this.#customMessageHandler,
deviceRelativeBaseUrl,
@@ -366,6 +372,12 @@ export default class InspectorProxy implements InspectorProxyQueries {
this.#devices.set(deviceId, newDevice);
this.#logger?.info(
"Connection established to app='%s' on device='%s'.",
appName,
deviceName,
);
debug(
"Got new device connection: name='%s', app=%s, device=%s, via=%s",
deviceName,
@@ -438,7 +450,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
);
socket.on('close', (code: number, reason: string) => {
debug(
this.#logger?.info(
"Connection closed to device='%s' for app='%s' with code='%s' and reason='%s'.",
deviceName,
appName,
@@ -514,7 +526,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
throw new Error(INTERNAL_ERROR_MESSAGES.UNREGISTERED_DEVICE);
}
debug(
this.#logger?.info(
"Connection established to DevTools for app='%s' on device='%s'.",
device.getApp() || 'unknown',
device.getName() || 'unknown',
@@ -582,7 +594,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
});
socket.on('close', (code: number, reason: string) => {
debug(
this.#logger?.info(
"Connection closed to DevTools for app='%s' on device='%s' with code='%s' and reason='%s'.",
device.getApp() || 'unknown',
device.getName() || 'unknown',
@@ -21,7 +21,6 @@ import type {NextHandleFunction} from 'connect';
import type {IncomingMessage, ServerResponse} from 'http';
import getDevToolsFrontendUrl from '../utils/getDevToolsFrontendUrl';
import {createHash} from 'crypto';
import url from 'url';
const LEGACY_SYNTHETIC_PAGE_TITLE =
@@ -191,15 +190,11 @@ export default function openDebuggerMiddleware({
}
}
if (shouldUseStandaloneFuseboxShell) {
const windowKey = createHash('sha256')
.update(
[
serverBaseUrl,
target.webSocketDebuggerUrl,
target.appId,
].join('-'),
)
.digest('hex');
const windowKey = [
serverBaseUrl,
target.webSocketDebuggerUrl,
target.appId,
].join('-');
if (!browserLauncher.unstable_showFuseboxShell) {
throw new Error(
'Fusebox shell is not supported by the current browser launcher',
@@ -67,18 +67,18 @@ class ReactRootProjectPlugin : Plugin<Project> {
) {
project.logger.error(
"""
********************************************************************************
********************************************************************************
WARNING: Setting `newArchEnabled=false` in your `gradle.properties` file is not
supported anymore since React Native 0.82.
WARNING: Setting `newArchEnabled=false` in your `gradle.properties` file is not
supported anymore since React Native 0.82.
You can remove the line from your `gradle.properties` file.
The application will run with the New Architecture enabled by default.
You can remove the line from your `gradle.properties` file.
********************************************************************************
The application will run with the New Architecture enabled by default.
********************************************************************************
"""
"""
.trimIndent()
)
}
@@ -168,13 +168,13 @@ abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
# We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
# or link against a old prefab target (this is needed for React Native 0.76 on).
set(REACTNATIVE_MERGED_SO true)
{{ libraryIncludes }}
set(AUTOLINKED_LIBRARIES
{{ libraryModules }}
)
@@ -191,28 +191,28 @@ abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
* once the code is regenerated.
*
*/
#include "autolinking.h"
{{ autolinkingCppIncludes }}
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
{{ autolinkingCppTurboModuleJavaProviders }}
return nullptr;
}
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
{{ autolinkingCppTurboModuleCxxProviders }}
return nullptr;
}
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
{{ autolinkingCppComponentDescriptors }}
return;
}
} // namespace react
} // namespace facebook
"""
@@ -228,22 +228,22 @@ abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
* once the code is regenerated.
*
*/
#pragma once
#include <ReactCommon/CallInvoker.h>
#include <ReactCommon/JavaTurboModule.h>
#include <ReactCommon/TurboModule.h>
#include <jsi/jsi.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params);
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker);
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry);
} // namespace react
} // namespace facebook
"""
@@ -65,19 +65,19 @@ abstract class GenerateEntryPointTask : DefaultTask() {
val generatedFileContentsTemplate =
"""
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
import com.facebook.react.views.view.WindowUtilKt;
import com.facebook.react.soloader.OpenSourceMergedSoMapping;
import com.facebook.soloader.SoLoader;
import java.io.IOException;
/**
* This class is the entry point for loading React Native using the configuration
* that the users specifies in their .gradle files.
@@ -102,7 +102,7 @@ abstract class GenerateEntryPointTask : DefaultTask() {
}
}
}
"""
"""
.trimIndent()
}
}
@@ -137,61 +137,61 @@ abstract class GeneratePackageListTask : DefaultTask() {
val generatedFileContentsTemplate =
"""
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainPackageConfig;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.ArrayList;
{{ packageImports }}
@SuppressWarnings("deprecation")
public class PackageList {
private Application application;
private ReactNativeHost reactNativeHost;
private MainPackageConfig mConfig;
public PackageList(ReactNativeHost reactNativeHost) {
this(reactNativeHost, null);
}
public PackageList(Application application) {
this(application, null);
}
public PackageList(ReactNativeHost reactNativeHost, MainPackageConfig config) {
this.reactNativeHost = reactNativeHost;
mConfig = config;
}
public PackageList(Application application, MainPackageConfig config) {
this.reactNativeHost = null;
this.application = application;
mConfig = config;
}
private ReactNativeHost getReactNativeHost() {
return this.reactNativeHost;
}
private Resources getResources() {
return this.getApplication().getResources();
}
private Application getApplication() {
if (this.reactNativeHost == null) return this.application;
return this.reactNativeHost.getApplication();
}
private Context getApplicationContext() {
return this.getApplication().getApplicationContext();
}
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig){{ packageClassInstances }}
@@ -21,24 +21,24 @@ internal object BackwardCompatUtils {
if (reactMap.isNotEmpty()) {
project.logger.error(
"""
********************************************************************************
ERROR: Using old project.ext.react configuration.
We identified that your project is using a old configuration block as:
project.ext.react = [
// ...
]
You should migrate to the new configuration:
react {
// ...
}
You can find documentation inside `android/app/build.gradle` on how to use it.
********************************************************************************
"""
********************************************************************************
ERROR: Using old project.ext.react configuration.
We identified that your project is using a old configuration block as:
project.ext.react = [
// ...
]
You should migrate to the new configuration:
react {
// ...
}
You can find documentation inside `android/app/build.gradle` on how to use it.
********************************************************************************
"""
.trimIndent()
)
}
@@ -191,14 +191,6 @@ internal object DependencyUtils {
"The hermes-android dependency was modified to use the correct Maven group.",
)
)
} else if (hermesV1Enabled) {
dependencySubstitution.add(
Triple(
"com.facebook.react:hermes-android",
hermesVersionString,
"The hermes-android dependency was modified to use Hermes V1.",
)
)
}
return dependencySubstitution
}
@@ -105,11 +105,11 @@ private fun detectCliFile(reactNativeRoot: File, preconfiguredCliFile: File?): F
error(
"""
Couldn't determine CLI location!
Couldn't determine CLI location!
Please set `react { cliFile = file(...) }` inside your
build.gradle to the path of the react-native cli.js file.
This file typically resides in `node_modules/react-native/cli.js`
Please set `react { cliFile = file(...) }` inside your
build.gradle to the path of the react-native cli.js file.
This file typically resides in `node_modules/react-native/cli.js`
"""
.trimIndent()
)
@@ -242,7 +242,7 @@ internal fun readPackageJsonFile(
return packageJson?.let { JsonUtils.fromPackageJson(it) }
}
private const val HERMES_COMPILER_NPM_DIR = "node_modules/hermes-compiler/hermesc/%OS-BIN%/"
private const val HERMES_COMPILER_NPM_DIR = "node_modules/hermes-compiler/%OS-BIN%/"
private const val HERMESC_IN_REACT_NATIVE_DIR = "node_modules/react-native/sdks/hermesc/%OS-BIN%/"
private const val HERMESC_BUILT_FROM_SOURCE_DIR =
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/"
@@ -120,20 +120,20 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
assertThat(output)
.isEqualTo(
"""
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
# We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
# or link against a old prefab target (this is needed for React Native 0.76 on).
set(REACTNATIVE_MERGED_SO true)
set(AUTOLINKED_LIBRARIES
)
"""
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
# We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
# or link against a old prefab target (this is needed for React Native 0.76 on).
set(REACTNATIVE_MERGED_SO true)
set(AUTOLINKED_LIBRARIES
)
"""
.trimIndent()
)
}
@@ -147,24 +147,24 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
assertThat(output)
.isEqualTo(
"""
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
# We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
# or link against a old prefab target (this is needed for React Native 0.76 on).
set(REACTNATIVE_MERGED_SO true)
add_subdirectory("./a/directory/" aPackage_autolinked_build)
add_subdirectory("./another/directory/with\ spaces/" anotherPackage_autolinked_build)
add_subdirectory("./another/directory/cxx/" anotherPackage_cxxmodule_autolinked_build)
set(AUTOLINKED_LIBRARIES
react_codegen_aPackage
react_codegen_anotherPackage
another_cxxModule
)
"""
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
# We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
# or link against a old prefab target (this is needed for React Native 0.76 on).
set(REACTNATIVE_MERGED_SO true)
add_subdirectory("./a/directory/" aPackage_autolinked_build)
add_subdirectory("./another/directory/with\ spaces/" anotherPackage_autolinked_build)
add_subdirectory("./another/directory/cxx/" anotherPackage_cxxmodule_autolinked_build)
set(AUTOLINKED_LIBRARIES
react_codegen_aPackage
react_codegen_anotherPackage
another_cxxModule
)
"""
.trimIndent()
)
}
@@ -178,38 +178,38 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
assertThat(output)
.isEqualTo(
"""
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
#include "autolinking.h"
#include "autolinking.h"
namespace facebook {
namespace react {
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
return nullptr;
}
return nullptr;
}
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
return nullptr;
}
return nullptr;
}
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
return;
}
return;
}
} // namespace react
} // namespace facebook
"""
} // namespace react
} // namespace facebook
"""
.trimIndent()
)
}
@@ -223,50 +223,50 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
assertThat(output)
.isEqualTo(
"""
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
#include "autolinking.h"
#include <aPackage.h>
#include <anotherPackage.h>
#include <react/renderer/components/anotherPackage/ComponentDescriptors.h>
#include <AnotherCxxModule.h>
#include "autolinking.h"
#include <aPackage.h>
#include <anotherPackage.h>
#include <react/renderer/components/anotherPackage/ComponentDescriptors.h>
#include <AnotherCxxModule.h>
namespace facebook {
namespace react {
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
auto module_aPackage = aPackage_ModuleProvider(moduleName, params);
if (module_aPackage != nullptr) {
return module_aPackage;
}
auto module_anotherPackage = anotherPackage_ModuleProvider(moduleName, params);
if (module_anotherPackage != nullptr) {
return module_anotherPackage;
}
return nullptr;
}
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
auto module_aPackage = aPackage_ModuleProvider(moduleName, params);
if (module_aPackage != nullptr) {
return module_aPackage;
}
auto module_anotherPackage = anotherPackage_ModuleProvider(moduleName, params);
if (module_anotherPackage != nullptr) {
return module_anotherPackage;
}
return nullptr;
}
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
if (moduleName == AnotherCxxModule::kModuleName) {
return std::make_shared<AnotherCxxModule>(jsInvoker);
}
return nullptr;
}
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
if (moduleName == AnotherCxxModule::kModuleName) {
return std::make_shared<AnotherCxxModule>(jsInvoker);
}
return nullptr;
}
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
providerRegistry->add(concreteComponentDescriptorProvider<AnotherPackageComponentDescriptor>());
return;
}
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
providerRegistry->add(concreteComponentDescriptorProvider<AnotherPackageComponentDescriptor>());
return;
}
} // namespace react
} // namespace facebook
"""
} // namespace react
} // namespace facebook
"""
.trimIndent()
)
}
@@ -138,16 +138,16 @@ class GenerateCodegenArtifactsTaskTest {
// language=JSON
writeText(
"""
{
"name": "@a/library",
"codegenConfig": {
"name": "an-awesome-library",
"android": {
"javaPackageName": "com.awesome.package"
}
}
}
"""
{
"name": "@a/library",
"codegenConfig": {
"name": "an-awesome-library",
"android": {
"javaPackageName": "com.awesome.package"
}
}
}
"""
.trimIndent()
)
}
@@ -172,12 +172,12 @@ class GenerateCodegenArtifactsTaskTest {
// language=JSON
writeText(
"""
{
"name": "@a/library",
"codegenConfig": {
}
}
"""
{
"name": "@a/library",
"codegenConfig": {
}
}
"""
.trimIndent()
)
}
@@ -47,45 +47,45 @@ class GenerateEntryPointTaskTest {
assertThat(result)
.isEqualTo(
"""
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
import com.facebook.react.views.view.WindowUtilKt;
import com.facebook.react.soloader.OpenSourceMergedSoMapping;
import com.facebook.soloader.SoLoader;
import java.io.IOException;
/**
* This class is the entry point for loading React Native using the configuration
* that the users specifies in their .gradle files.
*
* The `loadReactNative(this)` method invocation should be called inside the
* application onCreate otherwise the app won't load correctly.
*/
public class ReactNativeApplicationEntryPoint {
public static void loadReactNative(Context context) {
try {
SoLoader.init(context, OpenSourceMergedSoMapping.INSTANCE);
} catch (IOException error) {
throw new RuntimeException(error);
}
if (com.facebook.react.BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
DefaultNewArchitectureEntryPoint.load();
}
if (com.facebook.react.BuildConfig.IS_EDGE_TO_EDGE_ENABLED) {
WindowUtilKt.setEdgeToEdgeFeatureFlagOn();
}
}
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
import com.facebook.react.views.view.WindowUtilKt;
import com.facebook.react.soloader.OpenSourceMergedSoMapping;
import com.facebook.soloader.SoLoader;
import java.io.IOException;
/**
* This class is the entry point for loading React Native using the configuration
* that the users specifies in their .gradle files.
*
* The `loadReactNative(this)` method invocation should be called inside the
* application onCreate otherwise the app won't load correctly.
*/
public class ReactNativeApplicationEntryPoint {
public static void loadReactNative(Context context) {
try {
SoLoader.init(context, OpenSourceMergedSoMapping.INSTANCE);
} catch (IOException error) {
throw new RuntimeException(error);
}
"""
if (com.facebook.react.BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
DefaultNewArchitectureEntryPoint.load();
}
if (com.facebook.react.BuildConfig.IS_EDGE_TO_EDGE_ENABLED) {
WindowUtilKt.setEdgeToEdgeFeatureFlagOn();
}
}
}
"""
.trimIndent()
)
}
@@ -59,11 +59,11 @@ class GeneratePackageListTaskTest {
assertThat(result)
.isEqualTo(
"""
// @react-native/a-package
import com.facebook.react.aPackage;
// @react-native/another-package
import com.facebook.react.anotherPackage;
"""
// @react-native/a-package
import com.facebook.react.aPackage;
// @react-native/another-package
import com.facebook.react.anotherPackage;
"""
.trimIndent()
)
}
@@ -85,10 +85,10 @@ class GeneratePackageListTaskTest {
assertThat(result)
.isEqualTo(
"""
,
new APackage(),
new AnotherPackage()
"""
,
new APackage(),
new AnotherPackage()
"""
.trimIndent()
)
}
@@ -234,69 +234,69 @@ class GeneratePackageListTaskTest {
assertThat(result)
.isEqualTo(
"""
package com.facebook.react;
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainPackageConfig;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.ArrayList;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainPackageConfig;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.ArrayList;
@SuppressWarnings("deprecation")
public class PackageList {
private Application application;
private ReactNativeHost reactNativeHost;
private MainPackageConfig mConfig;
@SuppressWarnings("deprecation")
public class PackageList {
private Application application;
private ReactNativeHost reactNativeHost;
private MainPackageConfig mConfig;
public PackageList(ReactNativeHost reactNativeHost) {
this(reactNativeHost, null);
}
public PackageList(ReactNativeHost reactNativeHost) {
this(reactNativeHost, null);
}
public PackageList(Application application) {
this(application, null);
}
public PackageList(Application application) {
this(application, null);
}
public PackageList(ReactNativeHost reactNativeHost, MainPackageConfig config) {
this.reactNativeHost = reactNativeHost;
mConfig = config;
}
public PackageList(ReactNativeHost reactNativeHost, MainPackageConfig config) {
this.reactNativeHost = reactNativeHost;
mConfig = config;
}
public PackageList(Application application, MainPackageConfig config) {
this.reactNativeHost = null;
this.application = application;
mConfig = config;
}
public PackageList(Application application, MainPackageConfig config) {
this.reactNativeHost = null;
this.application = application;
mConfig = config;
}
private ReactNativeHost getReactNativeHost() {
return this.reactNativeHost;
}
private ReactNativeHost getReactNativeHost() {
return this.reactNativeHost;
}
private Resources getResources() {
return this.getApplication().getResources();
}
private Resources getResources() {
return this.getApplication().getResources();
}
private Application getApplication() {
if (this.reactNativeHost == null) return this.application;
return this.reactNativeHost.getApplication();
}
private Application getApplication() {
if (this.reactNativeHost == null) return this.application;
return this.reactNativeHost.getApplication();
}
private Context getApplicationContext() {
return this.getApplication().getApplicationContext();
}
private Context getApplicationContext() {
return this.getApplication().getApplicationContext();
}
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig)
));
}
}
"""
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig)
));
}
}
"""
.trimIndent()
)
}
@@ -312,74 +312,74 @@ class GeneratePackageListTaskTest {
assertThat(result)
.isEqualTo(
"""
package com.facebook.react;
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainPackageConfig;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.ArrayList;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainPackageConfig;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.ArrayList;
// @react-native/a-package
import com.facebook.react.aPackage;
// @react-native/another-package
import com.facebook.react.anotherPackage;
// @react-native/a-package
import com.facebook.react.aPackage;
// @react-native/another-package
import com.facebook.react.anotherPackage;
@SuppressWarnings("deprecation")
public class PackageList {
private Application application;
private ReactNativeHost reactNativeHost;
private MainPackageConfig mConfig;
@SuppressWarnings("deprecation")
public class PackageList {
private Application application;
private ReactNativeHost reactNativeHost;
private MainPackageConfig mConfig;
public PackageList(ReactNativeHost reactNativeHost) {
this(reactNativeHost, null);
}
public PackageList(ReactNativeHost reactNativeHost) {
this(reactNativeHost, null);
}
public PackageList(Application application) {
this(application, null);
}
public PackageList(Application application) {
this(application, null);
}
public PackageList(ReactNativeHost reactNativeHost, MainPackageConfig config) {
this.reactNativeHost = reactNativeHost;
mConfig = config;
}
public PackageList(ReactNativeHost reactNativeHost, MainPackageConfig config) {
this.reactNativeHost = reactNativeHost;
mConfig = config;
}
public PackageList(Application application, MainPackageConfig config) {
this.reactNativeHost = null;
this.application = application;
mConfig = config;
}
public PackageList(Application application, MainPackageConfig config) {
this.reactNativeHost = null;
this.application = application;
mConfig = config;
}
private ReactNativeHost getReactNativeHost() {
return this.reactNativeHost;
}
private ReactNativeHost getReactNativeHost() {
return this.reactNativeHost;
}
private Resources getResources() {
return this.getApplication().getResources();
}
private Resources getResources() {
return this.getApplication().getResources();
}
private Application getApplication() {
if (this.reactNativeHost == null) return this.application;
return this.reactNativeHost.getApplication();
}
private Application getApplication() {
if (this.reactNativeHost == null) return this.application;
return this.reactNativeHost.getApplication();
}
private Context getApplicationContext() {
return this.getApplication().getApplicationContext();
}
private Context getApplicationContext() {
return this.getApplication().getApplicationContext();
}
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig),
new APackage(),
new AnotherPackage()
));
}
}
"""
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig),
new APackage(),
new AnotherPackage()
));
}
}
"""
.trimIndent()
)
}
@@ -34,9 +34,9 @@ class AgpConfiguratorUtilsTest {
writeText(
// language=xml
"""
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
"""
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
"""
.trimIndent()
)
}
@@ -53,9 +53,9 @@ class AgpConfiguratorUtilsTest {
writeText(
// language=xml
"""
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.facebook.react" >
</manifest>
"""
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.facebook.react" >
</manifest>
"""
.trimIndent()
)
}
@@ -549,9 +549,9 @@ class DependencyUtilsTest {
tempFolder.newFile("gradle.properties").apply {
writeText(
"""
VERSION_NAME=1000.0.0
ANOTHER_PROPERTY=true
"""
VERSION_NAME=1000.0.0
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -560,9 +560,9 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_V1_VERSION_NAME=1000.0.0
ANOTHER_PROPERTY=true
"""
HERMES_V1_VERSION_NAME=1000.0.0
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -583,11 +583,11 @@ class DependencyUtilsTest {
tempFolder.newFile("gradle.properties").apply {
writeText(
"""
VERSION_NAME=0.0.0-20221101-2019-cfe811ab1
HERMES_VERSION_NAME=0.12.0-commitly-20221101-2019-cfe811ab1
HERMES_V1_VERSION_NAME=250829098.0.0-stable
ANOTHER_PROPERTY=true
"""
VERSION_NAME=0.0.0-20221101-2019-cfe811ab1
HERMES_VERSION_NAME=0.12.0-commitly-20221101-2019-cfe811ab1
HERMES_V1_VERSION_NAME=250829098.0.0-stable
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -596,9 +596,9 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_V1_VERSION_NAME=250829098.0.0-stable
ANOTHER_PROPERTY=true
"""
HERMES_V1_VERSION_NAME=250829098.0.0-stable
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -619,8 +619,8 @@ class DependencyUtilsTest {
tempFolder.newFile("gradle.properties").apply {
writeText(
"""
ANOTHER_PROPERTY=true
"""
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -629,8 +629,8 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
ANOTHER_PROPERTY=true
"""
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -650,9 +650,9 @@ class DependencyUtilsTest {
tempFolder.newFile("gradle.properties").apply {
writeText(
"""
VERSION_NAME=
ANOTHER_PROPERTY=true
"""
VERSION_NAME=
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -661,9 +661,9 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -683,10 +683,10 @@ class DependencyUtilsTest {
tempFolder.newFile("gradle.properties").apply {
writeText(
"""
react.internal.publishingGroup=io.github.test
react.internal.hermesPublishingGroup=io.github.test
ANOTHER_PROPERTY=true
"""
react.internal.publishingGroup=io.github.test
react.internal.hermesPublishingGroup=io.github.test
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -695,9 +695,9 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -716,8 +716,8 @@ class DependencyUtilsTest {
tempFolder.newFile("gradle.properties").apply {
writeText(
"""
ANOTHER_PROPERTY=true
"""
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -726,9 +726,9 @@ class DependencyUtilsTest {
tempFolder.newFile("version.properties").apply {
writeText(
"""
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
HERMES_V1_VERSION_NAME=
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
}
@@ -165,8 +165,8 @@ class PathUtilsTest {
@Test
@WithOs(OS.MAC)
fun detectOSAwareHermesCommand_withHermesV1Enabled() {
tempFolder.newFolder("node_modules/hermes-compiler/hermesc/osx-bin/")
val expected = tempFolder.newFile("node_modules/hermes-compiler/hermesc/osx-bin/hermesc")
tempFolder.newFolder("node_modules/hermes-compiler/osx-bin/")
val expected = tempFolder.newFile("node_modules/hermes-compiler/osx-bin/hermesc")
assertThat(detectOSAwareHermesCommand(tempFolder.root, "", hermesV1Enabled = true))
.isEqualTo(expected.toString())
@@ -320,11 +320,11 @@ class PathUtilsTest {
writeText(
// language=json
"""
{
"name": "a-library",
"codegenConfig": {}
}
"""
{
"name": "a-library",
"codegenConfig": {}
}
"""
.trimIndent()
)
}
@@ -150,11 +150,11 @@ class ProjectUtilsTest {
writeText(
// language=json
"""
{
"name": "a-library",
"codegenConfig": {}
}
"""
{
"name": "a-library",
"codegenConfig": {}
}
"""
.trimIndent()
)
}
@@ -170,10 +170,10 @@ class ProjectUtilsTest {
writeText(
// language=json
"""
{
"name": "a-library"
}
"""
{
"name": "a-library"
}
"""
.trimIndent()
)
}
@@ -238,30 +238,30 @@ class ReactSettingsExtensionTest {
File(generatedFolder, "autolinking.json").apply {
writeText(
"""
{
"root": "/",
"reactNativePath": "/node_modules/react-native",
"reactNativeVersion": "0.75",
"dependencies": {},
"healthChecks": [],
"platforms": {
"ios": {},
"android": {}
},
"assets": [],
"project": {
"ios": {},
"android": {
"sourceDir": "/",
"appName": "app",
"packageName": "com.TestApp",
"applicationId": "com.TestApp",
"mainActivity": ".MainActivity",
"assets": []
}
}
}
"""
{
"root": "/",
"reactNativePath": "/node_modules/react-native",
"reactNativeVersion": "0.75",
"dependencies": {},
"healthChecks": [],
"platforms": {
"ios": {},
"android": {}
},
"assets": [],
"project": {
"ios": {},
"android": {
"sourceDir": "/",
"appName": "app",
"packageName": "com.TestApp",
"applicationId": "com.TestApp",
"mainActivity": ".MainActivity",
"assets": []
}
}
}
"""
.trimIndent()
)
}
@@ -309,13 +309,13 @@ class ReactSettingsExtensionTest {
File(generatedFolder, "autolinking.json").apply {
writeText(
"""
{
"project": {
"ios": {},
"android": {}
}
}
"""
{
"project": {
"ios": {},
"android": {}
}
}
"""
.trimIndent()
)
}
@@ -197,10 +197,10 @@ class JsonUtilsTest {
val validJson =
createJsonFile(
"""
> AwesomeProject@0.0.1 npx
> rnc-cli config
{
"reactNativeVersion": "1000.0.0",
"project": {
-30
View File
@@ -10,41 +10,11 @@
'use strict';
const {version: packageVersion} = require('../package.json');
const main = require('./configs/main');
module.exports = function (babel, options) {
return main(options);
};
let cacheKey;
module.exports.getCacheKey = () => {
if (cacheKey != null) {
// Memoize
return cacheKey;
}
if (!packageVersion.endsWith('-main')) {
// Assume the integrity of package contents for published npm releases.
cacheKey = packageVersion;
return cacheKey;
}
// For anyone working with a `-main` version, contents may vary over time
// even though the version does not. Hash the relevant contents of this
// package. Lazy-load dependencies we only need on this slow path.
const {createHash} = require('crypto');
const {readFileSync} = require('fs');
const key = createHash('md5');
[
readFileSync(__filename),
readFileSync(require.resolve('./configs/main.js')),
readFileSync(require.resolve('./configs/hmr.js')),
readFileSync(require.resolve('./configs/lazy-imports.js')),
readFileSync(require.resolve('./passthrough-syntax-plugins.js')),
readFileSync(require.resolve('./plugin-warn-on-deep-imports.js')),
].forEach(part => key.update(part));
cacheKey = key.digest('hex');
return cacheKey;
};
module.exports.getPreset = main.getPreset;
module.exports.passthroughSyntaxPlugins = require('./passthrough-syntax-plugins');
+1 -2
View File
@@ -23,14 +23,13 @@ import type {
*/
const {parseSync, transformFromAstSync} = require('@babel/core');
const {getCacheKey: getPresetCacheKey} = require('@react-native/babel-preset');
const makeHMRConfig = require('@react-native/babel-preset/src/configs/hmr');
const crypto = require('crypto');
const fs = require('fs');
const nullthrows = require('nullthrows');
const path = require('path');
const cacheKeyParts = [getPresetCacheKey(), fs.readFileSync(__filename)];
const cacheKeyParts = [fs.readFileSync(__filename)];
// TS detection conditions copied from @react-native/babel-preset
function isTypeScriptSource(fileName /*: string */) {
@@ -47,7 +47,7 @@ function combineSchemas(
}
return merged;
},
{modules: {} /*:: as SchemaType['modules'] */},
{modules: {}},
);
return {
@@ -540,7 +540,7 @@ function buildEventEmitterSchema(
return {
name: eventemitterName,
optional: Boolean(property.optional),
optional: false,
typeAnnotation: {
type: 'EventEmitterTypeAnnotation',
typeAnnotation: eventTypeAnnotation,
@@ -873,6 +873,56 @@ describe('Animated', () => {
});
});
describe('Animated Interactions', () => {
let Animated; // eslint-disable-line no-shadow
let InteractionManager;
beforeEach(() => {
jest.mock('../../Interaction/InteractionManager');
Animated = require('../Animated').default;
InteractionManager =
require('../../Interaction/InteractionManager').default;
});
afterEach(() => {
jest.unmock('../../Interaction/InteractionManager');
});
it('registers an interaction by default', () => {
// $FlowFixMe[prop-missing]
InteractionManager.createInteractionHandle.mockReturnValue(777);
const value = new Animated.Value(0);
const callback = jest.fn();
Animated.timing(value, {
toValue: 100,
duration: 100,
useNativeDriver: false,
}).start(callback);
jest.runAllTimers();
expect(InteractionManager.createInteractionHandle).toBeCalled();
expect(InteractionManager.clearInteractionHandle).toBeCalledWith(777);
expect(callback).toBeCalledWith({finished: true});
});
it('does not register an interaction when specified', () => {
const value = new Animated.Value(0);
const callback = jest.fn();
Animated.timing(value, {
toValue: 100,
duration: 100,
isInteraction: false,
useNativeDriver: false,
}).start(callback);
jest.runAllTimers();
expect(InteractionManager.createInteractionHandle).not.toBeCalled();
expect(InteractionManager.clearInteractionHandle).not.toBeCalled();
expect(callback).toBeCalledWith({finished: true});
});
});
describe('Animated Tracking', () => {
it('should track values', () => {
const value1 = new Animated.Value(0);
@@ -14,10 +14,8 @@ import FlatList, {type FlatListProps} from '../../Lists/FlatList';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
export default createAnimatedComponent(FlatList) as $FlowFixMe as component<
// $FlowExpectedError[unclear-type]
ItemT = any,
>(
// $FlowExpectedError[unclear-type]
export default (createAnimatedComponent(FlatList): component<ItemT = any>(
ref?: React.RefSetter<FlatList<ItemT>>,
...props: AnimatedProps<FlatListProps<ItemT>>
);
));
@@ -14,10 +14,9 @@ import Image from '../../Image/Image';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
export default (createAnimatedComponent<
$FlowFixMe,
React.ElementRef<typeof Image>,
>((Image: $FlowFixMe)): AnimatedComponentType<
export default (createAnimatedComponent(
(Image: $FlowFixMe),
): AnimatedComponentType<
React.ElementConfig<typeof Image>,
React.ElementRef<typeof Image>,
>);
@@ -15,7 +15,7 @@ import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
// $FlowFixMe[incompatible-type]
export default createAnimatedComponent(SectionList) as $FlowFixMe as component<
export default (createAnimatedComponent(SectionList): component<
// $FlowExpectedError[unclear-type]
ItemT = any,
// $FlowExpectedError[unclear-type]
@@ -23,4 +23,4 @@ export default createAnimatedComponent(SectionList) as $FlowFixMe as component<
>(
ref?: React.RefSetter<SectionList<ItemT, SectionT>>,
...props: AnimatedProps<SectionListProps<ItemT, SectionT>>
);
));
@@ -14,10 +14,6 @@ import Text, {type TextProps} from '../../Text/Text';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
export default (createAnimatedComponent<
$FlowFixMe,
React.ElementRef<typeof Text>,
>((Text: $FlowFixMe)): AnimatedComponentType<
TextProps,
React.ElementRef<typeof Text>,
>);
export default (createAnimatedComponent(
(Text: $FlowFixMe),
): AnimatedComponentType<TextProps, React.ElementRef<typeof Text>>);
@@ -15,8 +15,7 @@ import View from '../../Components/View/View';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
// $FlowFixMe[incompatible-type]
export default createAnimatedComponent(View) as AnimatedComponentType<
export default (createAnimatedComponent(View): AnimatedComponentType<
ViewProps,
React.ElementRef<typeof View>,
>;
>);
@@ -63,29 +63,17 @@ type PassThroughProps = $ReadOnly<{
passthroughAnimatedPropExplicitValues?: ViewProps | null,
}>;
type LooseOmit<O: interface {}, K: $Keys<$FlowFixMe>> = Pick<
O,
Exclude<$Keys<O>, K>,
>;
export type AnimatedProps<Props: {...}> = {
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
} & PassThroughProps;
export type AnimatedProps<Props: {...}> = LooseOmit<
{
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
},
'ref',
> &
PassThroughProps;
export type AnimatedBaseProps<Props: {...}> = LooseOmit<
{
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
},
'ref',
>;
export type AnimatedBaseProps<Props: {...}> = {
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
};
export type AnimatedComponentType<Props: {...}, +Instance = mixed> = component(
ref?: React.RefSetter<Instance>,
@@ -18,6 +18,7 @@ import type {AnimatedNodeConfig} from './AnimatedNode';
import type AnimatedTracking from './AnimatedTracking';
import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
import InteractionManager from '../../Interaction/InteractionManager';
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedWithChildren from './AnimatedWithChildren';
@@ -311,6 +312,10 @@ export default class AnimatedValue extends AnimatedWithChildren {
* See https://reactnative.dev/docs/animatedvalue#animate
*/
animate(animation: Animation, callback: ?EndCallback): void {
let handle = null;
if (animation.__isInteraction) {
handle = InteractionManager.createInteractionHandle();
}
const previousAnimation = this._animation;
this._animation && this._animation.stop();
this._animation = animation;
@@ -323,6 +328,9 @@ export default class AnimatedValue extends AnimatedWithChildren {
},
result => {
this._animation = null;
if (handle !== null) {
InteractionManager.clearInteractionHandle(handle);
}
callback && callback(result);
},
previousAnimation,
@@ -49,7 +49,7 @@ export interface RefreshControlPropsAndroid extends ViewProps {
/**
* Size of the refresh indicator, see RefreshControl.SIZE.
*/
size?: 'default' | 'large' | undefined;
size?: number | undefined;
}
export interface RefreshControlProps
@@ -1690,7 +1690,6 @@ class ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
return (
<StickyHeaderComponent
key={key}
/* $FlowFixMe[incompatible-type] */
ref={ref => this._setStickyHeaderRef(key, ref)}
nextHeaderLayoutY={this._headerLayoutYs.get(
this._getKeyForIndex(nextIndex, children),
@@ -44,7 +44,7 @@ interface Instance extends React.ElementRef<typeof Animated.View> {
}
const ScrollViewStickyHeader: component(
ref?: React.RefSetter<Instance>,
ref: React.RefSetter<Instance>,
...props: ScrollViewStickyHeaderProps
) = function ScrollViewStickyHeader({
ref: forwardedRef,
@@ -282,7 +282,7 @@ const ScrollViewStickyHeader: component(
const passthroughAnimatedPropExplicitValues =
isFabric && translateY != null
? {
style: {transform: [{translateY}]},
style: {transform: [{translateY: translateY}]},
}
: null;
@@ -303,20 +303,20 @@ const ScrollViewStickyHeader: component(
passthroughAnimatedPropExplicitValues
}>
{cloneElement(child, {
onLayout: undefined, // we call this manually through our this._onLayout
style: styles.fill, // We transfer the child style to the wrapper.
onLayout: undefined, // we call this manually through our this._onLayout
})}
</Animated.View>
);
};
const styles = StyleSheet.create({
fill: {
flex: 1,
},
header: {
zIndex: 10,
},
fill: {
flex: 1,
},
});
export default ScrollViewStickyHeader;
@@ -449,12 +449,6 @@ function InternalTextInput(props: TextInputProps): React.Node {
before we can get to the long term breaking change.
*/
if (instance != null) {
// Register the input immediately when the ref is set so that focus()
// can be called from ref callbacks
// Double registering during useLayoutEffect is fine, because the underlying
// state is a Set.
TextInputState.registerInput(instance);
// $FlowFixMe[prop-missing] - See the explanation above.
// $FlowFixMe[unsafe-object-assign]
Object.assign(instance, {
@@ -47,14 +47,15 @@ class TouchableBounce extends React.Component<
_createPressabilityConfig(): PressabilityConfig {
return {
android_disableSound: this.props.touchSoundDisabled,
cancelable: !this.props.rejectResponderTermination,
disabled: this.props.disabled,
hitSlop: this.props.hitSlop,
delayLongPress: this.props.delayLongPress,
delayPressIn: this.props.delayPressIn,
delayPressOut: this.props.delayPressOut,
disabled: this.props.disabled,
hitSlop: this.props.hitSlop,
minPressDuration: 0,
pressRectOffset: this.props.pressRetentionOffset,
android_disableSound: this.props.touchSoundDisabled,
onBlur: event => {
if (Platform.isTV) {
this._bounceTo(1, 0.4, 0);
@@ -112,7 +113,6 @@ class TouchableBounce extends React.Component<
this.props.onPressOut(event);
}
},
pressRectOffset: this.props.pressRetentionOffset,
};
}
@@ -123,10 +123,10 @@ class TouchableBounce extends React.Component<
callback?: ?() => void,
) {
Animated.spring(this.state.scale, {
bounciness,
toValue,
useNativeDriver: true,
velocity,
bounciness,
useNativeDriver: true,
}).start(callback);
}
@@ -230,6 +230,6 @@ export default (function TouchableBounceWrapper({
}) {
return <TouchableBounce {...props} hostRef={hostRef} />;
} as component(
ref?: React.RefSetter<mixed>,
ref: React.RefSetter<mixed>,
...props: $ReadOnly<Omit<TouchableBounceProps, 'hostRef'>>
));
@@ -21,14 +21,12 @@ const ViewNativeComponent: HostComponent<Props> =
}));
interface NativeCommands {
+focus: (viewRef: HostInstance) => void;
+blur: (viewRef: HostInstance) => void;
+hotspotUpdate: (viewRef: HostInstance, x: number, y: number) => void;
+setPressed: (viewRef: HostInstance, pressed: boolean) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['focus', 'blur', 'hotspotUpdate', 'setPressed'],
supportedCommands: ['hotspotUpdate', 'setPressed'],
});
/**
+21 -21
View File
@@ -39,24 +39,6 @@ function DebuggingOverlay({
useImperativeHandle(
ref,
() => ({
clearElementsHighlight() {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.clearElementsHighlights(nativeComponentRef.current);
}
},
highlightElements(elements) {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.highlightElements(nativeComponentRef.current, elements);
}
},
highlightTraceUpdates(updates) {
if (!isNativeComponentReady) {
return;
@@ -73,6 +55,24 @@ function DebuggingOverlay({
);
}
},
highlightElements(elements) {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.highlightElements(nativeComponentRef.current, elements);
}
},
clearElementsHighlight() {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.clearElementsHighlights(nativeComponentRef.current);
}
},
}),
[],
);
@@ -95,14 +95,14 @@ function DebuggingOverlay({
const styles = StyleSheet.create({
overlay: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
},
});
export default DebuggingOverlay as component(
ref?: React.RefSetter<DebuggingOverlayHandle>,
ref: React.RefSetter<DebuggingOverlayHandle>,
);
+6 -3
View File
@@ -8,8 +8,11 @@
* @format
*/
import type {HostInstance} from '../..';
import type {AbstractImageAndroid, AbstractImageIOS} from './ImageTypes.flow';
import type {
AbstractImageAndroid,
AbstractImageIOS,
ImageType as ImageComponent,
} from './ImageTypes.flow';
import useMergeRefs from '../Utilities/useMergeRefs';
import * as React from 'react';
@@ -30,7 +33,7 @@ export function unstable_getImageComponentDecorator(): ?ImageComponentDecorator
return injectedImageComponentDecorator;
}
type ImageInstance = HostInstance;
type ImageInstance = React.ElementRef<ImageComponent>;
type ImageAttachedCallback = (
imageInstance: ImageInstance,
@@ -8,11 +8,12 @@
* @format
*/
import type {HostInstance} from '../..';
import type {RootTag} from '../Types/RootTagTypes';
import type {ResolvedAssetSource} from './AssetSourceResolver';
import type {ImageProps as ImagePropsType} from './ImageProps';
import type {ImageSource} from './ImageSource';
import typeof ImageViewNativeComponent from './ImageViewNativeComponent';
import typeof TextInlineImageNativeComponent from './TextInlineImageNativeComponent';
import * as React from 'react';
@@ -66,14 +67,17 @@ type ImageComponentStaticsAndroid = $ReadOnly<{
}>;
export type AbstractImageAndroid = component(
ref?: React.RefSetter<HostInstance>,
ref?: React.RefSetter<
| React.ElementRef<TextInlineImageNativeComponent>
| React.ElementRef<ImageViewNativeComponent>,
>,
...props: ImagePropsType
);
export type ImageAndroid = AbstractImageAndroid & ImageComponentStaticsAndroid;
export type AbstractImageIOS = component(
ref?: React.RefSetter<HostInstance>,
ref?: React.RefSetter<React.ElementRef<ImageViewNativeComponent>>,
...props: ImagePropsType
);
@@ -7,7 +7,7 @@
#import <React/RCTShadowView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
__attribute__((deprecated("This API will be removed along with the legacy architecture.")))
@interface RCTImageShadowView : RCTShadowView
@@ -9,7 +9,7 @@
#import <React/RCTLog.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
@implementation RCTImageShadowView
@@ -9,7 +9,7 @@
#import <React/RCTView.h>
#import <UIKit/UIKit.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
@class RCTBridge;
@class RCTImageSource;
@@ -29,4 +29,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -17,7 +17,7 @@
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
/**
* Determines whether an image of `currentSize` should be reloaded for display
@@ -505,4 +505,4 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,11 +7,11 @@
#import <React/RCTViewManager.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
__attribute__((deprecated("This API will be removed along with the legacy architecture.")))
@interface RCTImageViewManager : RCTViewManager
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTImageViewManager.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <UIKit/UIKit.h>
@@ -117,4 +117,4 @@ RCT_EXPORT_METHOD(queryCache
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
+51 -6
View File
@@ -12,6 +12,7 @@
import type {GestureResponderEvent} from '../Types/CoreEventTypes';
const InteractionManager = require('./InteractionManager').default;
const TouchHistoryMath = require('./TouchHistoryMath').default;
const currentCentroidXOfTouchesChangedAfter =
@@ -30,6 +31,9 @@ const currentCentroidY = TouchHistoryMath.currentCentroidY;
* single-touch gestures resilient to extra touches, and can be used to
* recognize simple multi-touch gestures.
*
* By default, `PanResponder` holds an `InteractionManager` handle to block
* long-running JS events from interrupting active gestures.
*
* It provides a predictable wrapper of the responder handlers provided by the
* [gesture responder system](docs/gesture-responder-system.html).
* For each handler, it provides a new `gestureState` object alongside the
@@ -401,6 +405,9 @@ const PanResponder = {
getInteractionHandle: () => ?number,
panHandlers: GestureResponderHandlerMethods,
} {
const interactionState = {
handle: (null: ?number),
};
const gestureState: PanResponderGestureState = {
// Useful for debugging
stateID: Math.random(),
@@ -457,6 +464,10 @@ const PanResponder = {
},
onResponderGrant(event: GestureResponderEvent): boolean {
if (!interactionState.handle) {
interactionState.handle =
InteractionManager.createInteractionHandle();
}
gestureState.x0 = currentCentroidX(event.touchHistory);
gestureState.y0 = currentCentroidY(event.touchHistory);
gestureState.dx = 0;
@@ -471,11 +482,21 @@ const PanResponder = {
},
onResponderReject(event: GestureResponderEvent): void {
config.onPanResponderReject?.call(undefined, event, gestureState);
clearInteractionHandle(
interactionState,
config.onPanResponderReject,
event,
gestureState,
);
},
onResponderRelease(event: GestureResponderEvent): void {
config.onPanResponderRelease?.call(undefined, event, gestureState);
clearInteractionHandle(
interactionState,
config.onPanResponderRelease,
event,
gestureState,
);
PanResponder._initializeGestureState(gestureState);
},
@@ -508,11 +529,21 @@ const PanResponder = {
onResponderEnd(event: GestureResponderEvent): void {
const touchHistory = event.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
config.onPanResponderEnd?.call(undefined, event, gestureState);
clearInteractionHandle(
interactionState,
config.onPanResponderEnd,
event,
gestureState,
);
},
onResponderTerminate(event: GestureResponderEvent): void {
config.onPanResponderTerminate?.call(undefined, event, gestureState);
clearInteractionHandle(
interactionState,
config.onPanResponderTerminate,
event,
gestureState,
);
PanResponder._initializeGestureState(gestureState);
},
@@ -525,13 +556,27 @@ const PanResponder = {
return {
panHandlers,
getInteractionHandle(): ?number {
// TODO: Deprecate and delete this method.
return null;
return interactionState.handle;
},
};
},
};
function clearInteractionHandle(
interactionState: {handle: ?number, ...},
callback: ?(ActiveCallback | PassiveCallback),
event: GestureResponderEvent,
gestureState: PanResponderGestureState,
) {
if (interactionState.handle) {
InteractionManager.clearInteractionHandle(interactionState.handle);
interactionState.handle = null;
}
if (callback) {
callback(event, gestureState);
}
}
export type PanResponderInstance = ReturnType<(typeof PanResponder)['create']>;
export default PanResponder;
@@ -129,13 +129,11 @@ export function getWithFallback_DEPRECATED<Config: {...}>(
// `getRuntimeConfig == null` when static view configs are disabled
// If `setRuntimeConfigProvider` is not configured, use native reflection.
if (hasNativeViewConfig(name)) {
/* $FlowFixMe[incompatible-type] Extra ref prop */
return get<Config>(name, viewConfigProvider);
}
} else {
// If there is no runtime config, then the native component is unavailable.
if (getRuntimeConfig(name) != null) {
/* $FlowFixMe[incompatible-type] Extra ref prop */
return get<Config>(name, viewConfigProvider);
}
}
@@ -14,7 +14,6 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import type {HostInstance} from 'react-native';
import ReactNativeElement from '../../../../src/private/webapis/dom/nodes/ReactNativeElement';
import TextInput from '../../../Components/TextInput/TextInput';
import TextInputState from '../../../Components/TextInput/TextInputState';
import View from '../../../Components/View/View';
import ReactFabricHostComponent from '../ReactFabricHostComponent';
@@ -49,7 +48,7 @@ describe('ReactFabricPublicInstance', () => {
const nodeRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(<TextInput ref={nodeRef} />);
root.render(<View ref={nodeRef} />);
});
const node = nullthrows(nodeRef.current);
@@ -74,7 +73,7 @@ describe('ReactFabricPublicInstance', () => {
const ref = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(<TextInput ref={ref} />);
root.render(<View ref={ref} />);
});
const node = nullthrows(ref.current);
@@ -7,7 +7,7 @@
#import <React/RCTShadowView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import "RCTTextAttributes.h"
@@ -32,4 +32,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
NS_ASSUME_NONNULL_END
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTBaseTextShadowView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <React/RCTShadowView+Layout.h>
@@ -159,4 +159,4 @@ static void RCTInlineViewYogaNodeDirtied(YGNodeConstRef node)
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTViewManager.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
NS_ASSUME_NONNULL_BEGIN
@@ -18,4 +18,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
NS_ASSUME_NONNULL_END
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTBaseTextViewManager.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
@implementation RCTBaseTextViewManager
@@ -61,4 +61,4 @@ RCT_REMAP_SHADOW_PROPERTY(textTransform, textAttributes.textTransform, RCTTextTr
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -11,7 +11,7 @@
#import <React/RCTTextDecorationLineType.h>
#import <React/RCTTextTransform.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
NS_ASSUME_NONNULL_BEGIN
@@ -104,4 +104,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
NS_ASSUME_NONNULL_END
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTTextAttributes.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <React/RCTAssert.h>
#import <React/RCTFont.h>
@@ -355,4 +355,4 @@ static NSString *capitalizeText(NSString *text)
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTShadowView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
NS_ASSUME_NONNULL_BEGIN
@@ -20,4 +20,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
NS_ASSUME_NONNULL_END
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTRawTextShadowView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <React/RCTShadowView+Layout.h>
@@ -35,4 +35,4 @@
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTViewManager.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
NS_ASSUME_NONNULL_BEGIN
@@ -18,4 +18,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
NS_ASSUME_NONNULL_END
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTRawTextViewManager.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <React/RCTRawTextShadowView.h>
@@ -29,4 +29,4 @@ RCT_EXPORT_SHADOW_PROPERTY(text, NSString)
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTShadowView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import "RCTBaseTextShadowView.h"
@@ -30,4 +30,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
NS_ASSUME_NONNULL_END
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTTextShadowView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <React/RCTBridge.h>
#import <React/RCTShadowView+Layout.h>
@@ -467,4 +467,4 @@ static float RCTTextShadowViewBaseline(YGNodeConstRef node, const float width, c
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTComponent.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <UIKit/UIKit.h>
@@ -31,4 +31,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
NS_ASSUME_NONNULL_END
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTTextView.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import <MobileCoreServices/UTCoreTypes.h>
@@ -295,4 +295,4 @@
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT
@@ -7,7 +7,7 @@
#import <React/RCTViewManager.h>
#ifndef RCT_REMOVE_LEGACY_ARCH
#ifndef RCT_FIT_RM_OLD_COMPONENT
#import "RCTBaseTextViewManager.h"
@@ -16,4 +16,4 @@ __attribute__((deprecated("This API will be removed along with the legacy archit
@end
#endif // RCT_REMOVE_LEGACY_ARCH
#endif // RCT_FIT_RM_OLD_COMPONENT

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