mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
73
Commits
nc/react-sync
...
v0.70.2
+12
-12
@@ -3,14 +3,14 @@ GEM
|
||||
specs:
|
||||
CFPropertyList (3.0.5)
|
||||
rexml
|
||||
activesupport (6.1.5)
|
||||
activesupport (6.1.7)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
addressable (2.8.1)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
algoliasearch (1.27.5)
|
||||
httpclient (~> 2.8, >= 2.8.3)
|
||||
json (>= 1.5.1)
|
||||
@@ -45,7 +45,7 @@ GEM
|
||||
public_suffix (~> 4.0)
|
||||
typhoeus (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.5)
|
||||
cocoapods-downloader (1.6.1)
|
||||
cocoapods-downloader (1.6.3)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.1)
|
||||
@@ -63,29 +63,29 @@ GEM
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.10.0)
|
||||
i18n (1.12.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.6.1)
|
||||
minitest (5.15.0)
|
||||
json (2.6.2)
|
||||
minitest (5.16.3)
|
||||
molinillo (0.8.0)
|
||||
nanaimo (0.3.0)
|
||||
nap (1.1.0)
|
||||
netrc (0.11.0)
|
||||
public_suffix (4.0.6)
|
||||
public_suffix (4.0.7)
|
||||
rexml (3.2.5)
|
||||
ruby-macho (2.5.1)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (2.0.4)
|
||||
tzinfo (2.0.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
xcodeproj (1.21.0)
|
||||
xcodeproj (1.22.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (~> 3.2.4)
|
||||
zeitwerk (2.5.4)
|
||||
zeitwerk (2.6.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -97,4 +97,4 @@ RUBY VERSION
|
||||
ruby 2.7.5p203
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.10
|
||||
2.3.11
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type {EventSubscription} from '../../vendor/emitter/EventEmitter';
|
||||
import type {ElementRef} from 'react';
|
||||
|
||||
// Events that are only supported on Android.
|
||||
type AccessibilityEventDefinitionsAndroid = {
|
||||
accessibilityServiceChanged: [boolean],
|
||||
};
|
||||
|
||||
// Events that are only supported on iOS.
|
||||
type AccessibilityEventDefinitionsIOS = {
|
||||
announcementFinished: [{announcement: string, success: boolean}],
|
||||
boldTextChanged: [boolean],
|
||||
grayscaleChanged: [boolean],
|
||||
invertColorsChanged: [boolean],
|
||||
reduceTransparencyChanged: [boolean],
|
||||
};
|
||||
|
||||
type AccessibilityEventDefinitions = {
|
||||
...AccessibilityEventDefinitionsAndroid,
|
||||
...AccessibilityEventDefinitionsIOS,
|
||||
change: [boolean], // screenReaderChanged
|
||||
reduceMotionChanged: [boolean],
|
||||
screenReaderChanged: [boolean],
|
||||
};
|
||||
|
||||
type AccessibilityEventTypes = 'click' | 'focus';
|
||||
/**
|
||||
* Sometimes it's useful to know whether or not the device has a screen reader
|
||||
* that is currently active. The `AccessibilityInfo` API is designed for this
|
||||
* purpose. You can use it to query the current state of the screen reader as
|
||||
* well as to register to be notified when the state of the screen reader
|
||||
* changes.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo
|
||||
*/
|
||||
export interface AccessibilityInfo {
|
||||
/**
|
||||
* Query whether bold text is currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when bold text is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#isBoldTextEnabled
|
||||
*/
|
||||
isBoldTextEnabled: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Query whether grayscale is currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when grayscale is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#isGrayscaleEnabled
|
||||
*/
|
||||
isGrayscaleEnabled: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Query whether inverted colors are currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when invert color is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#isInvertColorsEnabled
|
||||
*/
|
||||
isInvertColorsEnabled: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Query whether reduced motion is currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when a reduce motion is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#isReduceMotionEnabled
|
||||
*/
|
||||
isReduceMotionEnabled: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Query whether reduce motion and prefer cross-fade transitions settings are currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when prefer cross-fade transitions is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#prefersCrossFadeTransitions
|
||||
*/
|
||||
prefersCrossFadeTransitions: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Query whether reduced transparency is currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when a reduce transparency is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#isReduceTransparencyEnabled
|
||||
*/
|
||||
isReduceTransparencyEnabled: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Query whether a screen reader is currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when a screen reader is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#isScreenReaderEnabled
|
||||
*/
|
||||
isScreenReaderEnabled: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Query whether Accessibility Service is currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when any service is enabled and `false` otherwise.
|
||||
*
|
||||
* @platform android
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo/#isaccessibilityserviceenabled-android
|
||||
*/
|
||||
isAccessibilityServiceEnabled: () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Add an event handler. Supported events:
|
||||
*
|
||||
* - `reduceMotionChanged`: Fires when the state of the reduce motion toggle changes.
|
||||
* The argument to the event handler is a boolean. The boolean is `true` when a reduce
|
||||
* motion is enabled (or when "Transition Animation Scale" in "Developer options" is
|
||||
* "Animation off") and `false` otherwise.
|
||||
* - `screenReaderChanged`: Fires when the state of the screen reader changes. The argument
|
||||
* to the event handler is a boolean. The boolean is `true` when a screen
|
||||
* reader is enabled and `false` otherwise.
|
||||
*
|
||||
* These events are only supported on iOS:
|
||||
*
|
||||
* - `boldTextChanged`: iOS-only event. Fires when the state of the bold text toggle changes.
|
||||
* The argument to the event handler is a boolean. The boolean is `true` when a bold text
|
||||
* is enabled and `false` otherwise.
|
||||
* - `grayscaleChanged`: iOS-only event. Fires when the state of the gray scale toggle changes.
|
||||
* The argument to the event handler is a boolean. The boolean is `true` when a gray scale
|
||||
* is enabled and `false` otherwise.
|
||||
* - `invertColorsChanged`: iOS-only event. Fires when the state of the invert colors toggle
|
||||
* changes. The argument to the event handler is a boolean. The boolean is `true` when a invert
|
||||
* colors is enabled and `false` otherwise.
|
||||
* - `reduceTransparencyChanged`: iOS-only event. Fires when the state of the reduce transparency
|
||||
* toggle changes. The argument to the event handler is a boolean. The boolean is `true`
|
||||
* when a reduce transparency is enabled and `false` otherwise.
|
||||
* - `announcementFinished`: iOS-only event. Fires when the screen reader has
|
||||
* finished making an announcement. The argument to the event handler is a
|
||||
* dictionary with these keys:
|
||||
* - `announcement`: The string announced by the screen reader.
|
||||
* - `success`: A boolean indicating whether the announcement was
|
||||
* successfully made.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#addeventlistener
|
||||
*/
|
||||
addEventListener<K: $Keys<AccessibilityEventDefinitions>>(
|
||||
eventName: K,
|
||||
handler: (...$ElementType<AccessibilityEventDefinitions, K>) => void,
|
||||
): EventSubscription;
|
||||
|
||||
/**
|
||||
* Set accessibility focus to a React component.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#setaccessibilityfocus
|
||||
*/
|
||||
setAccessibilityFocus: (reactTag: number) => void;
|
||||
|
||||
/**
|
||||
* Send a named accessibility event to a HostComponent.
|
||||
*/
|
||||
sendAccessibilityEvent: (
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
eventType: AccessibilityEventTypes,
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Post a string to be announced by the screen reader.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#announceforaccessibility
|
||||
*/
|
||||
announceForAccessibility: (announcement: string) => void;
|
||||
|
||||
/**
|
||||
* Post a string to be announced by the screen reader.
|
||||
* - `announcement`: The string announced by the screen reader.
|
||||
* - `options`: An object that configures the reading options.
|
||||
* - `queue`: The announcement will be queued behind existing announcements. iOS only.
|
||||
*/
|
||||
announceForAccessibilityWithOptions: (
|
||||
announcement: string,
|
||||
options: {queue?: boolean},
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Get the recommended timeout for changes to the UI needed by this user.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#getrecommendedtimeoutmillis
|
||||
*/
|
||||
getRecommendedTimeoutMillis: (originalTimeout: number) => Promise<number>;
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import NativeAccessibilityInfoAndroid from './NativeAccessibilityInfo';
|
||||
import NativeAccessibilityManagerIOS from './NativeAccessibilityManager';
|
||||
import legacySendAccessibilityEvent from './legacySendAccessibilityEvent';
|
||||
import type {ElementRef} from 'react';
|
||||
import type {AccessibilityInfo as AccessibilityInfoType} from './AccessibilityInfo.flow';
|
||||
|
||||
// Events that are only supported on Android.
|
||||
type AccessibilityEventDefinitionsAndroid = {
|
||||
@@ -73,7 +74,7 @@ const EventNames: Map<
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo
|
||||
*/
|
||||
const AccessibilityInfo = {
|
||||
const AccessibilityInfo: AccessibilityInfoType = {
|
||||
/**
|
||||
* Query whether bold text is currently enabled.
|
||||
*
|
||||
@@ -178,6 +179,34 @@ const AccessibilityInfo = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Query whether reduce motion and prefer cross-fade transitions settings are currently enabled.
|
||||
*
|
||||
* Returns a promise which resolves to a boolean.
|
||||
* The result is `true` when prefer cross-fade transitions is enabled and `false` otherwise.
|
||||
*
|
||||
* See https://reactnative.dev/docs/accessibilityinfo#prefersCrossFadeTransitions
|
||||
*/
|
||||
prefersCrossFadeTransitions(): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (Platform.OS === 'android') {
|
||||
return Promise.resolve(false);
|
||||
} else {
|
||||
if (
|
||||
NativeAccessibilityManagerIOS?.getCurrentPrefersCrossFadeTransitionsState !=
|
||||
null
|
||||
) {
|
||||
NativeAccessibilityManagerIOS.getCurrentPrefersCrossFadeTransitionsState(
|
||||
resolve,
|
||||
reject,
|
||||
);
|
||||
} else {
|
||||
reject(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Query whether reduced transparency is currently enabled.
|
||||
*
|
||||
@@ -295,6 +324,7 @@ const AccessibilityInfo = {
|
||||
*/
|
||||
addEventListener<K: $Keys<AccessibilityEventDefinitions>>(
|
||||
eventName: K,
|
||||
// $FlowIssue[incompatible-type] - Flow bug with unions and generics (T128099423)
|
||||
handler: (...$ElementType<AccessibilityEventDefinitions, K>) => void,
|
||||
): EventSubscription {
|
||||
const deviceEventName = EventNames.get(eventName);
|
||||
@@ -315,7 +345,7 @@ const AccessibilityInfo = {
|
||||
/**
|
||||
* Send a named accessibility event to a HostComponent.
|
||||
*/
|
||||
sendAccessibilityEvent_unstable(
|
||||
sendAccessibilityEvent(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
eventType: AccessibilityEventTypes,
|
||||
) {
|
||||
|
||||
@@ -28,6 +28,10 @@ export interface Spec extends TurboModule {
|
||||
onSuccess: (isReduceMotionEnabled: boolean) => void,
|
||||
onError: (error: Object) => void,
|
||||
) => void;
|
||||
+getCurrentPrefersCrossFadeTransitionsState?: (
|
||||
onSuccess: (prefersCrossFadeTransitions: boolean) => void,
|
||||
onError: (error: Object) => void,
|
||||
) => void;
|
||||
+getCurrentReduceTransparencyState: (
|
||||
onSuccess: (isReduceTransparencyEnabled: boolean) => void,
|
||||
onError: (error: Object) => void,
|
||||
|
||||
@@ -24,7 +24,7 @@ export type KeyboardEventEasing =
|
||||
| 'linear'
|
||||
| 'keyboard';
|
||||
|
||||
export type KeyboardEventCoordinates = $ReadOnly<{|
|
||||
export type KeyboardMetrics = $ReadOnly<{|
|
||||
screenX: number,
|
||||
screenY: number,
|
||||
width: number,
|
||||
@@ -36,7 +36,7 @@ export type KeyboardEvent = AndroidKeyboardEvent | IOSKeyboardEvent;
|
||||
type BaseKeyboardEvent = {|
|
||||
duration: number,
|
||||
easing: KeyboardEventEasing,
|
||||
endCoordinates: KeyboardEventCoordinates,
|
||||
endCoordinates: KeyboardMetrics,
|
||||
|};
|
||||
|
||||
export type AndroidKeyboardEvent = $ReadOnly<{|
|
||||
@@ -47,7 +47,7 @@ export type AndroidKeyboardEvent = $ReadOnly<{|
|
||||
|
||||
export type IOSKeyboardEvent = $ReadOnly<{|
|
||||
...BaseKeyboardEvent,
|
||||
startCoordinates: KeyboardEventCoordinates,
|
||||
startCoordinates: KeyboardMetrics,
|
||||
isEventFromThisApp: boolean,
|
||||
|}>;
|
||||
|
||||
@@ -103,6 +103,8 @@ type KeyboardEventDefinitions = {
|
||||
*/
|
||||
|
||||
class Keyboard {
|
||||
_currentlyShowing: ?KeyboardEvent;
|
||||
|
||||
_emitter: NativeEventEmitter<KeyboardEventDefinitions> =
|
||||
new NativeEventEmitter(
|
||||
// T88715063: NativeEventEmitter only used this parameter on iOS. Now it uses it on all platforms, so this code was modified automatically to preserve its behavior
|
||||
@@ -110,6 +112,15 @@ class Keyboard {
|
||||
Platform.OS !== 'ios' ? null : NativeKeyboardObserver,
|
||||
);
|
||||
|
||||
constructor() {
|
||||
this.addListener('keyboardDidShow', ev => {
|
||||
this._currentlyShowing = ev;
|
||||
});
|
||||
this.addListener('keyboardDidHide', _ev => {
|
||||
this._currentlyShowing = null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The `addListener` function connects a JavaScript function to an identified native
|
||||
* keyboard notification event.
|
||||
@@ -157,6 +168,20 @@ class Keyboard {
|
||||
dismissKeyboard();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the keyboard is last known to be visible.
|
||||
*/
|
||||
isVisible(): boolean {
|
||||
return !!this._currentlyShowing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the metrics of the soft-keyboard if visible.
|
||||
*/
|
||||
metrics(): ?KeyboardMetrics {
|
||||
return this._currentlyShowing?.endCoordinates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for syncing TextInput (or other keyboard accessory view) size of
|
||||
* position changes with keyboard movements.
|
||||
|
||||
@@ -22,7 +22,8 @@ import type {
|
||||
ViewLayout,
|
||||
ViewLayoutEvent,
|
||||
} from '../View/ViewPropTypes';
|
||||
import type {KeyboardEvent, KeyboardEventCoordinates} from './Keyboard';
|
||||
import type {KeyboardEvent, KeyboardMetrics} from './Keyboard';
|
||||
import AccessibilityInfo from '../AccessibilityInfo/AccessibilityInfo';
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
...ViewProps,
|
||||
@@ -71,12 +72,24 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
||||
this.viewRef = React.createRef();
|
||||
}
|
||||
|
||||
_relativeKeyboardHeight(keyboardFrame: KeyboardEventCoordinates): number {
|
||||
async _relativeKeyboardHeight(
|
||||
keyboardFrame: KeyboardMetrics,
|
||||
): Promise<number> {
|
||||
const frame = this._frame;
|
||||
if (!frame || !keyboardFrame) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// On iOS when Prefer Cross-Fade Transitions is enabled, the keyboard position
|
||||
// & height is reported differently (0 instead of Y position value matching height of frame)
|
||||
if (
|
||||
Platform.OS === 'ios' &&
|
||||
keyboardFrame.screenY === 0 &&
|
||||
(await AccessibilityInfo.prefersCrossFadeTransitions())
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const keyboardY =
|
||||
keyboardFrame.screenY - (this.props.keyboardVerticalOffset ?? 0);
|
||||
|
||||
@@ -90,7 +103,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
||||
this._updateBottomIfNecessary();
|
||||
};
|
||||
|
||||
_onLayout = (event: ViewLayoutEvent) => {
|
||||
_onLayout = async (event: ViewLayoutEvent) => {
|
||||
const wasFrameNull = this._frame == null;
|
||||
this._frame = event.nativeEvent.layout;
|
||||
if (!this._initialFrameHeight) {
|
||||
@@ -99,7 +112,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
if (wasFrameNull) {
|
||||
this._updateBottomIfNecessary();
|
||||
await this._updateBottomIfNecessary();
|
||||
}
|
||||
|
||||
if (this.props.onLayout) {
|
||||
@@ -107,14 +120,14 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
_updateBottomIfNecessary = () => {
|
||||
_updateBottomIfNecessary = async () => {
|
||||
if (this._keyboardEvent == null) {
|
||||
this.setState({bottom: 0});
|
||||
return;
|
||||
}
|
||||
|
||||
const {duration, easing, endCoordinates} = this._keyboardEvent;
|
||||
const height = this._relativeKeyboardHeight(endCoordinates);
|
||||
const height = await this._relativeKeyboardHeight(endCoordinates);
|
||||
|
||||
if (this.state.bottom === height) {
|
||||
return;
|
||||
|
||||
@@ -42,7 +42,7 @@ import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type {ViewProps} from '../View/ViewPropTypes';
|
||||
import ScrollViewContext, {HORIZONTAL, VERTICAL} from './ScrollViewContext';
|
||||
import type {Props as ScrollViewStickyHeaderProps} from './ScrollViewStickyHeader';
|
||||
import type {KeyboardEvent} from '../Keyboard/Keyboard';
|
||||
import type {KeyboardEvent, KeyboardMetrics} from '../Keyboard/Keyboard';
|
||||
import type {EventSubscription} from '../../vendor/emitter/EventEmitter';
|
||||
|
||||
import Commands from './ScrollViewCommands';
|
||||
@@ -731,7 +731,7 @@ class ScrollView extends React.Component<Props, State> {
|
||||
new Map();
|
||||
_headerLayoutYs: Map<string, number> = new Map();
|
||||
|
||||
_keyboardWillOpenTo: ?KeyboardEvent = null;
|
||||
_keyboardMetrics: ?KeyboardMetrics = null;
|
||||
_additionalScrollOffset: number = 0;
|
||||
_isTouching: boolean = false;
|
||||
_lastMomentumScrollBeginTime: number = 0;
|
||||
@@ -769,7 +769,7 @@ class ScrollView extends React.Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
this._keyboardWillOpenTo = null;
|
||||
this._keyboardMetrics = Keyboard.metrics();
|
||||
this._additionalScrollOffset = 0;
|
||||
|
||||
this._subscriptionKeyboardWillShow = Keyboard.addListener(
|
||||
@@ -1075,8 +1075,8 @@ class ScrollView extends React.Component<Props, State> {
|
||||
let keyboardScreenY = Dimensions.get('window').height;
|
||||
|
||||
const scrollTextInputIntoVisibleRect = () => {
|
||||
if (this._keyboardWillOpenTo != null) {
|
||||
keyboardScreenY = this._keyboardWillOpenTo.endCoordinates.screenY;
|
||||
if (this._keyboardMetrics != null) {
|
||||
keyboardScreenY = this._keyboardMetrics.screenY;
|
||||
}
|
||||
let scrollOffsetY =
|
||||
top - keyboardScreenY + height + this._additionalScrollOffset;
|
||||
@@ -1094,8 +1094,8 @@ class ScrollView extends React.Component<Props, State> {
|
||||
this._preventNegativeScrollOffset = false;
|
||||
};
|
||||
|
||||
if (this._keyboardWillOpenTo == null) {
|
||||
// `_keyboardWillOpenTo` is set inside `scrollResponderKeyboardWillShow` which
|
||||
if (this._keyboardMetrics == null) {
|
||||
// `_keyboardMetrics` is set inside `scrollResponderKeyboardWillShow` which
|
||||
// is not guaranteed to be called before `_inputMeasureAndScrollToKeyboard` but native has already scheduled it.
|
||||
// In case it was not called before `_inputMeasureAndScrollToKeyboard`, we postpone scrolling to
|
||||
// text input.
|
||||
@@ -1243,32 +1243,28 @@ class ScrollView extends React.Component<Props, State> {
|
||||
scrollResponderKeyboardWillShow: (e: KeyboardEvent) => void = (
|
||||
e: KeyboardEvent,
|
||||
) => {
|
||||
this._keyboardWillOpenTo = e;
|
||||
this._keyboardMetrics = e.endCoordinates;
|
||||
this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e);
|
||||
};
|
||||
|
||||
scrollResponderKeyboardWillHide: (e: KeyboardEvent) => void = (
|
||||
e: KeyboardEvent,
|
||||
) => {
|
||||
this._keyboardWillOpenTo = null;
|
||||
this._keyboardMetrics = null;
|
||||
this.props.onKeyboardWillHide && this.props.onKeyboardWillHide(e);
|
||||
};
|
||||
|
||||
scrollResponderKeyboardDidShow: (e: KeyboardEvent) => void = (
|
||||
e: KeyboardEvent,
|
||||
) => {
|
||||
// TODO(7693961): The event for DidShow is not available on iOS yet.
|
||||
// Use the one from WillShow and do not assign.
|
||||
if (e) {
|
||||
this._keyboardWillOpenTo = e;
|
||||
}
|
||||
this._keyboardMetrics = e.endCoordinates;
|
||||
this.props.onKeyboardDidShow && this.props.onKeyboardDidShow(e);
|
||||
};
|
||||
|
||||
scrollResponderKeyboardDidHide: (e: KeyboardEvent) => void = (
|
||||
e: KeyboardEvent,
|
||||
) => {
|
||||
this._keyboardWillOpenTo = null;
|
||||
this._keyboardMetrics = null;
|
||||
this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e);
|
||||
};
|
||||
|
||||
@@ -1547,7 +1543,7 @@ class ScrollView extends React.Component<Props, State> {
|
||||
// keyboard, except on Android where setting windowSoftInputMode to
|
||||
// adjustNone leads to missing keyboard events.
|
||||
const softKeyboardMayBeOpen =
|
||||
this._keyboardWillOpenTo != null || Platform.OS === 'android';
|
||||
this._keyboardMetrics != null || Platform.OS === 'android';
|
||||
|
||||
return hasFocusedTextInput && softKeyboardMayBeOpen;
|
||||
};
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* @generated by scripts/set-rn-version.js
|
||||
*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @generated by scripts/set-rn-version.js
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
exports.version = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
minor: 70,
|
||||
patch: 2,
|
||||
prerelease: null,
|
||||
};
|
||||
|
||||
@@ -39,7 +39,10 @@ if (__DEV__) {
|
||||
// Get hostname from development server (packager)
|
||||
const devServer = getDevServer();
|
||||
const host = devServer.bundleLoadedFromServer
|
||||
? devServer.url.replace(/https?:\/\//, '').split(':')[0]
|
||||
? devServer.url
|
||||
.replace(/https?:\/\//, '')
|
||||
.replace(/\/$/, '')
|
||||
.split(':')[0]
|
||||
: 'localhost';
|
||||
|
||||
// Read the optional global variable for backward compatibility.
|
||||
|
||||
@@ -146,7 +146,7 @@ module.exports = {
|
||||
errorMessageForMethod('setLayoutAnimationEnabledExperimental'),
|
||||
);
|
||||
},
|
||||
// Please use AccessibilityInfo.sendAccessibilityEvent_unstable instead.
|
||||
// Please use AccessibilityInfo.sendAccessibilityEvent instead.
|
||||
// See SetAccessibilityFocusExample in AccessibilityExample.js for a migration example.
|
||||
sendAccessibilityEvent: (reactTag: ?number, eventType: number): void =>
|
||||
console.error(errorMessageForMethod('sendAccessibilityEvent')),
|
||||
|
||||
@@ -347,7 +347,12 @@ module.exports = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (__DEV__ && typeof value.process === 'function') {
|
||||
if (
|
||||
__DEV__ &&
|
||||
typeof value.process === 'function' &&
|
||||
typeof ReactNativeStyleAttributes[property]?.process === 'function' &&
|
||||
value.process !== ReactNativeStyleAttributes[property]?.process
|
||||
) {
|
||||
console.warn(`Overwriting ${property} style attribute preprocessor`);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {setStyleAttributePreprocessor} from '../StyleSheet';
|
||||
|
||||
describe(setStyleAttributePreprocessor, () => {
|
||||
const originalConsoleWarn = console.warn;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
console.warn = jest.fn();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
console.warn = originalConsoleWarn;
|
||||
});
|
||||
|
||||
it('should not show warning when set preprocessor first time', () => {
|
||||
const spyConsole = jest.spyOn(global.console, 'warn');
|
||||
setStyleAttributePreprocessor(
|
||||
'fontFamily',
|
||||
(fontFamily: string) => fontFamily,
|
||||
);
|
||||
expect(spyConsole).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should show warning when overwrite the preprocessor', () => {
|
||||
const spyConsole = jest.spyOn(global.console, 'warn');
|
||||
setStyleAttributePreprocessor(
|
||||
'fontFamily',
|
||||
(fontFamily: string) => fontFamily,
|
||||
);
|
||||
setStyleAttributePreprocessor(
|
||||
'fontFamily',
|
||||
(fontFamily: string) => `Scoped-${fontFamily}`,
|
||||
);
|
||||
expect(spyConsole).toHaveBeenCalledWith(
|
||||
'Overwriting fontFamily style attribute preprocessor',
|
||||
);
|
||||
});
|
||||
});
|
||||
+7
-1
@@ -47,7 +47,13 @@ Pod::Spec.new do |s|
|
||||
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
|
||||
s.header_dir = "React"
|
||||
s.framework = "JavaScriptCore"
|
||||
s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/RCT-Folly\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\" \"${PODS_ROOT}/Headers/Public/FlipperKit\" \"$(PODS_ROOT)/Headers/Public/ReactCommon\" \"$(PODS_ROOT)/Headers/Public/React-RCTFabric\"", "DEFINES_MODULE" => "YES", "GCC_PREPROCESSOR_DEFINITIONS" => "RCT_METRO_PORT=${RCT_METRO_PORT}", "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" }
|
||||
s.pod_target_xcconfig = {
|
||||
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/RCT-Folly\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\" \"${PODS_ROOT}/Headers/Public/FlipperKit\" \"$(PODS_ROOT)/Headers/Public/ReactCommon\" \"$(PODS_ROOT)/Headers/Public/React-RCTFabric\"",
|
||||
"FRAMEWORK_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"",
|
||||
"DEFINES_MODULE" => "YES",
|
||||
"GCC_PREPROCESSOR_DEFINITIONS" => "RCT_METRO_PORT=${RCT_METRO_PORT}",
|
||||
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
|
||||
}
|
||||
s.user_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/React-Core\""}
|
||||
s.default_subspec = "Default"
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
|
||||
#ifndef RCT_USE_HERMES
|
||||
@@ -28,13 +30,6 @@
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
#endif
|
||||
|
||||
RCT_EXTERN_C_BEGIN
|
||||
|
||||
void RCTAppSetupPrepareApp(UIApplication *application);
|
||||
UIView *RCTAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary *initialProperties);
|
||||
|
||||
RCT_EXTERN_C_END
|
||||
|
||||
#if RCT_NEW_ARCH_ENABLED
|
||||
RCT_EXTERN id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass);
|
||||
|
||||
@@ -42,3 +37,12 @@ std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutor
|
||||
RCTBridge *bridge,
|
||||
RCTTurboModuleManager *turboModuleManager);
|
||||
#endif
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
RCT_EXTERN_C_BEGIN
|
||||
|
||||
void RCTAppSetupPrepareApp(UIApplication *application);
|
||||
UIView *RCTAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary *initialProperties);
|
||||
|
||||
RCT_EXTERN_C_END
|
||||
|
||||
@@ -21,11 +21,11 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^(void){
|
||||
__rnVersion = @{
|
||||
RCTVersionMajor: @(0),
|
||||
RCTVersionMinor: @(0),
|
||||
RCTVersionPatch: @(0),
|
||||
RCTVersionPrerelease: [NSNull null],
|
||||
};
|
||||
RCTVersionMajor: @(0),
|
||||
RCTVersionMinor: @(70),
|
||||
RCTVersionPatch: @(2),
|
||||
RCTVersionPrerelease: [NSNull null],
|
||||
};
|
||||
});
|
||||
return __rnVersion;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ extern NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification; /
|
||||
@property (nonatomic, assign) BOOL isGrayscaleEnabled;
|
||||
@property (nonatomic, assign) BOOL isInvertColorsEnabled;
|
||||
@property (nonatomic, assign) BOOL isReduceMotionEnabled;
|
||||
@property (nonatomic, assign) BOOL prefersCrossFadeTransitions;
|
||||
@property (nonatomic, assign) BOOL isReduceTransparencyEnabled;
|
||||
@property (nonatomic, assign) BOOL isVoiceOverEnabled;
|
||||
|
||||
|
||||
@@ -358,6 +358,17 @@ RCT_EXPORT_METHOD(getCurrentReduceMotionState
|
||||
onSuccess(@[ @(_isReduceMotionEnabled) ]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getCurrentPrefersCrossFadeTransitionsState
|
||||
: (RCTResponseSenderBlock)onSuccess onError
|
||||
: (__unused RCTResponseSenderBlock)onError)
|
||||
{
|
||||
if (@available(iOS 14.0, *)) {
|
||||
onSuccess(@[ @(UIAccessibilityPrefersCrossFadeTransitions()) ]);
|
||||
} else {
|
||||
onSuccess(@[ @(false) ]);
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getCurrentReduceTransparencyState
|
||||
: (RCTResponseSenderBlock)onSuccess onError
|
||||
: (__unused RCTResponseSenderBlock)onError)
|
||||
|
||||
@@ -5,10 +5,15 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.hasProperty("kotlinVersion") ? rootProject.ext.kotlinVersion : KOTLIN_VERSION}"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("com.facebook.react")
|
||||
id("org.jetbrains.kotlin.android") version "1.6.10"
|
||||
id("maven-publish")
|
||||
id("de.undercouch.download")
|
||||
}
|
||||
@@ -483,3 +488,5 @@ afterEvaluate {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "org.jetbrains.kotlin.android"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-main
|
||||
VERSION_NAME=0.70.2
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
@@ -22,7 +22,7 @@ OKHTTP_VERSION=4.9.2
|
||||
POWERMOCK_VERSION=2.0.2
|
||||
PROGUARD_ANNOTATIONS_VERSION=1.19.0
|
||||
ROBOLECTRIC_VERSION=4.4
|
||||
SO_LOADER_VERSION=0.10.3
|
||||
SO_LOADER_VERSION=0.10.4
|
||||
SWIPEREFRESH_LAYOUT_VERSION=1.0.0
|
||||
|
||||
# Native Dependency Versions
|
||||
@@ -33,5 +33,8 @@ FOLLY_VERSION=2021.07.22.00
|
||||
GLOG_VERSION=0.3.5
|
||||
LIBEVENT_VERSION=2.1.12
|
||||
|
||||
# Plugins Versions
|
||||
KOTLIN_VERSION=1.6.10
|
||||
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
@@ -33,8 +33,11 @@ public class HermesExecutor extends JavaScriptExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
HermesExecutor(@Nullable RuntimeConfig config) {
|
||||
super(config == null ? initHybridDefaultConfig() : initHybrid(config.heapSizeMB));
|
||||
HermesExecutor(@Nullable RuntimeConfig config, boolean enableDebugger, String debuggerName) {
|
||||
super(
|
||||
config == null
|
||||
? initHybridDefaultConfig(enableDebugger, debuggerName)
|
||||
: initHybrid(enableDebugger, debuggerName, config.heapSizeMB));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +54,9 @@ public class HermesExecutor extends JavaScriptExecutor {
|
||||
*/
|
||||
public static native boolean canLoadFile(String path);
|
||||
|
||||
private static native HybridData initHybridDefaultConfig();
|
||||
private static native HybridData initHybridDefaultConfig(
|
||||
boolean enableDebugger, String debuggerName);
|
||||
|
||||
private static native HybridData initHybrid(long heapSizeMB);
|
||||
private static native HybridData initHybrid(
|
||||
boolean enableDebugger, String debuggerName, long heapSizeMB);
|
||||
}
|
||||
|
||||
+11
-1
@@ -15,6 +15,8 @@ public class HermesExecutorFactory implements JavaScriptExecutorFactory {
|
||||
private static final String TAG = "Hermes";
|
||||
|
||||
private final RuntimeConfig mConfig;
|
||||
private boolean mEnableDebugger = true;
|
||||
private String mDebuggerName = "";
|
||||
|
||||
public HermesExecutorFactory() {
|
||||
this(null);
|
||||
@@ -24,9 +26,17 @@ public class HermesExecutorFactory implements JavaScriptExecutorFactory {
|
||||
mConfig = config;
|
||||
}
|
||||
|
||||
public void setEnableDebugger(boolean enableDebugger) {
|
||||
mEnableDebugger = enableDebugger;
|
||||
}
|
||||
|
||||
public void setDebuggerName(String debuggerName) {
|
||||
mDebuggerName = debuggerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptExecutor create() {
|
||||
return new HermesExecutor(mConfig);
|
||||
return new HermesExecutor(mConfig, mEnableDebugger, mDebuggerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -69,26 +69,39 @@ class HermesExecutorHolder
|
||||
"Lcom/facebook/hermes/reactexecutor/HermesExecutor;";
|
||||
|
||||
static jni::local_ref<jhybriddata> initHybridDefaultConfig(
|
||||
jni::alias_ref<jclass>) {
|
||||
jni::alias_ref<jclass>,
|
||||
bool enableDebugger,
|
||||
std::string debuggerName) {
|
||||
JReactMarker::setLogPerfMarkerIfNeeded();
|
||||
|
||||
std::call_once(flag, []() {
|
||||
facebook::hermes::HermesRuntime::setFatalHandler(hermesFatalHandler);
|
||||
});
|
||||
return makeCxxInstance(
|
||||
std::make_unique<HermesExecutorFactory>(installBindings));
|
||||
auto factory = std::make_unique<HermesExecutorFactory>(installBindings);
|
||||
factory->setEnableDebugger(enableDebugger);
|
||||
if (!debuggerName.empty()) {
|
||||
factory->setDebuggerName(debuggerName);
|
||||
}
|
||||
return makeCxxInstance(std::move(factory));
|
||||
}
|
||||
|
||||
static jni::local_ref<jhybriddata> initHybrid(
|
||||
jni::alias_ref<jclass>,
|
||||
bool enableDebugger,
|
||||
std::string debuggerName,
|
||||
jlong heapSizeMB) {
|
||||
JReactMarker::setLogPerfMarkerIfNeeded();
|
||||
auto runtimeConfig = makeRuntimeConfig(heapSizeMB);
|
||||
std::call_once(flag, []() {
|
||||
facebook::hermes::HermesRuntime::setFatalHandler(hermesFatalHandler);
|
||||
});
|
||||
return makeCxxInstance(std::make_unique<HermesExecutorFactory>(
|
||||
installBindings, JSIExecutor::defaultTimeoutInvoker, runtimeConfig));
|
||||
auto factory = std::make_unique<HermesExecutorFactory>(
|
||||
installBindings, JSIExecutor::defaultTimeoutInvoker, runtimeConfig);
|
||||
factory->setEnableDebugger(enableDebugger);
|
||||
if (!debuggerName.empty()) {
|
||||
factory->setDebuggerName(debuggerName);
|
||||
}
|
||||
return makeCxxInstance(std::move(factory));
|
||||
}
|
||||
|
||||
static bool canLoadFile(jni::alias_ref<jclass>, const std::string &path) {
|
||||
|
||||
+2
-2
@@ -69,9 +69,9 @@ public class DevLoadingViewController {
|
||||
return;
|
||||
}
|
||||
|
||||
int port = parsedURL.getPort() != -1 ? parsedURL.getPort() : parsedURL.getDefaultPort();
|
||||
showMessage(
|
||||
context.getString(
|
||||
R.string.catalyst_loading_from_url, parsedURL.getHost() + ":" + parsedURL.getPort()));
|
||||
context.getString(R.string.catalyst_loading_from_url, parsedURL.getHost() + ":" + port));
|
||||
}
|
||||
|
||||
public void showForRemoteJSEnabled() {
|
||||
|
||||
@@ -703,7 +703,7 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
URL sourceUrl = new URL(getSourceUrl());
|
||||
String path = sourceUrl.getPath().substring(1); // strip initial slash in path
|
||||
String host = sourceUrl.getHost();
|
||||
int port = sourceUrl.getPort();
|
||||
int port = sourceUrl.getPort() != -1 ? sourceUrl.getPort() : sourceUrl.getDefaultPort();
|
||||
mCurrentContext
|
||||
.getJSModule(HMRClient.class)
|
||||
.setup("android", path, host, port, mDevSettings.isHotModuleReplacementEnabled());
|
||||
|
||||
@@ -44,7 +44,7 @@ target_link_libraries(
|
||||
react_render_uimanager
|
||||
react_utils
|
||||
react_config
|
||||
reactnativeutilsjni
|
||||
reactnativejni
|
||||
rrc_image
|
||||
rrc_modal
|
||||
rrc_progressbar
|
||||
|
||||
+3
-1
@@ -152,7 +152,9 @@ public class ForwardingCookieHandler extends CookieHandler {
|
||||
|| (message != null
|
||||
&& (message.contains("WebView provider")
|
||||
|| message.contains("No WebView installed")
|
||||
|| message.contains("Cannot load WebView")))) {
|
||||
|| message.contains("Cannot load WebView")
|
||||
|| message.contains("disableWebView")
|
||||
|| message.contains("WebView is disabled")))) {
|
||||
return null;
|
||||
} else {
|
||||
throw exception;
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ import java.util.Map;
|
||||
public class ReactNativeVersion {
|
||||
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
|
||||
"major", 0,
|
||||
"minor", 0,
|
||||
"patch", 0,
|
||||
"minor", 70,
|
||||
"patch", 2,
|
||||
"prerelease", null);
|
||||
}
|
||||
|
||||
@@ -287,7 +287,9 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
view.setSelected(false);
|
||||
}
|
||||
view.setTag(R.id.accessibility_state, accessibilityState);
|
||||
view.setEnabled(true);
|
||||
if (accessibilityState.hasKey("disabled") && !accessibilityState.getBoolean("disabled")) {
|
||||
view.setEnabled(true);
|
||||
}
|
||||
|
||||
// For states which don't have corresponding methods in
|
||||
// AccessibilityNodeInfo, update the view's content description
|
||||
|
||||
@@ -278,14 +278,16 @@ public class ViewProps {
|
||||
}
|
||||
return true;
|
||||
case BORDER_LEFT_COLOR:
|
||||
return !map.isNull(BORDER_LEFT_COLOR) && map.getInt(BORDER_LEFT_COLOR) == Color.TRANSPARENT;
|
||||
return map.getType(BORDER_LEFT_COLOR) == ReadableType.Number
|
||||
&& map.getInt(BORDER_LEFT_COLOR) == Color.TRANSPARENT;
|
||||
case BORDER_RIGHT_COLOR:
|
||||
return !map.isNull(BORDER_RIGHT_COLOR)
|
||||
return map.getType(BORDER_RIGHT_COLOR) == ReadableType.Number
|
||||
&& map.getInt(BORDER_RIGHT_COLOR) == Color.TRANSPARENT;
|
||||
case BORDER_TOP_COLOR:
|
||||
return !map.isNull(BORDER_TOP_COLOR) && map.getInt(BORDER_TOP_COLOR) == Color.TRANSPARENT;
|
||||
return map.getType(BORDER_TOP_COLOR) == ReadableType.Number
|
||||
&& map.getInt(BORDER_TOP_COLOR) == Color.TRANSPARENT;
|
||||
case BORDER_BOTTOM_COLOR:
|
||||
return !map.isNull(BORDER_BOTTOM_COLOR)
|
||||
return map.getType(BORDER_BOTTOM_COLOR) == ReadableType.Number
|
||||
&& map.getInt(BORDER_BOTTOM_COLOR) == Color.TRANSPARENT;
|
||||
case BORDER_WIDTH:
|
||||
return map.isNull(BORDER_WIDTH) || map.getDouble(BORDER_WIDTH) == 0d;
|
||||
|
||||
@@ -147,7 +147,7 @@ static int YGJNILogFunc(
|
||||
if (*jloggerPtr) {
|
||||
JNIEnv* env = getCurrentEnv();
|
||||
|
||||
jclass cl = env->FindClass("Lcom/facebook/yoga/YogaLogLevel;");
|
||||
jclass cl = env->FindClass("com/facebook/yoga/YogaLogLevel");
|
||||
static const jmethodID smethodId =
|
||||
facebook::yoga::vanillajni::getStaticMethodId(
|
||||
env, cl, "fromInt", "(I)Lcom/facebook/yoga/YogaLogLevel;");
|
||||
@@ -386,7 +386,7 @@ static void jni_YGNodeCalculateLayoutJNI(
|
||||
}
|
||||
} catch (const std::logic_error& ex) {
|
||||
env->ExceptionClear();
|
||||
jclass cl = env->FindClass("Ljava/lang/IllegalStateException;");
|
||||
jclass cl = env->FindClass("java/lang/IllegalStateException");
|
||||
static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId(
|
||||
env, cl, "<init>", "(Ljava/lang/String;)V");
|
||||
auto throwable = env->NewObject(cl, methodId, env->NewStringUTF(ex.what()));
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace yoga {
|
||||
namespace vanillajni {
|
||||
|
||||
YogaJniException::YogaJniException() {
|
||||
jclass cl = getCurrentEnv()->FindClass("Ljava/lang/RuntimeException;");
|
||||
jclass cl = getCurrentEnv()->FindClass("java/lang/RuntimeException");
|
||||
static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId(
|
||||
getCurrentEnv(), cl, "<init>", "()V");
|
||||
auto throwable = getCurrentEnv()->NewObject(cl, methodId);
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
# TODO Those two libraries are building against the same sources
|
||||
# and should probably be merged
|
||||
file(GLOB reactnativejni_SRC CONFIGURE_DEPENDS *.cpp)
|
||||
|
||||
add_compile_options(
|
||||
@@ -17,32 +15,6 @@ add_compile_options(
|
||||
-std=c++17
|
||||
-DWITH_INSPECTOR=1)
|
||||
|
||||
##########################
|
||||
### React Native Utils ###
|
||||
##########################
|
||||
|
||||
add_library(
|
||||
reactnativeutilsjni
|
||||
SHARED
|
||||
${reactnativejni_SRC}
|
||||
)
|
||||
|
||||
# TODO This should not be ../../
|
||||
target_include_directories(reactnativeutilsjni PUBLIC ../../)
|
||||
|
||||
target_link_libraries(reactnativeutilsjni
|
||||
android
|
||||
callinvokerholder
|
||||
fb
|
||||
fbjni
|
||||
folly_runtime
|
||||
glog_init
|
||||
react_render_runtimescheduler
|
||||
reactnative
|
||||
runtimeexecutor
|
||||
yoga
|
||||
)
|
||||
|
||||
######################
|
||||
### reactnativejni ###
|
||||
######################
|
||||
@@ -67,7 +39,6 @@ target_link_libraries(reactnativejni
|
||||
logger
|
||||
react_render_runtimescheduler
|
||||
reactnative
|
||||
reactnativeutilsjni
|
||||
runtimeexecutor
|
||||
yoga
|
||||
)
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace facebook::react {
|
||||
|
||||
constexpr struct {
|
||||
int32_t Major = 0;
|
||||
int32_t Minor = 0;
|
||||
int32_t Patch = 0;
|
||||
int32_t Minor = 70;
|
||||
int32_t Patch = 2;
|
||||
std::string_view Prerelease = "";
|
||||
} ReactNativeVersion;
|
||||
|
||||
|
||||
@@ -155,15 +155,20 @@ class DecoratedRuntime : public jsi::WithRuntimeDecorator<ReentrancyCheck> {
|
||||
DecoratedRuntime(
|
||||
std::unique_ptr<Runtime> runtime,
|
||||
HermesRuntime &hermesRuntime,
|
||||
std::shared_ptr<MessageQueueThread> jsQueue)
|
||||
std::shared_ptr<MessageQueueThread> jsQueue,
|
||||
bool enableDebugger,
|
||||
const std::string &debuggerName)
|
||||
: jsi::WithRuntimeDecorator<ReentrancyCheck>(*runtime, reentrancyCheck_),
|
||||
runtime_(std::move(runtime)),
|
||||
hermesRuntime_(hermesRuntime) {
|
||||
#ifdef HERMES_ENABLE_DEBUGGER
|
||||
auto adapter = std::make_unique<HermesExecutorRuntimeAdapter>(
|
||||
runtime_, hermesRuntime_, jsQueue);
|
||||
facebook::hermes::inspector::chrome::enableDebugging(
|
||||
std::move(adapter), "Hermes React Native");
|
||||
enableDebugger_ = enableDebugger;
|
||||
if (enableDebugger_) {
|
||||
auto adapter = std::make_unique<HermesExecutorRuntimeAdapter>(
|
||||
runtime_, hermesRuntime_, jsQueue);
|
||||
facebook::hermes::inspector::chrome::enableDebugging(
|
||||
std::move(adapter), debuggerName);
|
||||
}
|
||||
#else
|
||||
(void)hermesRuntime_;
|
||||
#endif
|
||||
@@ -171,7 +176,9 @@ class DecoratedRuntime : public jsi::WithRuntimeDecorator<ReentrancyCheck> {
|
||||
|
||||
~DecoratedRuntime() {
|
||||
#ifdef HERMES_ENABLE_DEBUGGER
|
||||
facebook::hermes::inspector::chrome::disableDebugging(*runtime_);
|
||||
if (enableDebugger_) {
|
||||
facebook::hermes::inspector::chrome::disableDebugging(*runtime_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -186,10 +193,21 @@ class DecoratedRuntime : public jsi::WithRuntimeDecorator<ReentrancyCheck> {
|
||||
std::shared_ptr<Runtime> runtime_;
|
||||
ReentrancyCheck reentrancyCheck_;
|
||||
HermesRuntime &hermesRuntime_;
|
||||
#ifdef HERMES_ENABLE_DEBUGGER
|
||||
bool enableDebugger_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void HermesExecutorFactory::setEnableDebugger(bool enableDebugger) {
|
||||
enableDebugger_ = enableDebugger;
|
||||
}
|
||||
|
||||
void HermesExecutorFactory::setDebuggerName(const std::string &debuggerName) {
|
||||
debuggerName_ = debuggerName;
|
||||
}
|
||||
|
||||
std::unique_ptr<JSExecutor> HermesExecutorFactory::createJSExecutor(
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
std::shared_ptr<MessageQueueThread> jsQueue) {
|
||||
@@ -197,7 +215,11 @@ std::unique_ptr<JSExecutor> HermesExecutorFactory::createJSExecutor(
|
||||
makeHermesRuntimeSystraced(runtimeConfig_);
|
||||
HermesRuntime &hermesRuntimeRef = *hermesRuntime;
|
||||
auto decoratedRuntime = std::make_shared<DecoratedRuntime>(
|
||||
std::move(hermesRuntime), hermesRuntimeRef, jsQueue);
|
||||
std::move(hermesRuntime),
|
||||
hermesRuntimeRef,
|
||||
jsQueue,
|
||||
enableDebugger_,
|
||||
debuggerName_);
|
||||
|
||||
// So what do we have now?
|
||||
// DecoratedRuntime -> HermesRuntime
|
||||
@@ -221,6 +243,12 @@ std::unique_ptr<JSExecutor> HermesExecutorFactory::createJSExecutor(
|
||||
decoratedRuntime, delegate, jsQueue, timeoutInvoker_, runtimeInstaller_);
|
||||
}
|
||||
|
||||
::hermes::vm::RuntimeConfig HermesExecutorFactory::defaultRuntimeConfig() {
|
||||
return ::hermes::vm::RuntimeConfig::Builder()
|
||||
.withEnableSampleProfiling(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
HermesExecutor::HermesExecutor(
|
||||
std::shared_ptr<jsi::Runtime> runtime,
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
|
||||
@@ -21,21 +21,29 @@ class HermesExecutorFactory : public JSExecutorFactory {
|
||||
JSIExecutor::RuntimeInstaller runtimeInstaller,
|
||||
const JSIScopedTimeoutInvoker &timeoutInvoker =
|
||||
JSIExecutor::defaultTimeoutInvoker,
|
||||
::hermes::vm::RuntimeConfig runtimeConfig = ::hermes::vm::RuntimeConfig())
|
||||
::hermes::vm::RuntimeConfig runtimeConfig = defaultRuntimeConfig())
|
||||
: runtimeInstaller_(runtimeInstaller),
|
||||
timeoutInvoker_(timeoutInvoker),
|
||||
runtimeConfig_(std::move(runtimeConfig)) {
|
||||
assert(timeoutInvoker_ && "Should not have empty timeoutInvoker");
|
||||
}
|
||||
|
||||
void setEnableDebugger(bool enableDebugger);
|
||||
|
||||
void setDebuggerName(const std::string &debuggerName);
|
||||
|
||||
std::unique_ptr<JSExecutor> createJSExecutor(
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
std::shared_ptr<MessageQueueThread> jsQueue) override;
|
||||
|
||||
private:
|
||||
static ::hermes::vm::RuntimeConfig defaultRuntimeConfig();
|
||||
|
||||
JSIExecutor::RuntimeInstaller runtimeInstaller_;
|
||||
JSIScopedTimeoutInvoker timeoutInvoker_;
|
||||
::hermes::vm::RuntimeConfig runtimeConfig_;
|
||||
bool enableDebugger_ = true;
|
||||
std::string debuggerName_ = "Hermes React Native";
|
||||
};
|
||||
|
||||
class HermesExecutor : public JSIExecutor {
|
||||
|
||||
@@ -139,7 +139,7 @@ class Connection::Impl : public inspector::InspectorObserver,
|
||||
|
||||
template <typename C>
|
||||
void runInExecutor(int id, C callback) {
|
||||
folly::via(executor_.get(), [cb = std::move(callback)]() { cb(); });
|
||||
executor_->add([cb = std::move(callback)]() { cb(); });
|
||||
}
|
||||
|
||||
std::shared_ptr<RuntimeAdapter> runtimeAdapter_;
|
||||
@@ -1411,20 +1411,14 @@ Connection::Impl::makePropsFromValue(
|
||||
}
|
||||
|
||||
void Connection::Impl::handle(const m::runtime::GetHeapUsageRequest &req) {
|
||||
auto resp = std::make_shared<m::runtime::GetHeapUsageResponse>();
|
||||
resp->id = req.id;
|
||||
|
||||
inspector_
|
||||
->executeIfEnabled(
|
||||
"Runtime.getHeapUsage",
|
||||
[this, req, resp](const debugger::ProgramState &state) {
|
||||
auto heapInfo = getRuntime().instrumentation().getHeapInfo(false);
|
||||
resp->usedSize = heapInfo["hermes_allocatedBytes"];
|
||||
resp->totalSize = heapInfo["hermes_heapSize"];
|
||||
})
|
||||
.via(executor_.get())
|
||||
.thenValue([this, resp](auto &&) { sendResponseToClient(*resp); })
|
||||
.thenError<std::exception>(sendErrorToClient(req.id));
|
||||
runInExecutor(req.id, [this, req]() {
|
||||
auto heapInfo = getRuntime().instrumentation().getHeapInfo(false);
|
||||
auto resp = std::make_shared<m::runtime::GetHeapUsageResponse>();
|
||||
resp->id = req.id;
|
||||
resp->usedSize = heapInfo["hermes_allocatedBytes"];
|
||||
resp->totalSize = heapInfo["hermes_heapSize"];
|
||||
sendResponseToClient(*resp);
|
||||
});
|
||||
}
|
||||
|
||||
void Connection::Impl::handle(const m::runtime::GetPropertiesRequest &req) {
|
||||
|
||||
@@ -244,8 +244,7 @@ void JSIExecutor::callFunction(
|
||||
// by value.
|
||||
auto errorProducer = [=] {
|
||||
std::stringstream ss;
|
||||
ss << "moduleID: " << moduleId << " methodID: " << methodId
|
||||
<< " arguments: " << folly::toJson(arguments);
|
||||
ss << "moduleID: " << moduleId << " methodID: " << methodId;
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ target_link_libraries(rrc_progressbar
|
||||
react_render_debug
|
||||
react_render_graphics
|
||||
react_render_uimanager
|
||||
reactnativeutilsjni
|
||||
reactnativejni
|
||||
rrc_view
|
||||
yoga
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ target_link_libraries(rrc_slider
|
||||
react_render_imagemanager
|
||||
react_render_mapbuffer
|
||||
react_render_uimanager
|
||||
reactnativeutilsjni
|
||||
reactnativejni
|
||||
rrc_image
|
||||
rrc_view
|
||||
yoga
|
||||
|
||||
@@ -28,7 +28,7 @@ target_link_libraries(
|
||||
react_render_debug
|
||||
react_render_graphics
|
||||
react_render_uimanager
|
||||
reactnativeutilsjni
|
||||
reactnativejni
|
||||
rrc_view
|
||||
yoga
|
||||
)
|
||||
|
||||
@@ -40,6 +40,6 @@ target_link_libraries(react_render_textlayoutmanager
|
||||
react_render_telemetry
|
||||
react_render_uimanager
|
||||
react_utils
|
||||
reactnativeutilsjni
|
||||
reactnativejni
|
||||
yoga
|
||||
)
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+2
-1
@@ -128,11 +128,12 @@ jest
|
||||
isGrayscaleEnabled: jest.fn(),
|
||||
isInvertColorsEnabled: jest.fn(),
|
||||
isReduceMotionEnabled: jest.fn(),
|
||||
prefersCrossFadeTransitions: jest.fn(),
|
||||
isReduceTransparencyEnabled: jest.fn(),
|
||||
isScreenReaderEnabled: jest.fn(() => Promise.resolve(false)),
|
||||
removeEventListener: jest.fn(),
|
||||
setAccessibilityFocus: jest.fn(),
|
||||
sendAccessibilityEvent_unstable: jest.fn(),
|
||||
sendAccessibilityEvent: jest.fn(),
|
||||
getRecommendedTimeoutMillis: jest.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
+49
-16
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"private": true,
|
||||
"version": "1000.0.0",
|
||||
"version": "0.70.2",
|
||||
"bin": "./cli.js",
|
||||
"description": "A framework for building native apps using React",
|
||||
"license": "MIT",
|
||||
@@ -94,18 +93,14 @@
|
||||
"test-android-e2e": "yarn run docker-build-android && yarn run test-android-run-e2e",
|
||||
"test-ios": "./scripts/objc-test.sh test"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/!(eslint-config-react-native-community)",
|
||||
"repo-config"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"react": "18.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jest/create-cache-key-function": "^27.0.1",
|
||||
"@react-native-community/cli": "^9.0.0-alpha.3",
|
||||
"@react-native-community/cli-platform-android": "^9.0.0-alpha.3",
|
||||
"@react-native-community/cli-platform-ios": "^9.0.0-alpha.3",
|
||||
"@react-native-community/cli": "9.1.3",
|
||||
"@react-native-community/cli-platform-android": "9.1.0",
|
||||
"@react-native-community/cli-platform-ios": "9.1.2",
|
||||
"@react-native/assets": "1.0.0",
|
||||
"@react-native/normalize-color": "2.0.0",
|
||||
"@react-native/polyfills": "2.0.0",
|
||||
@@ -116,15 +111,15 @@
|
||||
"invariant": "^2.2.4",
|
||||
"jsc-android": "^250230.2.1",
|
||||
"memoize-one": "^5.0.0",
|
||||
"metro-react-native-babel-transformer": "0.71.3",
|
||||
"metro-runtime": "0.71.3",
|
||||
"metro-source-map": "0.71.3",
|
||||
"metro-react-native-babel-transformer": "0.72.3",
|
||||
"metro-runtime": "0.72.3",
|
||||
"metro-source-map": "0.72.3",
|
||||
"mkdirp": "^0.5.1",
|
||||
"nullthrows": "^1.1.1",
|
||||
"pretty-format": "^26.5.2",
|
||||
"promise": "^8.0.3",
|
||||
"react-devtools-core": "4.24.0",
|
||||
"react-native-gradle-plugin": "^0.70.0",
|
||||
"react-native-gradle-plugin": "^0.70.3",
|
||||
"react-refresh": "^0.4.0",
|
||||
"react-shallow-renderer": "^16.15.0",
|
||||
"regenerator-runtime": "^0.13.2",
|
||||
@@ -132,13 +127,51 @@
|
||||
"stacktrace-parser": "^0.1.3",
|
||||
"use-sync-external-store": "^1.0.0",
|
||||
"whatwg-fetch": "^3.0.0",
|
||||
"ws": "^6.1.4"
|
||||
"ws": "^6.1.4",
|
||||
"react-native-codegen": "^0.70.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"flow-bin": "^0.182.0",
|
||||
"hermes-eslint": "0.8.0",
|
||||
"react": "18.1.0",
|
||||
"react-test-renderer": "^18.1.0"
|
||||
"react-test-renderer": "18.1.0",
|
||||
"@babel/core": "^7.14.0",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@babel/generator": "^7.14.0",
|
||||
"@babel/plugin-transform-regenerator": "^7.0.0",
|
||||
"@react-native-community/eslint-plugin": "*",
|
||||
"@react-native/eslint-plugin-specs": "^0.70.0",
|
||||
"@reactions/component": "^2.0.2",
|
||||
"async": "^3.2.2",
|
||||
"clang-format": "^1.2.4",
|
||||
"connect": "^3.6.5",
|
||||
"coveralls": "^3.1.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-fb-strict": "^26.0.0",
|
||||
"eslint-config-fbjs": "^3.1.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-babel": "^5.3.1",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-flowtype": "^7.0.0",
|
||||
"eslint-plugin-jest": "^25.2.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.26.1",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"eslint-plugin-react-native": "^3.11.0",
|
||||
"eslint-plugin-relay": "^1.8.2",
|
||||
"inquirer": "^7.1.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-junit": "^10.0.0",
|
||||
"jscodeshift": "^0.13.1",
|
||||
"metro-babel-register": "0.72.3",
|
||||
"metro-memory-fs": "0.72.3",
|
||||
"mkdirp": "^0.5.1",
|
||||
"prettier": "^2.4.1",
|
||||
"shelljs": "^0.8.5",
|
||||
"signedsource": "^1.0.0",
|
||||
"ws": "^6.1.4",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"codegenConfig": {
|
||||
"libraries": [
|
||||
@@ -158,4 +191,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@react-native/eslint-plugin-specs",
|
||||
"version": "0.0.4",
|
||||
"version": "0.70.0",
|
||||
"description": "ESLint rules to validate NativeModule and Component Specs",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -9,7 +9,7 @@
|
||||
"directory": "packages/eslint-plugin-specs"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "node prepublish.js"
|
||||
"prepack": "node prepack.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.14.0",
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
const path = require('path');
|
||||
const withBabelRegister = require('./with-babel-register');
|
||||
|
||||
// We run yarn prepublish before publishing package which will set this value to true
|
||||
// We use the prepack hook before publishing package to set this value to true
|
||||
const PACKAGE_USAGE = false;
|
||||
const ERRORS = {
|
||||
misnamedHasteModule(hasteModuleName) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-codegen",
|
||||
"version": "0.70.3",
|
||||
"version": "0.70.5",
|
||||
"description": "⚛️ Code generation tools for React Native",
|
||||
"homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-codegen",
|
||||
"repository": {
|
||||
|
||||
@@ -27,7 +27,9 @@ function filterJSFile(file: string) {
|
||||
// NativeSampleTurboModule is for demo purpose. It should be added manually to the
|
||||
// app for now.
|
||||
!file.endsWith('NativeSampleTurboModule.js') &&
|
||||
!file.includes('__tests')
|
||||
!file.includes('__tests') &&
|
||||
// Ignore TypeScript type declaration files.
|
||||
!file.endsWith('.d.ts')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {compareSnaps, compareTsArraySnaps} = require('../compareSnaps.js');
|
||||
|
||||
const flowFixtures = require('../../flow/components/__test_fixtures__/fixtures.js');
|
||||
const flowSnaps = require('../../../../src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap');
|
||||
const tsFixtures = require('../../typescript/components/__test_fixtures__/fixtures.js');
|
||||
const tsSnaps = require('../../../../src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap');
|
||||
const tsExtraCases = ['ARRAY2_PROP_TYPES_NO_EVENTS'];
|
||||
|
||||
compareSnaps(flowFixtures, flowSnaps, [], tsFixtures, tsSnaps, tsExtraCases);
|
||||
compareTsArraySnaps(tsSnaps, tsExtraCases);
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {compareSnaps, compareTsArraySnaps} = require('../compareSnaps.js');
|
||||
|
||||
const flowFixtures = require('../../flow/modules/__test_fixtures__/fixtures.js');
|
||||
const flowSnaps = require('../../../../src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap');
|
||||
const tsFixtures = require('../../typescript/modules/__test_fixtures__/fixtures.js');
|
||||
const tsSnaps = require('../../../../src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap');
|
||||
const tsExtraCases = [
|
||||
'NATIVE_MODULE_WITH_ARRAY2_WITH_ALIAS',
|
||||
'NATIVE_MODULE_WITH_ARRAY2_WITH_UNION_AND_TOUPLE',
|
||||
'NATIVE_MODULE_WITH_BASIC_ARRAY2',
|
||||
'NATIVE_MODULE_WITH_COMPLEX_ARRAY2',
|
||||
];
|
||||
|
||||
compareSnaps(flowFixtures, flowSnaps, [], tsFixtures, tsSnaps, tsExtraCases);
|
||||
compareTsArraySnaps(tsSnaps, tsExtraCases);
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails oncall+react_native
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function compareSnaps(
|
||||
flowFixtures,
|
||||
flowSnaps,
|
||||
flowExtraCases,
|
||||
tsFixtures,
|
||||
tsSnaps,
|
||||
tsExtraCases,
|
||||
) {
|
||||
const flowCases = Object.keys(flowFixtures).sort();
|
||||
const tsCases = Object.keys(tsFixtures).sort();
|
||||
const commonCases = flowCases.filter(name => tsCases.indexOf(name) !== -1);
|
||||
|
||||
describe('RN Codegen Parsers', () => {
|
||||
it('should not unintentionally contains test case for Flow but not for TypeScript', () => {
|
||||
expect(
|
||||
flowCases.filter(name => commonCases.indexOf(name) === -1),
|
||||
).toEqual(flowExtraCases);
|
||||
});
|
||||
|
||||
it('should not unintentionally contains test case for TypeScript but not for Flow', () => {
|
||||
expect(tsCases.filter(name => commonCases.indexOf(name) === -1)).toEqual(
|
||||
tsExtraCases,
|
||||
);
|
||||
});
|
||||
|
||||
for (const commonCase of commonCases) {
|
||||
it(`should generate the same snap from Flow and TypeScript for fixture ${commonCase}`, () => {
|
||||
expect(
|
||||
flowSnaps[
|
||||
`RN Codegen Flow Parser can generate fixture ${commonCase}`
|
||||
],
|
||||
).toEqual(
|
||||
tsSnaps[
|
||||
`RN Codegen TypeScript Parser can generate fixture ${commonCase}`
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function compareTsArraySnaps(tsSnaps, tsExtraCases) {
|
||||
for (const array2Case of tsExtraCases.filter(
|
||||
name => name.indexOf('ARRAY2') !== -1,
|
||||
)) {
|
||||
const arrayCase = array2Case.replace('ARRAY2', 'ARRAY');
|
||||
it(`should generate the same snap from fixture ${arrayCase} and ${array2Case}`, () => {
|
||||
expect(
|
||||
tsSnaps[
|
||||
`RN Codegen TypeScript Parser can generate fixture ${arrayCase}`
|
||||
],
|
||||
).toEqual(
|
||||
tsSnaps[
|
||||
`RN Codegen TypeScript Parser can generate fixture ${array2Case}`
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
compareSnaps,
|
||||
compareTsArraySnaps,
|
||||
};
|
||||
Vendored
+2
-2
@@ -141,7 +141,7 @@ import type {ViewProps} from 'ViewPropTypes';
|
||||
import type {HostComponent} from 'react-native';
|
||||
|
||||
interface NativeCommands {
|
||||
readonly hotspotUpdate: (viewRef: React.Ref<'RCTView'> | null | void, x: Int32, y: Int32) => void;
|
||||
readonly hotspotUpdate: (viewRef: React.Ref<'RCTView'> | null | undefined, x: Int32, y: Int32) => void;
|
||||
}
|
||||
|
||||
export interface ModuleProps extends ViewProps {
|
||||
@@ -249,7 +249,7 @@ import type {ViewProps} from 'ViewPropTypes';
|
||||
import type {HostComponent} from 'react-native';
|
||||
|
||||
export interface ModuleProps extends ViewProps {
|
||||
nullable_with_default: WithDefault<Float, 1.0> | null | void;
|
||||
nullable_with_default: WithDefault<Float, 1.0> | null | undefined;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>(
|
||||
|
||||
Vendored
+218
-85
@@ -15,33 +15,33 @@
|
||||
const EVENT_DEFINITION = `
|
||||
boolean_required: boolean;
|
||||
boolean_optional_key?: boolean;
|
||||
boolean_optional_value: boolean | null | void;
|
||||
boolean_optional_both?: boolean | null | void;
|
||||
boolean_optional_value: boolean | null | undefined;
|
||||
boolean_optional_both?: boolean | null | undefined;
|
||||
|
||||
string_required: string;
|
||||
string_optional_key?: string;
|
||||
string_optional_value: string | null | void;
|
||||
string_optional_both?: string | null | void;
|
||||
string_optional_value: string | null | undefined;
|
||||
string_optional_both?: string | null | undefined;
|
||||
|
||||
double_required: Double;
|
||||
double_optional_key?: Double;
|
||||
double_optional_value: Double | null | void;
|
||||
double_optional_both?: Double | null | void;
|
||||
double_optional_value: Double | null | undefined;
|
||||
double_optional_both?: Double | null | undefined;
|
||||
|
||||
float_required: Float;
|
||||
float_optional_key?: Float;
|
||||
float_optional_value: Float | null | void;
|
||||
float_optional_both?: Float | null | void;
|
||||
float_optional_value: Float | null | undefined;
|
||||
float_optional_both?: Float | null | undefined;
|
||||
|
||||
int32_required: Int32;
|
||||
int32_optional_key?: Int32;
|
||||
int32_optional_value: Int32 | null | void;
|
||||
int32_optional_both?: Int32 | null | void;
|
||||
int32_optional_value: Int32 | null | undefined;
|
||||
int32_optional_both?: Int32 | null | undefined;
|
||||
|
||||
enum_required: 'small' | 'large';
|
||||
enum_optional_key?: 'small' | 'large';
|
||||
enum_optional_value: ('small' | 'large') | null | void;
|
||||
enum_optional_both?: ('small' | 'large') | null | void;
|
||||
enum_optional_value: ('small' | 'large') | null | undefined;
|
||||
enum_optional_both?: ('small' | 'large') | null | undefined;
|
||||
|
||||
object_required: {
|
||||
boolean_required: boolean;
|
||||
@@ -52,21 +52,21 @@ const EVENT_DEFINITION = `
|
||||
};
|
||||
|
||||
object_optional_value: {
|
||||
float_optional_value: Float | null | void;
|
||||
} | null | void;
|
||||
float_optional_value: Float | null | undefined;
|
||||
} | null | undefined;
|
||||
|
||||
object_optional_both?: {
|
||||
int32_optional_both?: Int32 | null | void;
|
||||
} | null | void;
|
||||
int32_optional_both?: Int32 | null | undefined;
|
||||
} | null | undefined;
|
||||
|
||||
object_required_nested_2_layers: {
|
||||
object_optional_nested_1_layer?: {
|
||||
boolean_required: Int32;
|
||||
string_optional_key?: string;
|
||||
double_optional_value: Double | null | void;
|
||||
float_optional_value: Float | null | void;
|
||||
int32_optional_both?: Int32 | null | void;
|
||||
} | null | void;
|
||||
double_optional_value: Double | null | undefined;
|
||||
float_optional_value: Float | null | undefined;
|
||||
int32_optional_both?: Int32 | null | undefined;
|
||||
} | null | undefined;
|
||||
};
|
||||
|
||||
object_readonly_required: Readonly<{
|
||||
@@ -78,12 +78,12 @@ const EVENT_DEFINITION = `
|
||||
}>;
|
||||
|
||||
object_readonly_optional_value: Readonly<{
|
||||
float_optional_value: Float | null | void;
|
||||
}> | null | void;
|
||||
float_optional_value: Float | null | undefined;
|
||||
}> | null | undefined;
|
||||
|
||||
object_readonly_optional_both?: Readonly<{
|
||||
int32_optional_both?: Int32 | null | void;
|
||||
}> | null | void;
|
||||
int32_optional_both?: Int32 | null | undefined;
|
||||
}> | null | undefined;
|
||||
`;
|
||||
|
||||
const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = `
|
||||
@@ -265,43 +265,43 @@ export interface ModuleProps extends ViewProps {
|
||||
|
||||
// Object props
|
||||
object_optional_key?: Readonly<{prop: string}>;
|
||||
object_optional_both?: Readonly<{prop: string} | null | void>;
|
||||
object_optional_value: Readonly<{prop: string} | null | void>;
|
||||
object_optional_both?: Readonly<{prop: string} | null | undefined>;
|
||||
object_optional_value: Readonly<{prop: string} | null | undefined>;
|
||||
|
||||
// ImageSource props
|
||||
image_required: ImageSource;
|
||||
image_optional_value: ImageSource | null | void;
|
||||
image_optional_both?: ImageSource | null | void;
|
||||
image_optional_value: ImageSource | null | undefined;
|
||||
image_optional_both?: ImageSource | null | undefined;
|
||||
|
||||
// ColorValue props
|
||||
color_required: ColorValue;
|
||||
color_optional_key?: ColorValue;
|
||||
color_optional_value: ColorValue | null | void;
|
||||
color_optional_both?: ColorValue | null | void;
|
||||
color_optional_value: ColorValue | null | undefined;
|
||||
color_optional_both?: ColorValue | null | undefined;
|
||||
|
||||
// ColorArrayValue props
|
||||
color_array_required: ColorArrayValue;
|
||||
color_array_optional_key?: ColorArrayValue;
|
||||
color_array_optional_value: ColorArrayValue | null | void;
|
||||
color_array_optional_both?: ColorArrayValue | null | void;
|
||||
color_array_optional_value: ColorArrayValue | null | undefined;
|
||||
color_array_optional_both?: ColorArrayValue | null | undefined;
|
||||
|
||||
// ProcessedColorValue props
|
||||
processed_color_required: ProcessedColorValue;
|
||||
processed_color_optional_key?: ProcessedColorValue;
|
||||
processed_color_optional_value: ProcessedColorValue | null | void;
|
||||
processed_color_optional_both?: ProcessedColorValue | null | void;
|
||||
processed_color_optional_value: ProcessedColorValue | null | undefined;
|
||||
processed_color_optional_both?: ProcessedColorValue | null | undefined;
|
||||
|
||||
// PointValue props
|
||||
point_required: PointValue;
|
||||
point_optional_key?: PointValue;
|
||||
point_optional_value: PointValue | null | void;
|
||||
point_optional_both?: PointValue | null | void;
|
||||
point_optional_value: PointValue | null | undefined;
|
||||
point_optional_both?: PointValue | null | undefined;
|
||||
|
||||
// EdgeInsets props
|
||||
insets_required: EdgeInsetsValue;
|
||||
insets_optional_key?: EdgeInsetsValue;
|
||||
insets_optional_value: EdgeInsetsValue | null | void;
|
||||
insets_optional_both?: EdgeInsetsValue | null | void;
|
||||
insets_optional_value: EdgeInsetsValue | null | undefined;
|
||||
insets_optional_both?: EdgeInsetsValue | null | undefined;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>(
|
||||
@@ -342,32 +342,32 @@ export interface ModuleProps extends ViewProps {
|
||||
// Boolean props
|
||||
array_boolean_required: ReadonlyArray<boolean>;
|
||||
array_boolean_optional_key?: ReadonlyArray<boolean>;
|
||||
array_boolean_optional_value: ReadonlyArray<boolean> | null | void;
|
||||
array_boolean_optional_both?: ReadonlyArray<boolean> | null | void;
|
||||
array_boolean_optional_value: ReadonlyArray<boolean> | null | undefined;
|
||||
array_boolean_optional_both?: ReadonlyArray<boolean> | null | undefined;
|
||||
|
||||
// String props
|
||||
array_string_required: ReadonlyArray<string>;
|
||||
array_string_optional_key?: ReadonlyArray<string>;
|
||||
array_string_optional_value: ReadonlyArray<string> | null | void;
|
||||
array_string_optional_both?: ReadonlyArray<string> | null | void;
|
||||
array_string_optional_value: ReadonlyArray<string> | null | undefined;
|
||||
array_string_optional_both?: ReadonlyArray<string> | null | undefined;
|
||||
|
||||
// Double props
|
||||
array_double_required: ReadonlyArray<Double>;
|
||||
array_double_optional_key?: ReadonlyArray<Double>;
|
||||
array_double_optional_value: ReadonlyArray<Double> | null | void;
|
||||
array_double_optional_both?: ReadonlyArray<Double> | null | void;
|
||||
array_double_optional_value: ReadonlyArray<Double> | null | undefined;
|
||||
array_double_optional_both?: ReadonlyArray<Double> | null | undefined;
|
||||
|
||||
// Float props
|
||||
array_float_required: ReadonlyArray<Float>;
|
||||
array_float_optional_key?: ReadonlyArray<Float>;
|
||||
array_float_optional_value: ReadonlyArray<Float> | null | void;
|
||||
array_float_optional_both?: ReadonlyArray<Float> | null | void;
|
||||
array_float_optional_value: ReadonlyArray<Float> | null | undefined;
|
||||
array_float_optional_both?: ReadonlyArray<Float> | null | undefined;
|
||||
|
||||
// Int32 props
|
||||
array_int32_required: ReadonlyArray<Int32>;
|
||||
array_int32_optional_key?: ReadonlyArray<Int32>;
|
||||
array_int32_optional_value: ReadonlyArray<Int32> | null | void;
|
||||
array_int32_optional_both?: ReadonlyArray<Int32> | null | void;
|
||||
array_int32_optional_value: ReadonlyArray<Int32> | null | undefined;
|
||||
array_int32_optional_both?: ReadonlyArray<Int32> | null | undefined;
|
||||
|
||||
// String enum props
|
||||
array_enum_optional_key?: WithDefault<
|
||||
@@ -382,32 +382,32 @@ export interface ModuleProps extends ViewProps {
|
||||
// ImageSource props
|
||||
array_image_required: ReadonlyArray<ImageSource>;
|
||||
array_image_optional_key?: ReadonlyArray<ImageSource>;
|
||||
array_image_optional_value: ReadonlyArray<ImageSource> | null | void;
|
||||
array_image_optional_both?: ReadonlyArray<ImageSource> | null | void;
|
||||
array_image_optional_value: ReadonlyArray<ImageSource> | null | undefined;
|
||||
array_image_optional_both?: ReadonlyArray<ImageSource> | null | undefined;
|
||||
|
||||
// ColorValue props
|
||||
array_color_required: ReadonlyArray<ColorValue>;
|
||||
array_color_optional_key?: ReadonlyArray<ColorValue>;
|
||||
array_color_optional_value: ReadonlyArray<ColorValue> | null | void;
|
||||
array_color_optional_both?: ReadonlyArray<ColorValue> | null | void;
|
||||
array_color_optional_value: ReadonlyArray<ColorValue> | null | undefined;
|
||||
array_color_optional_both?: ReadonlyArray<ColorValue> | null | undefined;
|
||||
|
||||
// PointValue props
|
||||
array_point_required: ReadonlyArray<PointValue>;
|
||||
array_point_optional_key?: ReadonlyArray<PointValue>;
|
||||
array_point_optional_value: ReadonlyArray<PointValue> | null | void;
|
||||
array_point_optional_both?: ReadonlyArray<PointValue> | null | void;
|
||||
array_point_optional_value: ReadonlyArray<PointValue> | null | undefined;
|
||||
array_point_optional_both?: ReadonlyArray<PointValue> | null | undefined;
|
||||
|
||||
// EdgeInsetsValue props
|
||||
array_insets_required: ReadonlyArray<EdgeInsetsValue>;
|
||||
array_insets_optional_key?: ReadonlyArray<EdgeInsetsValue>;
|
||||
array_insets_optional_value: ReadonlyArray<EdgeInsetsValue> | null | void;
|
||||
array_insets_optional_both?: ReadonlyArray<EdgeInsetsValue> | null | void;
|
||||
array_insets_optional_value: ReadonlyArray<EdgeInsetsValue> | null | undefined;
|
||||
array_insets_optional_both?: ReadonlyArray<EdgeInsetsValue> | null | undefined;
|
||||
|
||||
// Object props
|
||||
array_object_required: ReadonlyArray<Readonly<{prop: string}>>;
|
||||
array_object_optional_key?: ReadonlyArray<Readonly<{prop: string}>>;
|
||||
array_object_optional_value: ArrayObjectType | null | void;
|
||||
array_object_optional_both?: ReadonlyArray<ObjectType> | null | void;
|
||||
array_object_optional_value: ArrayObjectType | null | undefined;
|
||||
array_object_optional_both?: ReadonlyArray<ObjectType> | null | undefined;
|
||||
|
||||
// Nested array object types
|
||||
array_of_array_object_required: ReadonlyArray<
|
||||
@@ -426,18 +426,18 @@ export interface ModuleProps extends ViewProps {
|
||||
Readonly<{
|
||||
// This needs to be the same name as the top level array above
|
||||
array_object_optional_value: ReadonlyArray<
|
||||
Readonly<{prop: string | null | void}>
|
||||
Readonly<{prop: string | null | undefined}>
|
||||
>;
|
||||
}>
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
array_of_array_object_optional_both?: ReadonlyArray<
|
||||
Readonly<{
|
||||
// This needs to be the same name as the top level array above
|
||||
array_object_optional_both: ReadonlyArray<
|
||||
Readonly<{prop?: string | null | void}>
|
||||
Readonly<{prop?: string | null | undefined}>
|
||||
>;
|
||||
}>
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
|
||||
// Nested array of array of object types
|
||||
array_of_array_of_object_required: ReadonlyArray<
|
||||
@@ -459,6 +459,138 @@ export default codegenNativeComponent<ModuleProps>(
|
||||
) as HostComponent<ModuleProps>;
|
||||
`;
|
||||
|
||||
const ARRAY2_PROP_TYPES_NO_EVENTS = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const codegenNativeComponent = require('codegenNativeComponent');
|
||||
|
||||
import type {Int32, Double, Float, WithDefault} from 'CodegenTypes';
|
||||
import type {ImageSource} from 'ImageSource';
|
||||
import type {
|
||||
ColorValue,
|
||||
ColorArrayValue,
|
||||
PointValue,
|
||||
EdgeInsetsValue,
|
||||
} from 'StyleSheetTypes';
|
||||
import type {ViewProps} from 'ViewPropTypes';
|
||||
import type {HostComponent} from 'react-native';
|
||||
|
||||
type ObjectType = Readonly<{prop: string}>;
|
||||
type ArrayObjectType = readonly Readonly<{prop: string}>[];
|
||||
|
||||
export interface ModuleProps extends ViewProps {
|
||||
// Props
|
||||
// Boolean props
|
||||
array_boolean_required: readonly boolean[];
|
||||
array_boolean_optional_key?: readonly boolean[];
|
||||
array_boolean_optional_value: readonly boolean[] | null | undefined;
|
||||
array_boolean_optional_both?: readonly boolean[] | null | undefined;
|
||||
|
||||
// String props
|
||||
array_string_required: readonly string[];
|
||||
array_string_optional_key?: readonly string[];
|
||||
array_string_optional_value: readonly string[] | null | undefined;
|
||||
array_string_optional_both?: readonly string[] | null | undefined;
|
||||
|
||||
// Double props
|
||||
array_double_required: readonly Double[];
|
||||
array_double_optional_key?: readonly Double[];
|
||||
array_double_optional_value: readonly Double[] | null | undefined;
|
||||
array_double_optional_both?: readonly Double[] | null | undefined;
|
||||
|
||||
// Float props
|
||||
array_float_required: readonly Float[];
|
||||
array_float_optional_key?: readonly Float[];
|
||||
array_float_optional_value: readonly Float[] | null | undefined;
|
||||
array_float_optional_both?: readonly Float[] | null | undefined;
|
||||
|
||||
// Int32 props
|
||||
array_int32_required: readonly Int32[];
|
||||
array_int32_optional_key?: readonly Int32[];
|
||||
array_int32_optional_value: readonly Int32[] | null | undefined;
|
||||
array_int32_optional_both?: readonly Int32[] | null | undefined;
|
||||
|
||||
// String enum props
|
||||
array_enum_optional_key?: WithDefault<
|
||||
readonly ('small' | 'large')[],
|
||||
'small'
|
||||
>;
|
||||
array_enum_optional_both?: WithDefault<
|
||||
readonly ('small' | 'large')[],
|
||||
'small'
|
||||
>;
|
||||
|
||||
// ImageSource props
|
||||
array_image_required: readonly ImageSource[];
|
||||
array_image_optional_key?: readonly ImageSource[];
|
||||
array_image_optional_value: readonly ImageSource[] | null | undefined;
|
||||
array_image_optional_both?: readonly ImageSource[] | null | undefined;
|
||||
|
||||
// ColorValue props
|
||||
array_color_required: readonly ColorValue[];
|
||||
array_color_optional_key?: readonly ColorValue[];
|
||||
array_color_optional_value: readonly ColorValue[] | null | undefined;
|
||||
array_color_optional_both?: readonly ColorValue[] | null | undefined;
|
||||
|
||||
// PointValue props
|
||||
array_point_required: readonly PointValue[];
|
||||
array_point_optional_key?: readonly PointValue[];
|
||||
array_point_optional_value: readonly PointValue[] | null | undefined;
|
||||
array_point_optional_both?: readonly PointValue[] | null | undefined;
|
||||
|
||||
// EdgeInsetsValue props
|
||||
array_insets_required: readonly EdgeInsetsValue[];
|
||||
array_insets_optional_key?: readonly EdgeInsetsValue[];
|
||||
array_insets_optional_value: readonly EdgeInsetsValue[] | null | undefined;
|
||||
array_insets_optional_both?: readonly EdgeInsetsValue[] | null | undefined;
|
||||
|
||||
// Object props
|
||||
array_object_required: readonly Readonly<{prop: string}>[];
|
||||
array_object_optional_key?: readonly Readonly<{prop: string}>[];
|
||||
array_object_optional_value: ArrayObjectType | null | undefined;
|
||||
array_object_optional_both?: readonly ObjectType[] | null | undefined;
|
||||
|
||||
// Nested array object types
|
||||
array_of_array_object_required: readonly Readonly<{
|
||||
// This needs to be the same name as the top level array above
|
||||
array_object_required: readonly Readonly<{prop: string}>[];
|
||||
}>[];
|
||||
array_of_array_object_optional_key?: readonly Readonly<{
|
||||
// This needs to be the same name as the top level array above
|
||||
array_object_optional_key: readonly Readonly<{prop?: string}>[];
|
||||
}>[];
|
||||
array_of_array_object_optional_value: readonly Readonly<{
|
||||
// This needs to be the same name as the top level array above
|
||||
array_object_optional_value: readonly Readonly<{prop: string | null | undefined}>[];
|
||||
}>[] | null | undefined;
|
||||
array_of_array_object_optional_both?: readonly Readonly<{
|
||||
// This needs to be the same name as the top level array above
|
||||
array_object_optional_both: readonly Readonly<{prop?: string | null | undefined}>[];
|
||||
}>[] | null | undefined;
|
||||
|
||||
// Nested array of array of object types
|
||||
array_of_array_of_object_required: readonly Readonly<{
|
||||
prop: string;
|
||||
}>[][];
|
||||
|
||||
// Nested array of array of object types (in file)
|
||||
array_of_array_of_object_required_in_file: readonly ObjectType[][];
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>(
|
||||
'Module',
|
||||
) as HostComponent<ModuleProps>;
|
||||
`;
|
||||
|
||||
const OBJECT_PROP_TYPES_NO_EVENTS = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@@ -514,46 +646,46 @@ export interface ModuleProps extends ViewProps {
|
||||
// ImageSource props
|
||||
image_required: Readonly<{prop: ImageSource}>;
|
||||
image_optional_key: Readonly<{prop?: ImageSource}>;
|
||||
image_optional_value: Readonly<{prop: ImageSource | null | void}>;
|
||||
image_optional_both: Readonly<{prop?: ImageSource | null | void}>;
|
||||
image_optional_value: Readonly<{prop: ImageSource | null | undefined}>;
|
||||
image_optional_both: Readonly<{prop?: ImageSource | null | undefined}>;
|
||||
|
||||
// ColorValue props
|
||||
color_required: Readonly<{prop: ColorValue}>;
|
||||
color_optional_key: Readonly<{prop?: ColorValue}>;
|
||||
color_optional_value: Readonly<{prop: ColorValue | null | void}>;
|
||||
color_optional_both: Readonly<{prop?: ColorValue | null | void}>;
|
||||
color_optional_value: Readonly<{prop: ColorValue | null | undefined}>;
|
||||
color_optional_both: Readonly<{prop?: ColorValue | null | undefined}>;
|
||||
|
||||
// ProcessedColorValue props
|
||||
processed_color_required: Readonly<{prop: ProcessedColorValue}>;
|
||||
processed_color_optional_key: Readonly<{prop?: ProcessedColorValue}>;
|
||||
processed_color_optional_value: Readonly<{
|
||||
prop: ProcessedColorValue | null | void;
|
||||
prop: ProcessedColorValue | null | undefined;
|
||||
}>;
|
||||
processed_color_optional_both: Readonly<{
|
||||
prop?: ProcessedColorValue | null | void;
|
||||
prop?: ProcessedColorValue | null | undefined;
|
||||
}>;
|
||||
|
||||
// PointValue props
|
||||
point_required: Readonly<{prop: PointValue}>;
|
||||
point_optional_key: Readonly<{prop?: PointValue}>;
|
||||
point_optional_value: Readonly<{prop: PointValue | null | void}>;
|
||||
point_optional_both: Readonly<{prop?: PointValue | null | void}>;
|
||||
point_optional_value: Readonly<{prop: PointValue | null | undefined}>;
|
||||
point_optional_both: Readonly<{prop?: PointValue | null | undefined}>;
|
||||
|
||||
// EdgeInsetsValue props
|
||||
insets_required: Readonly<{prop: EdgeInsetsValue}>;
|
||||
insets_optional_key: Readonly<{prop?: EdgeInsetsValue}>;
|
||||
insets_optional_value: Readonly<{prop: EdgeInsetsValue | null | void}>;
|
||||
insets_optional_both: Readonly<{prop?: EdgeInsetsValue | null | void}>;
|
||||
insets_optional_value: Readonly<{prop: EdgeInsetsValue | null | undefined}>;
|
||||
insets_optional_both: Readonly<{prop?: EdgeInsetsValue | null | undefined}>;
|
||||
|
||||
// Nested object props
|
||||
object_required: Readonly<{prop: Readonly<{nestedProp: string}>}>;
|
||||
object_optional_key?: Readonly<{prop: Readonly<{nestedProp: string}>}>;
|
||||
object_optional_value: Readonly<{
|
||||
prop: Readonly<{nestedProp: string}>;
|
||||
}> | null | void;
|
||||
}> | null | undefined;
|
||||
object_optional_both?: Readonly<{
|
||||
prop: Readonly<{nestedProp: string}>;
|
||||
}> | null | void;
|
||||
}> | null | undefined;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>(
|
||||
@@ -642,20 +774,20 @@ export interface ModuleProps extends ViewProps {
|
||||
Readonly<{
|
||||
${EVENT_DEFINITION}
|
||||
}>
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
|
||||
onDirectEventDefinedInlineOptionalBoth?: DirectEventHandler<
|
||||
Readonly<{
|
||||
${EVENT_DEFINITION}
|
||||
}>
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
|
||||
onDirectEventDefinedInlineWithPaperName?: DirectEventHandler<
|
||||
Readonly<{
|
||||
${EVENT_DEFINITION}
|
||||
}>,
|
||||
'paperDirectEventDefinedInlineWithPaperName'
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
|
||||
onBubblingEventDefinedInline: BubblingEventHandler<
|
||||
Readonly<{
|
||||
@@ -673,20 +805,20 @@ export interface ModuleProps extends ViewProps {
|
||||
Readonly<{
|
||||
${EVENT_DEFINITION}
|
||||
}>
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
|
||||
onBubblingEventDefinedInlineOptionalBoth?: BubblingEventHandler<
|
||||
Readonly<{
|
||||
${EVENT_DEFINITION}
|
||||
}>
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
|
||||
onBubblingEventDefinedInlineWithPaperName?: BubblingEventHandler<
|
||||
Readonly<{
|
||||
${EVENT_DEFINITION}
|
||||
}>,
|
||||
'paperBubblingEventDefinedInlineWithPaperName'
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>(
|
||||
@@ -718,21 +850,21 @@ export interface ModuleProps extends ViewProps {
|
||||
// Events defined inline
|
||||
onDirectEventDefinedInlineNull: DirectEventHandler<null>;
|
||||
onDirectEventDefinedInlineNullOptionalKey?: DirectEventHandler<null>;
|
||||
onDirectEventDefinedInlineNullOptionalValue: DirectEventHandler<null> | null | void;
|
||||
onDirectEventDefinedInlineNullOptionalValue: DirectEventHandler<null> | null | undefined;
|
||||
onDirectEventDefinedInlineNullOptionalBoth?: DirectEventHandler<null>;
|
||||
onDirectEventDefinedInlineNullWithPaperName?: DirectEventHandler<
|
||||
null,
|
||||
'paperDirectEventDefinedInlineNullWithPaperName'
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
|
||||
onBubblingEventDefinedInlineNull: BubblingEventHandler<null>;
|
||||
onBubblingEventDefinedInlineNullOptionalKey?: BubblingEventHandler<null>;
|
||||
onBubblingEventDefinedInlineNullOptionalValue: BubblingEventHandler<null> | null | void;
|
||||
onBubblingEventDefinedInlineNullOptionalBoth?: BubblingEventHandler<null> | null | void;
|
||||
onBubblingEventDefinedInlineNullOptionalValue: BubblingEventHandler<null> | null | undefined;
|
||||
onBubblingEventDefinedInlineNullOptionalBoth?: BubblingEventHandler<null> | null | undefined;
|
||||
onBubblingEventDefinedInlineNullWithPaperName?: BubblingEventHandler<
|
||||
null,
|
||||
'paperBubblingEventDefinedInlineNullWithPaperName'
|
||||
> | null | void;
|
||||
> | null | undefined;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>(
|
||||
@@ -959,6 +1091,7 @@ export default codegenNativeComponent<ModuleProps>(
|
||||
module.exports = {
|
||||
ALL_PROP_TYPES_NO_EVENTS,
|
||||
ARRAY_PROP_TYPES_NO_EVENTS,
|
||||
ARRAY2_PROP_TYPES_NO_EVENTS,
|
||||
OBJECT_PROP_TYPES_NO_EVENTS,
|
||||
PROPS_ALIASED_LOCALLY,
|
||||
ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS,
|
||||
|
||||
+684
@@ -1231,6 +1231,690 @@ exports[`RN Codegen TypeScript Parser can generate fixture ARRAY_PROP_TYPES_NO_E
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture ARRAY2_PROP_TYPES_NO_EVENTS 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'Module': {
|
||||
'type': 'Component',
|
||||
'components': {
|
||||
'Module': {
|
||||
'extendsProps': [
|
||||
{
|
||||
'type': 'ReactNativeBuiltInType',
|
||||
'knownTypeName': 'ReactNativeCoreViewProps'
|
||||
}
|
||||
],
|
||||
'events': [],
|
||||
'props': [
|
||||
{
|
||||
'name': 'array_boolean_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'BooleanTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_boolean_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'BooleanTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_boolean_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'BooleanTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_boolean_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'BooleanTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_string_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_string_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_string_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_string_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_double_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'DoubleTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_double_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'DoubleTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_double_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'DoubleTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_double_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'DoubleTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_float_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'FloatTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_float_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'FloatTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_float_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'FloatTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_float_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'FloatTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_int32_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'Int32TypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_int32_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'Int32TypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_int32_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'Int32TypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_int32_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'Int32TypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_enum_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringEnumTypeAnnotation',
|
||||
'default': 'small',
|
||||
'options': [
|
||||
'small',
|
||||
'large'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_enum_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringEnumTypeAnnotation',
|
||||
'default': 'small',
|
||||
'options': [
|
||||
'small',
|
||||
'large'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_image_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ImageSourcePrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_image_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ImageSourcePrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_image_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ImageSourcePrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_image_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ImageSourcePrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_color_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ColorPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_color_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ColorPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_color_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ColorPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_color_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'ColorPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_point_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'PointPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_point_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'PointPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_point_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'PointPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_point_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'PointPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_insets_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'EdgeInsetsPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_insets_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'EdgeInsetsPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_insets_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'EdgeInsetsPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_insets_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ReservedPropTypeAnnotation',
|
||||
'name': 'EdgeInsetsPrimitive'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_object_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_object_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_object_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_object_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_of_array_object_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'array_object_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_of_array_object_optional_key',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'array_object_optional_key',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_of_array_object_optional_value',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'array_object_optional_value',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_of_array_object_optional_both',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'array_object_optional_both',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_of_array_of_object_required',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'array_of_array_of_object_required_in_file',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'prop',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation',
|
||||
'default': null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'commands': []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_AND_EVENTS_TYPES_EXPORTED 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
||||
@@ -89,17 +89,17 @@ function getPropertyType(
|
||||
};
|
||||
|
||||
case 'TSUnionType':
|
||||
// Check for <T | null | void>
|
||||
// Check for <T | null | undefined>
|
||||
if (
|
||||
typeAnnotation.types.some(
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword',
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword',
|
||||
)
|
||||
) {
|
||||
const optionalType = typeAnnotation.types.filter(
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword',
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword',
|
||||
)[0];
|
||||
|
||||
// Check for <(T | T2) | null | void>
|
||||
// Check for <(T | T2) | null | undefined>
|
||||
if (optionalType.type === 'TSParenthesizedType') {
|
||||
return getPropertyType(name, true, optionalType.typeAnnotation);
|
||||
}
|
||||
@@ -201,15 +201,15 @@ function buildEventSchema(
|
||||
let optional = property.optional || false;
|
||||
let typeAnnotation = property.typeAnnotation.typeAnnotation;
|
||||
|
||||
// Check for T | null | void
|
||||
// Check for T | null | undefined
|
||||
if (
|
||||
typeAnnotation.type === 'TSUnionType' &&
|
||||
typeAnnotation.types.some(
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword',
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword',
|
||||
)
|
||||
) {
|
||||
typeAnnotation = typeAnnotation.types.filter(
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword',
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword',
|
||||
)[0];
|
||||
optional = true;
|
||||
}
|
||||
|
||||
@@ -41,22 +41,64 @@ function getPropProperties(
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeAnnotationForObjectAsArrayElement(
|
||||
objectType: $FlowFixMe,
|
||||
types: TypeDeclarationMap,
|
||||
) {
|
||||
return {
|
||||
type: 'ObjectTypeAnnotation',
|
||||
properties: flattenProperties(
|
||||
objectType.typeParameters.params[0].members ||
|
||||
objectType.typeParameters.params,
|
||||
types,
|
||||
)
|
||||
.map(prop => buildPropSchema(prop, types))
|
||||
.filter(Boolean),
|
||||
};
|
||||
}
|
||||
|
||||
function getTypeAnnotationForArrayOfArrayOfObject(
|
||||
typeAnnotation: $FlowFixMe,
|
||||
types: TypeDeclarationMap,
|
||||
) {
|
||||
// We need to go yet another level deeper to resolve
|
||||
// types that may be defined in a type alias
|
||||
const nestedObjectType = getValueFromTypes(typeAnnotation, types);
|
||||
|
||||
return {
|
||||
type: 'ArrayTypeAnnotation',
|
||||
elementType: getTypeAnnotationForObjectAsArrayElement(
|
||||
nestedObjectType,
|
||||
types,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function getTypeAnnotationForArray(
|
||||
name: string,
|
||||
typeAnnotation: $FlowFixMe,
|
||||
defaultValue: $FlowFixMe | null,
|
||||
types: TypeDeclarationMap,
|
||||
) {
|
||||
if (typeAnnotation.type === 'TSParenthesizedType') {
|
||||
return getTypeAnnotationForArray(
|
||||
name,
|
||||
typeAnnotation.typeAnnotation,
|
||||
defaultValue,
|
||||
types,
|
||||
);
|
||||
}
|
||||
|
||||
const extractedTypeAnnotation = getValueFromTypes(typeAnnotation, types);
|
||||
|
||||
if (
|
||||
extractedTypeAnnotation.type === 'TSUnionType' &&
|
||||
extractedTypeAnnotation.types.some(
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword',
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword',
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
'Nested optionals such as "ReadonlyArray<boolean | null | void>" are not supported, please declare optionals at the top level of value definitions as in "ReadonlyArray<boolean> | null | void"',
|
||||
'Nested optionals such as "ReadonlyArray<boolean | null | undefined>" are not supported, please declare optionals at the top level of value definitions as in "ReadonlyArray<boolean> | null | undefined"',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,44 +111,28 @@ function getTypeAnnotationForArray(
|
||||
);
|
||||
}
|
||||
|
||||
// Covers: T[]
|
||||
if (typeAnnotation.type === 'TSArrayType') {
|
||||
return getTypeAnnotationForArrayOfArrayOfObject(
|
||||
typeAnnotation.elementType,
|
||||
types,
|
||||
);
|
||||
}
|
||||
|
||||
if (extractedTypeAnnotation.type === 'TSTypeReference') {
|
||||
// Resolve the type alias if it's not defined inline
|
||||
const objectType = getValueFromTypes(extractedTypeAnnotation, types);
|
||||
|
||||
if (objectType.typeName.name === 'Readonly') {
|
||||
return {
|
||||
type: 'ObjectTypeAnnotation',
|
||||
properties: flattenProperties(
|
||||
objectType.typeParameters.params[0].members ||
|
||||
objectType.typeParameters.params,
|
||||
types,
|
||||
)
|
||||
.map(prop => buildPropSchema(prop, types))
|
||||
.filter(Boolean),
|
||||
};
|
||||
return getTypeAnnotationForObjectAsArrayElement(objectType, types);
|
||||
}
|
||||
|
||||
// Covers: ReadonlyArray<T>
|
||||
if (objectType.typeName.name === 'ReadonlyArray') {
|
||||
// We need to go yet another level deeper to resolve
|
||||
// types that may be defined in a type alias
|
||||
const nestedObjectType = getValueFromTypes(
|
||||
return getTypeAnnotationForArrayOfArrayOfObject(
|
||||
objectType.typeParameters.params[0],
|
||||
types,
|
||||
);
|
||||
|
||||
return {
|
||||
type: 'ArrayTypeAnnotation',
|
||||
elementType: {
|
||||
type: 'ObjectTypeAnnotation',
|
||||
properties: flattenProperties(
|
||||
nestedObjectType.typeParameters.params[0].members ||
|
||||
nestedObjectType.typeParameters.params,
|
||||
types,
|
||||
)
|
||||
.map(prop => buildPropSchema(prop, types))
|
||||
.filter(Boolean),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +265,7 @@ function getTypeAnnotation(
|
||||
type: 'ArrayTypeAnnotation',
|
||||
elementType: getTypeAnnotationForArray(
|
||||
name,
|
||||
typeAnnotation.typeAnnotation,
|
||||
typeAnnotation.typeAnnotation.elementType,
|
||||
defaultValue,
|
||||
types,
|
||||
),
|
||||
@@ -452,15 +478,15 @@ function buildPropSchema(
|
||||
let typeAnnotation = value;
|
||||
let optional = property.optional || false;
|
||||
|
||||
// Check for optional type in union e.g. T | null | void
|
||||
// Check for optional type in union e.g. T | null | undefined
|
||||
if (
|
||||
typeAnnotation.type === 'TSUnionType' &&
|
||||
typeAnnotation.types.some(
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword',
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword',
|
||||
)
|
||||
) {
|
||||
typeAnnotation = typeAnnotation.types.filter(
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword',
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword',
|
||||
)[0];
|
||||
optional = true;
|
||||
|
||||
@@ -483,13 +509,14 @@ function buildPropSchema(
|
||||
optional = true;
|
||||
}
|
||||
|
||||
// example: Readonly<{prop: string} | null | void>;
|
||||
// example: Readonly<{prop: string} | null | undefined>;
|
||||
if (
|
||||
value.type === 'TSTypeReference' &&
|
||||
typeAnnotation.typeParameters?.params[0].type === 'TSUnionType' &&
|
||||
typeAnnotation.typeParameters?.params[0].types.some(
|
||||
element =>
|
||||
element.type === 'TSNullKeyword' || element.type === 'TSVoidKeyword',
|
||||
element.type === 'TSNullKeyword' ||
|
||||
element.type === 'TSUndefinedKeyword',
|
||||
)
|
||||
) {
|
||||
optional = true;
|
||||
|
||||
+2
-2
@@ -148,11 +148,11 @@ import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly getSth: (a: number | null | void) => void;
|
||||
readonly getSth: (a: number | null | undefined) => void;
|
||||
}
|
||||
|
||||
export interface Spec2 extends TurboModule {
|
||||
readonly getSth: (a: number | null | void) => void;
|
||||
readonly getSth: (a: number | null | undefined) => void;
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
+2
-2
@@ -84,7 +84,7 @@ export interface Spec extends TurboModule {
|
||||
major: number;
|
||||
minor: number;
|
||||
patch?: number;
|
||||
prerelease: number | null | void;
|
||||
prerelease: number | null | undefined;
|
||||
};
|
||||
forceTouchAvailable: boolean;
|
||||
osVersion: string;
|
||||
@@ -295,7 +295,7 @@ import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly voidFunc: (arg: string | null | void) => void;
|
||||
readonly voidFunc: (arg: string | null | undefined) => void;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
@@ -75,15 +75,15 @@ function resolveTypeAnnotation(
|
||||
};
|
||||
|
||||
for (;;) {
|
||||
// Check for optional type in union e.g. T | null | void
|
||||
// Check for optional type in union e.g. T | null | undefined
|
||||
if (
|
||||
node.type === 'TSUnionType' &&
|
||||
node.types.some(
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword',
|
||||
t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword',
|
||||
)
|
||||
) {
|
||||
node = node.types.filter(
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword',
|
||||
t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword',
|
||||
)[0];
|
||||
nullable = true;
|
||||
} else if (node.type === 'TSTypeReference') {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-gradle-plugin",
|
||||
"version": "0.70.0",
|
||||
"version": "0.70.3",
|
||||
"description": "⚛️ Gradle Plugin for React Native",
|
||||
"homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-gradle-plugin",
|
||||
"repository": {
|
||||
|
||||
+11
-13
@@ -15,6 +15,7 @@ import com.facebook.react.tasks.BuildCodegenCLITask
|
||||
import com.facebook.react.tasks.GenerateCodegenArtifactsTask
|
||||
import com.facebook.react.tasks.GenerateCodegenSchemaTask
|
||||
import com.facebook.react.utils.JsonUtils
|
||||
import com.facebook.react.utils.findPackageJsonFile
|
||||
import java.io.File
|
||||
import kotlin.system.exitProcess
|
||||
import org.gradle.api.Plugin
|
||||
@@ -92,19 +93,16 @@ class ReactPlugin : Plugin<Project> {
|
||||
|
||||
// We're reading the package.json at configuration time to properly feed
|
||||
// the `jsRootDir` @Input property of this task. Therefore, the
|
||||
// parsePackageJson should be invoked here.
|
||||
val parsedPackageJson =
|
||||
extension.root.file("package.json").orNull?.asFile?.let {
|
||||
JsonUtils.fromCodegenJson(it)
|
||||
}
|
||||
// parsePackageJson should be invoked inside this lambda.
|
||||
val packageJson = findPackageJsonFile(project, extension)
|
||||
val parsedPackageJson = packageJson?.let { JsonUtils.fromCodegenJson(it) }
|
||||
|
||||
val parsedJsRootDir =
|
||||
parsedPackageJson?.codegenConfig?.jsSrcsDir?.let { relativePath ->
|
||||
extension.root.dir(relativePath)
|
||||
}
|
||||
?: extension.jsRootDir
|
||||
|
||||
it.jsRootDir.set(parsedJsRootDir)
|
||||
val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
|
||||
if (jsSrcsDirInPackageJson != null) {
|
||||
it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson))
|
||||
} else {
|
||||
it.jsRootDir.set(extension.jsRootDir)
|
||||
}
|
||||
}
|
||||
|
||||
// We create the task to generate Java code from schema.
|
||||
@@ -117,7 +115,7 @@ class ReactPlugin : Plugin<Project> {
|
||||
it.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
|
||||
it.codegenDir.set(extension.codegenDir)
|
||||
it.generatedSrcDir.set(generatedSrcDir)
|
||||
it.packageJsonFile.set(extension.root.file("package.json"))
|
||||
it.packageJsonFile.set(findPackageJsonFile(project, extension))
|
||||
it.codegenJavaPackageName.set(extension.codegenJavaPackageName)
|
||||
it.libraryName.set(extension.libraryName)
|
||||
}
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ abstract class GenerateCodegenSchemaTask : Exec() {
|
||||
val jsInputFiles =
|
||||
project.fileTree(jsRootDir) {
|
||||
it.include("**/*.js")
|
||||
it.include("**/*.ts")
|
||||
it.exclude("**/generated/source/codegen/**/*")
|
||||
}
|
||||
|
||||
|
||||
+23
-8
@@ -11,6 +11,7 @@ package com.facebook.react.utils
|
||||
|
||||
import com.facebook.react.ReactExtension
|
||||
import java.io.File
|
||||
import org.gradle.api.Project
|
||||
|
||||
/**
|
||||
* Computes the entry file for React Native. The Algo follows this order:
|
||||
@@ -145,7 +146,8 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String
|
||||
|
||||
// 3. If the react-native contains a pre-built hermesc, use it.
|
||||
val prebuiltHermesPath =
|
||||
HERMESC_IN_REACT_NATIVE_PATH.replace("%OS-BIN%", getHermesOSBin())
|
||||
HERMESC_IN_REACT_NATIVE_DIR.plus(getHermesCBin())
|
||||
.replace("%OS-BIN%", getHermesOSBin())
|
||||
// Execution on Windows fails with / as separator
|
||||
.replace('/', File.separatorChar)
|
||||
|
||||
@@ -162,7 +164,7 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String
|
||||
|
||||
/**
|
||||
* Gets the location where Hermesc should be. If nothing is specified, built hermesc is assumed to
|
||||
* be inside [HERMESC_BUILT_FROM_SOURCE_PATH]. Otherwise user can specify an override with
|
||||
* be inside [HERMESC_BUILT_FROM_SOURCE_DIR]. Otherwise user can specify an override with
|
||||
* [pathOverride], which is assumed to be an absolute path where Hermes source code is
|
||||
* provided/built.
|
||||
*
|
||||
@@ -170,11 +172,13 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String
|
||||
*/
|
||||
internal fun getBuiltHermescFile(projectRoot: File, pathOverride: String?) =
|
||||
if (!pathOverride.isNullOrBlank()) {
|
||||
File(pathOverride, "build/bin/hermesc")
|
||||
File(pathOverride, "build/bin/${getHermesCBin()}")
|
||||
} else {
|
||||
File(projectRoot, HERMESC_BUILT_FROM_SOURCE_PATH)
|
||||
File(projectRoot, HERMESC_BUILT_FROM_SOURCE_DIR.plus(getHermesCBin()))
|
||||
}
|
||||
|
||||
internal fun getHermesCBin() = if (Os.isWindows()) "hermesc.exe" else "hermesc"
|
||||
|
||||
internal fun getHermesOSBin(): String {
|
||||
if (Os.isWindows()) return "win64-bin"
|
||||
if (Os.isMac()) return "osx-bin"
|
||||
@@ -190,7 +194,18 @@ internal fun projectPathToLibraryName(projectPath: String): String =
|
||||
.joinToString("") { token -> token.replaceFirstChar { it.uppercase() } }
|
||||
.plus("Spec")
|
||||
|
||||
private const val HERMESC_IN_REACT_NATIVE_PATH =
|
||||
"node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
private const val HERMESC_BUILT_FROM_SOURCE_PATH =
|
||||
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc"
|
||||
/**
|
||||
* Function to look for the relevant `package.json`. We first look in the parent folder of this
|
||||
* Gradle module (generally the case for library projects) or we fallback to looking into the `root`
|
||||
* folder of a React Native project (generally the case for app projects).
|
||||
*/
|
||||
internal fun findPackageJsonFile(project: Project, extension: ReactExtension): File? =
|
||||
if (project.file("../package.json").exists()) {
|
||||
project.file("../package.json")
|
||||
} else {
|
||||
extension.root.file("package.json").orNull?.asFile
|
||||
}
|
||||
|
||||
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/"
|
||||
|
||||
+5
-3
@@ -29,15 +29,17 @@ class GenerateCodegenSchemaTaskTest {
|
||||
val jsRootDir =
|
||||
tempFolder.newFolder("js").apply {
|
||||
File(this, "file.js").createNewFile()
|
||||
File(this, "file.ts").createNewFile()
|
||||
File(this, "ignore.txt").createNewFile()
|
||||
}
|
||||
|
||||
val task = createTestTask<GenerateCodegenSchemaTask> { it.jsRootDir.set(jsRootDir) }
|
||||
|
||||
assertEquals(jsRootDir, task.jsInputFiles.dir)
|
||||
assertEquals(setOf("**/*.js"), task.jsInputFiles.includes)
|
||||
assertEquals(1, task.jsInputFiles.files.size)
|
||||
assertEquals(setOf(File(jsRootDir, "file.js")), task.jsInputFiles.files)
|
||||
assertEquals(setOf("**/*.js", "**/*.ts"), task.jsInputFiles.includes)
|
||||
assertEquals(2, task.jsInputFiles.files.size)
|
||||
assertEquals(
|
||||
setOf(File(jsRootDir, "file.js"), File(jsRootDir, "file.ts")), task.jsInputFiles.files)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+54
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.facebook.react.utils
|
||||
|
||||
import com.facebook.react.ReactExtension
|
||||
import com.facebook.react.TestReactExtension
|
||||
import com.facebook.react.tests.OS
|
||||
import com.facebook.react.tests.OsRule
|
||||
@@ -236,10 +237,63 @@ class PathUtilsTest {
|
||||
getBuiltHermescFile(tempFolder.root, ""))
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.WIN)
|
||||
fun getBuiltHermescFile_onWindows_withoutOverride() {
|
||||
assertEquals(
|
||||
File(
|
||||
tempFolder.root,
|
||||
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc.exe"),
|
||||
getBuiltHermescFile(tempFolder.root, ""))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getBuiltHermescFile_withOverride() {
|
||||
assertEquals(
|
||||
File("/home/circleci/hermes/build/bin/hermesc"),
|
||||
getBuiltHermescFile(tempFolder.root, "/home/circleci/hermes"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.WIN)
|
||||
fun getHermesCBin_onWindows_returnsHermescExe() {
|
||||
assertEquals("hermesc.exe", getHermesCBin())
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.UNIX)
|
||||
fun getHermesCBin_onUnix_returnsHermesc() {
|
||||
assertEquals("hermesc", getHermesCBin())
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithOs(OS.MAC)
|
||||
fun getHermesCBin_onMax_returnsHermesc() {
|
||||
assertEquals("hermesc", getHermesCBin())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findPackageJsonFile_withFileInParentFolder_picksItUp() {
|
||||
tempFolder.newFile("package.json")
|
||||
val moduleFolder = tempFolder.newFolder("awesome-module")
|
||||
|
||||
val project = ProjectBuilder.builder().withProjectDir(moduleFolder).build()
|
||||
project.plugins.apply("com.facebook.react")
|
||||
val extension = project.extensions.getByType(ReactExtension::class.java)
|
||||
|
||||
assertEquals(project.file("../package.json"), findPackageJsonFile(project, extension))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findPackageJsonFile_withFileConfiguredInExtension_picksItUp() {
|
||||
val moduleFolder = tempFolder.newFolder("awesome-module")
|
||||
val localFile = File(moduleFolder, "package.json").apply { writeText("{}") }
|
||||
|
||||
val project = ProjectBuilder.builder().withProjectDir(moduleFolder).build()
|
||||
project.plugins.apply("com.facebook.react")
|
||||
val extension =
|
||||
project.extensions.getByType(ReactExtension::class.java).apply { root.set(moduleFolder) }
|
||||
|
||||
assertEquals(localFile, findPackageJsonFile(project, extension))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,7 +956,7 @@ function SetAccessibilityFocusExample(props: {}): React.Node {
|
||||
|
||||
const onPress = () => {
|
||||
if (myRef && myRef.current) {
|
||||
AccessibilityInfo.sendAccessibilityEvent_unstable(myRef.current, 'focus');
|
||||
AccessibilityInfo.sendAccessibilityEvent(myRef.current, 'focus');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1114,6 +1114,11 @@ class DisplayOptionsStatusExample extends React.Component<{}> {
|
||||
optionChecker={AccessibilityInfo.isReduceMotionEnabled}
|
||||
notification={'reduceMotionChanged'}
|
||||
/>
|
||||
<DisplayOptionStatusExample
|
||||
optionName={'Prefer Cross-Fade Transitions'}
|
||||
optionChecker={AccessibilityInfo.prefersCrossFadeTransitions}
|
||||
notification={'prefersCrossFadeTransitionsChanged'}
|
||||
/>
|
||||
<DisplayOptionStatusExample
|
||||
optionName={'Screen Reader'}
|
||||
optionChecker={AccessibilityInfo.isScreenReaderEnabled}
|
||||
|
||||
@@ -214,6 +214,7 @@ function FallbackColorsExample() {
|
||||
style={{
|
||||
...styles.colorCell,
|
||||
backgroundColor: color.color,
|
||||
borderColor: color.color,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
+5
-3
@@ -102,20 +102,22 @@ def getHermesCommand = {
|
||||
}
|
||||
}
|
||||
|
||||
def hermescBin = Os.isFamily(Os.FAMILY_WINDOWS) ? 'hermesc.exe' : 'hermesc'
|
||||
|
||||
// 2. If the project is building hermes-engine from source, use hermesc from there
|
||||
// Also note that user can override the hermes source location with
|
||||
// the `REACT_NATIVE_OVERRIDE_HERMES_DIR` env variable.
|
||||
def hermesOverrideDir = System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR")
|
||||
def builtHermesc = hermesOverrideDir ?
|
||||
new File(hermesOverrideDir, "build/bin/hermesc") :
|
||||
new File(reactRoot, "node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc")
|
||||
new File(hermesOverrideDir, "build/bin/$hermescBin") :
|
||||
new File(reactRoot, "node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/$hermescBin")
|
||||
|
||||
if (builtHermesc.exists()) {
|
||||
return builtHermesc.getAbsolutePath()
|
||||
}
|
||||
|
||||
// 3. If the react-native contains a pre-built hermesc, use it.
|
||||
def prebuiltHermesPath = "node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
def prebuiltHermesPath = "node_modules/react-native/sdks/hermesc/%OS-BIN%/$hermescBin"
|
||||
.replaceAll("%OS-BIN%", getHermesOSBin())
|
||||
.replace('/' as char, File.separatorChar);
|
||||
def prebuiltHermes = new File(reactRoot, prebuiltHermesPath)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"@babel/generator": "^7.14.0",
|
||||
"@babel/plugin-transform-regenerator": "^7.0.0",
|
||||
"@react-native-community/eslint-plugin": "*",
|
||||
"@react-native/eslint-plugin-specs": ">0.0.2",
|
||||
"@react-native/eslint-plugin-specs": "^0.70.0",
|
||||
"@reactions/component": "^2.0.2",
|
||||
"async": "^3.2.2",
|
||||
"clang-format": "^1.2.4",
|
||||
@@ -39,16 +39,19 @@
|
||||
"jest": "^26.6.3",
|
||||
"jest-junit": "^10.0.0",
|
||||
"jscodeshift": "^0.13.1",
|
||||
"metro-babel-register": "0.71.3",
|
||||
"metro-memory-fs": "0.71.3",
|
||||
"metro-babel-register": "0.72.3",
|
||||
"metro-memory-fs": "0.72.3",
|
||||
"mkdirp": "^0.5.1",
|
||||
"prettier": "^2.4.1",
|
||||
"react": "18.1.0",
|
||||
"react-native-codegen": "^0.70.3",
|
||||
"react-native-codegen": "^0.70.5",
|
||||
"react-test-renderer": "18.1.0",
|
||||
"shelljs": "^0.8.5",
|
||||
"signedsource": "^1.0.0",
|
||||
"ws": "^6.1.4",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mock-fs": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ require_relative "./test_utils/PathnameMock.rb"
|
||||
require_relative "./test_utils/FileMock.rb"
|
||||
require_relative "./test_utils/DirMock.rb"
|
||||
require_relative "./test_utils/systemUtils.rb"
|
||||
require_relative "./test_utils/CodegenUtilsMock.rb"
|
||||
|
||||
class CodegenTests < Test::Unit::TestCase
|
||||
:third_party_provider_header
|
||||
@@ -182,4 +183,62 @@ class CodegenTests < Test::Unit::TestCase
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
# ================= #
|
||||
# Test - RunCodegen #
|
||||
# ================= #
|
||||
def testRunCodegen_whenNewArchEnabled_runsCodegen
|
||||
# Arrange
|
||||
app_path = "~/app"
|
||||
config_file = ""
|
||||
codegen_utils_mock = CodegenUtilsMock.new()
|
||||
|
||||
# Act
|
||||
run_codegen!(app_path, config_file, :new_arch_enabled => true, :codegen_utils => codegen_utils_mock)
|
||||
|
||||
# Assert
|
||||
assert_equal(codegen_utils_mock.use_react_native_codegen_discovery_params, [{
|
||||
:app_path=>"~/app",
|
||||
:codegen_disabled=>false,
|
||||
:codegen_output_dir=>"build/generated/ios",
|
||||
:config_file_dir=>"",
|
||||
:fabric_enabled=>false,
|
||||
:folly_version=>"2021.07.22.00",
|
||||
:react_native_path=>"../node_modules/react-native"
|
||||
}])
|
||||
assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [])
|
||||
assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [])
|
||||
end
|
||||
|
||||
def testRunCodegen_whenNewArchDisabled_runsCodegen
|
||||
# Arrange
|
||||
app_path = "~/app"
|
||||
config_file = ""
|
||||
package_json_file = "~/app/package.json"
|
||||
codegen_specs = { "name" => "React-Codegen" }
|
||||
codegen_utils_mock = CodegenUtilsMock.new(:react_codegen_spec => codegen_specs)
|
||||
|
||||
# Act
|
||||
run_codegen!(
|
||||
app_path,
|
||||
config_file,
|
||||
:new_arch_enabled => false,
|
||||
:fabric_enabled => true,
|
||||
:package_json_file => package_json_file,
|
||||
:codegen_utils => codegen_utils_mock)
|
||||
|
||||
# Assert
|
||||
assert_equal(codegen_utils_mock.use_react_native_codegen_discovery_params, [])
|
||||
assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{
|
||||
:fabric_enabled => true,
|
||||
:folly_version=>"2021.07.22.00",
|
||||
:package_json_file => "~/app/package.json",
|
||||
:script_phases => nil
|
||||
}])
|
||||
assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [{
|
||||
:codegen_output_dir=>"build/generated/ios",
|
||||
:react_codegen_spec=>{"name"=>"React-Codegen"}
|
||||
}])
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
# 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.
|
||||
|
||||
require "test/unit"
|
||||
require "json"
|
||||
require_relative "../codegen_utils.rb"
|
||||
require_relative "./test_utils/FileMock.rb"
|
||||
require_relative "./test_utils/DirMock.rb"
|
||||
require_relative "./test_utils/PodMock.rb"
|
||||
require_relative "./test_utils/PathnameMock.rb"
|
||||
require_relative "./test_utils/FinderMock.rb"
|
||||
require_relative "./test_utils/CodegenUtilsMock.rb"
|
||||
require_relative "./test_utils/CodegenScriptPhaseExtractorMock.rb"
|
||||
|
||||
class CodegenUtilsTests < Test::Unit::TestCase
|
||||
:base_path
|
||||
|
||||
def setup
|
||||
CodegenUtils.set_react_codegen_discovery_done(false)
|
||||
CodegenUtils.set_react_codegen_podspec_generated(false)
|
||||
Pod::Config.reset()
|
||||
File.enable_testing_mode!
|
||||
Dir.enable_testing_mode!
|
||||
@base_path = "~/app/ios"
|
||||
Pathname.pwd!(@base_path)
|
||||
Pod::Config.instance.installation_root.relative_path_from = @base_path
|
||||
end
|
||||
|
||||
def teardown
|
||||
Finder.reset()
|
||||
Pathname.reset()
|
||||
Pod::UI.reset()
|
||||
Pod::Executable.reset()
|
||||
File.reset()
|
||||
Dir.reset()
|
||||
end
|
||||
|
||||
# ================================== #
|
||||
# Test - GenerateReactCodegenPodspec #
|
||||
# ================================== #
|
||||
|
||||
def testGenerateReactCodegenPodspec_whenItHasBeenAlreadyGenerated_doesNothing
|
||||
# Arrange
|
||||
spec = { :name => "Test Podspec" }
|
||||
codegen_output_dir = "build"
|
||||
CodegenUtils.set_react_codegen_podspec_generated(true)
|
||||
|
||||
# Act
|
||||
CodegenUtils.new().generate_react_codegen_podspec!(spec, codegen_output_dir)
|
||||
|
||||
# Assert
|
||||
assert_equal(Pod::UI.collected_messages, ["[Codegen] Skipping React-Codegen podspec generation."])
|
||||
assert_equal(Pathname.pwd_invocation_count, 0)
|
||||
assert_equal(Pod::Executable.executed_commands, [])
|
||||
assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 0)
|
||||
assert_true(CodegenUtils.react_codegen_podspec_generated)
|
||||
end
|
||||
|
||||
def testGenerateReactCodegenPodspec_whenItHasNotBeenAlreadyGenerated_generatesIt
|
||||
# Arrange
|
||||
spec = { :name => "Test Podspec" }
|
||||
codegen_output_dir = "build"
|
||||
|
||||
# Act
|
||||
CodegenUtils.new().generate_react_codegen_podspec!(spec, codegen_output_dir)
|
||||
|
||||
# Assert
|
||||
assert_equal(Pathname.pwd_invocation_count, 1)
|
||||
assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1)
|
||||
assert_equal(Pod::Executable.executed_commands, [{ "command" => 'mkdir', "arguments" => ["-p", "~/app/ios/build"]}])
|
||||
assert_equal(Pod::UI.collected_messages, ["[Codegen] Generating ~/app/ios/build/React-Codegen.podspec.json"])
|
||||
assert_equal(File.open_files_with_mode["~/app/ios/build/React-Codegen.podspec.json"], 'w')
|
||||
assert_equal(File.open_files[0].collected_write, ['{"name":"Test Podspec"}'])
|
||||
assert_equal(File.open_files[0].fsync_invocation_count, 1)
|
||||
|
||||
assert_true(CodegenUtils.react_codegen_podspec_generated)
|
||||
end
|
||||
|
||||
# ========================== #
|
||||
# Test - GetReactCodegenSpec #
|
||||
# ========================== #
|
||||
|
||||
def testGetReactCodegenSpec_whenFabricDisabledAndNoScriptPhases_generatesAPodspec
|
||||
# Arrange
|
||||
File.files_to_read('package.json' => '{ "version": "99.98.97"}')
|
||||
|
||||
# Act
|
||||
podspec = CodegenUtils.new().get_react_codegen_spec(
|
||||
'package.json',
|
||||
:fabric_enabled => false,
|
||||
:script_phases => nil
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert_equal(podspec, get_podspec_no_fabric_no_script())
|
||||
assert_equal(Pod::UI.collected_messages, [])
|
||||
end
|
||||
|
||||
def testGetReactCodegenSpec_whenFabricEnabledAndScriptPhases_generatesAPodspec
|
||||
# Arrange
|
||||
File.files_to_read('package.json' => '{ "version": "99.98.97"}')
|
||||
|
||||
# Act
|
||||
podspec = CodegenUtils.new().get_react_codegen_spec(
|
||||
'package.json',
|
||||
:fabric_enabled => true,
|
||||
:script_phases => "echo Test Script Phase"
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert_equal(podspec, get_podspec_fabric_and_script_phases("echo Test Script Phase"))
|
||||
assert_equal(Pod::UI.collected_messages, ["[Codegen] Adding script_phases to React-Codegen."])
|
||||
end
|
||||
|
||||
# =============================== #
|
||||
# Test - GetCodegenConfigFromFile #
|
||||
# =============================== #
|
||||
|
||||
def testGetCodegenConfigFromFile_whenFileDoesNotExists_returnEmpty
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
codegen = CodegenUtils.new().get_codegen_config_from_file('package.json', 'codegenConfig')
|
||||
|
||||
# Assert
|
||||
assert_equal(codegen, {})
|
||||
end
|
||||
|
||||
def testGetCodegenConfigFromFile_whenFileExistsButHasNoKey_returnEmpty
|
||||
# Arrange
|
||||
File.mocked_existing_files(['package.json'])
|
||||
File.files_to_read('package.json' => '{ "codegenConfig": {}}')
|
||||
|
||||
# Act
|
||||
codegen = CodegenUtils.new().get_codegen_config_from_file('package.json', 'codegen')
|
||||
|
||||
# Assert
|
||||
assert_equal(codegen, {})
|
||||
end
|
||||
|
||||
def testGetCodegenConfigFromFile_whenFileExistsAndHasKey_returnObject
|
||||
# Arrange
|
||||
File.mocked_existing_files(['package.json'])
|
||||
File.files_to_read('package.json' => '{ "codegenConfig": {"name": "MySpec"}}')
|
||||
|
||||
# Act
|
||||
codegen = CodegenUtils.new().get_codegen_config_from_file('package.json', 'codegenConfig')
|
||||
|
||||
# Assert
|
||||
assert_equal(codegen, { "name" => "MySpec"})
|
||||
end
|
||||
|
||||
# ======================= #
|
||||
# Test - GetListOfJSSpecs #
|
||||
# ======================= #
|
||||
def testGetListOfJSSpecs_whenUsesLibraries_returnAListOfFiles
|
||||
# Arrange
|
||||
app_codegen_config = {
|
||||
'libraries' => [
|
||||
{
|
||||
'name' => 'First Lib',
|
||||
'jsSrcsDir' => './firstlib/js'
|
||||
},
|
||||
{
|
||||
'name' => 'Second Lib',
|
||||
'jsSrcsDir' => './secondlib/js'
|
||||
},
|
||||
]
|
||||
}
|
||||
app_path = "~/MyApp/"
|
||||
Finder.set_files_for_paths({
|
||||
'~/MyApp/./firstlib/js' => ["MyFabricComponent1NativeComponent.js", "MyFabricComponent2NativeComponent.js"],
|
||||
'~/MyApp/./secondlib/js' => ["NativeModule1.js", "NativeModule2.js"],
|
||||
})
|
||||
|
||||
# Act
|
||||
files = CodegenUtils.new().get_list_of_js_specs(app_codegen_config, app_path)
|
||||
|
||||
# Assert
|
||||
assert_equal(Pod::UI.collected_warns , ["[Deprecated] You are using the old `libraries` array to list all your codegen.\\nThis method will be removed in the future.\\nUpdate your `package.json` with a single object."])
|
||||
assert_equal(Finder.captured_paths, ['~/MyApp/./firstlib/js', '~/MyApp/./secondlib/js'])
|
||||
assert_equal(files, [
|
||||
"${PODS_ROOT}/../MyFabricComponent1NativeComponent.js",
|
||||
"${PODS_ROOT}/../MyFabricComponent2NativeComponent.js",
|
||||
"${PODS_ROOT}/../NativeModule1.js",
|
||||
"${PODS_ROOT}/../NativeModule2.js",
|
||||
])
|
||||
end
|
||||
|
||||
def testGetListOfJSSpecs_whenDoesNotUsesLibraries_returnAListOfFiles
|
||||
# Arrange
|
||||
app_codegen_config = {
|
||||
'name' => 'First Lib',
|
||||
'jsSrcsDir' => './js'
|
||||
}
|
||||
|
||||
app_path = "~/MyApp/"
|
||||
Finder.set_files_for_paths({
|
||||
'~/MyApp/./js' => ["MyFabricComponent1NativeComponent.js", "NativeModule1.js"],
|
||||
})
|
||||
|
||||
# Act
|
||||
files = CodegenUtils.new().get_list_of_js_specs(app_codegen_config, app_path)
|
||||
|
||||
# Assert
|
||||
assert_equal(Pod::UI.collected_warns , [])
|
||||
assert_equal(Finder.captured_paths, ['~/MyApp/./js'])
|
||||
assert_equal(files, [
|
||||
"${PODS_ROOT}/../MyFabricComponent1NativeComponent.js",
|
||||
"${PODS_ROOT}/../NativeModule1.js",
|
||||
])
|
||||
end
|
||||
|
||||
# ================================== #
|
||||
# Test - GetReactCodegenScriptPhases #
|
||||
# ================================== #
|
||||
|
||||
def testGetReactCodegenScriptPhases_whenAppPathNotDefined_abort
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
assert_raises() {
|
||||
CodegenUtils.new().get_react_codegen_script_phases(nil)
|
||||
}
|
||||
# Assert
|
||||
assert_equal(Pod::UI.collected_warns, ["[Codegen] error: app_path is requried to use codegen discovery."])
|
||||
end
|
||||
|
||||
def testGetReactCodegenScriptPhases_returnTheScriptObject
|
||||
# Arrange
|
||||
app_path = "~/MyApp"
|
||||
input_files = ["${PODS_ROOT}/../MyFabricComponent1NativeComponent.js", "${PODS_ROOT}/../NativeModule1.js"]
|
||||
computed_script = "echo ScriptPhases"
|
||||
codegen_config = { "name" => "MyCodegenModule", "jsSrcsDir" => "./js"}
|
||||
codegen_utils_mock = CodegenUtilsMock.new(:js_spec_list => input_files, :codegen_config => codegen_config)
|
||||
script_phase_extractor_mock = CodegenScriptPhaseExtractorMock.new(computed_script)
|
||||
|
||||
# Act
|
||||
|
||||
scripts = CodegenUtils.new().get_react_codegen_script_phases(
|
||||
app_path,
|
||||
:codegen_utils => codegen_utils_mock,
|
||||
:script_phase_extractor => script_phase_extractor_mock
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert_equal(codegen_utils_mock.get_codegen_config_from_file_params, [{
|
||||
"config_key" => "codegenConfig",
|
||||
"config_path" => "~/MyApp/package.json"
|
||||
}])
|
||||
assert_equal(codegen_utils_mock.get_list_of_js_specs_params, [{
|
||||
"app_codegen_config" => {"jsSrcsDir"=>"./js", "name"=>"MyCodegenModule"},
|
||||
"app_path" => "~/MyApp"
|
||||
}])
|
||||
assert_equal(script_phase_extractor_mock.extract_script_phase_params, [{
|
||||
fabric_enabled: false,
|
||||
react_native_path: "../node_modules/react-native",
|
||||
relative_app_root: "~/MyApp",
|
||||
relative_config_file_dir: ""
|
||||
}])
|
||||
assert_equal(scripts, {
|
||||
'name': 'Generate Specs',
|
||||
'execution_position': :before_compile,
|
||||
'input_files' => input_files,
|
||||
'show_env_vars_in_log': true,
|
||||
'output_files': ["${DERIVED_FILE_DIR}/react-codegen.log"],
|
||||
'script': computed_script
|
||||
})
|
||||
end
|
||||
|
||||
# ================================ #
|
||||
# Test - UseReactCodegenDiscovery! #
|
||||
# ================================ #
|
||||
|
||||
def testUseReactCodegenDiscovery_whenCodegenDisabled_doNothing
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
CodegenUtils.new().use_react_native_codegen_discovery!(true, nil)
|
||||
|
||||
# Assert
|
||||
assert_false(CodegenUtils.react_codegen_discovery_done())
|
||||
assert_equal(Pod::UI.collected_messages, [])
|
||||
assert_equal(Pod::UI.collected_warns, [])
|
||||
end
|
||||
|
||||
def testUseReactCodegenDiscovery_whenDiscoveryDone_doNothing
|
||||
# Arrange
|
||||
CodegenUtils.set_react_codegen_discovery_done(true)
|
||||
|
||||
# Act
|
||||
CodegenUtils.new().use_react_native_codegen_discovery!(false, nil)
|
||||
|
||||
# Assert
|
||||
assert_true(CodegenUtils.react_codegen_discovery_done())
|
||||
assert_equal(Pod::UI.collected_messages, ["[Codegen] Skipping use_react_native_codegen_discovery."])
|
||||
assert_equal(Pod::UI.collected_warns, [])
|
||||
end
|
||||
|
||||
def testUseReactCodegenDiscovery_whenAppPathUndefined_abort
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
assert_raises(){
|
||||
CodegenUtils.new().use_react_native_codegen_discovery!(false, nil)
|
||||
}
|
||||
|
||||
# Assert
|
||||
assert_false(CodegenUtils.react_codegen_discovery_done())
|
||||
assert_equal(Pod::UI.collected_messages, [])
|
||||
assert_equal(Pod::UI.collected_warns, [
|
||||
'[Codegen] Error: app_path is required for use_react_native_codegen_discovery.',
|
||||
'[Codegen] If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.'
|
||||
])
|
||||
end
|
||||
|
||||
def testUseReactCodegenDiscovery_whenParametersAreGood_executeCodegen
|
||||
# Arrange
|
||||
app_path = "~/app"
|
||||
computed_script = "echo TestScript"
|
||||
codegen_spec = {"name" => "React-Codegen"}
|
||||
|
||||
codegen_utils_mock = CodegenUtilsMock.new(
|
||||
:react_codegen_script_phases => computed_script,
|
||||
:react_codegen_spec => codegen_spec
|
||||
)
|
||||
|
||||
# Act
|
||||
CodegenUtils.new().use_react_native_codegen_discovery!(
|
||||
false,
|
||||
app_path,
|
||||
:codegen_utils => codegen_utils_mock
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert_true(CodegenUtils.react_codegen_discovery_done())
|
||||
assert_equal(Pod::UI.collected_warns, [
|
||||
'[Codegen] warn: using experimental new codegen integration'
|
||||
])
|
||||
assert_equal(codegen_utils_mock.get_react_codegen_script_phases_params, [{
|
||||
:app_path => "~/app",
|
||||
:config_file_dir => "",
|
||||
:config_key => "codegenConfig",
|
||||
:fabric_enabled => false,
|
||||
:react_native_path => "../node_modules/react-native"}
|
||||
])
|
||||
assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{
|
||||
:fabric_enabled => false,
|
||||
:folly_version=>"2021.07.22.00",
|
||||
:package_json_file => "../node_modules/react-native/package.json",
|
||||
:script_phases => "echo TestScript"
|
||||
}])
|
||||
assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [{
|
||||
:codegen_output_dir=>"build/generated/ios",
|
||||
:react_codegen_spec=>{"name"=>"React-Codegen"}
|
||||
}])
|
||||
assert_equal(Pod::Executable.executed_commands, [
|
||||
{
|
||||
"command" => "node",
|
||||
"arguments"=> ["~/app/ios/../node_modules/react-native/scripts/generate-artifacts.js",
|
||||
"-p", "~/app",
|
||||
"-o", Pod::Config.instance.installation_root,
|
||||
"-e", "false",
|
||||
"-c", ""]
|
||||
}
|
||||
])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_podspec_no_fabric_no_script
|
||||
spec = {
|
||||
'name' => "React-Codegen",
|
||||
'version' => "99.98.97",
|
||||
'summary' => 'Temp pod for generated files for React Native',
|
||||
'homepage' => 'https://facebook.com/',
|
||||
'license' => 'Unlicense',
|
||||
'authors' => 'Facebook',
|
||||
'compiler_flags' => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32 -Wno-documentation -Wno-nullability-completeness -std=c++17",
|
||||
'source' => { :git => '' },
|
||||
'header_mappings_dir' => './',
|
||||
'platforms' => {
|
||||
'ios' => '11.0',
|
||||
},
|
||||
'source_files' => "**/*.{h,mm,cpp}",
|
||||
'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" =>
|
||||
[
|
||||
"\"$(PODS_ROOT)/boost\"",
|
||||
"\"$(PODS_ROOT)/RCT-Folly\"",
|
||||
"\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"",
|
||||
"\"$(PODS_ROOT)/Headers/Private/React-Fabric\"",
|
||||
"\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"",
|
||||
].join(' ')
|
||||
},
|
||||
'dependencies': {
|
||||
"FBReactNativeSpec": ["99.98.97"],
|
||||
"React-jsiexecutor": ["99.98.97"],
|
||||
"RCT-Folly": ["2021.07.22.00"],
|
||||
"RCTRequired": ["99.98.97"],
|
||||
"RCTTypeSafety": ["99.98.97"],
|
||||
"React-Core": ["99.98.97"],
|
||||
"React-jsi": ["99.98.97"],
|
||||
"ReactCommon/turbomodule/core": ["99.98.97"]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def get_podspec_fabric_and_script_phases(script_phases)
|
||||
specs = get_podspec_no_fabric_no_script()
|
||||
|
||||
specs[:dependencies].merge!({
|
||||
'React-graphics': ["99.98.97"],
|
||||
'React-rncore': ["99.98.97"],
|
||||
})
|
||||
|
||||
specs[:'script_phases'] = script_phases
|
||||
|
||||
return specs
|
||||
end
|
||||
end
|
||||
@@ -208,10 +208,8 @@ def prepare_CXX_Flags_build_configuration(name)
|
||||
end
|
||||
|
||||
def prepare_pod_target_installation_results_mock(name, configs)
|
||||
return PodTargetInstallationResultsMock.new(
|
||||
:name => name,
|
||||
:native_target => TargetMock.new(name, configs)
|
||||
)
|
||||
target = TargetMock.new(name, configs)
|
||||
return TargetInstallationResultMock.new(target, target)
|
||||
end
|
||||
|
||||
def prepare_installer_for_cpp_flags(xcconfigs, build_configs)
|
||||
@@ -232,8 +230,6 @@ def prepare_installer_for_cpp_flags(xcconfigs, build_configs)
|
||||
[
|
||||
AggregatedProjectMock.new(:xcconfigs => xcconfigs_map, :base_path => "a/path/")
|
||||
],
|
||||
:target_installation_results => TargetInstallationResultsMock.new(
|
||||
:pod_target_installation_results => pod_target_installation_results_map
|
||||
)
|
||||
:pod_target_installation_results => pod_target_installation_results_map
|
||||
)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# 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.
|
||||
|
||||
class CodegenScriptPhaseExtractorMock
|
||||
|
||||
attr_reader :extract_script_phase_params
|
||||
@script_phase
|
||||
|
||||
def initialize(script_phase)
|
||||
@script_phase = script_phase
|
||||
@extract_script_phase_params = []
|
||||
end
|
||||
|
||||
def extract_script_phase(options)
|
||||
@extract_script_phase_params.push(options)
|
||||
return @script_phase
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,107 @@
|
||||
# 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.
|
||||
|
||||
class CodegenUtilsMock
|
||||
@js_spec_list
|
||||
@codegen_config
|
||||
|
||||
@react_codegen_script_phases
|
||||
@react_codegen_spec
|
||||
|
||||
attr_reader :get_codegen_config_from_file_params
|
||||
attr_reader :get_list_of_js_specs_params
|
||||
attr_reader :get_react_codegen_script_phases_params
|
||||
attr_reader :get_react_codegen_spec_params
|
||||
attr_reader :generate_react_codegen_spec_params
|
||||
attr_reader :use_react_native_codegen_discovery_params
|
||||
|
||||
def initialize(js_spec_list: [], codegen_config: {}, react_codegen_script_phases: "", react_codegen_spec: {})
|
||||
@js_spec_list = js_spec_list
|
||||
@codegen_config = codegen_config
|
||||
@get_codegen_config_from_file_params = []
|
||||
@get_list_of_js_specs_params = []
|
||||
|
||||
@react_codegen_script_phases = react_codegen_script_phases
|
||||
@react_codegen_spec = react_codegen_spec
|
||||
@get_react_codegen_script_phases_params = []
|
||||
@get_react_codegen_spec_params = []
|
||||
@generate_react_codegen_spec_params = []
|
||||
@use_react_native_codegen_discovery_params = []
|
||||
end
|
||||
|
||||
def get_codegen_config_from_file(config_path, config_key)
|
||||
@get_codegen_config_from_file_params.push({
|
||||
"config_path" => config_path,
|
||||
"config_key" => config_key
|
||||
})
|
||||
return @codegen_config
|
||||
end
|
||||
|
||||
def get_list_of_js_specs(app_codegen_config, app_path)
|
||||
@get_list_of_js_specs_params.push({
|
||||
"app_codegen_config" => app_codegen_config,
|
||||
"app_path" => app_path
|
||||
})
|
||||
return @js_spec_list
|
||||
end
|
||||
|
||||
def get_react_codegen_script_phases(
|
||||
app_path,
|
||||
fabric_enabled: false,
|
||||
config_file_dir: '',
|
||||
react_native_path: "../node_modules/react-native",
|
||||
config_key: 'codegenConfig',
|
||||
codegen_utils: CodegenUtils.new(),
|
||||
script_phase_extractor: CodegenScriptPhaseExtractor.new()
|
||||
)
|
||||
@get_react_codegen_script_phases_params.push({
|
||||
app_path: app_path,
|
||||
fabric_enabled: fabric_enabled,
|
||||
config_file_dir: config_file_dir,
|
||||
react_native_path: react_native_path,
|
||||
config_key: config_key
|
||||
})
|
||||
return @react_codegen_script_phases
|
||||
end
|
||||
|
||||
def get_react_codegen_spec(package_json_file, folly_version: '2021.07.22.00', fabric_enabled: false, script_phases: nil)
|
||||
@get_react_codegen_spec_params.push({
|
||||
package_json_file: package_json_file,
|
||||
folly_version: folly_version,
|
||||
fabric_enabled: fabric_enabled,
|
||||
script_phases: script_phases
|
||||
})
|
||||
return @react_codegen_spec
|
||||
end
|
||||
|
||||
def generate_react_codegen_podspec!(react_codegen_spec, codegen_output_dir)
|
||||
@generate_react_codegen_spec_params.push({
|
||||
react_codegen_spec: react_codegen_spec,
|
||||
codegen_output_dir: codegen_output_dir
|
||||
})
|
||||
end
|
||||
|
||||
def use_react_native_codegen_discovery!(
|
||||
codegen_disabled,
|
||||
app_path,
|
||||
react_native_path: "../node_modules/react-native",
|
||||
fabric_enabled: false,
|
||||
config_file_dir: '',
|
||||
codegen_output_dir: 'build/generated/ios',
|
||||
config_key: 'codegenConfig',
|
||||
folly_version: "2021.07.22.00",
|
||||
codegen_utils: CodegenUtils.new()
|
||||
)
|
||||
@use_react_native_codegen_discovery_params.push({
|
||||
codegen_disabled: codegen_disabled,
|
||||
app_path: app_path,
|
||||
react_native_path: react_native_path,
|
||||
fabric_enabled: fabric_enabled,
|
||||
config_file_dir: config_file_dir,
|
||||
codegen_output_dir: codegen_output_dir,
|
||||
folly_version: folly_version
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
# 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.
|
||||
|
||||
class Finder
|
||||
@@captured_paths = []
|
||||
@@files_for_paths = {}
|
||||
|
||||
|
||||
def self.find_codegen_file(path)
|
||||
@@captured_paths.push(path)
|
||||
return @@files_for_paths[path]
|
||||
end
|
||||
|
||||
def self.set_files_for_paths(files_for_paths)
|
||||
@@files_for_paths = files_for_paths
|
||||
end
|
||||
|
||||
def self.captured_paths
|
||||
return @@captured_paths
|
||||
end
|
||||
|
||||
def self.reset()
|
||||
@@captured_paths = []
|
||||
@@files_for_paths = {}
|
||||
end
|
||||
end
|
||||
@@ -41,10 +41,23 @@ class InstallerMock
|
||||
attr_reader :aggregate_targets
|
||||
attr_reader :target_installation_results
|
||||
|
||||
def initialize(pods_project = PodsProjectMock.new, aggregate_targets = [AggregatedProjectMock.new], target_installation_results: [])
|
||||
InstallationResults = Struct.new(:pod_target_installation_results, :aggregate_target_installation_results)
|
||||
|
||||
def initialize(pods_project = PodsProjectMock.new, aggregate_targets = [AggregatedProjectMock.new],
|
||||
pod_target_installation_results: {},
|
||||
aggregate_target_installation_results: {})
|
||||
@pods_project = pods_project
|
||||
@aggregate_targets = aggregate_targets
|
||||
@target_installation_results = target_installation_results
|
||||
|
||||
@target_installation_results = InstallationResults.new(pod_target_installation_results, aggregate_target_installation_results)
|
||||
aggregate_targets.each do |aggregate_target|
|
||||
aggregate_target.user_project.native_targets.each do |target|
|
||||
@target_installation_results.pod_target_installation_results[target.name] = TargetInstallationResultMock.new(target, target)
|
||||
end
|
||||
end
|
||||
pods_project.native_targets.each do |target|
|
||||
@target_installation_results.pod_target_installation_results[target.name] = TargetInstallationResultMock.new(target, target)
|
||||
end
|
||||
end
|
||||
|
||||
def target_with_name(name)
|
||||
@@ -168,20 +181,27 @@ class BuildConfigurationMock
|
||||
end
|
||||
end
|
||||
|
||||
class TargetInstallationResultsMock
|
||||
attr_reader :pod_target_installation_results
|
||||
|
||||
def initialize(pod_target_installation_results: {})
|
||||
@pod_target_installation_results = pod_target_installation_results
|
||||
end
|
||||
end
|
||||
|
||||
class PodTargetInstallationResultsMock
|
||||
attr_reader :name
|
||||
class TargetInstallationResultMock
|
||||
attr_reader :target
|
||||
attr_reader :native_target
|
||||
attr_reader :resource_bundle_targets
|
||||
attr_reader :test_native_targets
|
||||
attr_reader :test_resource_bundle_targets
|
||||
attr_reader :test_app_host_targets
|
||||
attr_reader :app_native_targets
|
||||
attr_reader :app_resource_bundle_targets
|
||||
|
||||
def initialize(name: "", native_target: TargetMock.new())
|
||||
@name = name
|
||||
def initialize(target = TargetMock, native_target = TargetMock,
|
||||
resource_bundle_targets = [], test_native_targets = [],
|
||||
test_resource_bundle_targets = {}, test_app_host_targets = [],
|
||||
app_native_targets = {}, app_resource_bundle_targets = {})
|
||||
@target = target
|
||||
@native_target = native_target
|
||||
@resource_bundle_targets = resource_bundle_targets
|
||||
@test_native_targets = test_native_targets
|
||||
@test_resource_bundle_targets = test_resource_bundle_targets
|
||||
@test_app_host_targets = test_app_host_targets
|
||||
@app_native_targets = app_native_targets
|
||||
@app_resource_bundle_targets = app_resource_bundle_targets
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,20 @@ class Pathname
|
||||
@@pwd = ""
|
||||
@@pwd_invocation_count = 0
|
||||
|
||||
attr_reader :path
|
||||
|
||||
def initialize(path)
|
||||
@path = path
|
||||
end
|
||||
|
||||
def realpath
|
||||
return self
|
||||
end
|
||||
|
||||
def relative_path_from(path)
|
||||
return @path
|
||||
end
|
||||
|
||||
def self.pwd!(pwd)
|
||||
@@pwd = pwd
|
||||
end
|
||||
|
||||
@@ -315,6 +315,60 @@ class UtilsTests < Test::Unit::TestCase
|
||||
assert_equal(pods_projects_mock.save_invocation_count, 1)
|
||||
end
|
||||
|
||||
# ============================================= #
|
||||
# Test - Fix React-bridging Header Search Paths #
|
||||
# ============================================= #
|
||||
|
||||
def test_fixReactBridgingHeaderSearchPaths_correctlySetsTheHeaderSearchPathsForAllTargets
|
||||
# Arrange
|
||||
first_target = prepare_target("FirstTarget")
|
||||
second_target = prepare_target("SecondTarget")
|
||||
third_target = TargetMock.new("ThirdTarget", [
|
||||
BuildConfigurationMock.new("Debug", {
|
||||
"HEADER_SEARCH_PATHS" => '$(inherited) "${PODS_ROOT}/Headers/Public" '
|
||||
}),
|
||||
BuildConfigurationMock.new("Release", {
|
||||
"HEADER_SEARCH_PATHS" => '$(inherited) "${PODS_ROOT}/Headers/Public" '
|
||||
}),
|
||||
], nil)
|
||||
|
||||
user_project_mock = UserProjectMock.new("a/path", [
|
||||
prepare_config("Debug"),
|
||||
prepare_config("Release"),
|
||||
],
|
||||
:native_targets => [
|
||||
first_target,
|
||||
second_target
|
||||
]
|
||||
)
|
||||
pods_projects_mock = PodsProjectMock.new([], {"hermes-engine" => {}}, :native_targets => [
|
||||
third_target
|
||||
])
|
||||
installer = InstallerMock.new(pods_projects_mock, [
|
||||
AggregatedProjectMock.new(user_project_mock)
|
||||
])
|
||||
|
||||
# Act
|
||||
ReactNativePodsUtils.fix_react_bridging_header_search_paths(installer)
|
||||
|
||||
# Assert
|
||||
first_target.build_configurations.each do |config|
|
||||
assert_equal(config.build_settings["HEADER_SEARCH_PATHS"].strip,
|
||||
'$(inherited) "$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging" "$(PODS_CONFIGURATION_BUILD_DIR)/React-bridging/react_bridging.framework/Headers"'
|
||||
)
|
||||
end
|
||||
second_target.build_configurations.each do |config|
|
||||
assert_equal(config.build_settings["HEADER_SEARCH_PATHS"].strip,
|
||||
'$(inherited) "$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging" "$(PODS_CONFIGURATION_BUILD_DIR)/React-bridging/react_bridging.framework/Headers"'
|
||||
)
|
||||
end
|
||||
third_target.build_configurations.each do |config|
|
||||
assert_equal(config.build_settings["HEADER_SEARCH_PATHS"].strip,
|
||||
'$(inherited) "${PODS_ROOT}/Headers/Public" "$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging" "$(PODS_CONFIGURATION_BUILD_DIR)/React-bridging/react_bridging.framework/Headers"'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# ================================= #
|
||||
# Test - Apply Mac Catalyst Patches #
|
||||
# ================================= #
|
||||
@@ -352,7 +406,7 @@ class UtilsTests < Test::Unit::TestCase
|
||||
third_target.build_configurations.each do |config|
|
||||
assert_equal(config.build_settings["CODE_SIGN_IDENTITY[sdk=macosx*]"], "-")
|
||||
end
|
||||
|
||||
|
||||
user_project_mock.native_targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
assert_equal(config.build_settings["DEAD_CODE_STRIPPING"], "YES")
|
||||
|
||||
@@ -65,3 +65,38 @@ def checkAndGenerateEmptyThirdPartyProvider!(react_native_path, new_arch_enabled
|
||||
File.delete(temp_schema_list_path) if File.exist?(temp_schema_list_path)
|
||||
end
|
||||
end
|
||||
|
||||
def run_codegen!(
|
||||
app_path,
|
||||
config_file_dir,
|
||||
new_arch_enabled: false,
|
||||
disable_codegen: false,
|
||||
react_native_path: "../node_modules/react-native",
|
||||
fabric_enabled: false,
|
||||
codegen_output_dir: 'build/generated/ios',
|
||||
config_key: 'codegenConfig',
|
||||
package_json_file: '~/app/package.json',
|
||||
folly_version: '2021.07.22.00',
|
||||
codegen_utils: CodegenUtils.new()
|
||||
)
|
||||
if new_arch_enabled
|
||||
codegen_utils.use_react_native_codegen_discovery!(
|
||||
disable_codegen,
|
||||
app_path,
|
||||
:react_native_path => react_native_path,
|
||||
:fabric_enabled => fabric_enabled,
|
||||
:config_file_dir => config_file_dir,
|
||||
:codegen_output_dir => codegen_output_dir,
|
||||
:config_key => config_key,
|
||||
:folly_version => folly_version
|
||||
)
|
||||
else
|
||||
# Generate a podspec file for generated files.
|
||||
# This gets generated in use_react_native_codegen_discovery when codegen discovery is enabled.
|
||||
react_codegen_spec = codegen_utils.get_react_codegen_spec(
|
||||
package_json_file,
|
||||
:fabric_enabled => fabric_enabled
|
||||
)
|
||||
codegen_utils.generate_react_codegen_podspec!(react_codegen_spec, codegen_output_dir)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# 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.
|
||||
|
||||
class CodegenScriptPhaseExtractor
|
||||
def initialize()
|
||||
end
|
||||
|
||||
def extract_script_phase(options)
|
||||
get_script_phases_with_codegen_discovery(options)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,283 @@
|
||||
# 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.
|
||||
|
||||
require 'json'
|
||||
require_relative './helpers.rb'
|
||||
require_relative './codegen_script_phase_extractor.rb'
|
||||
|
||||
class CodegenUtils
|
||||
|
||||
def initialize()
|
||||
end
|
||||
|
||||
@@REACT_CODEGEN_PODSPEC_GENERATED = false
|
||||
|
||||
def self.set_react_codegen_podspec_generated(value)
|
||||
@@REACT_CODEGEN_PODSPEC_GENERATED = value
|
||||
end
|
||||
|
||||
def self.react_codegen_podspec_generated
|
||||
@@REACT_CODEGEN_PODSPEC_GENERATED
|
||||
end
|
||||
|
||||
@@REACT_CODEGEN_DISCOVERY_DONE = false
|
||||
|
||||
def self.set_react_codegen_discovery_done(value)
|
||||
@@REACT_CODEGEN_DISCOVERY_DONE = value
|
||||
end
|
||||
|
||||
def self.react_codegen_discovery_done
|
||||
@@REACT_CODEGEN_DISCOVERY_DONE
|
||||
end
|
||||
|
||||
# It takes some cocoapods specs and writes them into a file
|
||||
#
|
||||
# Parameters
|
||||
# - spec: the cocoapod specs
|
||||
# - codegen_output_dir: the output directory for the codegen
|
||||
def generate_react_codegen_podspec!(spec, codegen_output_dir)
|
||||
# This podspec file should only be create once in the session/pod install.
|
||||
# This happens when multiple targets are calling use_react_native!.
|
||||
if @@REACT_CODEGEN_PODSPEC_GENERATED
|
||||
Pod::UI.puts "[Codegen] Skipping React-Codegen podspec generation."
|
||||
return
|
||||
end
|
||||
|
||||
relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
|
||||
output_dir = "#{relative_installation_root}/#{codegen_output_dir}"
|
||||
Pod::Executable.execute_command("mkdir", ["-p", output_dir]);
|
||||
|
||||
podspec_path = File.join(output_dir, 'React-Codegen.podspec.json')
|
||||
Pod::UI.puts "[Codegen] Generating #{podspec_path}"
|
||||
|
||||
File.open(podspec_path, 'w') do |f|
|
||||
f.write(spec.to_json)
|
||||
f.fsync
|
||||
end
|
||||
|
||||
@@REACT_CODEGEN_PODSPEC_GENERATED = true
|
||||
end
|
||||
|
||||
# It generates the podspec object that represents the `React-Codegen.podspec` file
|
||||
#
|
||||
# Parameters
|
||||
# - package_json_file: the path to the `package.json`, required to extract the proper React Native version
|
||||
# - fabric_enabled: whether fabric is enabled or not.
|
||||
# - script_phases: whether we want to add some build script phases or not.
|
||||
def get_react_codegen_spec(package_json_file, folly_version: '2021.07.22.00', fabric_enabled: false, script_phases: nil)
|
||||
package = JSON.parse(File.read(package_json_file))
|
||||
version = package['version']
|
||||
|
||||
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
||||
boost_compiler_flags = '-Wno-documentation'
|
||||
|
||||
spec = {
|
||||
'name' => "React-Codegen",
|
||||
'version' => version,
|
||||
'summary' => 'Temp pod for generated files for React Native',
|
||||
'homepage' => 'https://facebook.com/',
|
||||
'license' => 'Unlicense',
|
||||
'authors' => 'Facebook',
|
||||
'compiler_flags' => "#{folly_compiler_flags} #{boost_compiler_flags} -Wno-nullability-completeness -std=c++17",
|
||||
'source' => { :git => '' },
|
||||
'header_mappings_dir' => './',
|
||||
'platforms' => {
|
||||
'ios' => '11.0',
|
||||
},
|
||||
'source_files' => "**/*.{h,mm,cpp}",
|
||||
'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" =>
|
||||
[
|
||||
"\"$(PODS_ROOT)/boost\"",
|
||||
"\"$(PODS_ROOT)/RCT-Folly\"",
|
||||
"\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"",
|
||||
"\"$(PODS_ROOT)/Headers/Private/React-Fabric\"",
|
||||
"\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"",
|
||||
].join(' ')
|
||||
},
|
||||
'dependencies': {
|
||||
"FBReactNativeSpec": [version],
|
||||
"React-jsiexecutor": [version],
|
||||
"RCT-Folly": [folly_version],
|
||||
"RCTRequired": [version],
|
||||
"RCTTypeSafety": [version],
|
||||
"React-Core": [version],
|
||||
"React-jsi": [version],
|
||||
"ReactCommon/turbomodule/core": [version]
|
||||
}
|
||||
}
|
||||
|
||||
if fabric_enabled
|
||||
spec[:'dependencies'].merge!({
|
||||
'React-graphics': [version],
|
||||
'React-rncore': [version],
|
||||
});
|
||||
end
|
||||
|
||||
if script_phases
|
||||
Pod::UI.puts "[Codegen] Adding script_phases to React-Codegen."
|
||||
spec[:'script_phases'] = script_phases
|
||||
end
|
||||
|
||||
return spec
|
||||
end
|
||||
|
||||
# It extracts the codegen config from the configuration file
|
||||
#
|
||||
# Parameters
|
||||
# - config_path: a path to the configuration file
|
||||
# - config_ket: the codegen configuration key
|
||||
#
|
||||
# Returns: the list of dependencies as extracted from the package.json
|
||||
def get_codegen_config_from_file(config_path, config_key)
|
||||
empty = {}
|
||||
if !File.exist?(config_path)
|
||||
return empty
|
||||
end
|
||||
|
||||
config = JSON.parse(File.read(config_path))
|
||||
return config[config_key] ? config[config_key] : empty
|
||||
end
|
||||
|
||||
# It creates a list of JS files that contains the JS specifications that Codegen needs to use to generate the code
|
||||
#
|
||||
# Parameters
|
||||
# - app_codegen_config: an object that contains the configurations
|
||||
# - app_path: path to the app
|
||||
#
|
||||
# Returns: the list of files that needs to be used by Codegen
|
||||
def get_list_of_js_specs(app_codegen_config, app_path)
|
||||
file_list = []
|
||||
|
||||
if app_codegen_config['libraries'] then
|
||||
Pod::UI.warn '[Deprecated] You are using the old `libraries` array to list all your codegen.\nThis method will be removed in the future.\nUpdate your `package.json` with a single object.'
|
||||
app_codegen_config['libraries'].each do |library|
|
||||
library_dir = File.join(app_path, library['jsSrcsDir'])
|
||||
file_list.concat(Finder.find_codegen_file(library_dir))
|
||||
end
|
||||
elsif app_codegen_config['jsSrcsDir'] then
|
||||
codegen_dir = File.join(app_path, app_codegen_config['jsSrcsDir'])
|
||||
file_list.concat (Finder.find_codegen_file(codegen_dir))
|
||||
end
|
||||
|
||||
input_files = file_list.map { |filename| "${PODS_ROOT}/../#{Pathname.new(filename).realpath().relative_path_from(Pod::Config.instance.installation_root)}" }
|
||||
|
||||
return input_files
|
||||
end
|
||||
|
||||
# It generates the build script phase for the codegen
|
||||
#
|
||||
# Parameters
|
||||
# - app_path: the path to the app
|
||||
# - fabric_enabled: whether fabric is enabled or not
|
||||
# - config_file_dir: the directory of the config file
|
||||
# - react_native_path: the path to React Native
|
||||
# - config_key: the configuration key to use in the package.json for the Codegen
|
||||
# - codegen_utils: an object which exposes utilities functions for the codegen
|
||||
# - script_phase_extractor: an object that is able to extract the Xcode Script Phases for React Native
|
||||
#
|
||||
# Return: an object containing the script phase
|
||||
def get_react_codegen_script_phases(
|
||||
app_path,
|
||||
fabric_enabled: false,
|
||||
config_file_dir: '',
|
||||
react_native_path: "../node_modules/react-native",
|
||||
config_key: 'codegenConfig',
|
||||
codegen_utils: CodegenUtils.new(),
|
||||
script_phase_extractor: CodegenScriptPhaseExtractor.new()
|
||||
)
|
||||
if !app_path
|
||||
Pod::UI.warn '[Codegen] error: app_path is requried to use codegen discovery.'
|
||||
abort
|
||||
end
|
||||
|
||||
# We need to convert paths to relative path from installation_root for the script phase for CI.
|
||||
relative_app_root = Pathname.new(app_path).realpath().relative_path_from(Pod::Config.instance.installation_root)
|
||||
|
||||
relative_config_file_dir = ''
|
||||
if config_file_dir != ''
|
||||
relative_config_file_dir = Pathname.new(config_file_dir).relative_path_from(Pod::Config.instance.installation_root)
|
||||
end
|
||||
|
||||
# Generate input files for in-app libaraies which will be used to check if the script needs to be run.
|
||||
# TODO: Ideally, we generate the input_files list from generate-artifacts.js and read the result here.
|
||||
# Or, generate this podspec in generate-artifacts.js as well.
|
||||
app_package_path = File.join(app_path, 'package.json')
|
||||
app_codegen_config = codegen_utils.get_codegen_config_from_file(app_package_path, config_key)
|
||||
input_files = codegen_utils.get_list_of_js_specs(app_codegen_config, app_path)
|
||||
|
||||
# Add a script phase to trigger generate artifact.
|
||||
# Some code is duplicated so that it's easier to delete the old way and switch over to this once it's stabilized.
|
||||
return {
|
||||
'name': 'Generate Specs',
|
||||
'execution_position': :before_compile,
|
||||
'input_files' => input_files,
|
||||
'show_env_vars_in_log': true,
|
||||
'output_files': ["${DERIVED_FILE_DIR}/react-codegen.log"],
|
||||
'script': script_phase_extractor.extract_script_phase(
|
||||
react_native_path: react_native_path,
|
||||
relative_app_root: relative_app_root,
|
||||
relative_config_file_dir: relative_config_file_dir,
|
||||
fabric_enabled: fabric_enabled
|
||||
),
|
||||
}
|
||||
end
|
||||
|
||||
def use_react_native_codegen_discovery!(
|
||||
codegen_disabled,
|
||||
app_path,
|
||||
react_native_path: "../node_modules/react-native",
|
||||
fabric_enabled: false,
|
||||
config_file_dir: '',
|
||||
codegen_output_dir: 'build/generated/ios',
|
||||
config_key: 'codegenConfig',
|
||||
folly_version: '2021.07.22.00',
|
||||
codegen_utils: CodegenUtils.new()
|
||||
)
|
||||
return if codegen_disabled
|
||||
|
||||
if CodegenUtils.react_codegen_discovery_done()
|
||||
Pod::UI.puts "[Codegen] Skipping use_react_native_codegen_discovery."
|
||||
return
|
||||
end
|
||||
|
||||
if !app_path
|
||||
Pod::UI.warn '[Codegen] Error: app_path is required for use_react_native_codegen_discovery.'
|
||||
Pod::UI.warn '[Codegen] If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.'
|
||||
abort
|
||||
end
|
||||
|
||||
Pod::UI.warn '[Codegen] warn: using experimental new codegen integration'
|
||||
relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
|
||||
|
||||
# Generate React-Codegen podspec here to add the script phases.
|
||||
script_phases = codegen_utils.get_react_codegen_script_phases(
|
||||
app_path,
|
||||
:fabric_enabled => fabric_enabled,
|
||||
:config_file_dir => config_file_dir,
|
||||
:react_native_path => react_native_path,
|
||||
:config_key => config_key
|
||||
)
|
||||
react_codegen_spec = codegen_utils.get_react_codegen_spec(
|
||||
File.join(react_native_path, "package.json"),
|
||||
:folly_version => folly_version,
|
||||
:fabric_enabled => fabric_enabled,
|
||||
:script_phases => script_phases
|
||||
)
|
||||
codegen_utils.generate_react_codegen_podspec!(react_codegen_spec, codegen_output_dir)
|
||||
|
||||
out = Pod::Executable.execute_command(
|
||||
'node',
|
||||
[
|
||||
"#{relative_installation_root}/#{react_native_path}/scripts/generate-artifacts.js",
|
||||
"-p", "#{app_path}",
|
||||
"-o", Pod::Config.instance.installation_root,
|
||||
"-e", "#{fabric_enabled}",
|
||||
"-c", "#{config_file_dir}",
|
||||
])
|
||||
Pod::UI.puts out;
|
||||
|
||||
CodegenUtils.set_react_codegen_discovery_done(true)
|
||||
end
|
||||
end
|
||||
@@ -18,3 +18,11 @@ class Environment
|
||||
return RUBY_PLATFORM
|
||||
end
|
||||
end
|
||||
|
||||
class Finder
|
||||
def self.find_codegen_file(path)
|
||||
js_files = '-name "Native*.js" -or -name "*NativeComponent.js"'
|
||||
ts_files = '-name "Native*.ts" -or -name "*NativeComponent.ts"'
|
||||
return `find #{path} -type f \\( #{js_files} -or #{ts_files} \\)`.split("\n").sort()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,6 +93,18 @@ class ReactNativePodsUtils
|
||||
end
|
||||
end
|
||||
|
||||
def self.fix_react_bridging_header_search_paths(installer)
|
||||
installer.target_installation_results.pod_target_installation_results
|
||||
.each do |pod_name, target_installation_result|
|
||||
target_installation_result.native_target.build_configurations.each do |config|
|
||||
# For third party modules who have React-bridging dependency to search correct headers
|
||||
config.build_settings['HEADER_SEARCH_PATHS'] ||= '$(inherited) '
|
||||
config.build_settings['HEADER_SEARCH_PATHS'] << '"$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging" '
|
||||
config.build_settings['HEADER_SEARCH_PATHS'] << '"$(PODS_CONFIGURATION_BUILD_DIR)/React-bridging/react_bridging.framework/Headers" '
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.apply_mac_catalyst_patches(installer)
|
||||
# Fix bundle signing issues
|
||||
installer.pods_project.targets.each do |target|
|
||||
@@ -127,10 +139,12 @@ class ReactNativePodsUtils
|
||||
return
|
||||
end
|
||||
|
||||
# $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) causes problem with Xcode 12.5 + arm64 (Apple M1)
|
||||
# since the libraries there are only built for x86_64 and i386.
|
||||
lib_search_paths.delete("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)")
|
||||
lib_search_paths.delete("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
|
||||
if lib_search_paths.include?("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)") || lib_search_paths.include?("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
|
||||
# $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) causes problem with Xcode 12.5 + arm64 (Apple M1)
|
||||
# since the libraries there are only built for x86_64 and i386.
|
||||
lib_search_paths.delete("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)")
|
||||
lib_search_paths.delete("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
|
||||
end
|
||||
|
||||
if !(lib_search_paths.include?("$(SDKROOT)/usr/lib/swift") || lib_search_paths.include?("\"$(SDKROOT)/usr/lib/swift\""))
|
||||
# however, $(SDKROOT)/usr/lib/swift is required, at least if user is not running CocoaPods 1.11
|
||||
|
||||
@@ -13,13 +13,20 @@
|
||||
const underTest = require('../generate-artifacts-executor');
|
||||
const fixtures = require('../__test_fixtures__/fixtures');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const child_process = require('child_process');
|
||||
|
||||
const codegenConfigKey = 'codegenConfig';
|
||||
const reactNativeDependencyName = 'react-native';
|
||||
const rootPath = path.join(__dirname, '../../..');
|
||||
|
||||
describe('generateCode', () => {
|
||||
it('executeNodes with the right arguents', () => {
|
||||
afterEach(() => {
|
||||
jest.resetModules();
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('executeNodes with the right arguments', () => {
|
||||
// Define variables and expected values
|
||||
const iosOutputDir = 'app/ios/build/generated/ios';
|
||||
const library = {config: {name: 'library', type: 'all'}};
|
||||
@@ -32,46 +39,32 @@ describe('generateCode', () => {
|
||||
const tmpOutDir = path.join(tmpDir, 'out');
|
||||
|
||||
// mock used functions
|
||||
let mkdirSyncInvocationCount = 0;
|
||||
jest.mock('fs', () => ({
|
||||
mkdirSync: (location, config) => {
|
||||
if (mkdirSyncInvocationCount === 0) {
|
||||
expect(location).toEqual(tmpOutDir);
|
||||
}
|
||||
if (mkdirSyncInvocationCount === 1) {
|
||||
expect(location).toEqual(iosOutputDir);
|
||||
}
|
||||
|
||||
mkdirSyncInvocationCount += 1;
|
||||
},
|
||||
}));
|
||||
|
||||
let execSyncInvocationCount = 0;
|
||||
jest.mock('child_process', () => ({
|
||||
execSync: command => {
|
||||
if (execSyncInvocationCount === 0) {
|
||||
const expectedCommand = `${node} ${path.join(
|
||||
rnRoot,
|
||||
'generate-specs-cli.js',
|
||||
)} \
|
||||
--platform ios \
|
||||
--schemaPath ${pathToSchema} \
|
||||
--outputDir ${tmpOutDir} \
|
||||
--libraryName ${library.config.name} \
|
||||
--libraryType ${libraryType}`;
|
||||
expect(command).toEqual(expectedCommand);
|
||||
}
|
||||
|
||||
if (execSyncInvocationCount === 1) {
|
||||
expect(command).toEqual(`cp -R ${tmpOutDir}/* ${iosOutputDir}`);
|
||||
}
|
||||
|
||||
execSyncInvocationCount += 1;
|
||||
},
|
||||
}));
|
||||
jest.spyOn(fs, 'mkdirSync').mockImplementation();
|
||||
jest.spyOn(child_process, 'execSync').mockImplementation();
|
||||
|
||||
underTest._generateCode(iosOutputDir, library, tmpDir, node, pathToSchema);
|
||||
expect(mkdirSyncInvocationCount).toBe(2);
|
||||
|
||||
const expectedCommand = `${node} ${path.join(
|
||||
rnRoot,
|
||||
'generate-specs-cli.js',
|
||||
)} --platform ios --schemaPath ${pathToSchema} --outputDir ${tmpOutDir} --libraryName ${
|
||||
library.config.name
|
||||
} --libraryType ${libraryType}`;
|
||||
|
||||
expect(child_process.execSync).toHaveBeenCalledTimes(2);
|
||||
expect(child_process.execSync).toHaveBeenNthCalledWith(1, expectedCommand);
|
||||
expect(child_process.execSync).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
`cp -R ${tmpOutDir}/* ${iosOutputDir}`,
|
||||
);
|
||||
|
||||
expect(fs.mkdirSync).toHaveBeenCalledTimes(2);
|
||||
expect(fs.mkdirSync).toHaveBeenNthCalledWith(1, tmpOutDir, {
|
||||
recursive: true,
|
||||
});
|
||||
expect(fs.mkdirSync).toHaveBeenNthCalledWith(2, iosOutputDir, {
|
||||
recursive: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -202,6 +195,83 @@ describe('extractLibrariesFromJSON', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('findCodegenEnabledLibraries', () => {
|
||||
const mock = require('mock-fs');
|
||||
const {
|
||||
_findCodegenEnabledLibraries: findCodegenEnabledLibraries,
|
||||
} = require('../generate-artifacts-executor');
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
it('returns libraries defined in react-native.config.js', () => {
|
||||
const projectDir = path.join(__dirname, '../../../../test-project');
|
||||
const baseCodegenConfigFileDir = path.join(__dirname, '../../..');
|
||||
const baseCodegenConfigFilePath = path.join(
|
||||
baseCodegenConfigFileDir,
|
||||
'package.json',
|
||||
);
|
||||
|
||||
mock({
|
||||
[baseCodegenConfigFilePath]: `
|
||||
{
|
||||
"codegenConfig": {}
|
||||
}
|
||||
`,
|
||||
[projectDir]: {
|
||||
app: {
|
||||
'package.json': `{
|
||||
"name": "my-app"
|
||||
}`,
|
||||
'react-native.config.js': '',
|
||||
},
|
||||
'library-foo': {
|
||||
'package.json': `{
|
||||
"name": "react-native-foo",
|
||||
"codegenConfig": {
|
||||
"name": "RNFooSpec",
|
||||
"type": "modules",
|
||||
"jsSrcsDir": "src"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
jest.mock(path.join(projectDir, 'app', 'react-native.config.js'), () => ({
|
||||
dependencies: {
|
||||
'react-native-foo': {
|
||||
root: path.join(projectDir, 'library-foo'),
|
||||
},
|
||||
'react-native-bar': {
|
||||
root: path.join(projectDir, 'library-bar'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const libraries = findCodegenEnabledLibraries(
|
||||
`${projectDir}/app`,
|
||||
baseCodegenConfigFileDir,
|
||||
`package.json`,
|
||||
'codegenConfig',
|
||||
);
|
||||
|
||||
expect(libraries).toEqual([
|
||||
{
|
||||
library: 'react-native',
|
||||
config: {},
|
||||
libraryPath: baseCodegenConfigFileDir,
|
||||
},
|
||||
{
|
||||
library: 'react-native-foo',
|
||||
config: {name: 'RNFooSpec', type: 'modules', jsSrcsDir: 'src'},
|
||||
libraryPath: path.join(projectDir, 'library-foo'),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete empty files and folders', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
@@ -51,6 +51,44 @@ function readPackageJSON(appRootDir) {
|
||||
return JSON.parse(fs.readFileSync(path.join(appRootDir, 'package.json')));
|
||||
}
|
||||
|
||||
function printDeprecationWarningIfNeeded(dependency) {
|
||||
if (dependency === REACT_NATIVE_DEPENDENCY_NAME) {
|
||||
return;
|
||||
}
|
||||
console.log(`[Codegen] CodegenConfig Deprecated Setup for ${dependency}.
|
||||
The configuration file still contains the codegen in the libraries array.
|
||||
If possible, replace it with a single object.
|
||||
`);
|
||||
console.debug(`BEFORE:
|
||||
{
|
||||
// ...
|
||||
"codegenConfig": {
|
||||
"libraries": [
|
||||
{
|
||||
"name": "libName1",
|
||||
"type": "all|components|modules",
|
||||
"jsSrcsRoot": "libName1/js"
|
||||
},
|
||||
{
|
||||
"name": "libName2",
|
||||
"type": "all|components|modules",
|
||||
"jsSrcsRoot": "libName2/src"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
AFTER:
|
||||
{
|
||||
"codegenConfig": {
|
||||
"name": "libraries",
|
||||
"type": "all",
|
||||
"jsSrcsRoot": "."
|
||||
}
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
// Reading Libraries
|
||||
function extractLibrariesFromConfigurationArray(
|
||||
configFile,
|
||||
@@ -102,38 +140,7 @@ function extractLibrariesFromJSON(
|
||||
libraryPath: dependencyPath,
|
||||
});
|
||||
} else {
|
||||
console.log(`[Codegen] CodegenConfig Deprecated Setup for ${dependency}.
|
||||
The configuration file still contains the codegen in the libraries array.
|
||||
If possible, replace it with a single object.
|
||||
`);
|
||||
console.debug(`BEFORE:
|
||||
{
|
||||
// ...
|
||||
"codegenConfig": {
|
||||
"libraries": [
|
||||
{
|
||||
"name": "libName1",
|
||||
"type": "all|components|modules",
|
||||
"jsSrcsRoot": "libName1/js"
|
||||
},
|
||||
{
|
||||
"name": "libName2",
|
||||
"type": "all|components|modules",
|
||||
"jsSrcsRoot": "libName2/src"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
AFTER:
|
||||
{
|
||||
"codegenConfig": {
|
||||
"name": "libraries",
|
||||
"type": "all",
|
||||
"jsSrcsRoot": "."
|
||||
}
|
||||
}
|
||||
`);
|
||||
printDeprecationWarningIfNeeded(dependency);
|
||||
extractLibrariesFromConfigurationArray(
|
||||
configFile,
|
||||
codegenConfigKey,
|
||||
@@ -197,6 +204,55 @@ function handleThirdPartyLibraries(
|
||||
});
|
||||
}
|
||||
|
||||
function handleLibrariesFromReactNativeConfig(
|
||||
libraries,
|
||||
codegenConfigKey,
|
||||
codegenConfigFilename,
|
||||
appRootDir,
|
||||
) {
|
||||
const rnConfigFileName = 'react-native.config.js';
|
||||
|
||||
console.log(
|
||||
`\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in ${rnConfigFileName}`,
|
||||
);
|
||||
|
||||
const rnConfigFilePath = path.join(appRootDir, rnConfigFileName);
|
||||
|
||||
if (fs.existsSync(rnConfigFilePath)) {
|
||||
const rnConfig = require(rnConfigFilePath);
|
||||
|
||||
if (rnConfig.dependencies != null) {
|
||||
Object.keys(rnConfig.dependencies).forEach(name => {
|
||||
const dependencyConfig = rnConfig.dependencies[name];
|
||||
|
||||
if (dependencyConfig.root) {
|
||||
const codegenConfigFileDir = path.resolve(
|
||||
appRootDir,
|
||||
dependencyConfig.root,
|
||||
);
|
||||
const configFilePath = path.join(
|
||||
codegenConfigFileDir,
|
||||
codegenConfigFilename,
|
||||
);
|
||||
const pkgJsonPath = path.join(codegenConfigFileDir, 'package.json');
|
||||
|
||||
if (fs.existsSync(configFilePath)) {
|
||||
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath));
|
||||
const configFile = JSON.parse(fs.readFileSync(configFilePath));
|
||||
extractLibrariesFromJSON(
|
||||
configFile,
|
||||
libraries,
|
||||
codegenConfigKey,
|
||||
pkgJson.name,
|
||||
codegenConfigFileDir,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleInAppLibraries(
|
||||
libraries,
|
||||
pkgJson,
|
||||
@@ -355,6 +411,39 @@ function createComponentProvider(
|
||||
}
|
||||
}
|
||||
|
||||
function findCodegenEnabledLibraries(
|
||||
appRootDir,
|
||||
baseCodegenConfigFileDir,
|
||||
codegenConfigFilename,
|
||||
codegenConfigKey,
|
||||
) {
|
||||
const pkgJson = readPackageJSON(appRootDir);
|
||||
const dependencies = {...pkgJson.dependencies, ...pkgJson.devDependencies};
|
||||
const libraries = [];
|
||||
|
||||
handleReactNativeCodeLibraries(
|
||||
libraries,
|
||||
codegenConfigFilename,
|
||||
codegenConfigKey,
|
||||
);
|
||||
handleThirdPartyLibraries(
|
||||
libraries,
|
||||
baseCodegenConfigFileDir,
|
||||
dependencies,
|
||||
codegenConfigFilename,
|
||||
codegenConfigKey,
|
||||
);
|
||||
handleLibrariesFromReactNativeConfig(
|
||||
libraries,
|
||||
codegenConfigKey,
|
||||
codegenConfigFilename,
|
||||
appRootDir,
|
||||
);
|
||||
handleInAppLibraries(libraries, pkgJson, codegenConfigKey, appRootDir);
|
||||
|
||||
return libraries;
|
||||
}
|
||||
|
||||
// It removes all the empty files and empty folders
|
||||
// it finds, starting from `filepath`, recursively.
|
||||
//
|
||||
@@ -422,23 +511,12 @@ function execute(
|
||||
}
|
||||
|
||||
try {
|
||||
const pkgJson = readPackageJSON(appRootDir);
|
||||
const dependencies = {...pkgJson.dependencies, ...pkgJson.devDependencies};
|
||||
const libraries = [];
|
||||
|
||||
handleReactNativeCodeLibraries(
|
||||
libraries,
|
||||
codegenConfigFilename,
|
||||
codegenConfigKey,
|
||||
);
|
||||
handleThirdPartyLibraries(
|
||||
libraries,
|
||||
const libraries = findCodegenEnabledLibraries(
|
||||
appRootDir,
|
||||
baseCodegenConfigFileDir,
|
||||
dependencies,
|
||||
codegenConfigFilename,
|
||||
codegenConfigKey,
|
||||
);
|
||||
handleInAppLibraries(libraries, pkgJson, codegenConfigKey, appRootDir);
|
||||
|
||||
if (libraries.length === 0) {
|
||||
console.log('[Codegen] No codegen-enabled libraries found.');
|
||||
@@ -475,6 +553,7 @@ module.exports = {
|
||||
execute: execute,
|
||||
// exported for testing purposes only:
|
||||
_extractLibrariesFromJSON: extractLibrariesFromJSON,
|
||||
_findCodegenEnabledLibraries: findCodegenEnabledLibraries,
|
||||
_executeNodeScript: executeNodeScript,
|
||||
_generateCode: generateCode,
|
||||
_cleanupEmptyFilesAndFolders: cleanupEmptyFilesAndFolders,
|
||||
|
||||
+51
-250
@@ -11,6 +11,7 @@ require_relative './cocoapods/hermes.rb'
|
||||
require_relative './cocoapods/flipper.rb'
|
||||
require_relative './cocoapods/fabric.rb'
|
||||
require_relative './cocoapods/codegen.rb'
|
||||
require_relative './cocoapods/codegen_utils.rb'
|
||||
require_relative './cocoapods/utils.rb'
|
||||
require_relative './cocoapods/new_architecture.rb'
|
||||
require_relative './cocoapods/local_podspec_patch.rb'
|
||||
@@ -18,28 +19,34 @@ require_relative './cocoapods/local_podspec_patch.rb'
|
||||
$CODEGEN_OUTPUT_DIR = 'build/generated/ios'
|
||||
$CODEGEN_COMPONENT_DIR = 'react/renderer/components'
|
||||
$CODEGEN_MODULE_DIR = '.'
|
||||
$REACT_CODEGEN_PODSPEC_GENERATED = false
|
||||
$REACT_CODEGEN_DISCOVERY_DONE = false
|
||||
|
||||
$START_TIME = Time.now.to_i
|
||||
|
||||
def use_react_native! (options={})
|
||||
# The prefix to react-native
|
||||
prefix = options[:path] ||= "../node_modules/react-native"
|
||||
# Function that setup all the react native dependencies
|
||||
#
|
||||
# Parameters
|
||||
# - path: path to react_native installation.
|
||||
# - fabric_enabled: whether fabric should be enabled or not.
|
||||
# - new_arch_enabled: whether the new architecture should be enabled or not.
|
||||
# - production: whether the dependencies must be installed to target a Debug or a Release build.
|
||||
# - hermes_enabled: whether Hermes should be enabled or not.
|
||||
# - flipper_configuration: The configuration to use for flipper.
|
||||
# - app_path: path to the React Native app. Required by the New Architecture.
|
||||
# - config_file_dir: directory of the `package.json` file, required by the New Architecture.
|
||||
def use_react_native! (
|
||||
path: "../node_modules/react-native",
|
||||
fabric_enabled: false,
|
||||
new_arch_enabled: ENV['RCT_NEW_ARCH_ENABLED'] == '1',
|
||||
production: ENV['PRODUCTION'] == '1',
|
||||
hermes_enabled: true,
|
||||
flipper_configuration: FlipperConfiguration.disabled,
|
||||
app_path: '..',
|
||||
config_file_dir: '')
|
||||
|
||||
# Include Fabric dependencies
|
||||
fabric_enabled = options[:fabric_enabled] ||= false
|
||||
prefix = path
|
||||
|
||||
# New arch enabled
|
||||
new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
||||
|
||||
# Include DevSupport dependency
|
||||
production = options[:production] ||= false
|
||||
|
||||
# Include Hermes dependencies
|
||||
hermes_enabled = options[:hermes_enabled] != nil ? options[:hermes_enabled] : true
|
||||
|
||||
flipper_configuration = options[:flipper_configuration] ||= FlipperConfiguration.disabled
|
||||
# The version of folly that must be used
|
||||
folly_version = '2021.07.22.00'
|
||||
|
||||
ReactNativePodsUtils.warn_if_not_on_arm64()
|
||||
|
||||
@@ -79,21 +86,17 @@ def use_react_native! (options={})
|
||||
pod 'boost', :podspec => "#{prefix}/third-party-podspecs/boost.podspec"
|
||||
pod 'RCT-Folly', :podspec => "#{prefix}/third-party-podspecs/RCT-Folly.podspec", :modular_headers => true
|
||||
|
||||
if new_arch_enabled
|
||||
app_path = options[:app_path]
|
||||
config_file_dir = options[:config_file_dir]
|
||||
use_react_native_codegen_discovery!({
|
||||
react_native_path: prefix,
|
||||
app_path: app_path,
|
||||
fabric_enabled: fabric_enabled,
|
||||
config_file_dir: config_file_dir,
|
||||
})
|
||||
else
|
||||
# Generate a podspec file for generated files.
|
||||
# This gets generated in use_react_native_codegen_discovery when codegen discovery is enabled.
|
||||
react_codegen_spec = get_react_codegen_spec(fabric_enabled: fabric_enabled)
|
||||
generate_react_codegen_podspec!(react_codegen_spec)
|
||||
end
|
||||
run_codegen!(
|
||||
app_path,
|
||||
config_file_dir,
|
||||
:new_arch_enabled => new_arch_enabled,
|
||||
:disable_codegen => ENV['DISABLE_CODEGEN'] == '1',
|
||||
:react_native_path => prefix,
|
||||
:fabric_enabled => fabric_enabled,
|
||||
:codegen_output_dir => $CODEGEN_OUTPUT_DIR,
|
||||
:package_json_file => File.join(__dir__, "..", "package.json"),
|
||||
:folly_version => folly_version
|
||||
)
|
||||
|
||||
pod 'React-Codegen', :path => $CODEGEN_OUTPUT_DIR, :modular_headers => true
|
||||
|
||||
@@ -123,15 +126,27 @@ def use_react_native! (options={})
|
||||
end
|
||||
end
|
||||
|
||||
# It returns the default flags.
|
||||
def get_default_flags()
|
||||
return ReactNativePodsUtils.get_default_flags()
|
||||
end
|
||||
|
||||
# It installs the flipper dependencies into the project.
|
||||
#
|
||||
# Parameters
|
||||
# - versions: a dictionary of Flipper Library -> Versions that can be used to customize which version of Flipper to install.
|
||||
# - configurations: an array of configuration where to install the dependencies.
|
||||
def use_flipper!(versions = {}, configurations: ['Debug'])
|
||||
Pod::UI.warn "use_flipper is deprecated, use the flipper_configuration option in the use_react_native function"
|
||||
use_flipper_pods(versions, :configurations => configurations)
|
||||
end
|
||||
|
||||
# Function that executes after React Native has been installed to configure some flags and build settings.
|
||||
#
|
||||
# Parameters
|
||||
# - installer: the Cocoapod object that allows to customize the project.
|
||||
# - react_native_path: path to React Native.
|
||||
# - mac_catalyst_enabled: whether we are running the Pod on a Mac Catalyst project or not.
|
||||
def react_native_post_install(installer, react_native_path = "../node_modules/react-native", mac_catalyst_enabled: false)
|
||||
ReactNativePodsUtils.apply_mac_catalyst_patches(installer) if mac_catalyst_enabled
|
||||
|
||||
@@ -141,6 +156,7 @@ def react_native_post_install(installer, react_native_path = "../node_modules/re
|
||||
|
||||
ReactNativePodsUtils.exclude_i386_architecture_while_using_hermes(installer)
|
||||
ReactNativePodsUtils.fix_library_search_paths(installer)
|
||||
ReactNativePodsUtils.fix_react_bridging_header_search_paths(installer)
|
||||
ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path)
|
||||
|
||||
NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer)
|
||||
@@ -150,224 +166,9 @@ def react_native_post_install(installer, react_native_path = "../node_modules/re
|
||||
Pod::UI.puts "Pod install took #{Time.now.to_i - $START_TIME} [s] to run".green
|
||||
end
|
||||
|
||||
def get_react_codegen_spec(options={})
|
||||
fabric_enabled = options[:fabric_enabled] ||= false
|
||||
script_phases = options[:script_phases] ||= nil
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "..", "package.json")))
|
||||
version = package['version']
|
||||
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
|
||||
else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
||||
folly_version = '2021.07.22.00'
|
||||
boost_version = '1.76.0'
|
||||
boost_compiler_flags = '-Wno-documentation'
|
||||
|
||||
spec = {
|
||||
'name' => "React-Codegen",
|
||||
'version' => version,
|
||||
'summary' => 'Temp pod for generated files for React Native',
|
||||
'homepage' => 'https://facebook.com/',
|
||||
'license' => 'Unlicense',
|
||||
'authors' => 'Facebook',
|
||||
'compiler_flags' => "#{folly_compiler_flags} #{boost_compiler_flags} -Wno-nullability-completeness -std=c++17",
|
||||
'source' => { :git => '' },
|
||||
'header_mappings_dir' => './',
|
||||
'platforms' => {
|
||||
'ios' => '11.0',
|
||||
},
|
||||
'source_files' => "**/*.{h,mm,cpp}",
|
||||
'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" =>
|
||||
[
|
||||
"\"$(PODS_ROOT)/boost\"",
|
||||
"\"$(PODS_ROOT)/RCT-Folly\"",
|
||||
"\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"",
|
||||
"\"$(PODS_ROOT)/Headers/Private/React-Fabric\"",
|
||||
"\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"",
|
||||
].join(' ')
|
||||
},
|
||||
'dependencies': {
|
||||
"FBReactNativeSpec": [version],
|
||||
"React-jsiexecutor": [version],
|
||||
"RCT-Folly": [folly_version],
|
||||
"RCTRequired": [version],
|
||||
"RCTTypeSafety": [version],
|
||||
"React-Core": [version],
|
||||
"React-jsi": [version],
|
||||
"ReactCommon/turbomodule/core": [version]
|
||||
}
|
||||
}
|
||||
|
||||
if fabric_enabled
|
||||
spec[:'dependencies'].merge!({
|
||||
'React-graphics': [version],
|
||||
'React-rncore': [version],
|
||||
});
|
||||
end
|
||||
|
||||
if script_phases
|
||||
Pod::UI.puts "[Codegen] Adding script_phases to React-Codegen."
|
||||
spec[:'script_phases'] = script_phases
|
||||
end
|
||||
|
||||
return spec
|
||||
end
|
||||
|
||||
def get_codegen_config_from_file(config_path, config_key)
|
||||
empty = {'libraries' => []}
|
||||
if !File.exist?(config_path)
|
||||
return empty
|
||||
end
|
||||
|
||||
config = JSON.parse(File.read(config_path))
|
||||
return config[config_key] ? config[config_key] : empty
|
||||
end
|
||||
|
||||
def get_react_codegen_script_phases(options={})
|
||||
app_path = options[:app_path] ||= ''
|
||||
if !app_path
|
||||
Pod::UI.warn '[Codegen] error: app_path is requried to use codegen discovery.'
|
||||
exit 1
|
||||
end
|
||||
|
||||
# We need to convert paths to relative path from installation_root for the script phase for CI.
|
||||
relative_app_root = Pathname.new(app_path).realpath().relative_path_from(Pod::Config.instance.installation_root)
|
||||
|
||||
config_file_dir = options[:config_file_dir] ||= ''
|
||||
relative_config_file_dir = ''
|
||||
if config_file_dir != ''
|
||||
relative_config_file_dir = Pathname.new(config_file_dir).relative_path_from(Pod::Config.instance.installation_root)
|
||||
end
|
||||
|
||||
fabric_enabled = options[:fabric_enabled] ||= false
|
||||
|
||||
# react_native_path should be relative already.
|
||||
react_native_path = options[:react_native_path] ||= "../node_modules/react-native"
|
||||
|
||||
# Generate input files for in-app libaraies which will be used to check if the script needs to be run.
|
||||
# TODO: Ideally, we generate the input_files list from generate-artifacts.js and read the result here.
|
||||
# Or, generate this podspec in generate-artifacts.js as well.
|
||||
config_key = options[:config_key] ||= 'codegenConfig'
|
||||
app_package_path = File.join(app_path, 'package.json')
|
||||
app_codegen_config = get_codegen_config_from_file(app_package_path, config_key)
|
||||
file_list = []
|
||||
if app_codegen_config['libraries'] then
|
||||
Pod::UI.warn '[Deprecated] You are using the old `libraries` array to list all your codegen.\nThis method will be removed in the future.\nUpdate your `package.json` with a single object.'
|
||||
app_codegen_config['libraries'].each do |library|
|
||||
library_dir = File.join(app_path, library['jsSrcsDir'])
|
||||
file_list.concat (`find #{library_dir} -type f \\( -name "Native*.js" -or -name "*NativeComponent.js" \\)`.split("\n").sort)
|
||||
end
|
||||
elsif app_codegen_config['jsSrcsDir'] then
|
||||
codegen_dir = File.join(app_path, app_codegen_config['jsSrcsDir'])
|
||||
file_list.concat (`find #{codegen_dir} -type f \\( -name "Native*.js" -or -name "*NativeComponent.js" \\)`.split("\n").sort)
|
||||
else
|
||||
Pod::UI.warn '[Error] Codegen not properly configured. Please add the `codegenConf` entry to your `package.json`'
|
||||
exit 1
|
||||
end
|
||||
|
||||
input_files = file_list.map { |filename| "${PODS_ROOT}/../#{Pathname.new(filename).realpath().relative_path_from(Pod::Config.instance.installation_root)}" }
|
||||
|
||||
# Add a script phase to trigger generate artifact.
|
||||
# Some code is duplicated so that it's easier to delete the old way and switch over to this once it's stabilized.
|
||||
return {
|
||||
'name': 'Generate Specs',
|
||||
'execution_position': :before_compile,
|
||||
'input_files' => input_files,
|
||||
'show_env_vars_in_log': true,
|
||||
'output_files': ["${DERIVED_FILE_DIR}/react-codegen.log"],
|
||||
'script': get_script_phases_with_codegen_discovery(
|
||||
react_native_path: react_native_path,
|
||||
relative_app_root: relative_app_root,
|
||||
relative_config_file_dir: relative_config_file_dir,
|
||||
fabric_enabled: fabric_enabled
|
||||
),
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
def set_react_codegen_podspec_generated(value)
|
||||
$REACT_CODEGEN_PODSPEC_GENERATED = value
|
||||
end
|
||||
|
||||
def has_react_codegen_podspec_generated()
|
||||
return $REACT_CODEGEN_PODSPEC_GENERATED
|
||||
end
|
||||
|
||||
def generate_react_codegen_podspec!(spec)
|
||||
# This podspec file should only be create once in the session/pod install.
|
||||
# This happens when multiple targets are calling use_react_native!.
|
||||
if has_react_codegen_podspec_generated()
|
||||
Pod::UI.puts "[Codegen] Skipping React-Codegen podspec generation."
|
||||
return
|
||||
end
|
||||
relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
|
||||
output_dir = "#{relative_installation_root}/#{$CODEGEN_OUTPUT_DIR}"
|
||||
Pod::Executable.execute_command("mkdir", ["-p", output_dir]);
|
||||
|
||||
podspec_path = File.join(output_dir, 'React-Codegen.podspec.json')
|
||||
Pod::UI.puts "[Codegen] Generating #{podspec_path}"
|
||||
|
||||
File.open(podspec_path, 'w') do |f|
|
||||
f.write(spec.to_json)
|
||||
f.fsync
|
||||
end
|
||||
|
||||
set_react_codegen_podspec_generated(true)
|
||||
|
||||
return {
|
||||
"spec" => spec,
|
||||
"path" => $CODEGEN_OUTPUT_DIR, # Path needs to be relative to `Podfile`
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def use_react_native_codegen_discovery!(options={})
|
||||
return if ENV['DISABLE_CODEGEN'] == '1'
|
||||
|
||||
if $REACT_CODEGEN_DISCOVERY_DONE
|
||||
Pod::UI.puts "[Codegen] Skipping use_react_native_codegen_discovery."
|
||||
return
|
||||
end
|
||||
|
||||
Pod::UI.warn '[Codegen] warn: using experimental new codegen integration'
|
||||
react_native_path = options[:react_native_path] ||= "../node_modules/react-native"
|
||||
app_path = options[:app_path]
|
||||
fabric_enabled = options[:fabric_enabled] ||= false
|
||||
config_file_dir = options[:config_file_dir] ||= ''
|
||||
relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
|
||||
|
||||
if !app_path
|
||||
Pod::UI.warn '[Codegen] Error: app_path is required for use_react_native_codegen_discovery.'
|
||||
Pod::UI.warn '[Codegen] If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.'
|
||||
exit 1
|
||||
end
|
||||
|
||||
# Generate React-Codegen podspec here to add the script phases.
|
||||
script_phases = get_react_codegen_script_phases(options)
|
||||
react_codegen_spec = get_react_codegen_spec(fabric_enabled: fabric_enabled, script_phases: script_phases)
|
||||
generate_react_codegen_podspec!(react_codegen_spec)
|
||||
|
||||
out = Pod::Executable.execute_command(
|
||||
'node',
|
||||
[
|
||||
"#{relative_installation_root}/#{react_native_path}/scripts/generate-artifacts.js",
|
||||
"-p", "#{app_path}",
|
||||
"-o", Pod::Config.instance.installation_root,
|
||||
"-e", "#{fabric_enabled}",
|
||||
"-c", "#{config_file_dir}",
|
||||
])
|
||||
Pod::UI.puts out;
|
||||
|
||||
$REACT_CODEGEN_DISCOVERY_DONE = true
|
||||
end
|
||||
|
||||
# === LEGACY METHOD ===
|
||||
# We need to keep this while we continue to support the old architecture.
|
||||
# =====================
|
||||
def use_react_native_codegen!(spec, options={})
|
||||
return if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
||||
# TODO: Once the new codegen approach is ready for use, we should output a warning here to let folks know to migrate.
|
||||
|
||||
@@ -33,7 +33,6 @@ selected_vm=""
|
||||
PACKAGE_VERSION=""
|
||||
|
||||
test_android(){
|
||||
generate_maven_artifacts
|
||||
if [ "$1" == "1" ]; then
|
||||
test_android_hermes
|
||||
elif [ "$1" == "2" ]; then
|
||||
@@ -43,7 +42,8 @@ test_android(){
|
||||
|
||||
generate_maven_artifacts(){
|
||||
rm -rf android
|
||||
./gradlew :ReactAndroid:installArchives || error "Couldn't generate artifacts"
|
||||
./gradlew :ReactAndroid:installArchives || error "Couldn't generate React Native Maven artifacts"
|
||||
./gradlew :ReactAndroid:hermes-engine:installArchives || error "Couldn't generate Hermes Engine Maven artifacts"
|
||||
|
||||
success "Generated artifacts for Maven"
|
||||
}
|
||||
@@ -109,6 +109,10 @@ kill_packagers(){
|
||||
init_template_app(){
|
||||
kill_packagers
|
||||
|
||||
if [ "$selected_platform" == "1" ]; then
|
||||
generate_maven_artifacts
|
||||
fi
|
||||
|
||||
PACKAGE_VERSION=$(cat package.json \
|
||||
| grep version \
|
||||
| head -1 \
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
hermes-2022-09-14-RNv0.70.1-2a6b111ab289b55d7b78b5fdf105f466ba270fd7
|
||||
@@ -31,8 +31,10 @@ elsif version == '1000.0.0'
|
||||
source[:commit] = `git ls-remote https://github.com/facebook/hermes main | cut -f 1`.strip
|
||||
elsif currentremote.strip.end_with?("facebook/react-native.git") and currentbranch.strip.end_with?("-stable")
|
||||
Pod::UI.puts '[Hermes] Detected that you are on a React Native release branch, building Hermes from source...'.yellow if Object.const_defined?("Pod::UI")
|
||||
hermestag_file = File.join(__dir__, "..", ".hermesversion")
|
||||
hermestag = File.read(hermestag_file).strip
|
||||
source[:git] = git
|
||||
source[:commit] = `git ls-remote https://github.com/facebook/hermes main | cut -f 1`.strip
|
||||
source[:tag] = hermestag
|
||||
else
|
||||
source[:http] = "https://github.com/facebook/react-native/releases/download/v#{version}/hermes-runtime-darwin-v#{version}.tar.gz"
|
||||
end
|
||||
|
||||
@@ -30,6 +30,7 @@ build/
|
||||
local.properties
|
||||
*.iml
|
||||
*.hprof
|
||||
.cxx/
|
||||
|
||||
# node.js
|
||||
#
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
apply plugin: "com.android.application"
|
||||
|
||||
import com.android.build.OutputFile
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
/**
|
||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||
@@ -142,26 +143,14 @@ android {
|
||||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the NDK build only if you decide to opt-in for the New Architecture.
|
||||
// We configure the CMake build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "APP_PLATFORM=android-21",
|
||||
"APP_STL=c++_shared",
|
||||
"NDK_TOOLCHAIN_VERSION=clang",
|
||||
"GENERATED_SRC_DIR=$buildDir/generated/source",
|
||||
"PROJECT_BUILD_DIR=$buildDir",
|
||||
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
|
||||
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
|
||||
"NODE_MODULES_DIR=$rootDir/../node_modules"
|
||||
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
|
||||
cppFlags "-std=c++17"
|
||||
// Make sure this target name is the same you specify inside the
|
||||
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
|
||||
targets "helloworld_appmodules"
|
||||
// Fix for windows limit on number of character in file paths and in command lines
|
||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
arguments "NDK_APP_SHORT_COMMANDS=true"
|
||||
}
|
||||
cmake {
|
||||
arguments "-DPROJECT_BUILD_DIR=$buildDir",
|
||||
"-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
|
||||
"-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
|
||||
"-DNODE_MODULES_DIR=$rootDir/../node_modules",
|
||||
"-DANDROID_STL=c++_shared"
|
||||
}
|
||||
}
|
||||
if (!enableSeparateBuildPerCPUArchitecture) {
|
||||
@@ -175,8 +164,8 @@ android {
|
||||
if (isNewArchitectureEnabled()) {
|
||||
// We configure the NDK build only if you decide to opt-in for the New Architecture.
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path "$projectDir/src/main/jni/Android.mk"
|
||||
cmake {
|
||||
path "$projectDir/src/main/jni/CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
|
||||
@@ -198,15 +187,15 @@ android {
|
||||
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
|
||||
|
||||
// Due to a bug inside AGP, we have to explicitly set a dependency
|
||||
// between configureNdkBuild* tasks and the preBuild tasks.
|
||||
// between configureCMakeDebug* tasks and the preBuild tasks.
|
||||
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
|
||||
configureNdkBuildRelease.dependsOn(preReleaseBuild)
|
||||
configureNdkBuildDebug.dependsOn(preDebugBuild)
|
||||
configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
|
||||
configureCMakeDebug.dependsOn(preDebugBuild)
|
||||
reactNativeArchitectures().each { architecture ->
|
||||
tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
|
||||
tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
|
||||
dependsOn("preDebugBuild")
|
||||
}
|
||||
tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
|
||||
tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
|
||||
dependsOn("preReleaseBuild")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
THIS_DIR := $(call my-dir)
|
||||
|
||||
include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
|
||||
|
||||
# If you wish to add a custom TurboModule or Fabric component in your app you
|
||||
# will have to include the following autogenerated makefile.
|
||||
# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
|
||||
|
||||
# Includes the MK file for autolinked libraries
|
||||
include $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni/Android-rncli.mk
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_PATH := $(THIS_DIR)
|
||||
|
||||
# You can customize the name of your application .so file here.
|
||||
LOCAL_MODULE := helloworld_appmodules
|
||||
|
||||
# The generated/rncli/src/main/jni folder contains Autolinking support files.
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH) $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni
|
||||
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) $(wildcard $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni/*.cpp)
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(PROJECT_BUILD_DIR)/generated/rncli/src/main/jni
|
||||
|
||||
# Here you should add any native library you wish to depend on.
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libfabricjni \
|
||||
libfbjni \
|
||||
libfolly_runtime \
|
||||
libglog \
|
||||
libjsi \
|
||||
libreact_codegen_rncore \
|
||||
libreact_debug \
|
||||
libreact_nativemodule_core \
|
||||
libreact_render_componentregistry \
|
||||
libreact_render_core \
|
||||
libreact_render_debug \
|
||||
libreact_render_graphics \
|
||||
librrc_view \
|
||||
libruntimeexecutor \
|
||||
libturbomodulejsijni \
|
||||
libyoga
|
||||
|
||||
# Autolinked libraries
|
||||
LOCAL_SHARED_LIBRARIES += $(call import-codegen-modules)
|
||||
|
||||
# If you wish to add a custom TurboModule or Fabric component in your app you
|
||||
# will have to link against it here:
|
||||
# LOCAL_SHARED_LIBRARIES += \
|
||||
# libreact_codegen_<your library name>
|
||||
|
||||
LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
# Define the library name here.
|
||||
project(helloworld_appmodules)
|
||||
|
||||
# This file includes all the necessary to let you build your application with the New Architecture.
|
||||
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)
|
||||
@@ -1,5 +1,3 @@
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "18.1.0",
|
||||
"react-native": "1000.0.0"
|
||||
"react-native": "0.70.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
@@ -20,7 +20,7 @@
|
||||
"babel-jest": "^26.6.3",
|
||||
"eslint": "^7.32.0",
|
||||
"jest": "^26.6.3",
|
||||
"metro-react-native-babel-preset": "^0.71.3",
|
||||
"metro-react-native-babel-preset": "0.72.3",
|
||||
"react-test-renderer": "18.1.0"
|
||||
},
|
||||
"jest": {
|
||||
|
||||
Reference in New Issue
Block a user