Update flow parser to use codegenNativeComponent

Summary:
This diff updated the codegen flow types syntax replacing:

```
type Options = {
  isDeprecatedPaperComponentNameRCT: true,
};

type ActivityIndicatorNativeType = CodegenNativeComponent<
  'ActivityIndicatorView',
  NativeProps,
  Options,
>;

module.exports = ((requireNativeComponent(
  'RCTActivityIndicatorView',
): any): ActivityIndicatorNativeType);
```
with:

```
export default codegenNativeComponent<NativeProps>('ActivityIndicatorView', {
  isDeprecatedPaperComponentNameRCT: true,
});
```

This is from Tim's comment in the [View Config Codegen Quip](https://fb.quip.com/jR2aASHad4Se):

> What it CodegenNativeComponent were instead `NativeComponent.fromFlow<T>('…')` that returned `'...'`?
>And the Babel plugin swapped it for NativeComponent.fromSchema('...', {…}) which would both register and return '...'?

I went with `codegenNativeComponent` because it has nice parity with `requireNativeComponent`

I also didn't update the babel output here (we can update that whenever) because I think `registerGeneratedViewConfig` is more clear for what it's doing

Reviewed By: cpojer

Differential Revision: D15602077

fbshipit-source-id: 2d24dc32136ba6d31724f8c929b51417ba625a58
This commit is contained in:
Rick Hanlon 2019-06-07 12:23:56 -07:00 коммит произвёл Facebook Github Bot
Родитель efec97f2be
Коммит 504fc0c7d0
13 изменённых файлов: 143 добавлений и 147 удалений

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

@ -21,7 +21,7 @@ import type {ViewProps} from '../View/ViewPropTypes';
const PlatformActivityIndicator =
Platform.OS === 'android'
? require('../ProgressBarAndroid/ProgressBarAndroid')
: require('./ActivityIndicatorViewNativeComponent');
: require('./ActivityIndicatorViewNativeComponent').default;
const GRAY = '#999999';

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

@ -10,15 +10,12 @@
'use strict';
import type {
WithDefault,
CodegenNativeComponent,
} from '../../Types/CodegenTypes';
import type {WithDefault} from '../../Types/CodegenTypes';
import type {ColorValue} from '../../StyleSheet/StyleSheetTypes';
import type {ViewProps} from '../View/ViewPropTypes';
const requireNativeComponent = require('../../ReactNative/requireNativeComponent');
import codegenNativeComponent from '../../Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
@ -53,16 +50,6 @@ type NativeProps = $ReadOnly<{|
size?: ?WithDefault<'small' | 'large', 'small'>,
|}>;
type Options = {
export default codegenNativeComponent<NativeProps>('ActivityIndicatorView', {
isDeprecatedPaperComponentNameRCT: true,
};
type ActivityIndicatorNativeType = CodegenNativeComponent<
'ActivityIndicatorView',
NativeProps,
Options,
>;
module.exports = ((requireNativeComponent(
'RCTActivityIndicatorView',
): any): ActivityIndicatorNativeType);
});

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

@ -15,15 +15,14 @@ import type {
BubblingEvent,
DirectEvent,
WithDefault,
CodegenNativeComponent,
} from '../../Types/CodegenTypes';
import codegenNativeComponent from '../../Utilities/codegenNativeComponent';
import type {ColorValue} from '../../StyleSheet/StyleSheetTypes';
import type {ImageSource} from '../../Image/ImageSource';
import type {ViewProps} from '../View/ViewPropTypes';
const requireNativeComponent = require('../../ReactNative/requireNativeComponent');
type Event = $ReadOnly<{|
value: Float,
fromUser?: boolean,
@ -54,11 +53,7 @@ type NativeProps = $ReadOnly<{|
onSlidingComplete?: ?(event: DirectEvent<Event>) => void,
|}>;
type Options = {
module.exports = codegenNativeComponent<NativeProps>('Slider', {
interfaceOnly: true,
isDeprecatedPaperComponentNameRCT: true,
};
type SliderType = CodegenNativeComponent<'Slider', NativeProps, Options>;
module.exports = ((requireNativeComponent('RCTSlider'): any): SliderType);
});

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

@ -26,13 +26,6 @@ export type Int32 = number;
//
// TODO: (rickhanlonii) T44881457 If a default is provided, it should always be optional
// but that is currently not supported in the codegen since we require a default
// eslint-disable-next-line no-unused-vars
export type WithDefault<Type: number | boolean | string, Value: Type> = Type;
// We're not using ComponentName or Options in JS
// We only use these types to codegen native code
//
// eslint-disable-next-line no-unused-vars
export type CodegenNativeComponent<ComponentName, Props, Options = {}> = Class<
NativeComponent<Props>,
>;
export type WithDefault<Type: number | boolean | string, Value: Type> = Type;

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

@ -0,0 +1,41 @@
/**
* 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
*/
// TODO: move this file to shims/ReactNative (requires React update and sync)
'use strict';
import type {NativeComponent} from '../../Libraries/Renderer/shims/ReactNative';
import requireNativeComponent from '../../Libraries/ReactNative/requireNativeComponent';
// TODO: import from CodegenSchema once workspaces are enabled
type Options = $ReadOnly<{|
interfaceOnly?: boolean,
isDeprecatedPaperComponentNameRCT?: boolean,
|}>;
function codegenNativeComponent<Props>(
componentName: string,
options?: Options,
): Class<NativeComponent<Props>> {
let componentNameInUse = componentName;
if (options && options.isDeprecatedPaperComponentNameRCT === true) {
componentNameInUse = `RCT${componentName}`;
}
// If this function is run at runtime then that means the view configs were not
// generated with the view config babel plugin, so we need to require the native component.
//
// This will be useful during migration, but eventually this will error.
return ((requireNativeComponent(componentNameInUse): any): Class<
NativeComponent<Props>,
>);
}
export default codegenNativeComponent;

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

@ -16,13 +16,12 @@ export default 'Not a view config'
`;
const FULL_NATIVE_COMPONENT = `
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
BubblingEvent,
DirectEvent,
WithDefault,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
import type {ViewProps} from 'ViewPropTypes';
@ -38,14 +37,10 @@ type ModuleProps = $ReadOnly<{|
onBubblingEventDefinedInlineNull: (event: BubblingEvent<null>) => void,
|}>;
type Options = {
export default codegenNativeComponent<ModuleProps>('Module', {
interfaceOnly: true,
isDeprecatedPaperComponentNameRCT: true,
};
type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
});
`;
module.exports = {

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

@ -1,9 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Babel plugin inline view configs can inline config for FullNativeComponent.js 1`] = `
"const requireNativeComponent = require('requireNativeComponent');
"const codegenNativeComponent = require('codegenNativeComponent');
import type { BubblingEvent, DirectEvent, WithDefault, CodegenNativeComponent } from 'CodegenFlowtypes';
import type { BubblingEvent, DirectEvent, WithDefault } from 'CodegenFlowtypes';
import type { ViewProps } from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{| ...ViewProps,
// Props
@ -12,11 +12,6 @@ type ModuleProps = $ReadOnly<{| ...ViewProps,
onDirectEventDefinedInlineNull: (event: DirectEvent<null>) => void,
onBubblingEventDefinedInlineNull: (event: BubblingEvent<null>) => void,
|}>;
type Options = {
interfaceOnly: true,
isDeprecatedPaperComponentNameRCT: true,
};
type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>;
const registerGeneratedViewConfig = require('registerGeneratedViewConfig');
@ -42,7 +37,7 @@ const ModuleViewConfig = {
}
};
registerGeneratedViewConfig('RCTModule', ModuleViewConfig);
module.exports = 'RCTModule'; // RCT prefix present for paper support"
export default 'RCTModule'; // RCT prefix present for paper support"
`;
exports[`Babel plugin inline view configs can inline config for NotANativeComponent.js 1`] = `

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

@ -25,33 +25,39 @@ function generateViewConfig(filename, code) {
});
}
function isCodegenDeclaration(declaration) {
if (!declaration) {
return false;
}
if (
declaration.left &&
declaration.left.left &&
declaration.left.left.name === 'codegenNativeComponent'
) {
return true;
} else if (
declaration.callee &&
declaration.callee.name &&
declaration.callee.name === 'codegenNativeComponent'
) {
return true;
}
return false;
}
module.exports = function(context) {
return {
pre(state) {
this.code = state.code;
this.filename = state.opts.filename;
this.inserted = false;
},
visitor: {
TypeAlias(nodePath, state) {
if (
!this.inserted &&
nodePath.node.right &&
nodePath.node.right.type === 'GenericTypeAnnotation' &&
nodePath.node.right.id.name === 'CodegenNativeComponent'
) {
const code = generateViewConfig(this.filename, this.code);
// Remove the original export
nodePath.parentPath.traverse({
MemberExpression(exportPath) {
if (exportPath.node.property.name === 'exports') {
exportPath.parentPath.remove();
}
},
});
nodePath.insertAfter(context.parse(code).program.body);
this.inserted = true;
ExportDefaultDeclaration(nodePath, state) {
if (isCodegenDeclaration(nodePath.node.declaration)) {
const viewConfig = generateViewConfig(this.filename, this.code);
nodePath.replaceWithMultiple(context.parse(viewConfig).program.body);
}
},
},

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

@ -89,7 +89,7 @@ const ::_COMPONENT_NAME_::ViewConfig = VIEW_CONFIG;
registerGeneratedViewConfig('::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', ::_COMPONENT_NAME_::ViewConfig);
module.exports = '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_::
export default '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_::
`.trim();
// Replicates the behavior of RCTNormalizeInputEventName in RCTEventDispatcher.m

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

@ -32,7 +32,7 @@ const ArrayPropsNativeComponentViewConfig = {
registerGeneratedViewConfig('ArrayPropsNativeComponent', ArrayPropsNativeComponentViewConfig);
module.exports = 'ArrayPropsNativeComponent';
export default 'ArrayPropsNativeComponent';
",
}
`;
@ -63,7 +63,7 @@ const BooleanPropNativeComponentViewConfig = {
registerGeneratedViewConfig('BooleanPropNativeComponent', BooleanPropNativeComponentViewConfig);
module.exports = 'BooleanPropNativeComponent';
export default 'BooleanPropNativeComponent';
",
}
`;
@ -94,7 +94,7 @@ const ColorPropNativeComponentViewConfig = {
registerGeneratedViewConfig('ColorPropNativeComponent', ColorPropNativeComponentViewConfig);
module.exports = 'ColorPropNativeComponent';
export default 'ColorPropNativeComponent';
",
}
`;
@ -125,7 +125,7 @@ const EnumPropsNativeComponentViewConfig = {
registerGeneratedViewConfig('EnumPropsNativeComponent', EnumPropsNativeComponentViewConfig);
module.exports = 'EnumPropsNativeComponent';
export default 'EnumPropsNativeComponent';
",
}
`;
@ -166,7 +166,7 @@ const EventsNestedObjectNativeComponentViewConfig = {
registerGeneratedViewConfig('EventsNestedObjectNativeComponent', EventsNestedObjectNativeComponentViewConfig);
module.exports = 'EventsNestedObjectNativeComponent';
export default 'EventsNestedObjectNativeComponent';
",
}
`;
@ -222,7 +222,7 @@ const EventsNativeComponentViewConfig = {
registerGeneratedViewConfig('EventsNativeComponent', EventsNativeComponentViewConfig);
module.exports = 'EventsNativeComponent';
export default 'EventsNativeComponent';
",
}
`;
@ -258,7 +258,7 @@ const FloatPropNativeComponentViewConfig = {
registerGeneratedViewConfig('FloatPropNativeComponent', FloatPropNativeComponentViewConfig);
module.exports = 'FloatPropNativeComponent';
export default 'FloatPropNativeComponent';
",
}
`;
@ -289,7 +289,7 @@ const ImagePropNativeComponentViewConfig = {
registerGeneratedViewConfig('ImagePropNativeComponent', ImagePropNativeComponentViewConfig);
module.exports = 'ImagePropNativeComponent';
export default 'ImagePropNativeComponent';
",
}
`;
@ -322,7 +322,7 @@ const IntegerPropNativeComponentViewConfig = {
registerGeneratedViewConfig('IntegerPropNativeComponent', IntegerPropNativeComponentViewConfig);
module.exports = 'IntegerPropNativeComponent';
export default 'IntegerPropNativeComponent';
",
}
`;
@ -363,7 +363,7 @@ const InterfaceOnlyComponentViewConfig = {
registerGeneratedViewConfig('RCTInterfaceOnlyComponent', InterfaceOnlyComponentViewConfig);
module.exports = 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support
export default 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support
",
}
`;
@ -397,7 +397,7 @@ const ImageColorPropNativeComponentViewConfig = {
registerGeneratedViewConfig('ImageColorPropNativeComponent', ImageColorPropNativeComponentViewConfig);
module.exports = 'ImageColorPropNativeComponent';
export default 'ImageColorPropNativeComponent';
",
}
`;
@ -428,7 +428,7 @@ const PointPropNativeComponentViewConfig = {
registerGeneratedViewConfig('PointPropNativeComponent', PointPropNativeComponentViewConfig);
module.exports = 'PointPropNativeComponent';
export default 'PointPropNativeComponent';
",
}
`;
@ -459,7 +459,7 @@ const StringPropComponentViewConfig = {
registerGeneratedViewConfig('StringPropComponent', StringPropComponentViewConfig);
module.exports = 'StringPropComponent';
export default 'StringPropComponent';
",
}
`;
@ -490,7 +490,7 @@ const MultiFile1NativeComponentViewConfig = {
registerGeneratedViewConfig('MultiFile1NativeComponent', MultiFile1NativeComponentViewConfig);
module.exports = 'MultiFile1NativeComponent';
export default 'MultiFile1NativeComponent';
const MultiFile2NativeComponentViewConfig = {
uiViewClassName: 'MultiFile2NativeComponent',
@ -502,7 +502,7 @@ const MultiFile2NativeComponentViewConfig = {
registerGeneratedViewConfig('MultiFile2NativeComponent', MultiFile2NativeComponentViewConfig);
module.exports = 'MultiFile2NativeComponent';
export default 'MultiFile2NativeComponent';
",
}
`;
@ -533,7 +533,7 @@ const MultiComponent1NativeComponentViewConfig = {
registerGeneratedViewConfig('MultiComponent1NativeComponent', MultiComponent1NativeComponentViewConfig);
module.exports = 'MultiComponent1NativeComponent';
export default 'MultiComponent1NativeComponent';
const MultiComponent2NativeComponentViewConfig = {
uiViewClassName: 'MultiComponent2NativeComponent',
@ -545,7 +545,7 @@ const MultiComponent2NativeComponentViewConfig = {
registerGeneratedViewConfig('MultiComponent2NativeComponent', MultiComponent2NativeComponentViewConfig);
module.exports = 'MultiComponent2NativeComponent';
export default 'MultiComponent2NativeComponent';
",
}
`;

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

@ -55,6 +55,7 @@ const EVENT_DEFINITION = `
}
}
`;
const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
@ -68,14 +69,13 @@ const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = `
'use strict';
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
BubblingEvent,
DirectEvent,
WithDefault,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
} from 'CodegenTypes';
import type {ViewProps} from 'ViewPropTypes';
@ -90,14 +90,10 @@ type ModuleProps = $ReadOnly<{|
onBubblingEventDefinedInlineNull: (event: BubblingEvent<null>) => void,
|}>;
type Options = {
export default codegenNativeComponent<ModuleProps>('Module', {
interfaceOnly: true,
isDeprecatedPaperComponentNameRCT: true,
};
type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
});
`;
const ALL_PROP_TYPES_NO_EVENTS = `
@ -113,14 +109,13 @@ const ALL_PROP_TYPES_NO_EVENTS = `
'use strict';
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
Int32,
Float,
WithDefault,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
} from 'CodegenTypes';
import type {ColorValue, ColorArrayValue, PointValue} from 'StyleSheetTypes';
import type {ImageSource} from 'ImageSource';
@ -184,9 +179,7 @@ type ModuleProps = $ReadOnly<{|
point_optional_both?: ?PointValue,
|}>;
type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
export default codegenNativeComponent<ModuleProps, Options>('Module');
`;
const ARRAY_PROP_TYPES_NO_EVENTS = `
@ -202,14 +195,13 @@ const ARRAY_PROP_TYPES_NO_EVENTS = `
'use strict';
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
Int32,
Float,
WithDefault,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
} from 'CodegenTypes';
import type {ColorValue, PointValue} from 'StyleSheetTypes';
import type {ImageSource} from 'ImageSource';
@ -268,9 +260,7 @@ type ModuleProps = $ReadOnly<{|
array_point_optional_both?: ?$ReadOnlyArray<PointValue>,
|}>;
type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
export default codegenNativeComponent<ModuleProps>('Module');
`;
const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = `
@ -286,15 +276,14 @@ const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = `
'use strict';
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
Int32,
Float,
BubblingEvent,
DirectEvent,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
} from 'CodegenTypes';
import type {ViewProps} from 'ViewPropTypes';
@ -368,9 +357,7 @@ type ModuleProps = $ReadOnly<{|
) => void,
|}>;
type ModuleType = CodegenNativeComponent<'Module', ModuleProps>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
export default codegenNativeComponent<ModuleProps>('Module');
`;
const EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES = `
@ -386,15 +373,14 @@ const EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES = `
'use strict';
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
Float,
Int32,
BubblingEvent,
DirectEvent,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
} from 'CodegenTypes';
import type {ViewProps} from 'ViewPropTypes';
@ -430,9 +416,7 @@ type ModuleProps = $ReadOnly<{|
) => void,
|}>;
type ModuleType = CodegenNativeComponent<'Module', ModuleProps>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
export default codegenNativeComponent<ModuleProps>('Module');
`;
const EVENTS_DEFINED_AS_NULL_IN_FILE = `
@ -448,13 +432,12 @@ const EVENTS_DEFINED_AS_NULL_IN_FILE = `
'use strict';
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
BubblingEvent,
DirectEvent,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
} from 'CodegenTypes';
import type {ViewProps} from 'ViewPropTypes';
@ -492,9 +475,8 @@ type ModuleProps = $ReadOnly<{|
) => void,
|}>;
type ModuleType = CodegenNativeComponent<'Module', ModuleProps>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
export default codegenNativeComponent<ModuleProps>('Module');
`;
const EVENTS_DEFINED_AS_NULL_INLINE = `
@ -510,13 +492,12 @@ const EVENTS_DEFINED_AS_NULL_INLINE = `
'use strict';
const requireNativeComponent = require('requireNativeComponent');
const codegenNativeComponent = require('codegenNativeComponent');
import type {
BubblingEvent,
DirectEvent,
CodegenNativeComponent,
} from 'CodegenFlowtypes';
} from 'CodegenTypese';
import type {ViewProps} from 'ViewPropTypes';
@ -549,9 +530,7 @@ type ModuleProps = $ReadOnly<{|
) => void,
|}>;
type ModuleType = CodegenNativeComponent<'Module', ModuleProps>;
module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType);
export default codegenNativeComponent<ModuleProps>('Module');
`;
module.exports = {

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

@ -20,19 +20,24 @@ const {getProps} = require('./props');
const {getOptions} = require('./options');
const {getExtendsProps} = require('./extends');
function findConfig(types) {
function findConfig(ast) {
const foundConfigs = [];
Object.keys(types).forEach(key => {
const allExports = ast.body.filter(
node => node.type === 'ExportDefaultDeclaration',
);
allExports.forEach(statement => {
try {
const type = types[key];
if (type.right.id.name === 'CodegenNativeComponent') {
const params = type.right.typeParameters.params;
if (statement.declaration.callee.name === 'codegenNativeComponent') {
const typeArgumentParams = statement.declaration.typeArguments.params;
const funcArgumentParams = statement.declaration.arguments;
const nativeComponentType = {};
nativeComponentType.componentName = params[0].value;
nativeComponentType.propsTypeName = params[1].id.name;
if (params.length > 2) {
nativeComponentType.optionsTypeName = params[2].id.name;
nativeComponentType.propsTypeName = typeArgumentParams[0].id.name;
nativeComponentType.componentName = funcArgumentParams[0].value;
if (funcArgumentParams.length > 1) {
nativeComponentType.optionsExpression = funcArgumentParams[1];
}
foundConfigs.push(nativeComponentType);
}
@ -75,12 +80,12 @@ function processString(contents: string) {
const ast = flowParser.parse(contents);
const types = getTypes(ast);
const {componentName, propsTypeName, optionsTypeName} = findConfig(types);
const {componentName, propsTypeName, optionsExpression} = findConfig(ast);
const propProperties = getPropProperties(propsTypeName, types);
const extendsProps = getExtendsProps(propProperties);
const options = getOptions(types[optionsTypeName]);
const options = getOptions(optionsExpression);
const props = getProps(propProperties);
const events = getEvents(propProperties, types);

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

@ -15,12 +15,12 @@ import type {OptionsShape} from '../../CodegenSchema.js';
// $FlowFixMe there's no flowtype for ASTs
type OptionsAST = Object;
function getOptions(optionsDefinition: OptionsAST): ?OptionsShape {
if (!optionsDefinition) {
function getOptions(optionsExpression: OptionsAST): ?OptionsShape {
if (!optionsExpression) {
return null;
}
try {
return optionsDefinition.right.properties.reduce((options, prop) => {
return optionsExpression.properties.reduce((options, prop) => {
options[prop.key.name] = prop.value.value;
return options;
}, {});