0
# @pnpm/workspace.pkgs-graph
1
2
@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.
3
4
## Package Information
5
6
- **Package Name**: @pnpm/workspace.pkgs-graph
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `pnpm add @pnpm/workspace.pkgs-graph`
10
11
## Core Imports
12
13
```typescript
14
import { createPkgGraph, type Package, type PackageNode } from "@pnpm/workspace.pkgs-graph";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { createPkgGraph } = require("@pnpm/workspace.pkgs-graph");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { createPkgGraph } from "@pnpm/workspace.pkgs-graph";
27
28
const packages = [
29
{
30
rootDir: "/workspace/foo",
31
manifest: {
32
name: "foo",
33
version: "1.0.0",
34
dependencies: {
35
bar: "^1.0.0",
36
},
37
},
38
},
39
{
40
rootDir: "/workspace/bar",
41
manifest: {
42
name: "bar",
43
version: "1.1.0",
44
},
45
}
46
];
47
48
const { graph, unmatched } = createPkgGraph(packages);
49
50
console.log(graph);
51
// {
52
// "/workspace/foo": {
53
// dependencies: ["/workspace/bar"],
54
// package: { rootDir: "/workspace/foo", manifest: { ... } }
55
// },
56
// "/workspace/bar": {
57
// dependencies: [],
58
// package: { rootDir: "/workspace/bar", manifest: { ... } }
59
// }
60
// }
61
62
console.log(unmatched);
63
// [] - empty array means all dependencies were matched
64
```
65
66
## Architecture
67
68
The package is built around several key concepts:
69
70
- **Dependency Graph Creation**: Analyzes package arrays to create directed dependency graphs
71
- **Workspace Protocol Support**: Handles `workspace:` protocol dependencies with version range resolution
72
- **Multiple Dependency Types**: Processes regular, dev, peer, and optional dependencies
73
- **Path Resolution**: Supports both relative path dependencies and file: protocol references
74
- **Version Matching**: Intelligent version range resolution within workspace environments
75
- **Unmatched Tracking**: Reports dependencies that couldn't be resolved to workspace packages
76
77
## Capabilities
78
79
### Graph Creation
80
81
Creates a dependency graph from an array of packages with configurable options for dependency processing.
82
83
```typescript { .api }
84
/**
85
* Creates a dependency graph from an array of packages
86
* @param pkgs - Array of packages to analyze
87
* @param opts - Optional configuration for graph creation
88
* @returns Object containing the dependency graph and unmatched dependencies
89
*/
90
function createPkgGraph<Pkg extends Package>(
91
pkgs: Pkg[],
92
opts?: {
93
ignoreDevDeps?: boolean;
94
linkWorkspacePackages?: boolean;
95
}
96
): {
97
graph: Record<ProjectRootDir, PackageNode<Pkg>>;
98
unmatched: Array<{ pkgName: string; range: string }>;
99
};
100
```
101
102
**Usage Examples:**
103
104
```typescript
105
// Basic graph creation
106
const result = createPkgGraph(packages);
107
108
// Ignore dev dependencies
109
const prodGraph = createPkgGraph(packages, {
110
ignoreDevDeps: true
111
});
112
113
// Disable workspace package linking
114
const strictGraph = createPkgGraph(packages, {
115
linkWorkspacePackages: false
116
});
117
```
118
119
### Workspace Protocol Support
120
121
The library fully supports pnpm's workspace protocol syntax for referencing workspace packages:
122
123
```typescript
124
// Supported workspace dependency formats
125
const packagesWithWorkspaceDeps = [
126
{
127
rootDir: "/workspace/app",
128
manifest: {
129
name: "app",
130
version: "1.0.0",
131
dependencies: {
132
"utils": "workspace:^1.0.0", // Version range
133
"config": "workspace:*", // Any version
134
"shared": "workspace:~", // Compatible version
135
"ui-alias": "workspace:ui@*", // Aliased package reference
136
},
137
},
138
}
139
];
140
```
141
142
### Directory Dependencies
143
144
Handles local directory dependencies using relative paths and file: protocol:
145
146
```typescript
147
const packagesWithLocalDeps = [
148
{
149
rootDir: "/workspace/app",
150
manifest: {
151
name: "app",
152
dependencies: {
153
"local-utils": "../utils", // Relative path
154
"shared-lib": "file:../shared", // File protocol
155
},
156
},
157
}
158
];
159
```
160
161
## Types
162
163
```typescript { .api }
164
/**
165
* Represents a package with manifest and root directory
166
*/
167
interface Package {
168
/** Package manifest containing metadata and dependencies */
169
manifest: BaseManifest;
170
/** Absolute path to the package root directory */
171
rootDir: ProjectRootDir;
172
}
173
174
/**
175
* Represents a node in the dependency graph
176
*/
177
interface PackageNode<Pkg extends Package> {
178
/** The package data */
179
package: Pkg;
180
/** Array of root directories of packages this package depends on */
181
dependencies: ProjectRootDir[];
182
}
183
184
/**
185
* Project root directory path (from @pnpm/types)
186
*/
187
type ProjectRootDir = string;
188
189
/**
190
* Base manifest interface (from @pnpm/types)
191
* Contains standard package.json fields including:
192
* - name: string
193
* - version: string
194
* - dependencies: Record<string, string>
195
* - devDependencies: Record<string, string>
196
* - peerDependencies: Record<string, string>
197
* - optionalDependencies: Record<string, string>
198
*/
199
interface BaseManifest {
200
name?: string;
201
version?: string;
202
dependencies?: Record<string, string>;
203
devDependencies?: Record<string, string>;
204
peerDependencies?: Record<string, string>;
205
optionalDependencies?: Record<string, string>;
206
}
207
```
208
209
## Configuration Options
210
211
### ignoreDevDeps
212
213
When set to `true`, development dependencies are excluded from the dependency graph:
214
215
```typescript
216
const result = createPkgGraph(packages, { ignoreDevDeps: true });
217
// Only includes dependencies, peerDependencies, and optionalDependencies
218
```
219
220
### linkWorkspacePackages
221
222
Controls whether non-workspace dependencies should be linked to workspace packages. When set to `false`, only explicit workspace: dependencies are linked:
223
224
```typescript
225
const result = createPkgGraph(packages, { linkWorkspacePackages: false });
226
// Regular version ranges won't match workspace packages
227
// Only workspace: prefixed dependencies will be linked
228
```
229
230
## Return Value Details
231
232
### Graph Structure
233
234
The `graph` object maps each package's root directory to its `PackageNode`:
235
236
```typescript
237
const { graph } = createPkgGraph(packages);
238
239
// Access specific package node
240
const fooNode = graph["/workspace/foo"];
241
console.log(fooNode.dependencies); // Array of dependency root dirs
242
console.log(fooNode.package); // Original package data
243
```
244
245
### Unmatched Dependencies
246
247
The `unmatched` array contains dependencies that couldn't be resolved to workspace packages:
248
249
```typescript
250
const { unmatched } = createPkgGraph(packages);
251
252
unmatched.forEach(({ pkgName, range }) => {
253
console.log(`Could not resolve ${pkgName}@${range} to workspace package`);
254
});
255
```
256
257
Common reasons for unmatched dependencies:
258
- External packages not present in workspace
259
- Version ranges that don't match any workspace package versions
260
- Malformed dependency specifications
261
262
## Edge Cases and Error Handling
263
264
### Missing Package Versions
265
266
The library gracefully handles packages without version fields:
267
268
```typescript
269
const packagesWithoutVersions = [
270
{
271
rootDir: "/workspace/utils",
272
manifest: {
273
name: "utils",
274
// No version field
275
},
276
}
277
];
278
279
// Still creates valid graph structure
280
const result = createPkgGraph(packagesWithoutVersions);
281
```
282
283
### Invalid Dependencies
284
285
Malformed or invalid dependency specifications are silently ignored:
286
287
```typescript
288
const packagesWithInvalidDeps = [
289
{
290
rootDir: "/workspace/app",
291
manifest: {
292
name: "app",
293
dependencies: {
294
"weird-dep": ":aaaaa", // Invalid spec - ignored
295
"valid-dep": "^1.0.0",
296
},
297
},
298
}
299
];
300
```
301
302
### Case Sensitivity
303
304
The library handles case mismatches on case-insensitive filesystems by using both fast and slow path resolution strategies.
305
306
### Prerelease Versions
307
308
Correctly matches prerelease versions when using wildcard ranges:
309
310
```typescript
311
const prereleasePackages = [
312
{
313
rootDir: "/workspace/beta",
314
manifest: {
315
name: "beta",
316
version: "1.0.0-beta.1", // Prerelease version
317
},
318
}
319
];
320
321
// "*" range will match prerelease versions
322
const result = createPkgGraph([
323
{
324
rootDir: "/workspace/app",
325
manifest: {
326
dependencies: { "beta": "*" }
327
}
328
},
329
...prereleasePackages
330
]);
331
```