Skip to main content
Glama
nrwl

Nx MCP Server

Official
by nrwl
nx-project-tree-view.ts4.16 kB
import { TreeMap, TreeNode } from '@nx-console/shared-types'; import { getWorkspacePath } from '@nx-console/vscode-utils'; import type { ProjectConfiguration } from 'nx/src/devkit-exports'; import { join, parse } from 'path'; import { TreeItemCollapsibleState } from 'vscode'; import { BaseView, FolderViewItem, ProjectGraphErrorViewItem, ProjectViewItem, TargetGroupViewItem, TargetViewItem, } from './nx-project-base-view'; export type TreeViewItem = | FolderViewItem | ProjectViewItem | TargetViewItem | TargetGroupViewItem | ProjectGraphErrorViewItem; export type ProjectInfo = { dir: string; configuration: ProjectConfiguration; }; /* eslint-disable @typescript-eslint/no-non-null-assertion -- dealing with maps is hard */ export class TreeView extends BaseView { treeMap: TreeMap; roots: TreeNode[]; async getChildren( element?: TreeViewItem ): Promise<TreeViewItem[] | undefined> { if (!element) { const items: TreeViewItem[] = []; if (this.workspaceData?.errors) { items.push( this.createProjectGraphErrorViewItem(this.workspaceData.errors.length) ); } // if there's only a single root, start with it expanded const isSingleProject = this.roots.length === 1; items.push( ...this.roots .sort((a, b) => { // the VSCode tree view looks chaotic when folders and projects are on the same level // so we sort the nodes to have folders first and projects after if (!!a.projectName == !!b.projectName) { return a.dir.localeCompare(b.dir); } return a.projectName ? 1 : -1; }) .map((root) => this.createFolderOrProjectTreeItemFromNode( root, isSingleProject ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed ) ) ); return items; } if (element.contextValue === 'project') { const targetChildren = (await this.createTargetsAndGroupsFromProject(element)) ?? []; let folderAndProjectChildren: (ProjectViewItem | FolderViewItem)[] = []; if (element.nxProject && this.treeMap.has(element.nxProject.root)) { folderAndProjectChildren = this.treeMap .get(element.nxProject.root)! .children.map((folderOrProjectNodeDir) => this.createFolderOrProjectTreeItemFromNode( this.treeMap.get(folderOrProjectNodeDir)! ) ); } return [...targetChildren, ...folderAndProjectChildren]; } if (element.contextValue === 'folder') { if (this.treeMap.has(element.path)) { return this.treeMap .get(element.path)! .children.map((folderOrProjectNodeDir) => this.createFolderOrProjectTreeItemFromNode( this.treeMap.get(folderOrProjectNodeDir)! ) ); } } if (element.contextValue === 'targetGroup') { return this.createTargetsFromTargetGroup(element); } if (element.contextValue === 'target') { return this.createConfigurationsFromTarget(element); } } private createFolderTreeItem( path: string, collapsible = TreeItemCollapsibleState.Collapsed ): FolderViewItem { const folderName = parse(path).base; /** * In case that a project does not have a root value. * Show a placeholder value instead */ const label = folderName === '' ? '<root>' : folderName; return { id: `$folder:${path}`, contextValue: 'folder', path, label, resource: join(getWorkspacePath(), path), collapsible, }; } private createFolderOrProjectTreeItemFromNode( node: TreeNode, collapsible = TreeItemCollapsibleState.Collapsed ): ProjectViewItem | FolderViewItem { const config = node.projectConfiguration; return config ? this.createProjectViewItem( [config.name ?? node.projectName ?? '', config], collapsible ) : this.createFolderTreeItem(node.dir, collapsible); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nrwl/nx-console'

If you have feedback or need assistance with the MCP directory API, please join our Discord server