CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-npmcli--arborist

Comprehensive node_modules tree management library for npm dependency resolution and reification

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

links.mddocs/

Symbolic Links

The Link class extends Node to represent symbolic links within node_modules directories. Links delegate dependency resolution to their targets while maintaining their own position in the tree structure.

Capabilities

Constructor

Creates a new Link instance representing a symbolic link.

/**
 * Create a new symbolic link node
 * @param options - Link configuration options
 */
constructor(options?: LinkOptions): Link;

interface LinkOptions extends NodeOptions {
  /** Link target node */
  target?: Node;
  /** Real path to link target (required) */
  realpath: string;
  /** Is store link */
  isStoreLink?: boolean;
}

Usage Example:

const { Link } = require('@npmcli/arborist');

// Create a link to a target node
const link = new Link({
  name: 'my-package',
  parent: rootNode,
  realpath: '/path/to/actual/package',
  target: targetNode
});

Link-Specific Properties

Properties that distinguish links from regular nodes.

interface LinkSpecificProperties {
  /** Always true for Link instances */
  isLink: true;
  /** Target node that the link points to */
  target: Node;
  /** Relative path to target (computed property) */
  resolved: string;
  /** Is store link */
  isStoreLink: boolean;
  /** Always empty Map (read-only) */
  children: Map<string, Node>;
}

Usage Examples:

// Check if node is a link
if (node.isLink) {
  console.log(`Link target: ${node.target.name}@${node.target.version}`);
  console.log(`Target path: ${node.target.path}`);
  console.log(`Resolved path: ${node.resolved}`);
}

// Links have no direct children
console.log(`Link children count: ${node.children.size}`); // Always 0

// Access target's children instead
console.log(`Target children: ${Array.from(node.target.children.keys())}`);

Target Delegation

Links delegate certain operations to their targets, particularly dependency resolution.

/**
 * Links inherit most Node methods but delegate resolution to target
 * Dependencies are resolved from target location, not link location
 */
interface LinkDelegation {
  /** Delegates to target.resolve() */
  resolve(name: string): Node | undefined;
  /** Target's package.json content */
  package: object;
  /** Target's version */
  version: string;
  /** Target's dependency edges */
  edgesOut: Map<string, Edge>;
}

Usage Example:

// Resolution happens from target location
const dependency = link.resolve('express');
// This is equivalent to:
const dependency2 = link.target.resolve('express');

// Package information comes from target
console.log(`Link package name: ${link.package.name}`);
console.log(`Link version: ${link.version}`);

// Dependencies come from target
console.log(`Link dependencies: ${Array.from(link.edgesOut.keys())}`);

Path Resolution

Links maintain their own path while pointing to a target with a different path.

interface LinkPathResolution {
  /** Path to the link itself */
  path: string;
  /** Real path to the target */
  realpath: string;
  /** Computed relative path from link to target */
  resolved: string;
}

Usage Example:

console.log(`Link path: ${link.path}`);           // e.g. /proj/node_modules/pkg
console.log(`Target path: ${link.realpath}`);     // e.g. /proj/packages/pkg  
console.log(`Resolved path: ${link.resolved}`);   // e.g. ../../packages/pkg

Store Links

Special type of links used for package stores and global installations.

/**
 * Store links are special links used in package stores
 * @param isStoreLink - Whether this is a store link
 */
interface StoreLinkProperties {
  /** Is this a store link */
  isStoreLink: boolean;
}

Usage Example:

// Check if this is a store link
if (link.isStoreLink) {
  console.log('This is a store link (global or cached package)');
}

// Create a store link
const storeLink = new Link({
  name: 'global-package',
  realpath: '/usr/local/lib/node_modules/global-package',
  target: globalPackageNode,
  isStoreLink: true
});

Key Differences from Node

Children Handling

Links cannot have direct children - their children map is always empty.

// Regular node can have children
const regularNode = new Node({ name: 'parent' });
regularNode.children.set('child', childNode); // Works

// Link cannot have children
const link = new Link({ name: 'link', target: targetNode });
link.children.set('child', childNode); // children remains empty
console.log(link.children.size); // Always 0

Dependency Resolution

Dependencies are resolved from the target's location, not the link's location.

// If link is at /project/node_modules/my-package
// But target is at /project/packages/my-package
// Resolution happens from /project/packages/my-package
const resolved = link.resolve('dependency');
// Uses Node.js resolution from target location

Tree Structure

Links maintain their position in the tree while delegating content to targets.

// Link has its own parent/location
console.log(`Link parent: ${link.parent.name}`);
console.log(`Link location: ${link.location}`);

// But content comes from target
console.log(`Package content: ${link.package.name}`);
console.log(`Dependencies: ${Array.from(link.edgesOut.keys())}`);

// Target might be elsewhere in tree or outside tree entirely
console.log(`Target parent: ${link.target.parent?.name || 'none'}`);

Common Use Cases

Workspace Links

Links between packages in a monorepo workspace.

// Package A depends on Package B in same workspace
const workspaceLink = new Link({
  name: 'package-b',
  parent: packageANode,
  realpath: '/workspace/packages/package-b',
  target: packageBNode
});

Global Package Links

Links to globally installed packages.

// Global CLI tool linked into project
const globalLink = new Link({
  name: 'some-cli',
  parent: rootNode,
  realpath: '/usr/local/lib/node_modules/some-cli',
  target: globalCliNode,
  isStoreLink: true
});

Development Links

Links created during development (e.g., npm link).

// Development package linked for testing
const devLink = new Link({
  name: 'my-dev-package',
  parent: testProjectNode,
  realpath: '/home/dev/my-dev-package',
  target: devPackageNode
});

Store Cache Links

Links to packages in a content-addressable store.

// Package from content store
const cacheLink = new Link({
  name: 'cached-package',
  parent: rootNode,
  realpath: '/cache/store/abc123/node_modules/cached-package',
  target: cachedPackageNode,
  isStoreLink: true
});

Working with Links

Detecting Links

// Check if a node is a link
if (node.isLink) {
  console.log('This is a symbolic link');
  console.log(`Points to: ${node.target.path}`);
} else {
  console.log('This is a regular package');
}

Following Links

// Get the actual package content
const actualPackage = node.isLink ? node.target : node;
console.log(`Actual package: ${actualPackage.name}@${actualPackage.version}`);

Finding Link Sources

// Find what links to a target
if (node.linksIn.size > 0) {
  console.log(`This package has ${node.linksIn.size} links pointing to it:`);
  for (const link of node.linksIn) {
    console.log(`  - ${link.location} -> ${node.location}`);
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-npmcli--arborist

docs

arborist.md

edges.md

index.md

links.md

shrinkwrap.md

tree-navigation.md

tile.json