mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: ## Changes 1. In the NativeModule spec parser, the moduleName is now being extracted from the TurboModuleRegistry.get<Spec>(...) call by examining the Flow ast node. Previously, we used regex parsing, which was unsafe because it could be fooled by TurboModuleRegistry.get<Spec>(...) calls in comments. 2. The logic to parse and validate the TurboModuleRegistry.get<Spec>(...) call is now centralized in the NativeModule Spec Parser (it was removed from the react-native-modules ESLint rule). The linter is now only responsible for three things: 1. Detecting if a JavaScript file contains a TurboModuleRegistry.get<Spec> call or a TurboModule interface, and if so 2. Running the NativeModule spec parser on it. 3. It also validates that the Module spec's filename starts with the prefix "Native". The React Native Modules linter now completely delegates to the NativeModules Spec parser, without doing any error checking of its own. If an error is reported by the React Native Modules linter, and that error doesn't have anything to do with the "Native" prefix, then it *must* be addressed. Otherwise, it will cause the NativeModule Spec Parser to fail on that particular spec. Changelog: [Internal] Reviewed By: hramos Differential Revision: D25153243 fbshipit-source-id: da74dbb66b1d8dca3a2b1952402222c6696b73d6
175 lines
4.8 KiB
JavaScript
175 lines
4.8 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its 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
|
|
*/
|
|
|
|
'use strict';
|
|
const NOT_A_NATIVE_COMPONENT = `
|
|
const requireNativeComponent = require('requireNativeComponent');
|
|
|
|
export default 'Not a view config'
|
|
`;
|
|
|
|
const FULL_NATIVE_COMPONENT = `
|
|
// @flow
|
|
|
|
const codegenNativeCommands = require('codegenNativeCommands');
|
|
const codegenNativeComponent = require('codegenNativeComponent');
|
|
|
|
import type {
|
|
Int32,
|
|
BubblingEventHandler,
|
|
DirectEventHandler,
|
|
WithDefault,
|
|
} from 'CodegenFlowtypes';
|
|
import type {NativeComponentType} from 'codegenNativeComponent';
|
|
|
|
import type {ViewProps} from 'ViewPropTypes';
|
|
|
|
type ModuleProps = $ReadOnly<{|
|
|
...ViewProps,
|
|
|
|
// Props
|
|
boolean_default_true_optional_both?: WithDefault<boolean, true>,
|
|
|
|
// Events
|
|
onDirectEventDefinedInlineNull: DirectEventHandler<null>,
|
|
onBubblingEventDefinedInlineNull: BubblingEventHandler<null>,
|
|
|}>;
|
|
|
|
type NativeType = NativeComponentType<ModuleProps>;
|
|
|
|
interface NativeCommands {
|
|
+hotspotUpdate: (viewRef: React.ElementRef<NativeType>, x: Int32, y: Int32) => void;
|
|
+scrollTo: (viewRef: React.ElementRef<NativeType>, y: Int32, animated: boolean) => void;
|
|
}
|
|
|
|
export const Commands = codegenNativeCommands<NativeCommands>({
|
|
supportedCommands: ['hotspotUpdate', 'scrollTo'],
|
|
});
|
|
|
|
export default codegenNativeComponent<ModuleProps>('Module', {
|
|
interfaceOnly: true,
|
|
paperComponentName: 'RCTModule',
|
|
});
|
|
`;
|
|
|
|
const FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT = `
|
|
// @flow
|
|
|
|
const codegenNativeCommands = require('codegenNativeCommands');
|
|
const codegenNativeComponent = require('codegenNativeComponent');
|
|
import type {NativeComponentType} from 'codegenNativeComponent';
|
|
|
|
import type {
|
|
Int32,
|
|
BubblingEventHandler,
|
|
DirectEventHandler,
|
|
WithDefault,
|
|
} from 'CodegenFlowtypes';
|
|
|
|
import type {ViewProps} from 'ViewPropTypes';
|
|
|
|
type ModuleProps = $ReadOnly<{|
|
|
...ViewProps,
|
|
|
|
// Props
|
|
boolean_default_true_optional_both?: WithDefault<boolean, true>,
|
|
|
|
// Events
|
|
onDirectEventDefinedInlineNull: DirectEventHandler<null>,
|
|
onBubblingEventDefinedInlineNull: BubblingEventHandler<null>,
|
|
|}>;
|
|
|
|
type NativeType = NativeComponentType<ModuleProps>;
|
|
|
|
interface NativeCommands {
|
|
+hotspotUpdate: (viewRef: React.ElementRef<NativeType>, x: Int32, y: Int32) => void;
|
|
+scrollTo: (viewRef: React.ElementRef<NativeType>, y: Int32, animated: boolean) => void;
|
|
}
|
|
|
|
export const Commands = codegenNativeCommands<NativeCommands>({
|
|
supportedCommands: ['hotspotUpdate', 'scrollTo'],
|
|
});
|
|
|
|
export default (codegenNativeComponent<ModuleProps>('Module', {
|
|
interfaceOnly: true,
|
|
paperComponentName: 'RCTModule',
|
|
}): NativeType);
|
|
`;
|
|
|
|
const SAMPLE_TURBO_MODULE_SINGLE_DEFAULT_EXPORT = `
|
|
// @flow
|
|
|
|
import type {RootTag, TurboModule} from '../RCTExport';
|
|
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
|
|
|
export interface Spec extends TurboModule {
|
|
// Exported methods.
|
|
+getConstants: () => {|
|
|
const1: boolean,
|
|
const2: number,
|
|
const3: string,
|
|
|};
|
|
+voidFunc: () => void;
|
|
+getBool: (arg: boolean) => boolean;
|
|
+getNumber: (arg: number) => number;
|
|
+getString: (arg: string) => string;
|
|
+getArray: (arg: Array<any>) => Array<any>;
|
|
+getObject: (arg: Object) => Object;
|
|
+getRootTag: (arg: RootTag) => RootTag;
|
|
+getValue: (x: number, y: string, z: Object) => Object;
|
|
+getValueWithCallback: (callback: (value: string) => void) => void;
|
|
+getValueWithPromise: (error: boolean) => Promise<string>;
|
|
}
|
|
|
|
export default (TurboModuleRegistry.getEnforcing<Spec>(
|
|
'SampleTurboModule',
|
|
): Spec);
|
|
`;
|
|
|
|
const SAMPLE_TURBO_MODULE_VARIABLE_ASSIGNMENT = `
|
|
// @flow
|
|
|
|
import type {RootTag, TurboModule} from '../RCTExport';
|
|
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
|
|
|
export interface Spec extends TurboModule {
|
|
// Exported methods.
|
|
+getConstants: () => {|
|
|
const1: boolean,
|
|
const2: number,
|
|
const3: string,
|
|
|};
|
|
+voidFunc: () => void;
|
|
+getBool: (arg: boolean) => boolean;
|
|
+getNumber: (arg: number) => number;
|
|
+getString: (arg: string) => string;
|
|
+getArray: (arg: Array<any>) => Array<any>;
|
|
+getObject: (arg: Object) => Object;
|
|
+getRootTag: (arg: RootTag) => RootTag;
|
|
+getValue: (x: number, y: string, z: Object) => Object;
|
|
+getValueWithCallback: (callback: (value: string) => void) => void;
|
|
+getValueWithPromise: (error: boolean) => Promise<string>;
|
|
}
|
|
|
|
const module = TurboModuleRegistry.getEnforcing<Spec>(
|
|
'SampleTurboModule',
|
|
);
|
|
|
|
export default (module: Spec);
|
|
`;
|
|
|
|
module.exports = {
|
|
'NotANativeComponent.js': NOT_A_NATIVE_COMPONENT,
|
|
'FullNativeComponent.js': FULL_NATIVE_COMPONENT,
|
|
'FullTypedNativeComponent.js': FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT,
|
|
'NativeSampleTurboModule0.js': SAMPLE_TURBO_MODULE_SINGLE_DEFAULT_EXPORT,
|
|
'NativeSampleTurboModule1.js': SAMPLE_TURBO_MODULE_VARIABLE_ASSIGNMENT,
|
|
};
|