Comprehensive node_modules tree management library for npm dependency resolution and reification
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The Node class represents packages in the dependency tree, providing methods for navigation, querying, and tree manipulation. Each node corresponds to a package folder and maintains relationships with parent, children, and dependency edges.
Creates a new Node instance representing a package in the tree.
/**
* Create a new Node instance
* @param options - Node configuration options
*/
constructor(options?: NodeOptions): Node;
interface NodeOptions {
/** Absolute path to package */
path?: string;
/** Parent node in tree */
parent?: Node;
/** Package name */
name?: string;
/** Root node reference */
root?: Node;
/** Real filesystem path */
realpath?: string;
/** Child node configurations */
children?: object;
/** Is development dependency */
dev?: boolean;
/** Is optional dependency */
optional?: boolean;
/** Is peer dependency */
peer?: boolean;
/** Is extraneous package */
extraneous?: boolean;
/** Is global package */
global?: boolean;
/** Error object if parsing failed */
error?: Error;
}Core properties that identify and locate the node in the filesystem and tree.
interface NodeIdentity {
/** Package name */
name: string;
/** Package name from package.json */
packageName: string;
/** Package version */
version: string;
/** Filesystem path */
path: string;
/** Real filesystem path */
realpath: string;
/** Relative location from root */
location: string;
/** Unique package identifier */
pkgid: string;
}Properties defining the node's position and relationships in the tree hierarchy.
interface NodeTreeStructure {
/** Parent node */
parent: Node | null;
/** Root node of tree */
root: Node;
/** Child nodes by name */
children: Map<string, Node>;
/** Filesystem children */
fsChildren: Set<Node>;
/** Top-level ancestor */
top: Node;
/** Is root node */
isRoot: boolean;
/** Is top-level dependency */
isTop: boolean;
/** Depth in tree */
depth: number;
}Usage Example:
// Navigate tree structure
console.log(`Node: ${node.name}@${node.version}`);
console.log(`Parent: ${node.parent?.name || 'none'}`);
console.log(`Children: ${Array.from(node.children.keys()).join(', ')}`);
console.log(`Depth: ${node.depth}`);Properties containing package metadata and content information.
interface NodePackageInfo {
/** Contents of package.json */
package: object;
/** Resolved URL or path */
resolved: string;
/** Package integrity hash */
integrity: string;
/** Parsing errors */
errors: Error[];
}Properties describing the node's dependency relationships and flags.
interface NodeDependencyInfo {
/** Outgoing dependency edges */
edgesOut: Map<string, Edge>;
/** Incoming dependency edges */
edgesIn: Set<Edge>;
/** Is development dependency */
dev: boolean;
/** Is optional dependency */
optional: boolean;
/** Is dev-optional dependency */
devOptional: boolean;
/** Is peer dependency */
peer: boolean;
/** Is extraneous */
extraneous: boolean;
/** Is bundled dependency */
bundled: boolean;
}Usage Example:
// Check dependency flags
if (node.dev) {
console.log('This is a development dependency');
}
if (node.optional) {
console.log('This is an optional dependency');
}
// Examine dependencies
for (const [name, edge] of node.edgesOut) {
console.log(`Depends on: ${name}@${edge.spec}`);
}Resolves dependencies using Node.js module resolution algorithm.
/**
* Resolve a dependency by name using Node.js resolution algorithm
* @param name - Dependency name to resolve
* @returns Resolved node or undefined if not found
*/
resolve(name: string): Node | undefined;Usage Example:
// Resolve a dependency
const expressNode = node.resolve('express');
if (expressNode) {
console.log(`Express resolved to: ${expressNode.path}`);
} else {
console.log('Express not found in resolution path');
}Methods for navigating the tree structure and examining relationships.
/**
* Generator yielding all ancestors up to root
* @returns Generator of ancestor nodes
*/
ancestry(): Generator<Node>;
/**
* Check if this node is a descendant of another node
* @param node - Potential ancestor node
* @returns True if this is a descendant of the given node
*/
isDescendantOf(node: Node): boolean;
/**
* Check if node is located within a node_modules directory
* @returns True if in node_modules
*/
inNodeModules(): boolean;Usage Examples:
// Walk up ancestry
for (const ancestor of node.ancestry()) {
console.log(`Ancestor: ${ancestor.name}`);
}
// Check relationships
if (childNode.isDescendantOf(rootNode)) {
console.log('Child is descendant of root');
}
// Check location
if (node.inNodeModules()) {
console.log('Node is in node_modules');
}Methods for comparing nodes and validating dependency satisfaction.
/**
* Check if this node matches another node (same package and version)
* @param node - Node to compare against
* @returns True if nodes match
*/
matches(node: Node): boolean;
/**
* Check if this node satisfies a dependency request
* @param requested - Edge representing the dependency request
* @returns True if this node satisfies the request
*/
satisfies(requested: Edge): boolean;
/**
* Check if this node can replace another node
* @param node - Node to potentially replace
* @param ignorePeers - Ignore peer dependency conflicts
* @returns True if replacement is valid
*/
canReplace(node: Node, ignorePeers?: boolean): boolean;
/**
* Check if this node can be replaced by another node
* @param node - Node that would replace this one
* @param ignorePeers - Ignore peer dependency conflicts
* @returns True if replacement is valid
*/
canReplaceWith(node: Node, ignorePeers?: boolean): boolean;
/**
* Check if this node can be deduplicated
* @param preferDedupe - Prefer deduplication over newer versions
* @returns True if node can be deduplicated
*/
canDedupe(preferDedupe?: boolean): boolean;Usage Examples:
// Compare nodes
if (nodeA.matches(nodeB)) {
console.log('Nodes are identical');
}
// Check satisfaction
if (node.satisfies(edge)) {
console.log(`${node.name} satisfies ${edge.name}@${edge.spec}`);
}
// Check replacement possibility
if (newNode.canReplace(oldNode)) {
console.log('New node can replace old node');
}Methods for modifying the tree structure by moving and replacing nodes.
/**
* Replace this node with another node in the tree
* @param node - Node to replace this one with
*/
replace(node: Node): void;
/**
* Replace another node with this node
* @param node - Node to be replaced
*/
replaceWith(node: Node): void;
/**
* Get the bundling parent for this node
* @param path - Path for bundling resolution
* @returns Bundling parent node
*/
getBundler(path?: string[]): Node | null;Usage Example:
// Replace a node in the tree
if (newVersion.canReplace(oldVersion)) {
oldVersion.replace(newVersion);
console.log('Node replaced successfully');
}CSS-like selector queries for finding nodes in the tree.
/**
* Find nodes matching CSS-like selector
* @param query - CSS-like selector string
* @param opts - Query options
* @returns Array of matching nodes
*/
querySelectorAll(query: string, opts?: QueryOptions): Node[];
interface QueryOptions {
/** Return all matches vs first match */
all?: boolean;
}Usage Examples:
// Find all dev dependencies
const devDeps = tree.querySelectorAll('[dev]');
// Find nodes by name
const expressNodes = tree.querySelectorAll('[name="express"]');
// Find nodes with specific attributes
const optionalNodes = tree.querySelectorAll('[optional]');Methods for getting detailed information about the node and its presence in the tree.
/**
* Explain why this node is present in the tree
* @param edge - Specific edge to explain
* @param seen - Array of already seen nodes (for cycle detection)
* @returns Explanation object
*/
explain(edge?: Edge | null, seen?: Node[]): any;
/**
* Convert node to JSON representation
* @returns JSON representation of the node
*/
toJSON(): object;
/**
* Validate root overrides configuration
* @throws Error if overrides are invalid
*/
assertRootOverrides(): void;Usage Example:
// Get explanation for why node exists
const explanation = node.explain();
console.log('Node explanation:', explanation);
// Convert to JSON for inspection
const nodeData = node.toJSON();
console.log('Node data:', JSON.stringify(nodeData, null, 2));Properties specific to identifying and working with symbolic links.
interface NodeLinkInfo {
/** Is symbolic link (false for regular Node) */
isLink: boolean;
/** Link target (self for Node, target for Link) */
target: Node;
/** Incoming links */
linksIn: Set<Link>;
}Usage Example:
// Check if node is a link
if (node.isLink) {
console.log(`Link target: ${node.target.path}`);
} else {
console.log('Regular package node');
}
// Check for incoming links
if (node.linksIn.size > 0) {
console.log(`Node has ${node.linksIn.size} incoming links`);
}Install with Tessl CLI
npx tessl i tessl/npm-npmcli--arborist