import React from 'react';
import { JSONOutput } from 'typedoc';
import Link from '@docusaurus/Link';
import {
TokenPunctuation,
TokenPrimitive,
TokenKeyword,
TokenPlain,
TokenLiteral,
TokenType,
TokenAttrName
} from './tokens';
import renderReflection from './renderReflection';
import Params from './Params';
import Indent from './Indent';
type DeclarationType = JSONOutput.DeclarationReflection['type'];
function renderTypeArgument(
typeArguments: JSONOutput.SomeType[],
params: Params
) {
if (!typeArguments) {
return null;
}
return (
<>
<
{typeArguments.reduce(
(prev, curr) => (
<>
{prev}
{prev && , }
{renderType(curr, params)}
>
),
null
)}
>
>
);
}
export default function renderType(pt: DeclarationType, params: Params) {
let shouldBreak = false;
let nextParams: Params = params;
switch (pt.type) {
case 'reference':
const ref = pt as JSONOutput.ReferenceType;
let name = ref.name;
// We must resolve reflections because of a bug in Typedoc with default exports
const isLocalRef = 'id' in ref && !!params.resolveReflection(ref.id);
if (isLocalRef) {
name = params.resolveReflection(ref.id).name;
}
const nameToken = {name};
// TODO fix issue in multiple version docs
// See blocking issue on https://github.com/facebook/docusaurus/issues/3372
return (
<>
{isLocalRef ? (
{nameToken}
) : (
nameToken
)}
{renderTypeArgument(ref.typeArguments, params)}
>
);
case 'intrinsic':
return (
{(pt as JSONOutput.IntrinsicType).name}
);
case 'union':
const union = pt as JSONOutput.UnionType;
shouldBreak = union.types.length > 2;
return union.types
.map((u) => renderType(u, params))
.reduce((prev, curr) => (
<>
{prev}
{shouldBreak &&
}
{shouldBreak && }
{!shouldBreak && ' '}
{'| '}
{curr}
>
));
case 'intersection':
const intersection = pt as JSONOutput.IntersectionType;
shouldBreak = intersection.types.length > 2;
nextParams = shouldBreak ? params.withIndent() : params;
return intersection.types
.map((u) => renderType(u, nextParams))
.reduce((prev, curr) => (
<>
{prev}
{shouldBreak && (
<>
>
)}
{!shouldBreak && ' '}
{'& '}
{curr}
>
));
case 'conditional':
// Simplify conditionals as unions. API readers might not be familiar with
// typescript, and unions are easier to understand.
const cond = pt as JSONOutput.ConditionalType;
if (
cond.falseType.type === 'intrinsic' &&
(cond.falseType as JSONOutput.IntrinsicType).name === 'never'
) {
return renderType(cond.trueType, params);
}
return (
<>
{renderType(cond.trueType, params)}
{' | '}
{renderType(cond.falseType, params)}
>
);
case 'mapped':
const mapped = pt as unknown as JSONOutput.MappedType;
nextParams = params.withIndent();
return (
<>
{'{'}
{'['}
{mapped.parameter}
{': '}
{renderType(mapped.parameterType, nextParams)}
{']'}
{': '}
{renderType(mapped.templateType, nextParams)}
{'}'}
>
);
case 'literal':
const literal = pt as JSONOutput.LiteralType;
switch (typeof literal.value) {
case 'bigint':
case 'boolean':
case 'number':
return {String(literal.value)};
case 'undefined':
return {String(literal.value)};
case 'object':
if (literal.value === null) {
return {String(literal.value)};
}
break;
case 'string':
return {JSON.stringify(literal.value)};
}
console.warn('Unhandled literal type', literal);
throw new Error(`Unhandled literal ${literal.value}`);
case 'array':
const array = pt as JSONOutput.ArrayType;
return (
<>
Array
<
{renderType(array.elementType, params)}
>
>
);
case 'reflection':
const reflection = pt as JSONOutput.ReflectionType;
return renderReflection(
reflection.declaration,
params.withoutMemberLinks()
);
case 'typeOperator':
const to = pt as JSONOutput.TypeOperatorType;
return (
<>
{to.operator}
{renderType(to.target, params)}
>
);
case 'indexedAccess':
const acc = pt as unknown as JSONOutput.IndexedAccessType;
return (
<>
{renderType(acc.objectType, params)}
[
{renderType(acc.indexType, params)}
]
>
);
case 'query':
const query = pt as JSONOutput.QueryType;
return (
<>
typeof
{renderType(query.queryType, params)}
>
);
case 'predicate':
const predicate = pt as JSONOutput.PredicateType;
return (
<>
{predicate.asserts && asserts }
{predicate.name}
is
{predicate.targetType && renderType(predicate.targetType, params)}
>
);
default:
console.warn('Unhandled type', pt);
throw new Error(`Unhandled type ${pt.type}`);
}
}