[READ-ONLY] a fast, modern browser for the npm registry
at main 96 lines 3.4 kB view raw
1/** 2 * Signature Formatting 3 * 4 * Functions for formatting TypeScript signatures, parameters, and types. 5 * 6 * @module server/utils/docs/format 7 */ 8 9import type { DenoDocNode, FunctionParam, TsType } from '#shared/types/deno-doc' 10import { cleanSymbolName, stripAnsi } from './text' 11 12/** 13 * Generate a TypeScript signature string for a node. 14 */ 15export function getNodeSignature(node: DenoDocNode): string | null { 16 const name = cleanSymbolName(node.name) 17 18 switch (node.kind) { 19 case 'function': { 20 const typeParams = node.functionDef?.typeParams?.map(t => t.name).join(', ') 21 const typeParamsStr = typeParams ? `<${typeParams}>` : '' 22 const params = node.functionDef?.params?.map(p => formatParam(p)).join(', ') || '' 23 const ret = formatType(node.functionDef?.returnType) || 'void' 24 const asyncStr = node.functionDef?.isAsync ? 'async ' : '' 25 return `${asyncStr}function ${name}${typeParamsStr}(${params}): ${ret}` 26 } 27 case 'class': { 28 const ext = node.classDef?.extends ? ` extends ${formatType(node.classDef.extends)}` : '' 29 const impl = node.classDef?.implements?.map(t => formatType(t)).join(', ') 30 const implStr = impl ? ` implements ${impl}` : '' 31 const abstractStr = node.classDef?.isAbstract ? 'abstract ' : '' 32 return `${abstractStr}class ${name}${ext}${implStr}` 33 } 34 case 'interface': { 35 const typeParams = node.interfaceDef?.typeParams?.map(t => t.name).join(', ') 36 const typeParamsStr = typeParams ? `<${typeParams}>` : '' 37 const ext = node.interfaceDef?.extends?.map(t => formatType(t)).join(', ') 38 const extStr = ext ? ` extends ${ext}` : '' 39 return `interface ${name}${typeParamsStr}${extStr}` 40 } 41 case 'typeAlias': { 42 const typeParams = node.typeAliasDef?.typeParams?.map(t => t.name).join(', ') 43 const typeParamsStr = typeParams ? `<${typeParams}>` : '' 44 const type = formatType(node.typeAliasDef?.tsType) || 'unknown' 45 return `type ${name}${typeParamsStr} = ${type}` 46 } 47 case 'variable': { 48 const keyword = node.variableDef?.kind === 'const' ? 'const' : 'let' 49 const type = formatType(node.variableDef?.tsType) || 'unknown' 50 return `${keyword} ${name}: ${type}` 51 } 52 case 'enum': { 53 return `enum ${name}` 54 } 55 default: 56 return null 57 } 58} 59 60/** 61 * Format a function parameter. 62 */ 63export function formatParam(param: FunctionParam): string { 64 const optional = param.optional ? '?' : '' 65 const type = formatType(param.tsType) 66 return type ? `${param.name}${optional}: ${type}` : `${param.name}${optional}` 67} 68 69/** 70 * Format a TypeScript type. 71 */ 72export function formatType(type?: TsType): string { 73 if (!type) return '' 74 75 // Strip ANSI codes from repr (deno doc may include terminal colors since it's built for that) 76 if (type.repr) return stripAnsi(type.repr) 77 78 if (type.kind === 'keyword' && type.keyword) { 79 return type.keyword 80 } 81 82 if (type.kind === 'typeRef' && type.typeRef) { 83 const params = type.typeRef.typeParams?.map(t => formatType(t)).join(', ') 84 return params ? `${type.typeRef.typeName}<${params}>` : type.typeRef.typeName 85 } 86 87 if (type.kind === 'array' && type.array) { 88 return `${formatType(type.array)}[]` 89 } 90 91 if (type.kind === 'union' && type.union) { 92 return type.union.map(t => formatType(t)).join(' | ') 93 } 94 95 return type.repr ? stripAnsi(type.repr) : 'unknown' 96}