From 371e263847aff41dfd2d77dfcd5072d7e4b4affa Mon Sep 17 00:00:00 2001 From: Tarun Chauhan Date: Fri, 24 Feb 2023 08:00:20 -0800 Subject: [PATCH] create throwIfPartialNotAnnotatingTypeParameter and add extractAnnotatedElement method in parsers (#36272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: > Create a throwIfPartialNotAnnotatingTypeParameter function in the error-utils.js file and extract the error-emitting code from [Flow](https://github.com/facebook/react-native/blob/main/packages/react-native-codegen/src/parsers/flow/modules/index.js#L174-L178) and [Typescript](https://github.com/facebook/react-native/blob/main/packages/react-native-codegen/src/parsers/typescript/modules/index.js#L252-L259) index files. Notice that the way in which the annotatedElement is computed is different, therefore we should add an extractAnnotatedElement function to the Flow and TypeScript parsers. Part of the Codegen ☂️ Issue https://github.com/facebook/react-native/issues/34872 ## Changelog [Internal] [Changed] - create throwIfPartialNotAnnotatingTypeParameter and add extractAnnotatedElement method in parsers Pull Request resolved: https://github.com/facebook/react-native/pull/36272 Test Plan: `yarn jest react-native-codegen` Reviewed By: cipolleschi Differential Revision: D43564134 Pulled By: rshest fbshipit-source-id: 89a6567340a560d7b6c353cfff8a43e2dd0f76cc --- .../src/parsers/__tests__/error-utils-test.js | 76 +++++++++++++++++++ .../src/parsers/error-utils.js | 17 +++++ .../src/parsers/flow/modules/index.js | 17 +++-- .../src/parsers/flow/parser.js | 8 ++ .../src/parsers/parser.js | 12 +++ .../src/parsers/parserMock.js | 9 +++ .../src/parsers/typescript/modules/index.js | 17 +++-- .../src/parsers/typescript/parser.js | 8 ++ 8 files changed, 150 insertions(+), 14 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js b/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js index 51184fdfb85..48ceb29419b 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js @@ -25,6 +25,7 @@ const { throwIfUntypedModule, throwIfUnsupportedFunctionParamTypeAnnotationParserError, throwIfArrayElementTypeAnnotationIsUnsupported, + throwIfPartialNotAnnotatingTypeParameter, } = require('../error-utils'); const { UnsupportedModulePropertyParserError, @@ -720,3 +721,78 @@ describe('throwIfArrayElementTypeAnnotationIsUnsupported', () => { }).not.toThrow(UnsupportedArrayElementTypeAnnotationParserError); }); }); + +describe('throwIfPartialNotAnnotatingTypeParameter', () => { + const flowParser = new FlowParser(); + const typescriptParser = new TypeScriptParser(); + const typerscriptTypeAnnotation = { + typeParameters: { + params: [ + { + typeName: { + name: 'TypeDeclaration', + }, + }, + ], + }, + }; + const flowTypeAnnotation = { + typeParameters: { + params: [ + { + id: { + name: 'TypeDeclaration', + }, + }, + ], + }, + }; + + it('throw error if Partial Not Annotating Type Parameter in Flow', () => { + const types = {}; + + expect(() => { + throwIfPartialNotAnnotatingTypeParameter( + flowTypeAnnotation, + types, + flowParser, + ); + }).toThrowError('Partials only support annotating a type parameter.'); + }); + + it('throw error if Partial Not Annotating Type Parameter in TypeScript', () => { + const types = {}; + + expect(() => { + throwIfPartialNotAnnotatingTypeParameter( + typerscriptTypeAnnotation, + types, + typescriptParser, + ); + }).toThrowError('Partials only support annotating a type parameter.'); + }); + + it('does not throw error if Partial Annotating Type Parameter in Flow', () => { + const types = {TypeDeclaration: {}}; + + expect(() => { + throwIfPartialNotAnnotatingTypeParameter( + flowTypeAnnotation, + types, + flowParser, + ); + }).not.toThrowError(); + }); + + it('does not throw error if Partial Annotating Type Parameter in TypeScript', () => { + const types = {TypeDeclaration: {}}; + + expect(() => { + throwIfPartialNotAnnotatingTypeParameter( + typerscriptTypeAnnotation, + types, + typescriptParser, + ); + }).not.toThrowError(); + }); +}); diff --git a/packages/react-native-codegen/src/parsers/error-utils.js b/packages/react-native-codegen/src/parsers/error-utils.js index fea578eecb8..5bddcf4d3f6 100644 --- a/packages/react-native-codegen/src/parsers/error-utils.js +++ b/packages/react-native-codegen/src/parsers/error-utils.js @@ -13,6 +13,7 @@ import type {NativeModuleTypeAnnotation} from '../CodegenSchema'; import type {ParserType} from './errors'; import type {Parser} from './parser'; +import type {TypeDeclarationMap} from '../parsers/utils'; const { MisnamedModuleInterfaceParserError, @@ -280,6 +281,21 @@ function throwIfIncorrectModuleRegistryCallArgument( } } +function throwIfPartialNotAnnotatingTypeParameter( + typeAnnotation: $FlowFixMe, + types: TypeDeclarationMap, + parser: Parser, +) { + const annotatedElement = parser.extractAnnotatedElement( + typeAnnotation, + types, + ); + + if (!annotatedElement) { + throw new Error('Partials only support annotating a type parameter.'); + } +} + module.exports = { throwIfModuleInterfaceIsMisnamed, throwIfUnsupportedFunctionReturnTypeAnnotationParserError, @@ -295,4 +311,5 @@ module.exports = { throwIfUnsupportedFunctionParamTypeAnnotationParserError, throwIfArrayElementTypeAnnotationIsUnsupported, throwIfIncorrectModuleRegistryCallArgument, + throwIfPartialNotAnnotatingTypeParameter, }; diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index 9b649f98bd4..03dff7ef80a 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -69,6 +69,7 @@ const { throwIfIncorrectModuleRegistryCallArgument, throwIfUntypedModule, throwIfMoreThanOneModuleInterfaceParserError, + throwIfPartialNotAnnotatingTypeParameter, } = require('../../error-utils'); const language = 'Flow'; @@ -168,14 +169,16 @@ function translateTypeAnnotation( ); } - const annotatedElement = - types[typeAnnotation.typeParameters.params[0].id.name]; + const annotatedElement = parser.extractAnnotatedElement( + typeAnnotation, + types, + ); - if (!annotatedElement) { - throw new Error( - 'Partials only support annotating a type parameter.', - ); - } + throwIfPartialNotAnnotatingTypeParameter( + typeAnnotation, + types, + parser, + ); const properties = annotatedElement.right.properties.map(prop => { return { diff --git a/packages/react-native-codegen/src/parsers/flow/parser.js b/packages/react-native-codegen/src/parsers/flow/parser.js index 4eafbdebcb8..4d6e84836a3 100644 --- a/packages/react-native-codegen/src/parsers/flow/parser.js +++ b/packages/react-native-codegen/src/parsers/flow/parser.js @@ -21,6 +21,7 @@ import type { } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type {Parser} from '../parser'; +import type {TypeDeclarationMap} from '../utils'; // $FlowFixMe[untyped-import] there's no flowtype flow-parser const flowParser = require('flow-parser'); @@ -205,6 +206,13 @@ class FlowParser implements Parser { node.extends[0].id.name === 'TurboModule' ); } + + extractAnnotatedElement( + typeAnnotation: $FlowFixMe, + types: TypeDeclarationMap, + ): $FlowFixMe { + return types[typeAnnotation.typeParameters.params[0].id.name]; + } } module.exports = { diff --git a/packages/react-native-codegen/src/parsers/parser.js b/packages/react-native-codegen/src/parsers/parser.js index 5520deccd73..54e9605dafd 100644 --- a/packages/react-native-codegen/src/parsers/parser.js +++ b/packages/react-native-codegen/src/parsers/parser.js @@ -20,6 +20,7 @@ import type { NativeModuleEnumMembers, } from '../CodegenSchema'; import type {ParserType} from './errors'; +import type {TypeDeclarationMap} from './utils'; /** * This is the main interface for Parsers of various languages. @@ -157,4 +158,15 @@ export interface Parser { * Given a node, it returns true if it is a module interface */ isModuleInterface(node: $FlowFixMe): boolean; + + /** + * Given a typeAnnotation, it returns the annotated element. + * @paramater typeAnnotation: the annotation for a type. + * @paramater types: a map of type declarations. + * @returns: the annotated element. + */ + extractAnnotatedElement( + typeAnnotation: $FlowFixMe, + types: TypeDeclarationMap, + ): $FlowFixMe; } diff --git a/packages/react-native-codegen/src/parsers/parserMock.js b/packages/react-native-codegen/src/parsers/parserMock.js index 39e45ee1f2e..75874a0b85e 100644 --- a/packages/react-native-codegen/src/parsers/parserMock.js +++ b/packages/react-native-codegen/src/parsers/parserMock.js @@ -22,6 +22,8 @@ import type { NativeModuleEnumMembers, } from '../CodegenSchema'; +import type {TypeDeclarationMap} from './utils'; + // $FlowFixMe[untyped-import] there's no flowtype flow-parser const flowParser = require('flow-parser'); const { @@ -168,4 +170,11 @@ export class MockedParser implements Parser { node.extends[0].id.name === 'TurboModule' ); } + + extractAnnotatedElement( + typeAnnotation: $FlowFixMe, + types: TypeDeclarationMap, + ): $FlowFixMe { + return types[typeAnnotation.typeParameters.params[0].id.name]; + } } diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index 5b0ff7c7ef2..ab661e0ef15 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -75,6 +75,7 @@ const { throwIfMoreThanOneModuleInterfaceParserError, throwIfIncorrectModuleRegistryCallTypeParameterParserError, throwIfIncorrectModuleRegistryCallArgument, + throwIfPartialNotAnnotatingTypeParameter, } = require('../../error-utils'); const language = 'TypeScript'; @@ -249,14 +250,16 @@ function translateTypeAnnotation( ); } - const annotatedElement = - types[typeAnnotation.typeParameters.params[0].typeName.name]; + const annotatedElement = parser.extractAnnotatedElement( + typeAnnotation, + types, + ); - if (!annotatedElement) { - throw new Error( - 'Partials only support annotating a type parameter.', - ); - } + throwIfPartialNotAnnotatingTypeParameter( + typeAnnotation, + types, + parser, + ); const properties = annotatedElement.typeAnnotation.members.map( member => { diff --git a/packages/react-native-codegen/src/parsers/typescript/parser.js b/packages/react-native-codegen/src/parsers/typescript/parser.js index b200de3bbe5..b050c9a87ac 100644 --- a/packages/react-native-codegen/src/parsers/typescript/parser.js +++ b/packages/react-native-codegen/src/parsers/typescript/parser.js @@ -21,6 +21,7 @@ import type { } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type {Parser} from '../parser'; +import type {TypeDeclarationMap} from '../utils'; // $FlowFixMe[untyped-import] Use flow-types for @babel/parser const babelParser = require('@babel/parser'); @@ -201,6 +202,13 @@ class TypeScriptParser implements Parser { node.extends[0].expression.name === 'TurboModule' ); } + + extractAnnotatedElement( + typeAnnotation: $FlowFixMe, + types: TypeDeclarationMap, + ): $FlowFixMe { + return types[typeAnnotation.typeParameters.params[0].typeName.name]; + } } module.exports = { TypeScriptParser,