import { colors, Link, utils as sharedUtils } from '@0x/react-shared'; import { Type as TypeDef, TypeDefinitionByName, TypeDocTypes } from '@0x/types'; import { errorUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import * as ReactTooltip from 'react-tooltip'; import { DocsInfo } from '../docs_info'; import { Signature } from './signature'; import { TypeDefinition } from './type_definition'; const basicJsTypes = ['string', 'number', 'undefined', 'null', 'boolean']; const basicSolidityTypes = ['bytes', 'bytes4', 'bytes32', 'uint8', 'uint256', 'address']; const defaultProps = {}; export interface TypeProps { type: TypeDef; docsInfo: DocsInfo; sectionName: string; typeDefinitionByName?: TypeDefinitionByName; isInPopover: boolean; } // The return type needs to be `any` here so that we can recursively define components within // components (e.g when rendering the union type). export const Type: React.SFC = (props: TypeProps): any => { const type = props.type; const isReference = type.typeDocType === TypeDocTypes.Reference; const isArray = type.typeDocType === TypeDocTypes.Array; let typeNameColor = 'inherit'; let typeName: string | React.ReactNode; let typeArgs: React.ReactNode[] = []; switch (type.typeDocType) { case TypeDocTypes.Intrinsic: case TypeDocTypes.Unknown: typeName = type.name; typeNameColor = colors.orange; break; case TypeDocTypes.Reference: typeName = type.name; typeArgs = _.map(type.typeArguments, (arg: TypeDef) => { if (arg.typeDocType === TypeDocTypes.Array) { const key = `type-${arg.elementType.name}-${arg.elementType.typeDocType}`; return ( [] ); } else { const subType = ( ); return subType; } }); break; case TypeDocTypes.StringLiteral: typeName = `'${type.value}'`; typeNameColor = colors.green; break; case TypeDocTypes.Array: typeName = type.elementType.name; if (_.includes(basicJsTypes, typeName) || _.includes(basicSolidityTypes, typeName)) { typeNameColor = colors.orange; } break; case TypeDocTypes.Union: const unionTypes = _.map(type.types, t => { return ( ); }); typeName = _.reduce(unionTypes, (prev: React.ReactNode, curr: React.ReactNode) => { return [prev, '|', curr]; }); break; case TypeDocTypes.Reflection: if (!_.isUndefined(type.method)) { typeName = ( ); } else if (!_.isUndefined(type.indexSignature)) { const is = type.indexSignature; const param = ( {is.keyName}:{' '} ); typeName = ( {'{'}[{param}]: {is.valueName} {'}'} ); } else { throw new Error(`Unrecognized Reflection type that isn't a Method nor an Index Signature`); } break; case TypeDocTypes.TypeParameter: typeName = type.name; break; case TypeDocTypes.Intersection: const intersectionsTypes = _.map(type.types, t => { return ( ); }); typeName = _.reduce(intersectionsTypes, (prev: React.ReactNode, curr: React.ReactNode) => { return [prev, '&', curr]; }); break; case TypeDocTypes.Tuple: const tupleTypes = _.map(type.tupleElements, (t, i) => { return ( ); }); typeName = (
[{_.reduce(tupleTypes, (prev: React.ReactNode, curr: React.ReactNode) => { return [prev, ', ', curr]; })}]
); break; default: throw errorUtils.spawnSwitchErr('type.typeDocType', type.typeDocType); } // HACK: Normalize BigNumber to simply BigNumber. For some reason the type // name is unpredictably one or the other. if (typeName === 'BigNumber') { typeName = 'BigNumber'; } const commaSeparatedTypeArgs = _.reduce(typeArgs, (prev: React.ReactNode, curr: React.ReactNode) => { return [prev, ', ', curr]; }); const isExportedClassReference = !!props.type.isExportedClassReference; const typeNameUrlIfExists = !_.isUndefined(props.type.externalLink) ? props.type.externalLink : undefined; if (!_.isUndefined(typeNameUrlIfExists)) { typeName = props.isInPopover ? ( {typeName} ) : ( {typeName} ); } else if ( (isReference || isArray) && ((props.typeDefinitionByName && props.typeDefinitionByName[typeName as string]) || isExportedClassReference) ) { const id = Math.random().toString(); const typeDefinitionAnchorId = isExportedClassReference ? props.type.name : `${props.docsInfo.typeSectionName}-${typeName}`; typeName = ( {sharedUtils.isUserOnMobile() || props.isInPopover || isExportedClassReference ? ( {typeName} ) : ( {typeName} )} ); } return ( {typeName} {isArray && '[]'} {!_.isEmpty(typeArgs) && ( {'<'} {commaSeparatedTypeArgs} {'>'} )} ); }; Type.defaultProps = defaultProps;