Plugins
Creating a Custom Plugin

Creating a Custom Plugin

If you wish to extract information from your code that is not available with a built-in plugin, you can create a custom one.

Plugin Model

A plugin is a class that implements the BaseAnalyzerPluginModel interface. This interface defines the following properties:

PropertyTypeDescription
onFinishProcessing() => PluginAnalyzedEntity[]Callback function called when processing of all files finishes.
onAllFinishProcessing(items: AnalyzeResults, plugin: BasePlugin) => anyCallback function called when processing of all plugins finishes. Used for post-processor plugins
fileExtensionsRegExp[]Which files CodeInsights should scan
analyzeFile(analyzeInfo: T, pluginOptions: PluginOptions) => anyCalled on each file, this is where the logic of extracing the insights from the code exists
namestringName of the plugin.

Keep in mind that all of these properties are optional, so you can use only the ones you need.

Plugin Types

Start by creating a class with your plugin name. The plugin needs to extends one of the following classes:

  1. BaseAnalyzerPlugin - use this if you don't intend to parse any files with the plugin, but only do post-processing, or if you want to parse files that are not supported by CodeInsights.
  2. TypeScriptPlugin - use this if you intend to parse JS/TS files.
  3. HTMLPlugin - use this if you intend to parse HTML files.
  4. JSONPlugin - use this if you intend to parse JSON files.

These type of plugins will dictate which parser that CodeInsights will use to analyze the files, and the type of information that will be provided to the plugin in the analyzeFile function.

Example

For this example, we'll choose the TypeScriptPlugin:

class ImportsPlugin extends TypeScriptPlugin {
  fileExtensions = ["ts", "js"] // optional, this is the default with TypeScriptPlugin
 
  analyzeFile({ labels, visit }: TypeScriptAnalyzeInfo) {
 
  }
 
  onFinishProcessing() {
 
  }
 
  // Useful for post-processor plugins
  onAllFinishProcessing() {
 
  }
}

The analyzeFile method will be called for each file in the codebase, an ast as well as visit utils is provided, in addition to the file information.

From here, you can use the AST to extract specific information, and save it somewhere in the class.

The onFinishProcessing method will be called after all files have been analyzed. This is where you can do any post-processing requires by the plugin, and return the final result.

Make sure that this function returns the results, otherwise processor plugins won't be able to use them.

Full plugin:

interface ImportDefinition {
  type: "import";
  path: string;
  metrics: AnalyzedEntityMetrics;
  labels: {
    name: string;
    importedFrom: string;
  };
}
 
class ImportsPlugin extends TypeScriptPlugin {
  allFilesImports: ImportDefinition[] = [];
 
  analyzeFile({ labels, visit }: TypeScriptAnalyzeInfo) {
    const { filePath } = labels;
    const allFilesImports: ImportDefinition[] = [];
    visit({
      visitImportDeclaration(path) {
        const importPath = path.node.source.value as string;
        const importItems = path.node.specifiers;
        if (importItems?.length) {
          for (const item of importItems) {
            const getName = () => {
              if (
                item.type === "ImportDefaultSpecifier" ||
                item.type === "ImportNamespaceSpecifier"
              ) {
                return item.local?.name;
              }
              return item.imported.name;
            };
            const importDefinition: ImportDefinition = {
              type: "import",
              metrics: {},
              path: filePath,
              labels: {
                name: getName() as string,
                importedFrom: importPath,
              },
            };
            allFilesImports.push(importDefinition);
          }
        }
        this.traverse(path);
      },
    });
    this.allFilesImports.push(...allFilesImports);
  }
 
  onFinishProcessing() {
    return this.allFilesImports;
  }
}
 
export default ImportsPlugin;

Summary

Creating a plugin is simple once you understand the structure of it.

Even if you want to parse a file that is not yet supported, you can do this as the file contents is one of the metadata that is provided to the analyzeFile function.

Contributing a Plugin

We welcome the contributions of new plugins to the project. If you have created a plugin that you think would be useful to others, please consider submitting it to the project. If you'd like to maintain the plugin on your own, we are happy to feature it here.