PackagesTree

tcmts.vscode.extension.PackagesTree · #6dtqvxbw · class

The packages the codebase runs: each package, then (when it runs more than one) each compatible range, then the definitions that use it. A package or range opens its page (README, API, users).

import { running, session } from "#codebase/tcmts/vscode/extension";
import type { PackageNode, PackageRange } from "#codebase/tcmts/vscode/extension";
import * as vscode from "vscode";

export class PackagesTree implements vscode.TreeDataProvider<PackageNode> {
  changed = new vscode.EventEmitter<PackageNode | undefined | void>();
  onDidChangeTreeData = this.changed.event;

  refresh() {
    this.changed.fire();
  }
  async getChildren(element?: PackageNode): Promise<PackageNode[]> {
    if (!running()) return [];
    const client = session.client!;
    if (!element) {
      const pkgs = (await client.sendRequest("tcm/packages", {})) as { name: string; ranges: PackageRange[] }[];
      return pkgs.map((p): PackageNode => (p.ranges.length === 1 ? { kind: "range", name: p.name, ...p.ranges[0]!, only: true } : { kind: "package", ...p }));
    }
    if (element.kind === "package") return element.ranges.map((r) => ({ kind: "range" as const, name: element.name, ...r }));
    if (element.kind === "range") {
      const users = (await client.sendRequest("tcm/packageUsers", { name: element.name, range: element.range })) as { path: string; hash: string; signature: string; kind?: string }[];
      return users.map(({ kind, ...u }) => ({ kind: "user" as const, userKind: kind, ...u }));
    }
    return [];
  }
  getTreeItem(e: PackageNode): vscode.TreeItem {
    if (e.kind === "user") {
      const item = new vscode.TreeItem(e.path, vscode.TreeItemCollapsibleState.None);
      item.description = e.userKind === "type" ? "type" : e.signature;
      item.iconPath = new vscode.ThemeIcon(e.userKind === "type" ? "symbol-interface" : "symbol-function");
      item.command = { command: "tcm.openPage", title: "Open page", arguments: [{ hash: e.hash }] };
      return item;
    }
    if (e.kind === "package") {
      const item = new vscode.TreeItem(e.name, vscode.TreeItemCollapsibleState.Collapsed);
      item.id = `package:${e.name}`;
      item.description = `${e.ranges.length} ranges: ${e.ranges.map((r) => r.version).join(", ")}`;
      item.iconPath = new vscode.ThemeIcon("package");
      item.contextValue = "package";
      return item;
    }
    const label = e.only ? e.name : `${e.name} ${e.range}`;
    const item = new vscode.TreeItem(label, e.users ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None);
    item.id = `package:${e.name}@${e.range}`;
    item.description = `${e.version} · ${e.users ? `${e.users} use${e.users === 1 ? "" : "s"}` : "unused"}`;
    item.iconPath = new vscode.ThemeIcon(e.only ? "package" : "tag");
    item.tooltip = new vscode.MarkdownString(
      `**${e.name}** ${e.version} (range ${e.range})${e.types ? `\n\ntypes: @types ${e.types}` : ""}${e.integrity ? `\n\n\`${e.integrity.slice(0, 30)}…\`` : ""}`,
    );
    item.contextValue = "packageRange";
    item.command = { command: "tcm.openPackagePage", title: "Open page", arguments: [e] };
    return item;
  }
}

uses

used by