import { Heading } from 'ember-primitives/components/heading'; import { isReference } from '../narrowing.ts'; import { Comment, Type } from '../renderer.gts'; import { findChildDeclaration, Load } from '../utils.gts'; import { Args } from './args.gts'; import { Element } from './element.gts'; import type { TOC } from '@ember/component/template-only'; import type { ProjectReflection, Reflection, SomeType } from 'typedoc'; type SingleSignature = { Element: any; Args: any; Blocks: any }; type UnionSignature = { variants: SingleSignature[] }; type SignatureResult = SingleSignature | UnionSignature; function getSignatureType(info: Reflection, project: ProjectReflection) { /** * export const Foo: TOC<{ signature here }> = */ if (info.isDeclaration()) { if (isReference(info.type) && info.type?.typeArguments?.[0]?.type === 'reflection') { return info.type.typeArguments[0].declaration; } /** * export class Foo extends Component<{ signature here }> { ... } */ const extendedType = info.extendedTypes?.[0]; if (extendedType?.type === 'reference' && extendedType?.package === '@glimmer/component') { const typeArg = extendedType.typeArguments?.[0]; if (typeArg) { if (typeArg?.type === 'reflection') { return typeArg.declaration; } /** * export interface Signature { ... } * * export class Foo extends Component */ if ('_target' in typeArg) { const id = (typeArg as any)._target; return project.getReflectionById(id); } } } /** * export interface Signature { ... } * export const Foo: TOC = */ if (info.type?.type === 'reference') { const typeArg = info.type?.typeArguments?.[0]; if (typeArg && '_target' in typeArg) { const id = (typeArg as any)._target; return project.getReflectionById(id); } } } /** * export interface Signature { ... } */ return info; } function getSignatureFromType(type: Reflection): SingleSignature | undefined { const Element = findChildDeclaration(type, 'Element'); const Args = findChildDeclaration(type, 'Args'); const Blocks = findChildDeclaration(type, 'Blocks'); const hasAny = Element || Args || Blocks; if (!hasAny) return; return { Element, Args, Blocks }; } export function getSignature( info: Reflection | undefined, project: ProjectReflection ): SignatureResult | undefined { if (!info) return; const type = getSignatureType(info, project); if (!type) return; /** * Union type signatures, e.g.: * export type Signature = { Element: ...; Args: { a: string } } | { Element: ...; Args: { b: number } } * * Each member of the union is a separate signature variant. */ if (type.isDeclaration() && type.type?.type === 'union' && type.type.types) { const variants = type.type.types .map((unionMember: SomeType) => { if ( unionMember.type === 'reflection' && 'declaration' in unionMember && unionMember.declaration ) { return getSignatureFromType(unionMember.declaration as Reflection); } return undefined; }) .filter((v): v is SingleSignature => v !== undefined); if (variants.length > 0) { return { variants }; } } return getSignatureFromType(type); } function isUnionSignature(info: SignatureResult | undefined): info is UnionSignature { return info !== undefined && 'variants' in info; } export const ComponentSignature: TOC<{ Args: { /** * Which module to import the type from */ module: string; /** * The name of the component to render the type / JSDoc of */ name: string; /** * The name of the package to lookup the module and export name. */ package: string; }; }> = ; export const ComponentDeclaration: TOC<{ Args: { signature: SingleSignature; }; }> = ; const Blocks: TOC<{ Args: { info: any } }> = ;