From 22d6e04da12d7650a9bf0bcf00c2a5f86aaec62a Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Tue, 29 Sep 2020 14:33:06 -0700 Subject: [PATCH] Clean up Module/Component detection logic in Flow parser Summary: Just broke down getConfigType into two separate functions: `isModule` and `isComponent`. - Cleaned up `isComponent`, to check for the the AST node types. - Re-implemented `isModule` - Improved error messages. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23121896 fbshipit-source-id: 3df2b2e334c4cea8eabe2e73ecb9f1f1217e7be4 --- .../src/parsers/flow/index.js | 87 ++++++++++++------- .../__snapshots__/module-parser-test.js.snap | 7 +- 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/flow/index.js b/packages/react-native-codegen/src/parsers/flow/index.js index 47342b8d87f..aeca0a0a1ad 100644 --- a/packages/react-native-codegen/src/parsers/flow/index.js +++ b/packages/react-native-codegen/src/parsers/flow/index.js @@ -26,7 +26,9 @@ const {processModule} = require('./modules'); * generates them, and flow-parser is not type-safe. In the future, we should find * a way to get these types from our flow parser library. */ -function getTypes(ast): {[declarationName: string]: $FlowFixMe} { +type TypeDeclarations = {|[declarationName: string]: $FlowFixMe|}; + +function getTypes(ast): TypeDeclarations { return ast.body.reduce((types, node) => { if (node.type === 'ExportNamedDeclaration' && node.exportKind === 'type') { if ( @@ -45,58 +47,79 @@ function getTypes(ast): {[declarationName: string]: $FlowFixMe} { }, {}); } -function getConfigType(ast, types): 'module' | 'component' { +function isComponent(ast) { const defaultExports = ast.body.filter( node => node.type === 'ExportDefaultDeclaration', ); - let isComponent = false; - - if (defaultExports.length > 0) { - let declaration = defaultExports[0].declaration; - // codegenNativeComponent can be nested inside a cast - // expression so we need to go one level deeper - if (declaration.type === 'TypeCastExpression') { - declaration = declaration.expression; - } - - isComponent = - declaration && - declaration.callee && - declaration.callee.name === 'codegenNativeComponent'; + if (defaultExports.length === 0) { + return false; } - const typesExtendingTurboModule = Object.keys(types) - .map(typeName => types[typeName]) - .filter( - type => - type.extends && - type.extends[0] && - type.extends[0].id.name === 'TurboModule', - ); + let declaration = defaultExports[0].declaration; + // codegenNativeComponent can be nested inside a cast + // expression so we need to go one level deeper + if (declaration.type === 'TypeCastExpression') { + declaration = declaration.expression; + } - if (typesExtendingTurboModule.length > 1) { + if (declaration.type !== 'CallExpression') { + return false; + } + + return ( + declaration.callee.type === 'Identifier' && + declaration.callee.name === 'codegenNativeComponent' + ); +} + +function isModule(types: TypeDeclarations) { + const declaredModuleNames: Array = Object.keys(types).filter( + (typeName: string) => { + const declaration = types[typeName]; + return ( + declaration.type === 'InterfaceDeclaration' && + declaration.extends.length === 1 && + declaration.extends[0].type === 'InterfaceExtends' && + declaration.extends[0].id.name === 'TurboModule' + ); + }, + ); + + if (declaredModuleNames.length === 0) { + return false; + } + + if (declaredModuleNames.length > 1) { throw new Error( - 'Found two types extending "TurboModule" is one file. Split them into separated files.', + 'File contains declarations of more than one module: ' + + declaredModuleNames.join(', ') + + '. Please declare exactly one module in this file.', ); } - const isModule = typesExtendingTurboModule.length === 1; + return true; +} - if (isModule && isComponent) { +function getConfigType(ast, types: TypeDeclarations): 'module' | 'component' { + const isConfigAComponent = isComponent(ast); + const isConfigAModule = isModule(types); + + if (isConfigAModule && isConfigAComponent) { throw new Error( 'Found type extending "TurboModule" and exported "codegenNativeComponent" declaration in one file. Split them into separated files.', ); } - if (isModule) { + if (isConfigAModule) { return 'module'; - } else if (isComponent) { + } else if (isConfigAComponent) { return 'component'; } else { throw new Error( - `Default export for module specified incorrectly. It should containts - either type extending "TurboModule" or "codegenNativeComponent".`, + '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(...) macro.', ); } } diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-test.js.snap index 08193385e0a..1fcaee4231a 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-test.js.snap @@ -12,12 +12,9 @@ exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_REA exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_UNNAMED_PARAMS 1`] = `"Unsupported type for getBool. Please provide a name for every parameter."`; -exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_EXTENDING_TURBO_MODULE 1`] = `"Found two types extending \\"TurboModule\\" is one file. Split them into separated files."`; +exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_EXTENDING_TURBO_MODULE 1`] = `"File contains declarations of more than one module: Spec, Spec2. Please declare exactly one module in this file."`; -exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT 1`] = ` -"Default export for module specified incorrectly. It should containts - either type extending \\"TurboModule\\" or \\"codegenNativeComponent\\"." -`; +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(...) macro."`; exports[`RN Codegen Flow Parser can generate fixture EMPTY_NATIVE_MODULE 1`] = ` Object {