Search code examples
typescriptvisual-studio-codestatic-analysis

How to extract VS Code tooltip typescript information programmatically?


For example, I have this function:

import * as EC2 from "@aws-sdk/client-ec2";

const ec2 = new EC2.EC2({ region: "us-west-2" });

export async function getInfra() {
  const describeVpcs = await ec2.describeVpcs();

  const describeSubnets = await ec2.describeSubnets({
    Filters: [
      {
        Name: "vpc-id",
        Values: describeVpcs.Vpcs?.map((vpc) => vpc.VpcId!),
      },
    ],
  });

  const subnetIds = describeSubnets.Subnets?.map((subnet) => subnet.SubnetId!);

  return { describeVpcs, describeSubnets, subnetIds };
}

VS Code gives the awesome tooltip hover of:

function getInfra(): Promise<{
    describeVpcs: EC2.DescribeVpcsCommandOutput;
    describeSubnets: EC2.DescribeSubnetsCommandOutput;
    subnetIds: string[] | undefined;
}>

I would merely like to be able to generate this programmatically with a script. How might I do that?


Solution

  • Wow, how amazingly elegant ts is!

    const program = ts.createProgram([entryFile], {
        target: ts.ScriptTarget.Latest,
        module: ts.ModuleKind.CommonJS,
        noResolve: false,
        skipLibCheck: true,
      });
    
    const checker = program.getTypeChecker();
    const sourceFile = program.getSourceFile(entryFile);
    
    (function importsAndExportsFrom(sourceFile: ts.SourceFile) {
      ts.forEachChild(sourceFile, (node) => {
        switch (node.kind) {
          case ts.SyntaxKind.ExportDeclaration:
          case ts.SyntaxKind.ImportDeclaration: {
            const decl = node as ts.ImportDeclaration | ts.ExportDeclaration;
            const module = decl.moduleSpecifier;
            const symbol = checker.getSymbolAtLocation(module);
            if (!module || !symbol || module.getText().includes(pkg.name)) {
              return;
            }
            importsAndExportsFrom(symbol.declarations.pop() as ts.SourceFile);
            break;
          }
          case ts.SyntaxKind.FunctionDeclaration: {
            const func = node as ts.FunctionDeclaration;
            const name = func.name.getText();
            const signature = checker.getSignatureFromDeclaration(func);
            const parameters = func.parameters.map((p) => ({
              name: p.name.getText(),
              type: p.type.getText(),
            }));
            const returnType = checker.typeToString(
              checker.getReturnTypeOfSignature(signature),
              undefined,
              ts.TypeFormatFlags.NoTruncation
            );
            break;
          }
          default:
            break;
        }
      });
    })(sourceFile);