1import { Fragment } from 'react'; 2 3import { APIDataType } from '~/components/plugins/api/APIDataType'; 4import { 5 PropData, 6 TypeDeclarationContentData, 7 TypeDefinitionData, 8 TypeGeneralData, 9 TypeSignaturesData, 10} from '~/components/plugins/api/APIDataTypes'; 11import { APISectionDeprecationNote } from '~/components/plugins/api/APISectionDeprecationNote'; 12import { APISectionPlatformTags } from '~/components/plugins/api/APISectionPlatformTags'; 13import { 14 resolveTypeName, 15 renderFlags, 16 CommentTextBlock, 17 parseCommentContent, 18 renderTypeOrSignatureType, 19 getCommentOrSignatureComment, 20 getTagData, 21 renderParams, 22 ParamsTableHeadRow, 23 renderDefaultValue, 24 renderIndexSignature, 25 STYLES_APIBOX, 26 getTagNamesList, 27 H3Code, 28 getCommentContent, 29} from '~/components/plugins/api/APISectionUtils'; 30import { Cell, Row, Table } from '~/ui/components/Table'; 31import { H2, BOLD, P, CODE, MONOSPACE } from '~/ui/components/Text'; 32 33export type APISectionTypesProps = { 34 data: TypeGeneralData[]; 35}; 36 37const defineLiteralType = (types: TypeDefinitionData[]): JSX.Element | null => { 38 const uniqueTypes = Array.from( 39 new Set(types.map((t: TypeDefinitionData) => t.value && typeof t.value)) 40 ); 41 if (uniqueTypes.length === 1 && uniqueTypes.filter(Boolean).length === 1) { 42 return ( 43 <> 44 <CODE>{uniqueTypes[0]}</CODE> 45 {' - '} 46 </> 47 ); 48 } 49 return null; 50}; 51 52const renderTypeDeclarationTable = ( 53 { children, indexSignature, comment }: TypeDeclarationContentData, 54 index?: number 55): JSX.Element => ( 56 <Fragment key={`type-declaration-table-${children?.map(child => child.name).join('-')}`}> 57 {index && index > 0 ? <br /> : undefined} 58 <CommentTextBlock comment={comment} /> 59 <Table> 60 <ParamsTableHeadRow /> 61 <tbody> 62 {children?.map(renderTypePropertyRow)} 63 {indexSignature?.parameters && indexSignature.parameters.map(renderTypePropertyRow)} 64 </tbody> 65 </Table> 66 </Fragment> 67); 68 69const renderTypePropertyRow = ({ 70 name, 71 flags, 72 type, 73 comment, 74 defaultValue, 75 signatures, 76 kind, 77}: PropData): JSX.Element => { 78 const defaultTag = getTagData('default', comment); 79 const initValue = parseCommentContent( 80 defaultValue || (defaultTag ? getCommentContent(defaultTag.content) : undefined) 81 ); 82 const commentData = getCommentOrSignatureComment(comment, signatures); 83 const hasDeprecationNote = Boolean(getTagData('deprecated', comment)); 84 return ( 85 <Row key={name}> 86 <Cell fitContent> 87 <BOLD>{name}</BOLD> 88 {renderFlags(flags, initValue)} 89 {kind && renderIndexSignature(kind)} 90 </Cell> 91 <Cell fitContent>{renderTypeOrSignatureType(type, signatures, true)}</Cell> 92 <Cell fitContent> 93 <APISectionDeprecationNote comment={comment} /> 94 <CommentTextBlock 95 inlineHeaders 96 comment={commentData} 97 afterContent={renderDefaultValue(initValue)} 98 emptyCommentFallback={hasDeprecationNote ? undefined : '-'} 99 /> 100 </Cell> 101 </Row> 102 ); 103}; 104 105const renderType = ({ 106 name, 107 comment, 108 type, 109 typeParameter, 110}: TypeGeneralData): JSX.Element | undefined => { 111 if (type.declaration) { 112 // Object Types 113 return ( 114 <div key={`type-definition-${name}`} css={STYLES_APIBOX}> 115 <APISectionDeprecationNote comment={comment} /> 116 <APISectionPlatformTags comment={comment} prefix="Only for:" /> 117 <H3Code tags={getTagNamesList(comment)}> 118 <MONOSPACE weight="medium"> 119 {name} 120 {type.declaration.signatures ? '()' : ''} 121 </MONOSPACE> 122 </H3Code> 123 <CommentTextBlock comment={comment} includePlatforms={false} /> 124 {type.declaration.children && renderTypeDeclarationTable(type.declaration)} 125 {type.declaration.signatures 126 ? type.declaration.signatures.map(({ parameters, comment }: TypeSignaturesData) => ( 127 <div key={`type-definition-signature-${name}`}> 128 <CommentTextBlock comment={comment} /> 129 {parameters && renderParams(parameters)} 130 </div> 131 )) 132 : null} 133 </div> 134 ); 135 } else if (type.types && ['union', 'intersection'].includes(type.type)) { 136 const literalTypes = type.types.filter((t: TypeDefinitionData) => 137 ['literal', 'intrinsic', 'reference', 'tuple'].includes(t.type) 138 ); 139 const propTypes = type.types.filter((t: TypeDefinitionData) => t.type === 'reflection'); 140 if (propTypes.length) { 141 return ( 142 <div key={`prop-type-definition-${name}`} css={STYLES_APIBOX}> 143 <APISectionDeprecationNote comment={comment} /> 144 <APISectionPlatformTags comment={comment} prefix="Only for:" /> 145 <H3Code tags={getTagNamesList(comment)}> 146 <MONOSPACE weight="medium">{name}</MONOSPACE> 147 </H3Code> 148 <CommentTextBlock comment={comment} includePlatforms={false} /> 149 {type.type === 'intersection' ? ( 150 <> 151 <P> 152 {type.types 153 .filter(type => ['reference', 'union', 'intersection'].includes(type.type)) 154 .map(validType => ( 155 <Fragment key={`nested-reference-type-${validType.name}`}> 156 <CODE>{resolveTypeName(validType)}</CODE>{' '} 157 </Fragment> 158 ))} 159 extended by: 160 </P> 161 <br /> 162 </> 163 ) : null} 164 {propTypes.map( 165 (propType, index) => 166 propType.declaration && renderTypeDeclarationTable(propType.declaration, index) 167 )} 168 </div> 169 ); 170 } else if (literalTypes.length) { 171 return ( 172 <div key={`type-definition-${name}`} css={STYLES_APIBOX}> 173 <APISectionDeprecationNote comment={comment} /> 174 <APISectionPlatformTags comment={comment} prefix="Only for:" /> 175 <H3Code tags={getTagNamesList(comment)}> 176 <MONOSPACE weight="medium">{name}</MONOSPACE> 177 </H3Code> 178 <CommentTextBlock comment={comment} includePlatforms={false} /> 179 <P> 180 {defineLiteralType(literalTypes)} 181 Acceptable values are:{' '} 182 {literalTypes.map((lt, index) => ( 183 <span key={`${name}-literal-type-${index}`}> 184 <CODE>{resolveTypeName(lt)}</CODE> 185 {index + 1 !== literalTypes.length ? ', ' : '.'} 186 </span> 187 ))} 188 </P> 189 </div> 190 ); 191 } 192 } else if ((type.name === 'Record' && type.typeArguments) || type.type === 'reference') { 193 return ( 194 <div key={`record-definition-${name}`} css={STYLES_APIBOX}> 195 <APISectionDeprecationNote comment={comment} /> 196 <APISectionPlatformTags comment={comment} prefix="Only for:" /> 197 <H3Code tags={getTagNamesList(comment)}> 198 <MONOSPACE weight="medium">{name}</MONOSPACE> 199 </H3Code> 200 <div css={{ display: 'flex', gap: 8, marginBottom: 12 }}> 201 <BOLD>Type: </BOLD> 202 <APIDataType typeDefinition={type} /> 203 </div> 204 <CommentTextBlock comment={comment} includePlatforms={false} /> 205 </div> 206 ); 207 } else if (type.type === 'intrinsic') { 208 return ( 209 <div key={`generic-type-definition-${name}`} css={STYLES_APIBOX}> 210 <APISectionDeprecationNote comment={comment} /> 211 <APISectionPlatformTags comment={comment} prefix="Only for:" /> 212 <H3Code tags={getTagNamesList(comment)}> 213 <MONOSPACE weight="medium">{name}</MONOSPACE> 214 </H3Code> 215 <CommentTextBlock comment={comment} includePlatforms={false} /> 216 <P> 217 <BOLD>Type: </BOLD> 218 <CODE>{type.name}</CODE> 219 </P> 220 </div> 221 ); 222 } else if (type.type === 'conditional' && type.checkType) { 223 return ( 224 <div key={`conditional-type-definition-${name}`} css={STYLES_APIBOX}> 225 <APISectionDeprecationNote comment={comment} /> 226 <APISectionPlatformTags comment={comment} prefix="Only for:" /> 227 <H3Code tags={getTagNamesList(comment)}> 228 <MONOSPACE weight="medium"> 229 {name}<{type.checkType.name}> 230 </MONOSPACE> 231 </H3Code> 232 <CommentTextBlock comment={comment} includePlatforms={false} /> 233 <P> 234 <BOLD>Generic: </BOLD> 235 <CODE> 236 {type.checkType.name} 237 {typeParameter && <> extends {resolveTypeName(typeParameter[0].type)}</>} 238 </CODE> 239 </P> 240 <P> 241 <BOLD>Type: </BOLD> 242 <CODE> 243 {type.checkType.name} 244 {typeParameter && <> extends {type.extendsType && resolveTypeName(type.extendsType)}</>} 245 {' ? '} 246 {type.trueType && resolveTypeName(type.trueType)} 247 {' : '} 248 {type.falseType && resolveTypeName(type.falseType)} 249 </CODE> 250 </P> 251 </div> 252 ); 253 } 254 return undefined; 255}; 256 257const APISectionTypes = ({ data }: APISectionTypesProps) => 258 data?.length ? ( 259 <> 260 <H2 key="types-header">Types</H2> 261 {data.map(renderType)} 262 </> 263 ) : null; 264 265export default APISectionTypes; 266