List local packages that have changed since the last tagged release
npx @tessl/cli install tessl/npm-lerna--changed@6.6.00
# @lerna/changed
1
2
@lerna/changed is a command-line utility and programmatic API that identifies and lists local packages within a Lerna monorepo that have been modified since the last tagged release. It enables developers to track changes across their workspace for targeted builds, testing, and publishing workflows.
3
4
## Package Information
5
6
- **Package Name**: @lerna/changed
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @lerna/changed` or `lerna changed` command via main lerna package
10
11
## Core Imports
12
13
CommonJS (primary export format):
14
15
```javascript
16
const changedIndex = require("@lerna/changed");
17
const { ChangedCommand } = require("@lerna/changed");
18
```
19
20
Command module import:
21
22
```javascript
23
const command = require("@lerna/changed/command");
24
```
25
26
Available exports:
27
28
```javascript
29
// Main factory function (default export)
30
const factory = require("@lerna/changed");
31
32
// Named export for class
33
const { ChangedCommand } = require("@lerna/changed");
34
35
// Command configuration
36
const commandConfig = require("@lerna/changed/command");
37
```
38
39
## Basic Usage
40
41
### CLI Usage
42
43
```bash
44
# List changed packages since last tagged release
45
lerna changed
46
47
# Using alias
48
lerna updated
49
50
# With options
51
lerna changed --conventional-graduate
52
lerna changed --force-publish package-1
53
lerna changed --json
54
lerna changed --long
55
```
56
57
### Programmatic Usage
58
59
```javascript
60
const factory = require("@lerna/changed");
61
62
// Create command instance using factory
63
const command = factory(process.argv);
64
65
// Execute if initialization successful
66
if (command.initialize()) {
67
command.execute();
68
}
69
```
70
71
```javascript
72
const { ChangedCommand } = require("@lerna/changed");
73
74
// Direct class instantiation
75
const command = new ChangedCommand(argv);
76
77
if (command.initialize()) {
78
command.execute();
79
}
80
```
81
82
## Capabilities
83
84
### Changed Packages Detection
85
86
Lists packages that have changed since the last tagged release, supporting various detection modes and output formats.
87
88
```typescript { .api }
89
/**
90
* Factory function that creates a ChangedCommand instance
91
* @param argv - Command line arguments array
92
* @returns ChangedCommand instance
93
*/
94
declare function factory(argv: NodeJS.Process["argv"]): ChangedCommand;
95
```
96
97
### ChangedCommand Class
98
99
Main command class providing changed package detection functionality.
100
101
```typescript { .api }
102
interface ChangedCommandOptions extends CommandConfigOptions {
103
/** Enable conventional commits mode for determining changes */
104
conventionalCommits: boolean;
105
/** Detect prereleased packages that would graduate to non-prerelease */
106
conventionalGraduate: boolean;
107
/** Always include targeted packages when detecting changes */
108
forcePublish: boolean;
109
}
110
111
declare class ChangedCommand extends Command<ChangedCommandOptions> {
112
/** Formatted list of changed packages */
113
result: ReturnType<typeof listableFormat>;
114
115
/** Configuration compatibility with version and publish commands */
116
get otherCommandConfigs(): string[];
117
118
/**
119
* Initialize command, collect updates, and format results
120
* @returns false if no packages changed (prevents execution), void otherwise
121
*/
122
initialize(): boolean | void;
123
124
/** Execute command and output results to console */
125
execute(): void;
126
}
127
```
128
129
### Command Module Configuration
130
131
Yargs command module configuration for CLI integration.
132
133
```typescript { .api }
134
interface CommandModule {
135
/** Command name */
136
command: "changed";
137
/** Command aliases */
138
aliases: ["updated"];
139
/** Command description */
140
describe: "List local packages that have changed since the last tagged release";
141
/** Options builder function */
142
builder(yargs: any): any;
143
/** Command handler function */
144
handler(argv: any): any;
145
}
146
```
147
148
## Command Options
149
150
### Core Options
151
152
Options specific to the changed command (CLI format):
153
154
```typescript { .api }
155
interface ChangedOptions {
156
/** Enable conventional commits mode (hidden option, used internally) */
157
"conventional-commits"?: boolean;
158
159
/** Detect currently prereleased packages that would change to a non-prerelease version */
160
"conventional-graduate"?: boolean | string | string[];
161
162
/** Always include targeted packages when detecting changed packages, skipping default logic */
163
"force-publish"?: boolean | string | string[];
164
165
/** Ignore changes in files matched by glob(s) when detecting changed packages */
166
"ignore-changes"?: string[];
167
168
/** Include tags from merged branches when detecting changed packages */
169
"include-merged-tags"?: boolean;
170
}
171
```
172
173
### Listable Options
174
175
Inherited output formatting options from @lerna/core:
176
177
```typescript { .api }
178
interface ListableOptions {
179
/** Output in JSON format */
180
json?: boolean;
181
182
/** Output in newline-delimited JSON format */
183
ndjson?: boolean;
184
185
/** Include private packages */
186
all?: boolean;
187
188
/** Show extended information */
189
long?: boolean;
190
191
/** Show parseable output for scripts */
192
parseable?: boolean;
193
194
/** Sort packages topologically */
195
toposort?: boolean;
196
197
/** Show dependency graph */
198
graph?: boolean;
199
}
200
```
201
202
## Types
203
204
### Core Types from @lerna/core
205
206
```typescript { .api }
207
interface CommandConfigOptions {
208
/** Command line arguments */
209
_?: string[];
210
/** Number of concurrent processes */
211
concurrency?: number;
212
/** Sort packages topologically */
213
sort?: boolean;
214
/** Maximum buffer size for child processes */
215
maxBuffer?: number;
216
/** Stream output from child processes */
217
stream?: boolean;
218
/** Log level (silent, error, warn, info, verbose, silly) */
219
loglevel?: string;
220
/** Enable verbose logging */
221
verbose?: boolean;
222
/** Show progress bars */
223
progress?: boolean;
224
/** npm client to use (npm, yarn, pnpm) */
225
npmClient?: string;
226
/** Use Nx for task execution */
227
useNx?: boolean;
228
/** Independent versioning mode */
229
independent?: boolean;
230
/** CI environment flag */
231
ci?: boolean;
232
/** Use workspaces feature */
233
useWorkspaces?: boolean;
234
/** Git reference to compare against */
235
since?: string;
236
}
237
238
declare abstract class Command<T extends CommandConfigOptions = CommandConfigOptions> {
239
/** Command name */
240
name: string;
241
/** Whether command is composed of other commands */
242
composed: boolean;
243
/** Command options */
244
options: T;
245
/** Promise for command execution */
246
runner: Promise<unknown>;
247
/** Number of concurrent processes */
248
concurrency?: number;
249
/** Sort packages topologically */
250
toposort: boolean;
251
/** Execution options for child processes */
252
execOpts?: { cwd: string; maxBuffer?: number };
253
/** Package graph for dependency resolution */
254
packageGraph?: PackageGraph;
255
/** Logger instance */
256
logger: Logger;
257
258
/** Get project instance */
259
get project(): Project;
260
/** Set project instance */
261
set project(project: Project);
262
263
/** Whether command requires git repository */
264
get requiresGit(): boolean;
265
/** Configuration compatibility with other commands */
266
get otherCommandConfigs(): string[];
267
268
/** Initialize command */
269
abstract initialize(): void | boolean;
270
/** Execute command */
271
abstract execute(): void;
272
}
273
274
interface ExecutionOptions {
275
/** Current working directory */
276
cwd: string;
277
/** Maximum buffer size */
278
maxBuffer?: number;
279
}
280
281
interface Logger {
282
/** Log silly level message */
283
silly(prefix: string, message: string, ...args: any[]): void;
284
/** Log verbose level message */
285
verbose(prefix: string, message: string, ...args: any[]): void;
286
/** Log info level message */
287
info(prefix: string, message: string, ...args: any[]): void;
288
/** Log warn level message */
289
warn(prefix: string, message: string, ...args: any[]): void;
290
/** Log error level message */
291
error(prefix: string, message: string, ...args: any[]): void;
292
/** Log success level message */
293
success(prefix: string, message: string, ...args: any[]): void;
294
}
295
296
interface RawManifest {
297
name: string;
298
version: string;
299
private?: boolean;
300
bin?: Record<string, string> | string;
301
scripts?: Record<string, string>;
302
dependencies?: Record<string, string>;
303
devDependencies?: Record<string, string>;
304
optionalDependencies?: Record<string, string>;
305
peerDependencies?: Record<string, string>;
306
publishConfig?: Record<"directory" | "registry" | "tag", string>;
307
workspaces?: string[];
308
}
309
310
declare class Package {
311
/** Package name */
312
name: string;
313
314
/** Package location on filesystem */
315
get location(): string;
316
/** Whether package is private */
317
get private(): boolean;
318
/** Package version */
319
get version(): string;
320
/** Package contents directory */
321
get contents(): string;
322
/** Package dependencies */
323
get dependencies(): Record<string, string> | undefined;
324
/** Package devDependencies */
325
get devDependencies(): Record<string, string> | undefined;
326
/** Package optionalDependencies */
327
get optionalDependencies(): Record<string, string> | undefined;
328
/** Package peerDependencies */
329
get peerDependencies(): Record<string, string> | undefined;
330
331
/** Set private flag */
332
set private(isPrivate: boolean);
333
/** Set package version */
334
set version(version: string);
335
/** Set contents directory */
336
set contents(subDirectory: string);
337
338
/** Create lazy package instance */
339
static lazy(ref: string | Package | RawManifest, dir?: string): Package;
340
341
/** Get manifest property */
342
get(key: keyof RawManifest): RawManifest[keyof RawManifest];
343
/** Set manifest property */
344
set(key: keyof RawManifest, val: RawManifest[keyof RawManifest]): Package;
345
/** Convert to JSON */
346
toJSON(): RawManifest;
347
/** Refresh package from filesystem */
348
refresh(): Promise<Package>;
349
/** Serialize package to filesystem */
350
serialize(): Promise<Package>;
351
/** Update local dependency */
352
updateLocalDependency(resolved: any, depVersion: string, savePrefix: string, options?: { retainWorkspacePrefix: boolean }): void;
353
/** Remove private field */
354
removePrivate(): void;
355
}
356
357
declare class PackageGraphNode {
358
/** Package name */
359
name: string;
360
/** External dependencies */
361
externalDependencies: Map<string, any>;
362
/** Local dependencies within monorepo */
363
localDependencies: Map<string, any>;
364
/** Local dependents within monorepo */
365
localDependents: Map<string, PackageGraphNode>;
366
367
/** Package location */
368
get location(): string;
369
/** Package instance */
370
get pkg(): Package;
371
/** Prerelease identifier */
372
get prereleaseId(): string;
373
/** Package version */
374
get version(): string;
375
376
/** Check if package satisfies dependency */
377
satisfies(spec: any): boolean;
378
/** String representation */
379
toString(): string;
380
}
381
382
declare class PackageGraph extends Map<string, PackageGraphNode> {
383
/** Raw list of packages */
384
get rawPackageList(): Package[];
385
386
/** Add dependencies to filtered packages */
387
addDependencies(filteredPackages: Package[]): Package[];
388
/** Add dependents to filtered packages */
389
addDependents(filteredPackages: Package[]): Package[];
390
/** Extend package list with related packages */
391
extendList(packageList: Package[], nodeProp: "localDependencies" | "localDependents"): Package[];
392
/** Partition cyclic dependencies */
393
partitionCycles(rejectCycles: boolean): [Set<string[]>, Set<PackageGraphNode>];
394
/** Collapse cyclic dependencies */
395
collapseCycles(rejectCycles?: boolean): Set<any>;
396
/** Remove cyclic nodes */
397
pruneCycleNodes(cycleNodes: Set<PackageGraphNode>): void;
398
/** Prune nodes from graph */
399
prune(...candidates: PackageGraphNode[]): void;
400
/** Remove specific node */
401
remove(candidateNode: PackageGraphNode): void;
402
}
403
404
declare class Project {
405
/** Project configuration */
406
config: any;
407
/** Whether config was found */
408
configNotFound: boolean;
409
/** Root config location */
410
rootConfigLocation: string;
411
/** Root path */
412
rootPath: string;
413
414
/** Project version */
415
get version(): string;
416
/** Set project version */
417
set version(val: string);
418
/** Package configurations */
419
get packageConfigs(): string[];
420
/** Package parent directories */
421
get packageParentDirs(): string[];
422
/** Root package manifest */
423
get manifest(): Package;
424
425
/** Get all packages */
426
getPackages(): Promise<Package[]>;
427
/** Get all packages synchronously */
428
getPackagesSync(): Package[];
429
/** Check if independent versioning */
430
isIndependent(): boolean;
431
/** Serialize configuration */
432
serializeConfig(): string;
433
}
434
435
/**
436
* Collect packages that have updates since last release
437
*/
438
declare function collectUpdates(
439
filteredPackages: Package[],
440
packageGraph: PackageGraph,
441
execOpts: ExecutionOptions,
442
commandOptions: any
443
): PackageGraphNode[];
444
445
/**
446
* Format package list for output
447
*/
448
declare function listableFormat(
449
pkgList: Package[],
450
options: ListableOptions
451
): {
452
text: string;
453
count: number;
454
};
455
456
/**
457
* Output text to console
458
*/
459
declare function output(...args: any[]): void;
460
```
461
462
## Dependencies
463
464
The package depends on:
465
466
- **lerna**: ^6.6.2 - Main Lerna monorepo management tool
467
- **@lerna/core**: Provides `collectUpdates`, `Command`, `listableFormat`, `output` utilities
468
469
## Behavior
470
471
### Exit Codes
472
473
- **0**: Success - packages found and listed
474
- **1**: No changed packages found since last tagged release
475
476
### Error Handling
477
478
- Throws error when no changed packages are found
479
- Sets `process.exitCode = 1` for CLI usage when no packages changed
480
- Logs warnings for deprecated option combinations
481
- Prevents execution if initialization returns false
482
483
### Package Detection Logic
484
485
1. Analyzes git history since last tagged release
486
2. Identifies packages with file changes
487
3. Applies ignore patterns and force-publish rules
488
4. Considers conventional commit patterns if enabled
489
5. Formats results according to output options
490
6. Reports count and names of changed packages
491
492
## Integration
493
494
This package integrates with:
495
496
- **Lerna core**: Uses collectUpdates and formatting utilities
497
- **Git**: Analyzes commit history and tags
498
- **Package.json**: Reads package configurations and dependencies
499
- **Conventional Commits**: Optional integration for semantic versioning workflows
500
501
## Common Use Cases
502
503
- **CI/CD Pipelines**: Determine which packages need building/testing
504
- **Selective Publishing**: Identify packages requiring version bumps
505
- **Development Workflows**: Focus on changed areas during development
506
- **Monorepo Management**: Track cross-package dependencies and changes