import generate from '@babel/generator' ; import * as t from '@babel/types' ; import { accessSafe } from './accessSafe' ; /**
 * getPropValueFromAttributes gets a prop by name from a list of attributes and accounts for potential spread operators.
 * Here's an example. Given this component:
 * ```
 * <Block coolProp="wow" {...spread1} neatProp="ok" {...spread2} />```
 * getPropValueFromAttributes will return the following:
 * - for propName `coolProp`:
 *   ```
 * accessSafe(spread1, 'coolProp') || accessSafe(spread2, 'coolProp') || 'wow'```
 * - for propName `neatProp`:
 *   ```
 * accessSafe(spread2, 'neatProp') || 'ok'```
 * - for propName `notPresent`: `null`
 *
 * The returned value should (obviously) be placed after spread operators.
 */ export function getPropValueFromAttributes ( propName , attrs ) { let propIndex = - 1 ; let jsxAttr = null ; for ( let idx = - 1 , len = attrs . length ; ++ idx < len ; ) { const attr = attrs [ idx ] ; if ( t . isJSXAttribute ( attr ) && attr . name && attr . name . name === propName ) { propIndex = idx ; jsxAttr = attr ; break ; } } if ( ! jsxAttr || jsxAttr . value == null ) { return null ; } let propValue = jsxAttr . value ; if ( t . isJSXExpressionContainer ( propValue ) ) { propValue = propValue . expression ; } if ( t . isJSXEmptyExpression ( propValue ) ) { console . error ( 'encountered JSXEmptyExpression' ) ; return null ; } const applicableSpreads = attrs . filter ( ( attr , idx ) : attr is t . JSXSpreadAttribute => { if ( t . isJSXSpreadAttribute ( attr ) ) { if ( t . isIdentifier ( attr . argument ) || t . isMemberExpression ( attr . argument ) ) { return idx > propIndex ; } if ( t . isLogicalExpression ( attr . argument ) ) { return false ; } throw new Error ( `unsupported spread of type "${ attr . argument . type }": ${ generate ( attr ) . code }` ) ; } return false ; } ) . map ( ( attr ) => attr . argument ) ; if ( applicableSpreads . length > 0 ) { propValue = applicableSpreads . reduce < t . Expression > ( ( acc , val ) => t . logicalExpression ( '||' , accessSafe ( val , propName ) , acc ) , propValue ) ; } return propValue ; }