chore: Add getKeyName function to codegen Parser class (#35202)

Summary:
This PR adds a  `getKeyName`  function to the codegen Parser class and implements it in the Flow and TypeScript parsers as requested on https://github.com/facebook/react-native/issues/34872.

## Changelog

[Internal] [Added] - Add `getKeyName` function to codegen Parser class

Pull Request resolved: https://github.com/facebook/react-native/pull/35202

Test Plan:
Run `yarn jest react-native-codegen` and ensure CI is green

![image](https://user-images.githubusercontent.com/11707729/200028600-87e9c1d7-d56d-4cf7-bdbc-18bdf1b03fc5.png)

Reviewed By: cipolleschi

Differential Revision: D41081711

Pulled By: jacdebug

fbshipit-source-id: 7ad2953a0e2f90f04d03270bda40d669d4d0d50a
This commit is contained in:
Gabriel Donadel Dall'Agnol 2022-11-10 09:04:48 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 90b6735c3b
Коммит f849f49525
9 изменённых файлов: 210 добавлений и 33 удалений

Просмотреть файл

@ -28,8 +28,10 @@ const {
} = require('../errors');
import {MockedParser} from '../parserMock';
import {TypeScriptParser} from '../typescript/parser';
const parser = new MockedParser();
const typeScriptParser = new TypeScriptParser();
const flowTranslateTypeAnnotation = require('../flow/modules/index');
const typeScriptTranslateTypeAnnotation = require('../typescript/modules/index');
@ -316,9 +318,9 @@ describe('parseObjectProperty', () => {
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
flowTranslateTypeAnnotation,
parser,
),
).toThrow(expected);
});
@ -349,9 +351,9 @@ describe('parseObjectProperty', () => {
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
typeScriptTranslateTypeAnnotation,
parser,
),
).toThrow(expected);
});
@ -377,9 +379,9 @@ describe('parseObjectProperty', () => {
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
typeScriptTranslateTypeAnnotation,
typeScriptParser,
);
const expected = {
name: 'testName',

Просмотреть файл

@ -0,0 +1,129 @@
/**
* Copyright (c) Meta Platforms, Inc. and 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
* @oncall react_native
*/
'use-strict';
const {
UnsupportedObjectPropertyTypeAnnotationParserError,
} = require('../errors');
import {TypeScriptParser} from '../typescript/parser';
import {FlowParser} from '../flow/parser';
const hasteModuleName = 'moduleName';
describe('TypeScriptParser', () => {
const parser = new FlowParser();
describe('getKeyName', () => {
describe('when propertyOrIndex is ObjectTypeProperty', () => {
it('returns property name', () => {
const property = {
type: 'ObjectTypeProperty',
key: {
name: 'propertyName',
},
};
const expected = 'propertyName';
expect(parser.getKeyName(property, hasteModuleName)).toEqual(expected);
});
});
describe('when propertyOrIndex is ObjectTypeIndexer', () => {
it('returns indexer name', () => {
const indexer = {
type: 'ObjectTypeIndexer',
id: {
name: 'indexerName',
},
};
const expected = 'indexerName';
expect(parser.getKeyName(indexer, hasteModuleName)).toEqual(expected);
});
it('returns `key` if indexer has no name', () => {
const indexer = {
type: 'ObjectTypeIndexer',
id: {},
};
const expected = 'key';
expect(parser.getKeyName(indexer, hasteModuleName)).toEqual(expected);
});
});
describe('when propertyOrIndex is not ObjectTypeProperty or ObjectTypeIndexer', () => {
it('throw UnsupportedObjectPropertyTypeAnnotationParserError', () => {
const indexer = {
type: 'EnumDeclaration',
memberType: 'NumberTypeAnnotation',
};
expect(() => parser.getKeyName(indexer, hasteModuleName)).toThrowError(
UnsupportedObjectPropertyTypeAnnotationParserError,
);
});
});
});
});
describe('FlowParser', () => {
const parser = new TypeScriptParser();
describe('getKeyName', () => {
describe('when propertyOrIndex is TSPropertySignature', () => {
it('returns property name', () => {
const property = {
type: 'TSPropertySignature',
key: {
name: 'propertyName',
},
};
const expected = 'propertyName';
expect(parser.getKeyName(property, hasteModuleName)).toEqual(expected);
});
});
describe('when propertyOrIndex is TSIndexSignature', () => {
it('returns indexer name', () => {
const indexer = {
type: 'TSIndexSignature',
parameters: [
{
name: 'indexerName',
},
],
};
const expected = 'indexerName';
expect(parser.getKeyName(indexer, hasteModuleName)).toEqual(expected);
});
});
describe('when propertyOrIndex is not TSPropertySignature or TSIndexSignature', () => {
it('throw UnsupportedObjectPropertyTypeAnnotationParserError', () => {
const indexer = {
type: 'TSEnumDeclaration',
memberType: 'NumberTypeAnnotation',
};
expect(() => parser.getKeyName(indexer, hasteModuleName)).toThrowError(
UnsupportedObjectPropertyTypeAnnotationParserError,
);
});
});
});
});

Просмотреть файл

@ -266,9 +266,9 @@ function translateTypeAnnotation(
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
translateTypeAnnotation,
parser,
);
});
},

Просмотреть файл

@ -13,9 +13,30 @@
import type {ParserType} from '../errors';
import type {Parser} from '../parser';
const {
UnsupportedObjectPropertyTypeAnnotationParserError,
} = require('../errors');
class FlowParser implements Parser {
typeParameterInstantiation: string = 'TypeParameterInstantiation';
getKeyName(propertyOrIndex: $FlowFixMe, hasteModuleName: string): string {
switch (propertyOrIndex.type) {
case 'ObjectTypeProperty':
return propertyOrIndex.key.name;
case 'ObjectTypeIndexer':
// flow index name is optional
return propertyOrIndex.id?.name ?? 'key';
default:
throw new UnsupportedObjectPropertyTypeAnnotationParserError(
hasteModuleName,
propertyOrIndex,
propertyOrIndex.type,
this.language(),
);
}
}
getMaybeEnumMemberType(maybeEnumDeclaration: $FlowFixMe): string {
return maybeEnumDeclaration.body.type
.replace('EnumNumberBody', 'NumberTypeAnnotation')

Просмотреть файл

@ -22,6 +22,14 @@ export interface Parser {
*/
typeParameterInstantiation: string;
/**
* Given a property or an index declaration, it returns the key name.
* @parameter propertyOrIndex: an object containing a property or an index declaration.
* @parameter hasteModuleName: a string with the native module name.
* @returns: the key name.
* @throws if propertyOrIndex does not contain a property or an index declaration.
*/
getKeyName(propertyOrIndex: $FlowFixMe, hasteModuleName: string): string;
/**
* Given a type declaration, it possibly returns the name of the Enum type.
* @parameter maybeEnumDeclaration: an object possibly containing an Enum declaration.

Просмотреть файл

@ -13,9 +13,30 @@
import type {Parser} from './parser';
import type {ParserType} from './errors';
const {
UnsupportedObjectPropertyTypeAnnotationParserError,
} = require('./errors');
export class MockedParser implements Parser {
typeParameterInstantiation: string = 'TypeParameterInstantiation';
getKeyName(propertyOrIndex: $FlowFixMe, hasteModuleName: string): string {
switch (propertyOrIndex.type) {
case 'ObjectTypeProperty':
return propertyOrIndex.key.name;
case 'ObjectTypeIndexer':
// flow index name is optional
return propertyOrIndex.id?.name ?? 'key';
default:
throw new UnsupportedObjectPropertyTypeAnnotationParserError(
hasteModuleName,
propertyOrIndex,
propertyOrIndex.type,
this.language(),
);
}
}
getMaybeEnumMemberType(maybeEnumDeclaration: $FlowFixMe): string {
return maybeEnumDeclaration.body.type
.replace('EnumNumberBody', 'NumberTypeAnnotation')

Просмотреть файл

@ -129,10 +129,12 @@ function parseObjectProperty(
aliasMap: {...NativeModuleAliasMap},
tryParse: ParserErrorCapturer,
cxxOnly: boolean,
language: ParserType,
nullable: boolean,
translateTypeAnnotation: $FlowFixMe,
parser: Parser,
): NamedShape<Nullable<NativeModuleBaseTypeAnnotation>> {
const language = parser.language();
if (!isObjectProperty(property, language)) {
throw new UnsupportedObjectPropertyTypeAnnotationParserError(
hasteModuleName,
@ -143,7 +145,7 @@ function parseObjectProperty(
}
const {optional = false} = property;
const name = getKeyName(property, hasteModuleName, language);
const name = parser.getKeyName(property, hasteModuleName);
const languageTypeAnnotation =
language === 'TypeScript'
? property.typeAnnotation.typeAnnotation
@ -282,31 +284,6 @@ function translateDefault(
);
}
function getKeyName(
propertyOrIndex: $FlowFixMe,
hasteModuleName: string,
language: ParserType,
): string {
switch (propertyOrIndex.type) {
case 'ObjectTypeProperty':
case 'TSPropertySignature':
return propertyOrIndex.key.name;
case 'ObjectTypeIndexer':
// flow index name is optional
return propertyOrIndex.id?.name ?? 'key';
case 'TSIndexSignature':
// TypeScript index name is mandatory
return propertyOrIndex.parameters[0].name;
default:
throw new UnsupportedObjectPropertyTypeAnnotationParserError(
hasteModuleName,
propertyOrIndex,
propertyOrIndex.type,
language,
);
}
}
module.exports = {
wrapModuleSchema,
unwrapNullable,
@ -316,5 +293,4 @@ module.exports = {
parseObjectProperty,
emitUnionTypeAnnotation,
translateDefault,
getKeyName,
};

Просмотреть файл

@ -272,9 +272,9 @@ function translateTypeAnnotation(
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
translateTypeAnnotation,
parser,
);
});
},

Просмотреть файл

@ -13,9 +13,29 @@
import type {ParserType} from '../errors';
import type {Parser} from '../parser';
const {
UnsupportedObjectPropertyTypeAnnotationParserError,
} = require('../errors');
class TypeScriptParser implements Parser {
typeParameterInstantiation: string = 'TSTypeParameterInstantiation';
getKeyName(propertyOrIndex: $FlowFixMe, hasteModuleName: string): string {
switch (propertyOrIndex.type) {
case 'TSPropertySignature':
return propertyOrIndex.key.name;
case 'TSIndexSignature':
return propertyOrIndex.parameters[0].name;
default:
throw new UnsupportedObjectPropertyTypeAnnotationParserError(
hasteModuleName,
propertyOrIndex,
propertyOrIndex.type,
this.language(),
);
}
}
getMaybeEnumMemberType(maybeEnumDeclaration: $FlowFixMe): string {
if (maybeEnumDeclaration.members[0].initializer) {
return maybeEnumDeclaration.members[0].initializer.type