Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @flow strict-local
* @format
*/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @flow strict-local
* @format
*/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @flow strict-local
* @format
*/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @flow strict-local
* @format
*/

Expand Down
204 changes: 203 additions & 1 deletion packages/react-native-codegen/src/parsers/parsers-commons.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
* @flow strict-local
*/

'use strict';
Expand All @@ -28,6 +28,27 @@ const {
UnsupportedObjectPropertyTypeAnnotationParserError,
} = require('./errors');
const invariant = require('invariant');
const {getTypes, isModuleRegistryCall} = require('./flow/utils');
const {
throwIfIncorrectModuleRegistryCallTypeParameterParserError,
throwIfModuleInterfaceIsMisnamed,
throwIfModuleInterfaceNotFound,
throwIfMoreThanOneModuleInterfaceParserError,
throwIfMoreThanOneModuleRegistryCalls,
throwIfUntypedModule,
throwIfUnusedModuleInterfaceParserError,
throwIfWrongNumberOfCallExpressionArgs,
} = require('./error-utils');
const {verifyPlatforms, visit} = require('./utils');
const {
IncorrectModuleRegistryCallArgumentTypeParserError,
} = require('./errors');
import type {
NativeModuleAliasMap,
NativeModulePropertyShape,
} from '../CodegenSchema';
import type {ParserErrorCapturer} from './utils';
import type {Parser} from './parser';

function wrapModuleSchema(
nativeModuleSchema: NativeModuleSchema,
Expand Down Expand Up @@ -157,6 +178,186 @@ function emitUnionTypeAnnotation(
});
}

function buildModuleSchema(
hasteModuleName: string,
/**
* TODO(T108222691): Use flow-types for @babel/parser
*/
ast: $FlowFixMe,
tryParse: ParserErrorCapturer,
language: ParserType,
parser: Parser,
): NativeModuleSchema {
const types = getTypes(ast);

const moduleSpecs = (Object.values(types): $ReadOnlyArray<$FlowFixMe>).filter(
//$FlowFixMe
isModuleInterface,
);

throwIfModuleInterfaceNotFound(
moduleSpecs.length,
hasteModuleName,
ast,
language,
);

throwIfMoreThanOneModuleInterfaceParserError(
hasteModuleName,
moduleSpecs,
language,
);

const [moduleSpec] = moduleSpecs;

throwIfModuleInterfaceIsMisnamed(hasteModuleName, moduleSpec.id, language);

// Parse Module Names
const moduleName = tryParse((): string => {
const callExpressions = [];
visit(ast, {
CallExpression(node) {
if (isModuleRegistryCall(node)) {
callExpressions.push(node);
}
},
});

throwIfUnusedModuleInterfaceParserError(
hasteModuleName,
moduleSpec,
callExpressions,
language,
);

throwIfMoreThanOneModuleRegistryCalls(
hasteModuleName,
callExpressions,
callExpressions.length,
language,
);

const [callExpression] = callExpressions;
const typeParams =
language === 'TypeScript'
? callExpression.typeParameters
: callExpression.typeArguments;
const methodName = callExpression.callee.property.name;
const callExpressionArgumentType =
language === 'TypeScript' ? 'StringLiteral' : 'Literal';

throwIfWrongNumberOfCallExpressionArgs(
hasteModuleName,
callExpression,
methodName,
callExpression.arguments.length,
language,
);

if (callExpression.arguments[0].type !== callExpressionArgumentType) {
const {type} = callExpression.arguments[0];
throw new IncorrectModuleRegistryCallArgumentTypeParserError(
hasteModuleName,
callExpression.arguments[0],
methodName,
type,
language,
);
}

const $moduleName = callExpression.arguments[0].value;

throwIfUntypedModule(
typeParams,
hasteModuleName,
callExpression,
methodName,
$moduleName,
language,
);

throwIfIncorrectModuleRegistryCallTypeParameterParserError(
hasteModuleName,
typeParams,
methodName,
$moduleName,
language,
);

return $moduleName;
});

const moduleNames = moduleName == null ? [] : [moduleName];

// 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 {cxxOnly, excludedPlatforms} = verifyPlatforms(
hasteModuleName,
moduleNames,
);

let filteredModuleSpec;
if (language === 'TypeScript') {
filteredModuleSpec = moduleSpec.body.body.filter(
property =>
property.type === 'TSMethodSignature' ||
property.type === 'TSPropertySignature',
);
} else {
filteredModuleSpec = moduleSpec.body.properties.filter(
property => property.type === 'ObjectTypeProperty',
);
}

// $FlowFixMe[missing-type-arg]
return filteredModuleSpec
.map<?{
aliasMap: NativeModuleAliasMap,
propertyShape: NativeModulePropertyShape,
}>(property => {
const aliasMap: {...NativeModuleAliasMap} = {};

return tryParse(() => ({
aliasMap: aliasMap,
// $FlowFixMe
propertyShape: buildPropertySchema(
hasteModuleName,
property,
types,
aliasMap,
tryParse,
cxxOnly,
language,
parser,
),
}));
})
.filter(Boolean)
.reduce(
(moduleSchema: NativeModuleSchema, {aliasMap, propertyShape}) => {
return {
type: 'NativeModule',
aliases: {...moduleSchema.aliases, ...aliasMap},
spec: {
properties: [...moduleSchema.spec.properties, propertyShape],
},
moduleNames: moduleSchema.moduleNames,
excludedPlatforms: moduleSchema.excludedPlatforms,
};
},
{
type: 'NativeModule',
aliases: {},
spec: {properties: []},
moduleNames: moduleNames,
excludedPlatforms:
excludedPlatforms.length !== 0 ? [...excludedPlatforms] : undefined,
},
);
}

function getKeyName(
propertyOrIndex: $FlowFixMe,
hasteModuleName: string,
Expand Down Expand Up @@ -189,5 +390,6 @@ module.exports = {
assertGenericTypeAnnotationHasExactlyOneTypeParameter,
emitMixedTypeAnnotation,
emitUnionTypeAnnotation,
buildModuleSchema,
getKeyName,
};