or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-pnpm--workspace-pkgs-graph

Create a graph from an array of packages in workspace environments

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@pnpm/workspace.pkgs-graph@1000.0.x

To install, run

npx @tessl/cli install tessl/npm-pnpm--workspace-pkgs-graph@1000.0.0

index.mddocs/

@pnpm/workspace.pkgs-graph

@pnpm/workspace.pkgs-graph creates dependency graphs from arrays of workspace packages in monorepo environments. It analyzes package manifests and their dependencies to build directed graph structures that represent relationships between packages, supporting various dependency types and workspace-specific dependency references.

Package Information

  • Package Name: @pnpm/workspace.pkgs-graph
  • Package Type: npm
  • Language: TypeScript
  • Installation: pnpm add @pnpm/workspace.pkgs-graph

Core Imports

import { createPkgGraph, type Package, type PackageNode } from "@pnpm/workspace.pkgs-graph";

For CommonJS:

const { createPkgGraph } = require("@pnpm/workspace.pkgs-graph");

Basic Usage

import { createPkgGraph } from "@pnpm/workspace.pkgs-graph";

const packages = [
  {
    rootDir: "/workspace/foo",
    manifest: {
      name: "foo",
      version: "1.0.0",
      dependencies: {
        bar: "^1.0.0",
      },
    },
  },
  {
    rootDir: "/workspace/bar",
    manifest: {
      name: "bar",
      version: "1.1.0",
    },
  }
];

const { graph, unmatched } = createPkgGraph(packages);

console.log(graph);
// {
//   "/workspace/foo": {
//     dependencies: ["/workspace/bar"],
//     package: { rootDir: "/workspace/foo", manifest: { ... } }
//   },
//   "/workspace/bar": {
//     dependencies: [],
//     package: { rootDir: "/workspace/bar", manifest: { ... } }
//   }
// }

console.log(unmatched);
// [] - empty array means all dependencies were matched

Architecture

The package is built around several key concepts:

  • Dependency Graph Creation: Analyzes package arrays to create directed dependency graphs
  • Workspace Protocol Support: Handles workspace: protocol dependencies with version range resolution
  • Multiple Dependency Types: Processes regular, dev, peer, and optional dependencies
  • Path Resolution: Supports both relative path dependencies and file: protocol references
  • Version Matching: Intelligent version range resolution within workspace environments
  • Unmatched Tracking: Reports dependencies that couldn't be resolved to workspace packages

Capabilities

Graph Creation

Creates a dependency graph from an array of packages with configurable options for dependency processing.

/**
 * Creates a dependency graph from an array of packages
 * @param pkgs - Array of packages to analyze
 * @param opts - Optional configuration for graph creation
 * @returns Object containing the dependency graph and unmatched dependencies
 */
function createPkgGraph<Pkg extends Package>(
  pkgs: Pkg[], 
  opts?: {
    ignoreDevDeps?: boolean;
    linkWorkspacePackages?: boolean;
  }
): {
  graph: Record<ProjectRootDir, PackageNode<Pkg>>;
  unmatched: Array<{ pkgName: string; range: string }>;
};

Usage Examples:

// Basic graph creation
const result = createPkgGraph(packages);

// Ignore dev dependencies
const prodGraph = createPkgGraph(packages, { 
  ignoreDevDeps: true 
});

// Disable workspace package linking
const strictGraph = createPkgGraph(packages, { 
  linkWorkspacePackages: false 
});

Workspace Protocol Support

The library fully supports pnpm's workspace protocol syntax for referencing workspace packages:

// Supported workspace dependency formats
const packagesWithWorkspaceDeps = [
  {
    rootDir: "/workspace/app",
    manifest: {
      name: "app",
      version: "1.0.0",
      dependencies: {
        "utils": "workspace:^1.0.0",    // Version range
        "config": "workspace:*",        // Any version
        "shared": "workspace:~",        // Compatible version
        "ui-alias": "workspace:ui@*",   // Aliased package reference
      },
    },
  }
];

Directory Dependencies

Handles local directory dependencies using relative paths and file: protocol:

const packagesWithLocalDeps = [
  {
    rootDir: "/workspace/app",
    manifest: {
      name: "app",
      dependencies: {
        "local-utils": "../utils",           // Relative path
        "shared-lib": "file:../shared",      // File protocol
      },
    },
  }
];

Types

/**
 * Represents a package with manifest and root directory
 */
interface Package {
  /** Package manifest containing metadata and dependencies */
  manifest: BaseManifest;
  /** Absolute path to the package root directory */
  rootDir: ProjectRootDir;
}

/**
 * Represents a node in the dependency graph
 */
interface PackageNode<Pkg extends Package> {
  /** The package data */
  package: Pkg;
  /** Array of root directories of packages this package depends on */
  dependencies: ProjectRootDir[];
}

/**
 * Project root directory path (from @pnpm/types)
 */
type ProjectRootDir = string;

/**
 * Base manifest interface (from @pnpm/types)
 * Contains standard package.json fields including:
 * - name: string
 * - version: string  
 * - dependencies: Record<string, string>
 * - devDependencies: Record<string, string>
 * - peerDependencies: Record<string, string>
 * - optionalDependencies: Record<string, string>
 */
interface BaseManifest {
  name?: string;
  version?: string;
  dependencies?: Record<string, string>;
  devDependencies?: Record<string, string>;
  peerDependencies?: Record<string, string>;
  optionalDependencies?: Record<string, string>;
}

Configuration Options

ignoreDevDeps

When set to true, development dependencies are excluded from the dependency graph:

const result = createPkgGraph(packages, { ignoreDevDeps: true });
// Only includes dependencies, peerDependencies, and optionalDependencies

linkWorkspacePackages

Controls whether non-workspace dependencies should be linked to workspace packages. When set to false, only explicit workspace: dependencies are linked:

const result = createPkgGraph(packages, { linkWorkspacePackages: false });
// Regular version ranges won't match workspace packages
// Only workspace: prefixed dependencies will be linked

Return Value Details

Graph Structure

The graph object maps each package's root directory to its PackageNode:

const { graph } = createPkgGraph(packages);

// Access specific package node
const fooNode = graph["/workspace/foo"];
console.log(fooNode.dependencies); // Array of dependency root dirs
console.log(fooNode.package);      // Original package data

Unmatched Dependencies

The unmatched array contains dependencies that couldn't be resolved to workspace packages:

const { unmatched } = createPkgGraph(packages);

unmatched.forEach(({ pkgName, range }) => {
  console.log(`Could not resolve ${pkgName}@${range} to workspace package`);
});

Common reasons for unmatched dependencies:

  • External packages not present in workspace
  • Version ranges that don't match any workspace package versions
  • Malformed dependency specifications

Edge Cases and Error Handling

Missing Package Versions

The library gracefully handles packages without version fields:

const packagesWithoutVersions = [
  {
    rootDir: "/workspace/utils",
    manifest: {
      name: "utils",
      // No version field
    },
  }
];

// Still creates valid graph structure
const result = createPkgGraph(packagesWithoutVersions);

Invalid Dependencies

Malformed or invalid dependency specifications are silently ignored:

const packagesWithInvalidDeps = [
  {
    rootDir: "/workspace/app",
    manifest: {
      name: "app",
      dependencies: {
        "weird-dep": ":aaaaa", // Invalid spec - ignored
        "valid-dep": "^1.0.0",
      },
    },
  }
];

Case Sensitivity

The library handles case mismatches on case-insensitive filesystems by using both fast and slow path resolution strategies.

Prerelease Versions

Correctly matches prerelease versions when using wildcard ranges:

const prereleasePackages = [
  {
    rootDir: "/workspace/beta",
    manifest: {
      name: "beta",
      version: "1.0.0-beta.1", // Prerelease version
    },
  }
];

// "*" range will match prerelease versions
const result = createPkgGraph([
  {
    rootDir: "/workspace/app",
    manifest: {
      dependencies: { "beta": "*" }
    }
  },
  ...prereleasePackages
]);