Skip to content

Commit

Permalink
Extract tryParse (Flow, TypeScript) lambda into `parseObjectPropert…
Browse files Browse the repository at this point in the history
…y` fn (facebook#35076)

Summary:
This PR is a task of facebook#34872

> Extract the content of the tryParse (Flow, TypeScript)lambda into a proper `parseObjectProperty` function into the parsers-commons.js file.
also,
- added new helper fn `isObjectProperty` in `parsers-commons.js` file.
- added tests for `isObjectProperty` and `parseObjectProperty` fn 's

## Changelog

[Internal] [Changed] - Extracted the content of the `tryParse` ([Flow](https://github.com/facebook/react-native/blob/main/packages/react-native-codegen/src/parsers/flow/modules/index.js#L292-L337), [TypeScript](https://github.com/facebook/react-native/blob/main/packages/react-native-codegen/src/parsers/typescript/modules/index.js#L306-L351)) lambda into a proper `parseObjectProperty` fn into the `parsers-commons.js` file.

Pull Request resolved: facebook#35076

Test Plan:
- run
```bash
yarn lint && yarn flow && yarn test-ci
```
- and ensure everything is �

<img width="720" alt="image" src="https://user-images.githubusercontent.com/55224033/200105151-360b9b5e-52c7-4586-89b0-6860e9725f6e.png">

Reviewed By: cortinico

Differential Revision: D40797241

Pulled By: cipolleschi

fbshipit-source-id: 48b8900ead70d5eda2496f9ce044c11a9599a177
  • Loading branch information
Pranav-yadav authored and facebook-github-bot committed Nov 9, 2022
1 parent 114098d commit 5744b21
Show file tree
Hide file tree
Showing 7 changed files with 348 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,29 @@

'use-strict';

import {assertGenericTypeAnnotationHasExactlyOneTypeParameter} from '../parsers-commons';
import type {ParserType} from '../errors';
const {
import {
assertGenericTypeAnnotationHasExactlyOneTypeParameter,
isObjectProperty,
parseObjectProperty,
wrapNullable,
unwrapNullable,
emitUnionTypeAnnotation,
} = require('../parsers-commons.js');
const {UnsupportedUnionTypeAnnotationParserError} = require('../errors');
} from '../parsers-commons';
import type {ParserType} from '../errors';
import type {UnionTypeAnnotationMemberType} from '../../CodegenSchema';

const {
UnsupportedUnionTypeAnnotationParserError,
UnsupportedObjectPropertyTypeAnnotationParserError,
} = require('../errors');

import {MockedParser} from '../parserMock';

const parser = new MockedParser();

const flowTranslateTypeAnnotation = require('../flow/modules/index');
const typeScriptTranslateTypeAnnotation = require('../typescript/modules/index');

describe('wrapNullable', () => {
describe('when nullable is true', () => {
it('returns nullable type annotation', () => {
Expand Down Expand Up @@ -189,6 +199,200 @@ describe('assertGenericTypeAnnotationHasExactlyOneTypeParameter', () => {
});
});

describe('isObjectProperty', () => {
const propertyStub = {
/* type: 'notObjectTypeProperty', */
typeAnnotation: {
typeAnnotation: 'wrongTypeAnnotation',
},
value: 'wrongValue',
name: 'wrongName',
};

describe("when 'language' is 'Flow'", () => {
const language: ParserType = 'Flow';
it("returns 'true' if 'property.type' is 'ObjectTypeProperty'", () => {
const result = isObjectProperty(
{
type: 'ObjectTypeProperty',
...propertyStub,
},
language,
);
expect(result).toEqual(true);
});

it("returns 'true' if 'property.type' is 'ObjectTypeIndexer'", () => {
const result = isObjectProperty(
{
type: 'ObjectTypeIndexer',
...propertyStub,
},
language,
);
expect(result).toEqual(true);
});

it("returns 'false' if 'property.type' is not 'ObjectTypeProperty' or 'ObjectTypeIndexer'", () => {
const result = isObjectProperty(
{
type: 'notObjectTypeProperty',
...propertyStub,
},
language,
);
expect(result).toEqual(false);
});
});

describe("when 'language' is 'TypeScript'", () => {
const language: ParserType = 'TypeScript';
it("returns 'true' if 'property.type' is 'TSPropertySignature'", () => {
const result = isObjectProperty(
{
type: 'TSPropertySignature',
...propertyStub,
},
language,
);
expect(result).toEqual(true);
});

it("returns 'true' if 'property.type' is 'TSIndexSignature'", () => {
const result = isObjectProperty(
{
type: 'TSIndexSignature',
...propertyStub,
},
language,
);
expect(result).toEqual(true);
});

it("returns 'false' if 'property.type' is not 'TSPropertySignature' or 'TSIndexSignature'", () => {
const result = isObjectProperty(
{
type: 'notTSPropertySignature',
...propertyStub,
},
language,
);
expect(result).toEqual(false);
});
});
});

describe('parseObjectProperty', () => {
const moduleName = 'testModuleName';
const types = {['wrongName']: 'wrongType'};
const aliasMap = {};
const tryParse = () => null;
const cxxOnly = false;
const nullable = true;

describe("when 'language' is 'Flow'", () => {
const language: ParserType = 'Flow';
it("throws an 'UnsupportedObjectPropertyTypeAnnotationParserError' error if 'property.type' is not 'ObjectTypeProperty' or 'ObjectTypeIndexer'.", () => {
const property = {
type: 'notObjectTypeProperty',
typeAnnotation: {
type: 'notObjectTypeProperty',
typeAnnotation: 'wrongTypeAnnotation',
},
value: 'wrongValue',
name: 'wrongName',
};
const expected = new UnsupportedObjectPropertyTypeAnnotationParserError(
moduleName,
property,
property.type,
language,
);
expect(() =>
parseObjectProperty(
property,
moduleName,
types,
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
flowTranslateTypeAnnotation,
),
).toThrow(expected);
});
});

describe("when 'language' is 'TypeScript'", () => {
const language: ParserType = 'TypeScript';
it("throws an 'UnsupportedObjectPropertyTypeAnnotationParserError' error if 'property.type' is not 'TSPropertySignature' or 'TSIndexSignature'.", () => {
const property = {
type: 'notTSPropertySignature',
typeAnnotation: {
typeAnnotation: 'wrongTypeAnnotation',
},
value: 'wrongValue',
name: 'wrongName',
};
const expected = new UnsupportedObjectPropertyTypeAnnotationParserError(
moduleName,
property,
property.type,
language,
);
expect(() =>
parseObjectProperty(
property,
moduleName,
types,
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
typeScriptTranslateTypeAnnotation,
),
).toThrow(expected);
});

it("returns a 'NativeModuleBaseTypeAnnotation' object with 'typeAnnotation.type' equal to 'GenericObjectTypeAnnotation', if 'property.type' is 'TSIndexSignature'.", () => {
const property = {
type: 'TSIndexSignature',
typeAnnotation: {
type: 'TSIndexSignature',
typeAnnotation: 'TSIndexSignature',
},
key: {
name: 'testKeyName',
},
value: 'wrongValue',
name: 'wrongName',
parameters: [{name: 'testName'}],
};
const result = parseObjectProperty(
property,
moduleName,
types,
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
typeScriptTranslateTypeAnnotation,
);
const expected = {
name: 'testName',
optional: false,
typeAnnotation: wrapNullable(nullable, {
type: 'GenericObjectTypeAnnotation',
}),
};
expect(result).toEqual(expected);
});
});
});

describe('emitUnionTypeAnnotation', () => {
const hasteModuleName = 'SampleTurboModule';

Expand Down
2 changes: 1 addition & 1 deletion packages/react-native-codegen/src/parsers/error-utils.js
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-local
* @flow strict
* @format
*/

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

'use strict';
Expand Down
76 changes: 15 additions & 61 deletions packages/react-native-codegen/src/parsers/flow/modules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ import type {ParserErrorCapturer, TypeDeclarationMap} from '../../utils';
import type {NativeModuleTypeAnnotation} from '../../../CodegenSchema.js';
const {nullGuard} = require('../../parsers-utils');

const {throwIfMoreThanOneModuleRegistryCalls} = require('../../error-utils');
const {visit, isModuleRegistryCall} = require('../../utils');
const {visit, verifyPlatforms, isModuleRegistryCall} = require('../../utils');
const {resolveTypeAnnotation, getTypes} = require('../utils.js');
const {
unwrapNullable,
wrapNullable,
assertGenericTypeAnnotationHasExactlyOneTypeParameter,
parseObjectProperty,
emitUnionTypeAnnotation,
translateDefault,
} = require('../../parsers-commons');
Expand Down Expand Up @@ -62,15 +62,13 @@ const {
IncorrectModuleRegistryCallArgumentTypeParserError,
} = require('../../errors.js');

const {verifyPlatforms} = require('../../utils');

const {
throwIfUnsupportedFunctionReturnTypeAnnotationParserError,
throwIfModuleInterfaceNotFound,
throwIfModuleInterfaceIsMisnamed,
throwIfPropertyValueTypeIsUnsupported,
throwIfUnusedModuleInterfaceParserError,
throwIfWrongNumberOfCallExpressionArgs,
throwIfMoreThanOneModuleRegistryCalls,
throwIfIncorrectModuleRegistryCallTypeParameterParserError,
throwIfUntypedModule,
throwIfModuleTypeIsUnsupported,
Expand All @@ -79,7 +77,6 @@ const {
} = require('../../error-utils');

const {FlowParser} = require('../parser.js');
const {getKeyName} = require('../../parsers-commons');

const language = 'Flow';
const parser = new FlowParser();
Expand Down Expand Up @@ -262,61 +259,17 @@ function translateTypeAnnotation(
.map<?NamedShape<Nullable<NativeModuleBaseTypeAnnotation>>>(
property => {
return tryParse(() => {
if (
property.type !== 'ObjectTypeProperty' &&
property.type !== 'ObjectTypeIndexer'
) {
throw new UnsupportedObjectPropertyTypeAnnotationParserError(
hasteModuleName,
property,
property.type,
language,
);
}

const {optional = false} = property;
const name = getKeyName(property, hasteModuleName, language);
if (property.type === 'ObjectTypeIndexer') {
return {
name,
optional,
typeAnnotation: emitObject(nullable),
};
}
const [propertyTypeAnnotation, isPropertyNullable] =
unwrapNullable(
translateTypeAnnotation(
hasteModuleName,
property.value,
types,
aliasMap,
tryParse,
cxxOnly,
),
);

if (
propertyTypeAnnotation.type === 'FunctionTypeAnnotation' ||
propertyTypeAnnotation.type === 'PromiseTypeAnnotation' ||
propertyTypeAnnotation.type === 'VoidTypeAnnotation'
) {
throwIfPropertyValueTypeIsUnsupported(
hasteModuleName,
property.value,
property.key,
propertyTypeAnnotation.type,
language,
);
} else {
return {
name,
optional,
typeAnnotation: wrapNullable(
isPropertyNullable,
propertyTypeAnnotation,
),
};
}
return parseObjectProperty(
property,
hasteModuleName,
types,
aliasMap,
tryParse,
cxxOnly,
language,
nullable,
translateTypeAnnotation,
);
});
},
)
Expand Down Expand Up @@ -596,4 +549,5 @@ function buildModuleSchema(

module.exports = {
buildModuleSchema,
flowTranslateTypeAnnotation: translateTypeAnnotation,
};
Loading

0 comments on commit 5744b21

Please sign in to comment.