Add support for nullable params

Summary:
I'm not very confident with this part, but actually in existing codegen we wrap param into another object marked as `NullableTypeAnnotion`. It makes logic a little  more complicated. Also it allows for multiple `?` before type which is useless in code generation as well as nullable types inside arrays which also does not have impact on a final code generation.
I suggest adding `nullable` field into param which covers all existing cases (and probably all cases needed).

Reviewed By: TheSavior

Differential Revision: D16121609

fbshipit-source-id: 6e086d4d26bbd0aab3015ec7ecae106ebbaa5a2c
This commit is contained in:
Michał Osadnik
2019-07-08 09:40:21 -07:00
committed by Facebook Github Bot
parent 233c64c675
commit a7664dbaf1
5 changed files with 148 additions and 2 deletions
+1
View File
@@ -178,6 +178,7 @@ export type FunctionTypeAnnotationReturn =
|}>;
export type FunctionTypeAnnotationParam = $ReadOnly<{|
nullable: boolean,
name: string,
typeAnnotation: FunctionTypeAnnotationParamTypeAnnotation,
|}>;
@@ -183,6 +183,54 @@ export default TurboModuleRegistry.getEnforcing<SpecWithTypo>('SampleTurboModule
`;
const NATIVE_MODULE_NULLABLE_BOOLEAN = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {TurboModule} from '../RCTExport';
import * as TurboModuleRegistry from '../TurboModuleRegistry';
export interface Spec extends TurboModule {
+getSth(a : ?boolean) => void
}
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_NULLABLE_NUMBER = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {TurboModule} from '../RCTExport';
import * as TurboModuleRegistry from '../TurboModuleRegistry';
export interface Spec extends TurboModule {
+getSth(a : ?number) => void
}
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
@@ -352,6 +400,8 @@ module.exports = {
NATIVE_MODULES_WITH_PROMISE_WITHOUT_TYPE,
NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT_AS_PARAM,
NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT,
NATIVE_MODULE_NULLABLE_BOOLEAN,
NATIVE_MODULE_NULLABLE_NUMBER,
TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT,
NATIVE_MODULES_WITH_NOT_EXISTING_TYPE_AS_PARAM,
NATIVE_MODULES_WITH_NOT_EXISTING_TYPE_AS_RETURN,
@@ -147,6 +147,31 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_NULLABLE_PARAM = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {TurboModule} from '../RCTExport';
import * as TurboModuleRegistry from '../TurboModuleRegistry';
export interface Spec extends TurboModule {
// Exported methods.
+voidFunc: (arg: ?string) => void;
}
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
`;
const NATIVE_MODULE_WITH_BASIC_ARRAY = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
@@ -790,6 +815,7 @@ module.exports = {
NATIVE_MODULE_WITH_PROMISE,
NATIVE_MODULE_WITH_COMPLEX_OBJECTS,
NATIVE_MODULE_WITH_SIMPLE_OBJECT,
NATIVE_MODULE_WITH_NULLABLE_PARAM,
NATIVE_MODULE_WITH_BASIC_ARRAY,
NATIVE_MODULE_WITH_COMPLEX_ARRAY,
NATIVE_MODULE_WITH_ARRAY_WITH_ALIAS,
@@ -8,6 +8,10 @@ exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITHOU
exports[`RN Codegen Flow Parser Fails with error message INCORRECT_NATIVE_MODULES 1`] = `"Interface properties for \\"SpecWithTypo has been specified incorrectly.\\""`;
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULE_NULLABLE_BOOLEAN 1`] = `"Booleans and numbers cannot be nullable for param \\"a in method \\"getSth\\"."`;
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULE_NULLABLE_NUMBER 1`] = `"Booleans and numbers cannot be nullable for param \\"a in method \\"getSth\\"."`;
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT 1`] = `"Unsupported return type for getString: expected to find annotation for type of array contents"`;
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT_AS_PARAM 1`] = `"Unsupported type for getString, param: \\"arg\\": expected to find annotation for type of array contents"`;
@@ -3340,6 +3344,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"elementType": Object {
"type": "StringTypeAnnotation",
@@ -3379,6 +3384,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"elementType": Object {
"type": "StringTypeAnnotation",
@@ -3418,6 +3424,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"type": "BooleanTypeAnnotation",
},
@@ -3436,6 +3443,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"type": "NumberTypeAnnotation",
},
@@ -3454,6 +3462,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"type": "StringTypeAnnotation",
},
@@ -3487,6 +3496,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"elementType": Object {
"elementType": Object {
@@ -3544,6 +3554,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"properties": Array [
Object {
@@ -3594,6 +3605,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"properties": Array [
Object {
@@ -3620,6 +3632,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"properties": Array [
Object {
@@ -3674,6 +3687,40 @@ Object {
}
`;
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NULLABLE_PARAM 1`] = `
Object {
"modules": Object {
"SampleTurboModule": Object {
"nativeModules": Object {
"SampleTurboModule": Object {
"properties": Array [
Object {
"name": "voidFunc",
"typeAnnotation": Object {
"optional": false,
"params": Array [
Object {
"name": "arg",
"nullable": true,
"typeAnnotation": Object {
"type": "StringTypeAnnotation",
},
},
],
"returnTypeAnnotation": Object {
"type": "VoidTypeAnnotation",
},
"type": "FunctionTypeAnnotation",
},
},
],
},
},
},
},
}
`;
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE 1`] = `
Object {
"modules": Object {
@@ -3731,6 +3778,7 @@ Object {
"params": Array [
Object {
"name": "o",
"nullable": false,
"typeAnnotation": Object {
"type": "ObjectWithoutPropertiesTypeAnnotation",
},
@@ -3764,6 +3812,7 @@ Object {
"params": Array [
Object {
"name": "arg",
"nullable": false,
"typeAnnotation": Object {
"type": "NumberTypeAnnotation",
},
+22 -2
View File
@@ -123,16 +123,24 @@ function getElementTypeForArrayOrObject(
function getTypeAnnotationForParam(
name: string,
param,
paramAnnotation,
types: $ReadOnlyArray<TypesAST>,
): FunctionTypeAnnotationParam {
let param = paramAnnotation;
let paramName = param.name.name;
let nullable = false;
if (param.typeAnnotation.type === 'NullableTypeAnnotation') {
nullable = true;
param = paramAnnotation.typeAnnotation;
}
const typeAnnotation = getValueFromTypes(param.typeAnnotation, types);
const paramName = param.name.name;
if (
param.typeAnnotation.type === 'GenericTypeAnnotation' &&
param.typeAnnotation.id.name === 'Object'
) {
return {
nullable,
name: paramName,
typeAnnotation: {
type: 'ObjectWithoutPropertiesTypeAnnotation',
@@ -149,6 +157,7 @@ function getTypeAnnotationForParam(
) {
return {
name: paramName,
nullable,
typeAnnotation: {
type: 'ArrayTypeAnnotation',
elementType: getElementTypeForArrayOrObject(
@@ -167,6 +176,7 @@ function getTypeAnnotationForParam(
}
if (param.typeAnnotation.type === 'ObjectTypeAnnotation') {
return {
nullable,
name: paramName,
typeAnnotation: {
type: 'ObjectTypeAnnotation',
@@ -180,7 +190,17 @@ function getTypeAnnotationForParam(
};
}
const type = typeAnnotation.type;
if (
nullable &&
(type === 'NumberTypeAnnotation' || type === 'BooleanTypeAnnotation')
) {
throw new Error(
`Booleans and numbers cannot be nullable for param "${paramName} in method "${name}".`,
);
}
return {
nullable,
name: paramName,
typeAnnotation: wrapPrimitiveIntoTypeAnnotation(name, type, paramName),
};