DEV Community

Cover image for Inside Visual Studio Code - Classes and Interfaces
Alvaro Videla
Alvaro Videla

Posted on • Updated on

Inside Visual Studio Code - Classes and Interfaces

I've been trying to dive into the internals of Visual Studio Code, so I wanted to have a tool that would let me see the names of classes and interfaces declared in VSC own code.

This tool would traverse VSC own code, load the TypeScript files defined there, and then for each file it would output something like this:

ColorPickerBody|/path/to/vscode/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts
ColorPickerHeader|/path/to/vscode/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts

Where ColorPickerBody and ColorPickerHeader are two classes defined inside colorPickerWidget.ts.

Yesterday I asked on Twitter if someone knew about a tool that could extract this information from a TypeScript file. Someone recommended that I use ts-morph, which after taking a look at the examples on their docs, seemed to do just what I wanted.

So I started a new TypeScript project, npm'ed ts-morph and then built something like this:

import { Project, ClassDeclaration, InterfaceDeclaration } from "ts-morph";

const project = new Project();
project.addSourceFilesAtPaths("../vscode/src/vs/**/*.ts");

const sourceFiles = project.getSourceFiles();

for (let f of sourceFiles) {
    let fileName = f.getFilePath();
    let classDeclarations = f.getClasses();
    let interfaceDeclarations = f.getInterfaces();

    for (let c of classDeclarations) {
        console.log(`${c.getName()}|${fileName}`);
    }

    for (let i of interfaceDeclarations) {
        console.log(`${i.getName()}|${fileName}`);
    }
}

Let's see that in detail. First we import the required types from ts-morph:

import { Project, ClassDeclaration, InterfaceDeclaration } from "ts-morph";

Then we create a new project, and we add source files to it. In this case we asume the location of the VSC repo–of course you could provide this as a CLI argument.

const project = new Project();
project.addSourceFilesAtPaths("../vscode/src/vs/**/*.ts");

We are going to traverse those files to extract class and interface definitions. We do that by calling project.getSourceFiles(), which returns an array of SourceFile. SourceFile is a class that can return a lot of information about a TypeScript file, from it's file name, to the imports declared there, and so on.

Once we have the SourceFiles[] we are going to iterate it, to output the information we need:

for (let f of sourceFiles) {
    let fileName = f.getFilePath();
    let classDeclarations = f.getClasses();
    let interfaceDeclarations = f.getInterfaces();

    for (let c of classDeclarations) {
        console.log(`${c.getName()}|${fileName}`);
    }

    for (let i of interfaceDeclarations) {
        console.log(`${i.getName()}|${fileName}`);
    }
}

As you can see each SourceFile can tell us about its name, via f.getFilePath(), and also return the declared classes and interfaces via f.getClasses() and f.getInterfaces() respectively.

We use two for loops, where we output the information in the following format: className|fileName, or interfaceName|fileName.

And that's it, after we compile the project, we can run it from the CLI and get the information we want:

IStaticExtension|/path/to/vscode/src/vs/workbench/workbench.web.api.ts
ICommontTelemetryPropertiesResolver|/path/to/vscode/src/vs/workbench/workbench.web.api.ts
IExternalUriResolver|/path/to/vscode/src/vs/workbench/workbench.web.api.ts
TunnelOptions|/path/to/vscode/src/vs/workbench/workbench.web.api.ts

You might have been wondering why I want the information output in that format. I want to be able to pass this file to bash's sort and have an easy way to see which class & interface definition name are repeated across the project.

Why? Soon I'll write another article explaining why.

Top comments (0)