Back out "Back out "[RNCodegen] codegenNativeCommands takes list of supported commands""
Summary: Original commit changeset: 34a8f8395ca7 The problem with the original commit was the usage of optional chaining. This diff removes the usage of optional chaining with good old fashioned null checks. Reviewed By: rickhanlonii Differential Revision: D16593623 fbshipit-source-id: d24cc40c85de9a2e712e5de19e9deb196003ccf2
This commit is contained in:
Родитель
a84a62834c
Коммит
b526f66c19
|
@ -10,7 +10,11 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
function codegenNativeCommands<T>(): T {
|
||||
type Options<T = string> = $ReadOnly<{|
|
||||
supportedCommands: $ReadOnlyArray<T>,
|
||||
|}>;
|
||||
|
||||
function codegenNativeCommands<T>(options: Options<$Keys<T>>): T {
|
||||
return (({}: any): T);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,9 @@ type ModuleProps = $ReadOnly<{|
|
|||
onBubblingEventDefinedInlineNull: BubblingEventHandler<null>,
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>();
|
||||
export const Commands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['hotspotUpdate', 'scrollTo'],
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module', {
|
||||
interfaceOnly: true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"name": "babel-plugin-inline-view-configs",
|
||||
"description": "Babel plugin to inline view configs for React Native",
|
||||
"repository": {
|
||||
|
|
|
@ -41,7 +41,9 @@ export type ModuleProps = $ReadOnly<{|
|
|||
|
||||
export const Commands = codegenNativeCommands<{
|
||||
+hotspotUpdate: (ref: React.Ref<'RCTView'>, x: Int32, y: Int32) => void;
|
||||
}>();
|
||||
}>({
|
||||
supportedCommands: ['hotspotUpdate']
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
@ -79,8 +81,12 @@ export type ModuleProps = $ReadOnly<{|
|
|||
// No props or events
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>();
|
||||
export const Commands2 = codegenNativeCommands<NativeCommands>();
|
||||
export const Commands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['hotspotUpdate']
|
||||
});
|
||||
export const Commands2 = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['hotspotUpdate']
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
@ -118,10 +124,93 @@ export type ModuleProps = $ReadOnly<{|
|
|||
// No props or events
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['hotspotUpdate']
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
||||
const COMMANDS_DEFINED_WITH_MISMATCHED_METHOD_NAMES = `
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const codegenNativeComponent = require('codegenNativeComponent');
|
||||
const codegenNativeCommands = require('codegenNativeCommands');
|
||||
|
||||
import type {
|
||||
Int32,
|
||||
BubblingEventHandler,
|
||||
DirectEventHandler,
|
||||
} from 'CodegenTypes';
|
||||
|
||||
import type {ViewProps} from 'ViewPropTypes';
|
||||
|
||||
interface NativeCommands {
|
||||
+hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void;
|
||||
+scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void;
|
||||
}
|
||||
|
||||
export type ModuleProps = $ReadOnly<{|
|
||||
...ViewProps,
|
||||
// No props or events
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['scrollTo']
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
||||
const COMMANDS_DEFINED_WITHOUT_METHOD_NAMES = `
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const codegenNativeComponent = require('codegenNativeComponent');
|
||||
const codegenNativeCommands = require('codegenNativeCommands');
|
||||
|
||||
import type {
|
||||
Int32,
|
||||
BubblingEventHandler,
|
||||
DirectEventHandler,
|
||||
} from 'CodegenTypes';
|
||||
|
||||
import type {ViewProps} from 'ViewPropTypes';
|
||||
|
||||
interface NativeCommands {
|
||||
+hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void;
|
||||
+scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void;
|
||||
}
|
||||
|
||||
export type ModuleProps = $ReadOnly<{|
|
||||
...ViewProps,
|
||||
// No props or events
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>();
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
||||
const NULLABLE_WITH_DEFAULT = `
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
|
@ -186,6 +275,8 @@ export default codegenNativeComponent<ModuleProps>('Module');
|
|||
module.exports = {
|
||||
COMMANDS_DEFINED_INLINE,
|
||||
COMMANDS_DEFINED_MULTIPLE_TIMES,
|
||||
COMMANDS_DEFINED_WITH_MISMATCHED_METHOD_NAMES,
|
||||
COMMANDS_DEFINED_WITHOUT_METHOD_NAMES,
|
||||
COMMANDS_DEFINED_WITHOUT_REF,
|
||||
NULLABLE_WITH_DEFAULT,
|
||||
NON_OPTIONAL_KEY_WITH_DEFAULT_VALUE,
|
||||
|
|
|
@ -559,7 +559,9 @@ export type ModuleProps = $ReadOnly<{|
|
|||
// No props or events
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>();
|
||||
export const Commands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['hotspotUpdate', 'scrollTo']
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
@ -603,7 +605,9 @@ export type ModuleProps = $ReadOnly<{|
|
|||
// No props or events
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>();
|
||||
export const Commands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['scrollTo']
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
@ -656,7 +660,9 @@ export type ModuleProps = $ReadOnly<{|
|
|||
onDirectEventDefinedInlineWithPaperName: DirectEventHandler<EventInFile, 'paperDirectEventDefinedInlineWithPaperName'>,
|
||||
|}>;
|
||||
|
||||
export const Commands = codegenNativeCommands<NativeCommands>();
|
||||
export const Commands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['scrollTo']
|
||||
});
|
||||
|
||||
export default codegenNativeComponent<ModuleProps>('Module');
|
||||
`;
|
||||
|
|
|
@ -4,6 +4,10 @@ exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_INLINE
|
|||
|
||||
exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_MULTIPLE_TIMES 1`] = `"codegenNativeCommands may only be called once in a file"`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITH_MISMATCHED_METHOD_NAMES 1`] = `"codegenNativeCommands expected the same supportedCommands specified in the NativeCommands interface: hotspotUpdate, scrollTo"`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITHOUT_METHOD_NAMES 1`] = `"codegenNativeCommands must be passed options including the supported commands"`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITHOUT_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.Ref<>"`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NON_OPTIONAL_KEY_WITH_DEFAULT_VALUE 1`] = `"key required_key_with_default must be optional if used with WithDefault<> annotation"`;
|
||||
|
|
|
@ -14,7 +14,7 @@ import type {ComponentSchemaBuilderConfig} from './schema.js';
|
|||
const {getCommands} = require('./commands');
|
||||
const {getEvents} = require('./events');
|
||||
const {getProps} = require('./props');
|
||||
const {getOptions} = require('./options');
|
||||
const {getCommandOptions, getOptions} = require('./options');
|
||||
const {getExtendsProps} = require('./extends');
|
||||
|
||||
function findComponentConfig(ast) {
|
||||
|
@ -58,11 +58,12 @@ function findComponentConfig(ast) {
|
|||
|
||||
const commandsTypeNames = namedExports
|
||||
.map(statement => {
|
||||
let callExpression;
|
||||
let calleeName;
|
||||
try {
|
||||
calleeName = statement.declaration.declarations[0].init.callee.name;
|
||||
callExpression = statement.declaration.declarations[0].init;
|
||||
calleeName = callExpression.callee.name;
|
||||
} catch (e) {
|
||||
// Not a function call
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -70,8 +71,14 @@ function findComponentConfig(ast) {
|
|||
return;
|
||||
}
|
||||
|
||||
const typeArgumentParam =
|
||||
statement.declaration.declarations[0].init.typeArguments.params[0];
|
||||
// const statement.declaration.declarations[0].init
|
||||
if (callExpression.arguments.length !== 1) {
|
||||
throw new Error(
|
||||
'codegenNativeCommands must be passed options including the supported commands',
|
||||
);
|
||||
}
|
||||
|
||||
const typeArgumentParam = callExpression.typeArguments.params[0];
|
||||
|
||||
if (typeArgumentParam.type !== 'GenericTypeAnnotation') {
|
||||
throw new Error(
|
||||
|
@ -79,7 +86,10 @@ function findComponentConfig(ast) {
|
|||
);
|
||||
}
|
||||
|
||||
return typeArgumentParam.id.name;
|
||||
return {
|
||||
commandTypeName: typeArgumentParam.id.name,
|
||||
commandOptionsExpression: callExpression.arguments[0],
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
|
@ -89,7 +99,14 @@ function findComponentConfig(ast) {
|
|||
|
||||
return {
|
||||
...foundConfig,
|
||||
commandTypeName: commandsTypeNames[0],
|
||||
commandTypeName:
|
||||
commandsTypeNames[0] == null
|
||||
? null
|
||||
: commandsTypeNames[0].commandTypeName,
|
||||
commandOptionsExpression:
|
||||
commandsTypeNames[0] == null
|
||||
? null
|
||||
: commandsTypeNames[0].commandOptionsExpression,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -104,7 +121,7 @@ function getPropProperties(propsTypeName, types) {
|
|||
}
|
||||
}
|
||||
|
||||
function getCommandProperties(commandTypeName, types) {
|
||||
function getCommandProperties(commandTypeName, types, commandOptions) {
|
||||
if (commandTypeName == null) {
|
||||
return [];
|
||||
}
|
||||
|
@ -119,13 +136,39 @@ function getCommandProperties(commandTypeName, types) {
|
|||
);
|
||||
}
|
||||
|
||||
let properties;
|
||||
try {
|
||||
return typeAlias.body.properties;
|
||||
properties = typeAlias.body.properties;
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Failed to find type definition for "${commandTypeName}", please check that you have a valid codegen flow file`,
|
||||
);
|
||||
}
|
||||
|
||||
const flowPropertyNames = properties
|
||||
.map(property => property && property.key && property.key.name)
|
||||
.filter(Boolean);
|
||||
|
||||
if (commandOptions == null || commandOptions.supportedCommands == null) {
|
||||
throw new Error(
|
||||
'codegenNativeCommands must be given an options object with supportedCommands array',
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
commandOptions.supportedCommands.length !== flowPropertyNames.length ||
|
||||
!commandOptions.supportedCommands.every(supportedCommand =>
|
||||
flowPropertyNames.includes(supportedCommand),
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
`codegenNativeCommands expected the same supportedCommands specified in the ${commandTypeName} interface: ${flowPropertyNames.join(
|
||||
', ',
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
// $FlowFixMe there's no flowtype for AST
|
||||
|
@ -134,11 +177,18 @@ function processComponent(ast, types): ComponentSchemaBuilderConfig {
|
|||
componentName,
|
||||
propsTypeName,
|
||||
commandTypeName,
|
||||
commandOptionsExpression,
|
||||
optionsExpression,
|
||||
} = findComponentConfig(ast);
|
||||
|
||||
const propProperties = getPropProperties(propsTypeName, types);
|
||||
const commandProperties = getCommandProperties(commandTypeName, types);
|
||||
const commandOptions = getCommandOptions(commandOptionsExpression);
|
||||
|
||||
const commandProperties = getCommandProperties(
|
||||
commandTypeName,
|
||||
types,
|
||||
commandOptions,
|
||||
);
|
||||
|
||||
const extendsProps = getExtendsProps(propProperties);
|
||||
const options = getOptions(optionsExpression);
|
||||
|
|
|
@ -15,6 +15,38 @@ import type {OptionsShape} from '../../../CodegenSchema.js';
|
|||
// $FlowFixMe there's no flowtype for ASTs
|
||||
type OptionsAST = Object;
|
||||
|
||||
export type CommandOptions = $ReadOnly<{|
|
||||
supportedCommands: $ReadOnlyArray<string>,
|
||||
|}>;
|
||||
|
||||
function getCommandOptions(
|
||||
commandOptionsExpression: OptionsAST,
|
||||
): ?CommandOptions {
|
||||
if (commandOptionsExpression == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let foundOptions;
|
||||
try {
|
||||
foundOptions = commandOptionsExpression.properties.reduce(
|
||||
(options, prop) => {
|
||||
options[prop.key.name] = (
|
||||
(prop && prop.value && prop.value.elements) ||
|
||||
[]
|
||||
).map(element => element && element.value);
|
||||
return options;
|
||||
},
|
||||
{},
|
||||
);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
'Failed to parse command options, please check that they are defined correctly',
|
||||
);
|
||||
}
|
||||
|
||||
return foundOptions;
|
||||
}
|
||||
|
||||
function getOptions(optionsExpression: OptionsAST): ?OptionsShape {
|
||||
if (!optionsExpression) {
|
||||
return null;
|
||||
|
@ -44,5 +76,6 @@ function getOptions(optionsExpression: OptionsAST): ?OptionsShape {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
getCommandOptions,
|
||||
getOptions,
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче