CLI compatibility layer for older Nx workspaces that serves as a bridge to core nx functionality
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Types and interfaces for analyzing project dependencies and workspace structure. Provides comprehensive type definitions for working with project graphs, dependency relationships, and file metadata within Nx workspaces.
Main interface representing the complete project dependency graph.
/**
* Main project graph interface representing workspace structure and dependencies
*/
export interface ProjectGraph {
/** Map of project names to project nodes */
nodes: Record<string, ProjectGraphProjectNode>;
/** Map of external dependency names to external nodes (e.g., npm packages) */
externalNodes?: Record<string, ProjectGraphExternalNode>;
/** Map of project names to their dependency arrays */
dependencies: Record<string, ProjectGraphDependency[]>;
/** All workspace files with metadata */
allWorkspaceFiles?: FileData[];
/** Version of the project graph format */
version?: string;
}Type definitions for different types of nodes in the project graph.
/**
* Workspace project node representing internal projects
*/
export interface ProjectGraphProjectNode {
/** Type of project */
type: 'app' | 'e2e' | 'lib';
/** Project name */
name: string;
/** Project configuration and metadata */
data: ProjectConfiguration & {
files: FileData[];
description?: string;
};
}
/**
* External dependency node representing npm packages and other external dependencies
*/
export interface ProjectGraphExternalNode {
/** Type of external dependency */
type: 'npm';
/** External node name with prefix */
name: `npm:${string}`;
/** External dependency metadata */
data: {
version: string;
packageName: string;
hash?: string;
};
}Types for representing dependency relationships between projects.
/**
* Dependency relationship between projects or external dependencies
*/
export interface ProjectGraphDependency {
/** Type of dependency relationship */
type: DependencyType | string;
/** Target project or dependency name */
target: string;
/** Source project name */
source: string;
}
/**
* Types of dependency relationships
*/
export enum DependencyType {
/** Static imports and explicit dependencies */
static = 'static',
/** Dynamic imports and runtime dependencies */
dynamic = 'dynamic',
/** Implicit dependencies configured in nx.json */
implicit = 'implicit'
}Types for representing file information and dependencies.
/**
* File metadata with hash and dependency information
*/
export interface FileData {
/** File path relative to workspace root */
file: string;
/** Content hash of the file */
hash: string;
/** @deprecated Use dependencies instead */
deps?: string[];
/** Dependencies discovered in this file */
dependencies?: ProjectGraphDependency[];
}
/** Map of project names to their file arrays */
export type ProjectFileMap = Record<string, FileData[]>;Types for extending and processing project graphs.
/**
* Context provided to project graph processors
*/
export interface ProjectGraphProcessorContext {
/** Current workspace root path */
workspaceRoot: string;
/** Projects configuration */
projectsConfigurations: ProjectsConfigurations;
/** Nx configuration */
nxJsonConfiguration: NxJsonConfiguration;
/** Files mapped by project */
fileMap: ProjectFileMap;
/** Files mapped by project (updated by processors) */
filesToProcess: ProjectFileMap;
}
/**
* Function type for processing and extending project graphs
*/
export type ProjectGraphProcessor = (
graph: ProjectGraph,
context: ProjectGraphProcessorContext
) => ProjectGraph;import type { ProjectGraph, ProjectGraphDependency, DependencyType } from "@nrwl/tao/shared/project-graph";
function analyzeProjectDependencies(graph: ProjectGraph, projectName: string) {
const dependencies = graph.dependencies[projectName] || [];
// Group dependencies by type
const staticDeps = dependencies.filter(dep => dep.type === DependencyType.static);
const dynamicDeps = dependencies.filter(dep => dep.type === DependencyType.dynamic);
const implicitDeps = dependencies.filter(dep => dep.type === DependencyType.implicit);
console.log(`${projectName} dependencies:`);
console.log(` Static: ${staticDeps.length}`);
console.log(` Dynamic: ${dynamicDeps.length}`);
console.log(` Implicit: ${implicitDeps.length}`);
return {
static: staticDeps,
dynamic: dynamicDeps,
implicit: implicitDeps
};
}import type { ProjectGraph, ProjectGraphProjectNode } from "@nrwl/tao/shared/project-graph";
function getProjectsByType(graph: ProjectGraph): Record<string, ProjectGraphProjectNode[]> {
const projects = Object.values(graph.nodes);
return {
apps: projects.filter(p => p.type === 'app'),
libs: projects.filter(p => p.type === 'lib'),
e2e: projects.filter(p => p.type === 'e2e')
};
}
function getProjectFileCount(graph: ProjectGraph, projectName: string): number {
const project = graph.nodes[projectName];
return project?.data.files?.length || 0;
}import type { ProjectGraph, ProjectGraphExternalNode } from "@nrwl/tao/shared/project-graph";
function analyzeExternalDependencies(graph: ProjectGraph) {
const externalNodes = graph.externalNodes || {};
const npmPackages = Object.values(externalNodes)
.filter((node): node is ProjectGraphExternalNode => node.type === 'npm')
.map(node => ({
name: node.data.packageName,
version: node.data.version
}));
console.log(`External dependencies: ${npmPackages.length}`);
npmPackages.forEach(pkg => {
console.log(` ${pkg.name}@${pkg.version}`);
});
return npmPackages;
}import type { ProjectGraph, ProjectGraphDependency } from "@nrwl/tao/shared/project-graph";
function findDependencyChain(graph: ProjectGraph, from: string, to: string): string[] | null {
const visited = new Set<string>();
const path: string[] = [];
function dfs(current: string): boolean {
if (current === to) {
path.push(current);
return true;
}
if (visited.has(current)) {
return false;
}
visited.add(current);
path.push(current);
const dependencies = graph.dependencies[current] || [];
for (const dep of dependencies) {
if (dfs(dep.target)) {
return true;
}
}
path.pop();
return false;
}
return dfs(from) ? path : null;
}import type { FileData, ProjectFileMap } from "@nrwl/tao/shared/project-graph";
function getChangedFiles(fileMap: ProjectFileMap, previousHashes: Record<string, string>): FileData[] {
const changedFiles: FileData[] = [];
Object.values(fileMap).forEach(projectFiles => {
projectFiles.forEach(file => {
const previousHash = previousHashes[file.file];
if (!previousHash || previousHash !== file.hash) {
changedFiles.push(file);
}
});
});
return changedFiles;
}
function getFilesWithDependencies(fileMap: ProjectFileMap): FileData[] {
return Object.values(fileMap)
.flat()
.filter(file => file.dependencies && file.dependencies.length > 0);
}The project graph types integrate with other @nrwl/tao workspace management APIs:
import type { ProjectGraph } from "@nrwl/tao/shared/project-graph";
import { Workspaces } from "@nrwl/tao/shared/workspace";
import { logger } from "@nrwl/tao/shared/logger";
function analyzeWorkspaceStructure(root: string, graph: ProjectGraph) {
const workspaces = new Workspaces(root);
const projects = workspaces.readProjectsConfigurations();
// Compare project graph with workspace configuration
const configuredProjects = Object.keys(projects.projects);
const graphProjects = Object.keys(graph.nodes);
const missingFromGraph = configuredProjects.filter(p => !graphProjects.includes(p));
const missingFromConfig = graphProjects.filter(p => !configuredProjects.includes(p));
if (missingFromGraph.length > 0) {
logger.warn(`Projects missing from graph: ${missingFromGraph.join(', ')}`);
}
if (missingFromConfig.length > 0) {
logger.warn(`Projects missing from config: ${missingFromConfig.join(', ')}`);
}
}Install with Tessl CLI
npx tessl i tessl/npm-nrwl--tao