UNPKG

typedoc

Version:

Create api documentation for TypeScript projects.

105 lines (104 loc) 5.56 kB
// Converter functions for JSDoc defined types // @typedef // @callback import { ok } from "assert"; import ts from "typescript"; import { DeclarationReflection, IntrinsicType, ReflectionKind, ReflectionType, SignatureReflection, } from "../models/index.js"; import { ReflectionSymbolId } from "../models/reflections/ReflectionSymbolId.js"; import { ConverterEvents } from "./converter-events.js"; import { convertParameterNodes, convertTemplateParameterNodes, } from "./factories/signature.js"; export function convertJsDocAlias(context, symbol, declaration, exportSymbol) { if (declaration.typeExpression && ts.isJSDocTypeLiteral(declaration.typeExpression)) { convertJsDocInterface(context, declaration, symbol, exportSymbol); return; } // If the typedef tag is just referring to another type-space symbol, with no type parameters // or appropriate forwarding type parameters, then we treat it as a re-export instead of creating // a type alias with an import type. const aliasedSymbol = getTypedefReExportTarget(context, declaration); if (aliasedSymbol) { context.converter.convertSymbol(context, aliasedSymbol, exportSymbol ?? symbol); return; } const reflection = context.createDeclarationReflection(ReflectionKind.TypeAlias, symbol, exportSymbol); reflection.comment = context.getJsDocComment(declaration); reflection.type = context.converter.convertType(context.withScope(reflection), declaration.typeExpression?.type); convertTemplateParameters(context.withScope(reflection), declaration.parent); context.finalizeDeclarationReflection(reflection); } export function convertJsDocCallback(context, symbol, declaration, exportSymbol) { const alias = context.createDeclarationReflection(ReflectionKind.TypeAlias, symbol, exportSymbol); alias.comment = context.getJsDocComment(declaration); context.finalizeDeclarationReflection(alias); const ac = context.withScope(alias); alias.type = convertJsDocSignature(ac, declaration.typeExpression); convertTemplateParameters(ac, declaration.parent); } function convertJsDocInterface(context, declaration, symbol, exportSymbol) { const reflection = context.createDeclarationReflection(ReflectionKind.Interface, symbol, exportSymbol); reflection.comment = context.getJsDocComment(declaration); context.finalizeDeclarationReflection(reflection); const rc = context.withScope(reflection); const type = context.checker.getDeclaredTypeOfSymbol(symbol); for (const s of type.getProperties()) { context.converter.convertSymbol(rc, s); } convertTemplateParameters(rc, declaration.parent); } function convertJsDocSignature(context, node) { const symbol = context.getSymbolAtLocation(node) ?? node.symbol; const type = context.getTypeAtLocation(node); if (!symbol || !type) { return new IntrinsicType("Function"); } const reflection = new DeclarationReflection("__type", ReflectionKind.TypeLiteral, context.scope); context.registerReflection(reflection, symbol); context.converter.trigger(ConverterEvents.CREATE_DECLARATION, context, reflection); const signature = new SignatureReflection("__type", ReflectionKind.CallSignature, reflection); context.project.registerSymbolId(signature, new ReflectionSymbolId(symbol, node)); context.registerReflection(signature, void 0); const signatureCtx = context.withScope(signature); reflection.signatures = [signature]; signature.type = context.converter.convertType(signatureCtx, node.type?.typeExpression?.type); signature.parameters = convertParameterNodes(signatureCtx, signature, node.parameters); signature.typeParameters = convertTemplateParameterNodes(context.withScope(reflection), node.typeParameters); return new ReflectionType(reflection); } function convertTemplateParameters(context, node) { ok(context.scope instanceof DeclarationReflection); context.scope.typeParameters = convertTemplateParameterNodes(context, node.tags?.filter(ts.isJSDocTemplateTag)); } function getTypedefReExportTarget(context, declaration) { const typeExpression = declaration.typeExpression; if (!ts.isJSDocTypedefTag(declaration) || !typeExpression || ts.isJSDocTypeLiteral(typeExpression) || !ts.isImportTypeNode(typeExpression.type) || !typeExpression.type.qualifier || !ts.isIdentifier(typeExpression.type.qualifier)) { return; } const targetSymbol = context.expectSymbolAtLocation(typeExpression.type.qualifier); const decl = targetSymbol.declarations?.[0]; if (!decl || !(ts.isTypeAliasDeclaration(decl) || ts.isInterfaceDeclaration(decl) || ts.isJSDocTypedefTag(decl) || ts.isJSDocCallbackTag(decl))) { return; } const targetParams = ts.getEffectiveTypeParameterDeclarations(decl); const localParams = ts.getEffectiveTypeParameterDeclarations(declaration); const localArgs = typeExpression.type.typeArguments || []; // If we have type parameters, ensure they are forwarding parameters with no transformations. // This doesn't check constraints since they aren't checked in JSDoc types. if (targetParams.length !== localParams.length || localArgs.some((arg, i) => !ts.isTypeReferenceNode(arg) || !ts.isIdentifier(arg.typeName) || arg.typeArguments || localParams[i]?.name.text !== arg.typeName.text)) { return; } return targetSymbol; }