mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Codegen: denote Android/iOS exclusive platform modules in the schema
Summary: Some existing NativeModules have either Android or IOS suffix to denote the exclusive intent for that platform. For now, note this in the codegen schema output, so that the generator can skip irrelevant modules. Long term, each Flow type for module Spec should denote the intended/excluded platforms directly. Changelog: [Internal] Reviewed By: RSNara Differential Revision: D24370568 fbshipit-source-id: 8f725bdb39107d73c1aba0689db7f47ed7c374b0
This commit is contained in:
committed by
Facebook GitHub Bot
parent
3ed38df175
commit
ec094e75bd
@@ -264,6 +264,10 @@ export type NativeModuleSchema = $ReadOnly<{|
|
||||
aliases: NativeModuleAliasMap,
|
||||
spec: NativeModuleSpec,
|
||||
moduleNames: $ReadOnlyArray<string>,
|
||||
// Use for modules that are not used on other platforms.
|
||||
// TODO: It's clearer to define `restrictedToPlatforms` instead, but
|
||||
// `excludedPlatforms` is used here to be consistent with ComponentSchema.
|
||||
excludedPlatforms?: $ReadOnlyArray<PlatformType>,
|
||||
|}>;
|
||||
|
||||
type NativeModuleSpec = $ReadOnly<{|
|
||||
|
||||
+8
-8
@@ -152,12 +152,12 @@ function buildSchema(contents: string, filename: ?string): SchemaType {
|
||||
if (filename === undefined || filename === null) {
|
||||
throw new Error('Filepath expected while parasing a module');
|
||||
}
|
||||
const moduleName = path.basename(filename).replace(/\.js$/, '');
|
||||
const hasteModuleName = path.basename(filename).replace(/\.js$/, '');
|
||||
|
||||
const regex = new RegExp(TURBO_MODULE_REGISTRY_REQUIRE_REGEX_STRING, 'g');
|
||||
let match = regex.exec(contents);
|
||||
|
||||
const errorHeader = `Error while parsing Module '${moduleName}'`;
|
||||
const errorHeader = `Error while parsing Module '${hasteModuleName}'`;
|
||||
|
||||
if (match == null) {
|
||||
throw new Error(
|
||||
@@ -165,23 +165,23 @@ function buildSchema(contents: string, filename: ?string): SchemaType {
|
||||
);
|
||||
}
|
||||
|
||||
const moduleRequires = [];
|
||||
const moduleNames = [];
|
||||
while (match != null) {
|
||||
const resultGroups = match.groups;
|
||||
invariant(
|
||||
resultGroups != null,
|
||||
`Couldn't parse TurboModuleRegistry.(get|getEnforcing)<Spec> call in module '${moduleName}'.`,
|
||||
`Couldn't parse TurboModuleRegistry.(get|getEnforcing)<Spec> call in module '${hasteModuleName}'.`,
|
||||
);
|
||||
|
||||
if (!moduleRequires.includes(resultGroups.nativeModuleName)) {
|
||||
moduleRequires.push(resultGroups.nativeModuleName);
|
||||
if (!moduleNames.includes(resultGroups.nativeModuleName)) {
|
||||
moduleNames.push(resultGroups.nativeModuleName);
|
||||
}
|
||||
match = regex.exec(contents);
|
||||
}
|
||||
|
||||
return wrapModuleSchema(
|
||||
buildModuleSchema(moduleName, moduleRequires, types),
|
||||
moduleName,
|
||||
buildModuleSchema(hasteModuleName, moduleNames, types),
|
||||
hasteModuleName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+51
-1
@@ -27,7 +27,7 @@ import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
// mo methods
|
||||
// no methods
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
@@ -497,6 +497,54 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
const ANDROID_ONLY_NATIVE_MODULE = `
|
||||
/**
|
||||
* 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';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
// no methods
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModuleAndroid');
|
||||
|
||||
`;
|
||||
|
||||
const IOS_ONLY_NATIVE_MODULE = `
|
||||
/**
|
||||
* 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';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
// no methods
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModuleIOS');
|
||||
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
NATIVE_MODULE_WITH_OBJECT_WITH_OBJECT_DEFINED_IN_FILE_AS_PROPERTY,
|
||||
NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE,
|
||||
@@ -515,4 +563,6 @@ module.exports = {
|
||||
NATIVE_MODULE_WITH_BASIC_PARAM_TYPES,
|
||||
NATIVE_MODULE_WITH_CALLBACK,
|
||||
EMPTY_NATIVE_MODULE,
|
||||
ANDROID_ONLY_NATIVE_MODULE,
|
||||
IOS_ONLY_NATIVE_MODULE,
|
||||
};
|
||||
|
||||
+40
@@ -16,6 +16,26 @@ exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_EXTENDING_TU
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT 1`] = `"File neither contains a module declaration, nor a component declaration. For module declarations, please make sure your file has an InterfaceDeclaration extending TurboModule. For component declarations, please make sure your file has a default export calling the codegenNativeComponent<Props>(...) macro."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser can generate fixture ANDROID_ONLY_NATIVE_MODULE 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliases': {},
|
||||
'spec': {
|
||||
'properties': []
|
||||
},
|
||||
'moduleNames': [
|
||||
'SampleTurboModuleAndroid'
|
||||
],
|
||||
'excludedPlatforms': [
|
||||
'iOS'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser can generate fixture EMPTY_NATIVE_MODULE 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
@@ -33,6 +53,26 @@ exports[`RN Codegen Flow Parser can generate fixture EMPTY_NATIVE_MODULE 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliases': {},
|
||||
'spec': {
|
||||
'properties': []
|
||||
},
|
||||
'moduleNames': [
|
||||
'SampleTurboModuleIOS'
|
||||
],
|
||||
'excludedPlatforms': [
|
||||
'android'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
||||
@@ -363,7 +363,7 @@ function translateFunctionTypeAnnotation(
|
||||
}
|
||||
|
||||
function buildPropertySchema(
|
||||
moduleName: string,
|
||||
hasteModuleName: string,
|
||||
// TODO(T71778680): This is an ObjectTypeProperty containing either:
|
||||
// - a FunctionTypeAnnotation or GenericTypeAnnotation
|
||||
// - a NullableTypeAnnoation containing a FunctionTypeAnnotation or GenericTypeAnnotation
|
||||
@@ -390,13 +390,13 @@ function buildPropertySchema(
|
||||
optional: property.optional,
|
||||
typeAnnotation: wrapNullable(
|
||||
nullable,
|
||||
translateFunctionTypeAnnotation(moduleName, value, types, aliasMap),
|
||||
translateFunctionTypeAnnotation(hasteModuleName, value, types, aliasMap),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function buildModuleSchema(
|
||||
moduleName: string,
|
||||
hasteModuleName: string,
|
||||
moduleNames: $ReadOnlyArray<string>,
|
||||
types: TypeDeclarationMap,
|
||||
): NativeModuleSchema {
|
||||
@@ -424,6 +424,20 @@ function buildModuleSchema(
|
||||
"Nativemodule interface must be called 'Spec'",
|
||||
);
|
||||
|
||||
// Some module names use platform suffix to indicate platform-exclusive modules.
|
||||
// Eventually this should be made explicit in the Flow type itself.
|
||||
// Also check the hasteModuleName for platform suffix.
|
||||
// Note: this shape is consistent with ComponentSchema.
|
||||
const excludedPlatforms = [];
|
||||
const namesToValidate = [...moduleNames, hasteModuleName];
|
||||
namesToValidate.forEach(name => {
|
||||
if (name.endsWith('Android')) {
|
||||
excludedPlatforms.push('iOS');
|
||||
} else if (name.endsWith('IOS')) {
|
||||
excludedPlatforms.push('android');
|
||||
}
|
||||
});
|
||||
|
||||
const declaration = types[moduleInterfaceName];
|
||||
return (declaration.body.properties: $ReadOnlyArray<$FlowFixMe>)
|
||||
.filter(property => property.type === 'ObjectTypeProperty')
|
||||
@@ -432,7 +446,7 @@ function buildModuleSchema(
|
||||
return {
|
||||
aliasMap: aliasMap,
|
||||
propertySchema: buildPropertySchema(
|
||||
moduleName,
|
||||
hasteModuleName,
|
||||
property,
|
||||
types,
|
||||
aliasMap,
|
||||
@@ -448,6 +462,7 @@ function buildModuleSchema(
|
||||
properties: [...moduleSchema.spec.properties, propertySchema],
|
||||
},
|
||||
moduleNames: moduleSchema.moduleNames,
|
||||
excludedPlatforms: moduleSchema.excludedPlatforms,
|
||||
};
|
||||
},
|
||||
{
|
||||
@@ -455,6 +470,8 @@ function buildModuleSchema(
|
||||
aliases: {},
|
||||
spec: {properties: []},
|
||||
moduleNames: moduleNames,
|
||||
excludedPlatforms:
|
||||
excludedPlatforms.length !== 0 ? [...excludedPlatforms] : undefined,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user