mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Require Flow types in all react-native source files (#45786)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45786 Following D60377082, `packages/react-native/Libraries/` is now 100% parsable by `flow-api-translator` and covered by `flow-api-test`. This diff increases test strictness to preserve this state going forward. Changelog: [Internal] Reviewed By: cortinico Differential Revision: D60377123 fbshipit-source-id: 8c48bdd73d9d0d97a114d553eb70cc01faf18e89
This commit is contained in:
committed by
Facebook GitHub Bot
parent
776e822db5
commit
d17373c4ef
@@ -7739,341 +7739,6 @@ exports[`public API should not change unintentionally Libraries/ReactPrivate/Rea
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/implementations/ReactFabric-dev.js 1`] = `"UNTYPED MODULE"`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/implementations/ReactFabric-prod.js 1`] = `"UNTYPED MODULE"`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/implementations/ReactFabric-profiling.js 1`] = `"UNTYPED MODULE"`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/implementations/ReactNativeRenderer-dev.js 1`] = `"UNTYPED MODULE"`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/implementations/ReactNativeRenderer-prod.js 1`] = `"UNTYPED MODULE"`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js 1`] = `"UNTYPED MODULE"`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/shims/ReactFabric.js 1`] = `
|
||||
"declare module.exports: ReactFabricType;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/shims/ReactFeatureFlags.js 1`] = `
|
||||
"declare const ReactFeatureFlags: { debugRenderPhaseSideEffects: false };
|
||||
declare module.exports: ReactFeatureFlags;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/shims/ReactNative.js 1`] = `
|
||||
"declare module.exports: ReactNativeType;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/shims/ReactNativeTypes.js 1`] = `
|
||||
"export type MeasureOnSuccessCallback = (
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
pageX: number,
|
||||
pageY: number
|
||||
) => void;
|
||||
export type MeasureInWindowOnSuccessCallback = (
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number
|
||||
) => void;
|
||||
export type MeasureLayoutOnSuccessCallback = (
|
||||
left: number,
|
||||
top: number,
|
||||
width: number,
|
||||
height: number
|
||||
) => void;
|
||||
export type AttributeType<T, V> =
|
||||
| true
|
||||
| $ReadOnly<{
|
||||
diff?: (arg1: T, arg2: T) => boolean,
|
||||
process?: (arg1: V) => T,
|
||||
}>;
|
||||
export type AnyAttributeType = AttributeType<$FlowFixMe, $FlowFixMe>;
|
||||
export type AttributeConfiguration = $ReadOnly<{
|
||||
[propName: string]: AnyAttributeType,
|
||||
style: $ReadOnly<{
|
||||
[propName: string]: AnyAttributeType,
|
||||
...
|
||||
}>,
|
||||
...
|
||||
}>;
|
||||
export type PartialAttributeConfiguration = $ReadOnly<{
|
||||
[propName: string]: AnyAttributeType,
|
||||
style?: $ReadOnly<{
|
||||
[propName: string]: AnyAttributeType,
|
||||
...
|
||||
}>,
|
||||
...
|
||||
}>;
|
||||
export type ViewConfig = $ReadOnly<{
|
||||
Commands?: $ReadOnly<{ [commandName: string]: number, ... }>,
|
||||
Constants?: $ReadOnly<{ [name: string]: mixed, ... }>,
|
||||
Manager?: string,
|
||||
NativeProps?: $ReadOnly<{ [propName: string]: string, ... }>,
|
||||
baseModuleName?: ?string,
|
||||
bubblingEventTypes?: $ReadOnly<{
|
||||
[eventName: string]: $ReadOnly<{
|
||||
phasedRegistrationNames: $ReadOnly<{
|
||||
captured: string,
|
||||
bubbled: string,
|
||||
skipBubbling?: ?boolean,
|
||||
}>,
|
||||
}>,
|
||||
...
|
||||
}>,
|
||||
directEventTypes?: $ReadOnly<{
|
||||
[eventName: string]: $ReadOnly<{
|
||||
registrationName: string,
|
||||
}>,
|
||||
...
|
||||
}>,
|
||||
supportsRawText?: boolean,
|
||||
uiViewClassName: string,
|
||||
validAttributes: AttributeConfiguration,
|
||||
}>;
|
||||
export type PartialViewConfig = $ReadOnly<{
|
||||
bubblingEventTypes?: $PropertyType<ViewConfig, \\"bubblingEventTypes\\">,
|
||||
directEventTypes?: $PropertyType<ViewConfig, \\"directEventTypes\\">,
|
||||
supportsRawText?: boolean,
|
||||
uiViewClassName: string,
|
||||
validAttributes?: PartialAttributeConfiguration,
|
||||
}>;
|
||||
export interface INativeMethods {
|
||||
blur(): void;
|
||||
focus(): void;
|
||||
measure(callback: MeasureOnSuccessCallback): void;
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback): void;
|
||||
measureLayout(
|
||||
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail?: () => void
|
||||
): void;
|
||||
setNativeProps(nativeProps: { ... }): void;
|
||||
}
|
||||
export type NativeMethods = $ReadOnly<{|
|
||||
blur(): void,
|
||||
focus(): void,
|
||||
measure(callback: MeasureOnSuccessCallback): void,
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback): void,
|
||||
measureLayout(
|
||||
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail?: () => void
|
||||
): void,
|
||||
setNativeProps(nativeProps: { ... }): void,
|
||||
|}>;
|
||||
export type HostComponent<T> = AbstractComponent<T, $ReadOnly<NativeMethods>>;
|
||||
type SecretInternalsType = {
|
||||
computeComponentStackForErrorReporting(tag: number): string,
|
||||
...
|
||||
};
|
||||
type InspectorDataProps = $ReadOnly<{
|
||||
[propName: string]: string,
|
||||
...
|
||||
}>;
|
||||
type InspectorDataGetter = (
|
||||
<TElementType: ElementType>(
|
||||
componentOrHandle: ElementRef<TElementType> | number
|
||||
) => ?number
|
||||
) => $ReadOnly<{
|
||||
measure: (callback: MeasureOnSuccessCallback) => void,
|
||||
props: InspectorDataProps,
|
||||
}>;
|
||||
export type InspectorData = $ReadOnly<{
|
||||
closestInstance?: mixed,
|
||||
hierarchy: Array<{
|
||||
name: ?string,
|
||||
getInspectorData: InspectorDataGetter,
|
||||
}>,
|
||||
selectedIndex: ?number,
|
||||
props: InspectorDataProps,
|
||||
componentStack: string,
|
||||
}>;
|
||||
export type TouchedViewDataAtPoint = $ReadOnly<{
|
||||
pointerY: number,
|
||||
touchedViewTag?: number,
|
||||
frame: $ReadOnly<{
|
||||
top: number,
|
||||
left: number,
|
||||
width: number,
|
||||
height: number,
|
||||
}>,
|
||||
closestPublicInstance?: PublicInstance,
|
||||
...InspectorData,
|
||||
}>;
|
||||
export type RenderRootOptions = {
|
||||
onUncaughtError?: (
|
||||
error: mixed,
|
||||
errorInfo: { +componentStack?: ?string }
|
||||
) => void,
|
||||
onCaughtError?: (
|
||||
error: mixed,
|
||||
errorInfo: {
|
||||
+componentStack?: ?string,
|
||||
+errorBoundary?: ?React$Component<any, any>,
|
||||
}
|
||||
) => void,
|
||||
onRecoverableError?: (
|
||||
error: mixed,
|
||||
errorInfo: { +componentStack?: ?string }
|
||||
) => void,
|
||||
};
|
||||
export type ReactNativeType = {
|
||||
findHostInstance_DEPRECATED<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number)
|
||||
): ?ElementRef<HostComponent<mixed>>,
|
||||
findNodeHandle<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number)
|
||||
): ?number,
|
||||
isChildPublicInstance(
|
||||
parent: PublicInstance | HostComponent<mixed>,
|
||||
child: PublicInstance | HostComponent<mixed>
|
||||
): boolean,
|
||||
dispatchCommand(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
command: string,
|
||||
args: Array<mixed>
|
||||
): void,
|
||||
sendAccessibilityEvent(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
eventType: string
|
||||
): void,
|
||||
render(
|
||||
element: MixedElement,
|
||||
containerTag: number,
|
||||
callback: ?() => void,
|
||||
options: ?RenderRootOptions
|
||||
): ?ElementRef<ElementType>,
|
||||
unmountComponentAtNode(containerTag: number): void,
|
||||
unmountComponentAtNodeAndRemoveContainer(containerTag: number): void,
|
||||
+unstable_batchedUpdates: <T>(fn: (T) => void, bookkeeping: T) => void,
|
||||
+__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType,
|
||||
...
|
||||
};
|
||||
declare export opaque type Node;
|
||||
declare export opaque type InternalInstanceHandle;
|
||||
type PublicInstance = mixed;
|
||||
type PublicTextInstance = mixed;
|
||||
export type ReactFabricType = {
|
||||
findHostInstance_DEPRECATED<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number)
|
||||
): ?ElementRef<HostComponent<mixed>>,
|
||||
findNodeHandle<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number)
|
||||
): ?number,
|
||||
dispatchCommand(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
command: string,
|
||||
args: Array<mixed>
|
||||
): void,
|
||||
isChildPublicInstance(parent: PublicInstance, child: PublicInstance): boolean,
|
||||
sendAccessibilityEvent(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
eventType: string
|
||||
): void,
|
||||
render(
|
||||
element: MixedElement,
|
||||
containerTag: number,
|
||||
callback: ?() => void,
|
||||
concurrentRoot: ?boolean,
|
||||
options: ?RenderRootOptions
|
||||
): ?ElementRef<ElementType>,
|
||||
unmountComponentAtNode(containerTag: number): void,
|
||||
getNodeFromInternalInstanceHandle(
|
||||
internalInstanceHandle: InternalInstanceHandle
|
||||
): ?Node,
|
||||
getPublicInstanceFromInternalInstanceHandle(
|
||||
internalInstanceHandle: InternalInstanceHandle
|
||||
): PublicInstance | PublicTextInstance | null,
|
||||
...
|
||||
};
|
||||
export type ReactFabricEventTouch = {
|
||||
identifier: number,
|
||||
locationX: number,
|
||||
locationY: number,
|
||||
pageX: number,
|
||||
pageY: number,
|
||||
screenX: number,
|
||||
screenY: number,
|
||||
target: number,
|
||||
timestamp: number,
|
||||
force: number,
|
||||
...
|
||||
};
|
||||
export type ReactFabricEvent = {
|
||||
touches: Array<ReactFabricEventTouch>,
|
||||
changedTouches: Array<ReactFabricEventTouch>,
|
||||
targetTouches: Array<ReactFabricEventTouch>,
|
||||
target: number,
|
||||
...
|
||||
};
|
||||
export type LayoutAnimationType =
|
||||
| \\"spring\\"
|
||||
| \\"linear\\"
|
||||
| \\"easeInEaseOut\\"
|
||||
| \\"easeIn\\"
|
||||
| \\"easeOut\\"
|
||||
| \\"keyboard\\";
|
||||
export type LayoutAnimationProperty =
|
||||
| \\"opacity\\"
|
||||
| \\"scaleX\\"
|
||||
| \\"scaleY\\"
|
||||
| \\"scaleXY\\";
|
||||
export type LayoutAnimationAnimationConfig = $ReadOnly<{
|
||||
duration?: number,
|
||||
delay?: number,
|
||||
springDamping?: number,
|
||||
initialVelocity?: number,
|
||||
type?: LayoutAnimationType,
|
||||
property?: LayoutAnimationProperty,
|
||||
}>;
|
||||
export type LayoutAnimationConfig = $ReadOnly<{
|
||||
duration: number,
|
||||
create?: LayoutAnimationAnimationConfig,
|
||||
update?: LayoutAnimationAnimationConfig,
|
||||
delete?: LayoutAnimationAnimationConfig,
|
||||
}>;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js 1`] = `
|
||||
"declare export const customBubblingEventTypes: {
|
||||
[eventName: string]: $ReadOnly<{
|
||||
phasedRegistrationNames: $ReadOnly<{
|
||||
captured: string,
|
||||
bubbled: string,
|
||||
skipBubbling?: ?boolean,
|
||||
}>,
|
||||
}>,
|
||||
};
|
||||
declare export const customDirectEventTypes: {
|
||||
[eventName: string]: $ReadOnly<{
|
||||
registrationName: string,
|
||||
}>,
|
||||
};
|
||||
declare export function register(
|
||||
name: string,
|
||||
callback: () => ViewConfig
|
||||
): string;
|
||||
declare export function get(name: string): ViewConfig;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Renderer/shims/createReactNativeComponentClass.js 1`] = `
|
||||
"declare const createReactNativeComponentClass: (
|
||||
name: string,
|
||||
callback: () => ViewConfig
|
||||
) => string;
|
||||
declare module.exports: createReactNativeComponentClass;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Settings/NativeSettingsManager.js 1`] = `
|
||||
"export * from \\"../../src/private/specs/modules/NativeSettingsManager\\";
|
||||
declare export default typeof NativeSettingsManager;
|
||||
|
||||
+29
-41
@@ -26,12 +26,11 @@ const IGNORE_PATTERNS = [
|
||||
'**/*.fb.js',
|
||||
'**/*.macos.js',
|
||||
'**/*.windows.js',
|
||||
// Non source files
|
||||
'Libraries/Renderer/implementations/**',
|
||||
'Libraries/Renderer/shims/**',
|
||||
];
|
||||
|
||||
// Exclude list for files that fail to parse under flow-api-translator. Please
|
||||
// review your changes before adding new entries.
|
||||
const FILES_WITH_KNOWN_ERRORS = new Set<string>([]);
|
||||
|
||||
const sourceFiles = [
|
||||
'index.js',
|
||||
...glob.sync(JS_FILES_PATTERN, {
|
||||
@@ -46,47 +45,36 @@ describe('public API', () => {
|
||||
test.each(sourceFiles)('%s', async (file: string) => {
|
||||
const source = await fs.readFile(path.join(PACKAGE_ROOT, file), 'utf-8');
|
||||
|
||||
if (/@flow/.test(source)) {
|
||||
// Require and use adjacent .js.flow file when source file includes an
|
||||
// unsupported-syntax suppression
|
||||
if (source.includes('// $FlowFixMe[unsupported-syntax]')) {
|
||||
const flowDefPath = path.join(
|
||||
PACKAGE_ROOT,
|
||||
file.replace('.js', '.js.flow'),
|
||||
if (!/@flow/.test(source)) {
|
||||
throw new Error(
|
||||
file +
|
||||
' is untyped. All source files in the react-native package must be written using Flow (// @flow).',
|
||||
);
|
||||
}
|
||||
|
||||
// Require and use adjacent .js.flow file when source file includes an
|
||||
// unsupported-syntax suppression
|
||||
if (source.includes('// $FlowFixMe[unsupported-syntax]')) {
|
||||
const flowDefPath = path.join(
|
||||
PACKAGE_ROOT,
|
||||
file.replace('.js', '.js.flow'),
|
||||
);
|
||||
|
||||
if (!existsSync(flowDefPath)) {
|
||||
throw new Error(
|
||||
'Found an unsupported-syntax suppression in ' +
|
||||
file +
|
||||
', meaning types cannot be parsed. Add an adjacent <module>.js.flow file to fix this!',
|
||||
);
|
||||
|
||||
if (!existsSync(flowDefPath)) {
|
||||
throw new Error(
|
||||
'Found an unsupported-syntax suppression in ' +
|
||||
file +
|
||||
', meaning types cannot be parsed. Add an adjacent <module>.js.flow file to fix this!',
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let success = false;
|
||||
try {
|
||||
expect(await translateFlowToExportedAPI(source)).toMatchSnapshot();
|
||||
return;
|
||||
}
|
||||
|
||||
success = true;
|
||||
} catch (e) {
|
||||
if (!FILES_WITH_KNOWN_ERRORS.has(file)) {
|
||||
throw new Error(
|
||||
'Unable to parse file: ' + file + '\n\n' + e.message,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (success && FILES_WITH_KNOWN_ERRORS.has(file)) {
|
||||
throw new Error(
|
||||
'Expected parse error, please remove file exclude from FILES_WITH_KNOWN_ERRORS: ' +
|
||||
file,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expect('UNTYPED MODULE').toMatchSnapshot();
|
||||
try {
|
||||
expect(await translateFlowToExportedAPI(source)).toMatchSnapshot();
|
||||
} catch (e) {
|
||||
throw new Error('Unable to parse file: ' + file + '\n\n' + e.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user