bun-workspaces 1.8.2 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +51 -13
  2. package/package.json +1 -1
  3. package/src/2392.mjs +184 -3
  4. package/src/5166.mjs +1 -0
  5. package/src/8529.mjs +10 -0
  6. package/src/affected/affectedBaseRef.mjs +12 -0
  7. package/src/affected/externalDependencyChanges.mjs +47 -0
  8. package/src/affected/fileAffectedWorkspaces.mjs +145 -53
  9. package/src/affected/gitAffectedFiles.mjs +44 -1
  10. package/src/affected/gitAffectedWorkspaces.mjs +73 -3
  11. package/src/affected/index.mjs +2 -0
  12. package/src/ai/mcp/serverState.mjs +1 -1
  13. package/src/cli/commands/commandHandlerUtils.mjs +12 -7
  14. package/src/cli/commands/commands.mjs +4 -1
  15. package/src/cli/commands/handleSimpleCommands.mjs +2 -2
  16. package/src/cli/commands/listAffected.mjs +184 -0
  17. package/src/cli/commands/runScript/handleRunAffected.mjs +99 -0
  18. package/src/cli/commands/runScript/handleRunScript.mjs +19 -202
  19. package/src/cli/commands/runScript/index.mjs +1 -0
  20. package/src/cli/commands/runScript/scriptRunFlow.mjs +213 -0
  21. package/src/cli/index.d.ts +749 -134
  22. package/src/config/public.d.ts +66 -2
  23. package/src/config/rootConfig/rootConfig.mjs +4 -0
  24. package/src/config/rootConfig/rootConfigSchema.mjs +3 -0
  25. package/src/config/workspaceConfig/mergeWorkspaceConfig.mjs +33 -19
  26. package/src/config/workspaceConfig/workspaceConfig.mjs +3 -0
  27. package/src/config/workspaceConfig/workspaceConfigSchema.mjs +26 -0
  28. package/src/index.d.ts +307 -5
  29. package/src/index.mjs +1 -0
  30. package/src/internal/bun/bunLock.mjs +33 -0
  31. package/src/internal/generated/aiDocs/docs.mjs +152 -3
  32. package/src/internal/generated/ajv/validateRootConfig.mjs +1 -1
  33. package/src/internal/generated/ajv/validateWorkspaceConfig.mjs +1 -1
  34. package/src/project/implementations/fileSystemProject/affectedWorkspaces.mjs +225 -0
  35. package/src/project/implementations/{fileSystemProject.mjs → fileSystemProject/fileSystemProject.mjs} +169 -12
  36. package/src/project/implementations/fileSystemProject/index.mjs +4 -0
  37. package/src/project/implementations/memoryProject.mjs +1 -0
  38. package/src/project/index.mjs +1 -1
  39. package/src/rslib-runtime.mjs +0 -31
  40. package/src/workspaces/applyWorkspacePatternConfigs.mjs +10 -1
  41. package/src/workspaces/dependencyGraph/resolveDependencies.mjs +68 -18
  42. package/src/workspaces/findWorkspaces.mjs +1 -0
  43. package/src/workspaces/workspace.mjs +8 -2
@@ -36,6 +36,47 @@ export type WorkspaceDependenciesRule = {
36
36
  export type WorkspaceRules = {
37
37
  workspaceDependencies?: WorkspaceDependenciesRule;
38
38
  };
39
+ /**
40
+ * Configured inputs for a script.
41
+ *
42
+ * These can be used to specify the files and workspace patterns
43
+ * that should be considered inputs for the script.
44
+ *
45
+ * The default inputs when not provided are all git-trackable files in the workspace.
46
+ */
47
+ export type WorkspaceInputsConfig = {
48
+ /**
49
+ * File paths, directory paths, or globs relative to the workspace's path.
50
+ *
51
+ * Prefix with `!` to exclude.
52
+ *
53
+ * The default inputs when not provided are all git-trackable files in the workspace.
54
+ *
55
+ * Files that are not git-trackable are not considered inputs.
56
+ *
57
+ * Paths with a leading `/` are relative to the project root.
58
+ */
59
+ files?: string[];
60
+ /**
61
+ * Matched workspaces are treated as inputs for the script.
62
+ *
63
+ * For example, when workspaces are provided here, they will
64
+ * be treated like dependencies in the affected workspace resolution.
65
+ */
66
+ workspacePatterns?: string[];
67
+ /**
68
+ * Filters which of the workspace's declared external (non-workspace) deps
69
+ * participate in lockfile-change detection.
70
+ *
71
+ * - When omitted, every declared external dep participates (default).
72
+ * - When set to an empty array, no external deps participate (the workspace
73
+ * will not be flagged from a lockfile change unless something else makes it so).
74
+ * - When set to a non-empty list of package names, only the listed names
75
+ * participate. Names not present in the workspace's actual
76
+ * `externalDependencies` are silently ignored.
77
+ */
78
+ externalDependencies?: string[];
79
+ };
39
80
  /** Configuration that applies to a specific package.json script */
40
81
  export type ScriptConfig = {
41
82
  /**
@@ -45,6 +86,15 @@ export type ScriptConfig = {
45
86
  * of their relative path from the project root.
46
87
  */
47
88
  order?: number;
89
+ /**
90
+ * Inputs for the script.
91
+ *
92
+ * These can be used to specify the files and workspace patterns
93
+ * that should be considered inputs for the script.
94
+ *
95
+ * The default inputs when not provided are all git-trackable files in the workspace.
96
+ */
97
+ inputs?: WorkspaceInputsConfig;
48
98
  };
49
99
  /** Configuration that applies to a specific workspace */
50
100
  export type WorkspaceConfig = {
@@ -69,12 +119,18 @@ export type WorkspaceConfig = {
69
119
  * Rules that validate the workspace.
70
120
  */
71
121
  rules?: WorkspaceRules;
122
+ /**
123
+ * The default inputs for the workspace
124
+ * applied to all scripts that don't configure their own inputs.
125
+ */
126
+ defaultInputs?: WorkspaceInputsConfig;
72
127
  };
73
128
  export type ResolvedWorkspaceConfig = {
74
129
  aliases: string[];
75
130
  tags: string[];
76
131
  scripts: Record<string, ScriptConfig>;
77
132
  rules: WorkspaceRules;
133
+ defaultInputs?: WorkspaceInputsConfig;
78
134
  };
79
135
  /** Static workspace context passed to a {@link WorkspacePatternConfigFactory}.
80
136
  * Contains only the immutable, package.json-derived fields — not config-derived fields like aliases or tags. */
@@ -108,6 +164,8 @@ export type RootConfig = {
108
164
  shell?: ShellOption;
109
165
  /** Whether to include the root workspace in the workspaces list by default. (default: false) */
110
166
  includeRootWorkspace?: boolean;
167
+ /** The default base ref for affected workspace resolution. (default: "main") */
168
+ affectedBaseRef?: string;
111
169
  };
112
170
  /**
113
171
  * Workspace configs applied by pattern, in order, merging left to right,
@@ -124,6 +182,7 @@ export type ResolvedRootConfig = {
124
182
  shell: ScriptShellOption;
125
183
  /** `undefined` means the value was not set in the input config */
126
184
  includeRootWorkspace: boolean | undefined;
185
+ affectedBaseRef: string;
127
186
  };
128
187
  workspacePatternConfigs: WorkspacePatternConfigEntry[];
129
188
  };
@@ -142,8 +201,13 @@ export declare const defineWorkspaceConfig: (
142
201
  ) => ResolvedWorkspaceConfig;
143
202
  export type WorkspaceConfigFactory = (prev: WorkspaceConfig) => WorkspaceConfig;
144
203
  export type WorkspaceConfigInput = WorkspaceConfig | WorkspaceConfigFactory;
145
- /** Merge two or more workspace configs left to right, with each subsequent config taking precedence.
146
- * Any argument may be a factory function receiving the accumulated config up to that point. */
204
+ /**
205
+ * Merge two or more workspace configs left to right, with each subsequent config taking precedence.
206
+ * Any argument may be a factory function receiving the accumulated config up to that point.
207
+ *
208
+ * Generally, objects are deeply merged, and arrays are concatenated and deduplicated,
209
+ * **except** for inputs (defaultInputs and script inputs), which are replaced entirely.
210
+ */
147
211
  export declare const mergeWorkspaceConfig: (
148
212
  ...configs: WorkspaceConfigInput[]
149
213
  ) => WorkspaceConfig;
@@ -1,3 +1,4 @@
1
+ import { resolveDefaultAffectedBaseRef } from "../../affected/affectedBaseRef.mjs";
1
2
  import validateRootConfig from "../../internal/generated/ajv/validateRootConfig.mjs";
2
3
  import {
3
4
  determineParallelMax,
@@ -33,6 +34,9 @@ const resolveRootConfig = (config) => {
33
34
  includeRootWorkspace:
34
35
  config.defaults?.includeRootWorkspace ??
35
36
  getUserEnvVar("includeRootWorkspaceDefault") === "true",
37
+ affectedBaseRef: resolveDefaultAffectedBaseRef(
38
+ config.defaults?.affectedBaseRef,
39
+ ),
36
40
  },
37
41
  workspacePatternConfigs: config.workspacePatternConfigs ?? [],
38
42
  };
@@ -15,6 +15,9 @@ const ROOT_CONFIG_JSON_SCHEMA = {
15
15
  includeRootWorkspace: {
16
16
  type: "boolean",
17
17
  },
18
+ affectedBaseRef: {
19
+ type: "string",
20
+ },
18
21
  },
19
22
  },
20
23
  workspacePatternConfigs: {
@@ -52,24 +52,38 @@ const mergeScripts = (base, override) => {
52
52
  }
53
53
  return merged;
54
54
  };
55
- const applyConfig = (acc, config) => ({
56
- alias: uniqueArray([
57
- ...resolveOptionalArray(acc.alias ?? []),
58
- ...resolveOptionalArray(config.alias ?? []),
59
- ]),
60
- tags: uniqueArray([...(acc.tags ?? []), ...(config.tags ?? [])]),
61
- scripts: mergeScripts(acc.scripts, config.scripts),
62
- rules: mergeWorkspaceRules(acc.rules, config.rules),
63
- });
64
- /** Merge two or more workspace configs left to right, with each subsequent config taking precedence.
65
- * Any argument may be a factory function receiving the accumulated config up to that point. */ const mergeWorkspaceConfig =
66
- (...configs) =>
67
- configs.reduce((acc, configOrFactory) => {
68
- const config =
69
- typeof configOrFactory === "function"
70
- ? configOrFactory(acc)
71
- : configOrFactory;
72
- return applyConfig(acc, config);
73
- }, {});
55
+ const mergeDefaultInputs = (base, override) => override ?? base;
56
+ const applyConfig = (acc, config) => {
57
+ const defaultInputs = mergeDefaultInputs(
58
+ acc.defaultInputs,
59
+ config.defaultInputs,
60
+ );
61
+ return {
62
+ alias: uniqueArray([
63
+ ...resolveOptionalArray(acc.alias ?? []),
64
+ ...resolveOptionalArray(config.alias ?? []),
65
+ ]),
66
+ tags: uniqueArray([...(acc.tags ?? []), ...(config.tags ?? [])]),
67
+ scripts: mergeScripts(acc.scripts, config.scripts),
68
+ rules: mergeWorkspaceRules(acc.rules, config.rules),
69
+ ...(defaultInputs && {
70
+ defaultInputs,
71
+ }),
72
+ };
73
+ };
74
+ /**
75
+ * Merge two or more workspace configs left to right, with each subsequent config taking precedence.
76
+ * Any argument may be a factory function receiving the accumulated config up to that point.
77
+ *
78
+ * Generally, objects are deeply merged, and arrays are concatenated and deduplicated,
79
+ * **except** for inputs (defaultInputs and script inputs), which are replaced entirely.
80
+ */ const mergeWorkspaceConfig = (...configs) =>
81
+ configs.reduce((acc, configOrFactory) => {
82
+ const config =
83
+ typeof configOrFactory === "function"
84
+ ? configOrFactory(acc)
85
+ : configOrFactory;
86
+ return applyConfig(acc, config);
87
+ }, {});
74
88
 
75
89
  export { mergeWorkspaceConfig };
@@ -32,6 +32,9 @@ const resolveWorkspaceConfig = (config) => {
32
32
  tags: config.tags ?? [],
33
33
  scripts: config.scripts ?? {},
34
34
  rules: config.rules ?? {},
35
+ ...(config.defaultInputs && {
36
+ defaultInputs: config.defaultInputs,
37
+ }),
35
38
  };
36
39
  };
37
40
  const createDefaultWorkspaceConfig = () => resolveWorkspaceConfig({});
@@ -1,3 +1,27 @@
1
+ const WORKSPACE_INPUTS_CONFIG_SCHEMA = {
2
+ type: "object",
3
+ additionalProperties: false,
4
+ properties: {
5
+ files: {
6
+ type: "array",
7
+ items: {
8
+ type: "string",
9
+ },
10
+ },
11
+ workspacePatterns: {
12
+ type: "array",
13
+ items: {
14
+ type: "string",
15
+ },
16
+ },
17
+ externalDependencies: {
18
+ type: "array",
19
+ items: {
20
+ type: "string",
21
+ },
22
+ },
23
+ },
24
+ };
1
25
  const WORKSPACE_CONFIG_JSON_SCHEMA = {
2
26
  type: "object",
3
27
  additionalProperties: false,
@@ -24,6 +48,7 @@ const WORKSPACE_CONFIG_JSON_SCHEMA = {
24
48
  order: {
25
49
  type: "number",
26
50
  },
51
+ inputs: WORKSPACE_INPUTS_CONFIG_SCHEMA,
27
52
  },
28
53
  additionalProperties: false,
29
54
  },
@@ -52,6 +77,7 @@ const WORKSPACE_CONFIG_JSON_SCHEMA = {
52
77
  },
53
78
  },
54
79
  },
80
+ defaultInputs: WORKSPACE_INPUTS_CONFIG_SCHEMA,
55
81
  },
56
82
  };
57
83
  let _validateSchemaType;
package/src/index.d.ts CHANGED
@@ -45,6 +45,47 @@ export type WorkspaceDependenciesRule = {
45
45
  export type WorkspaceRules = {
46
46
  workspaceDependencies?: WorkspaceDependenciesRule;
47
47
  };
48
+ /**
49
+ * Configured inputs for a script.
50
+ *
51
+ * These can be used to specify the files and workspace patterns
52
+ * that should be considered inputs for the script.
53
+ *
54
+ * The default inputs when not provided are all git-trackable files in the workspace.
55
+ */
56
+ export type WorkspaceInputsConfig = {
57
+ /**
58
+ * File paths, directory paths, or globs relative to the workspace's path.
59
+ *
60
+ * Prefix with `!` to exclude.
61
+ *
62
+ * The default inputs when not provided are all git-trackable files in the workspace.
63
+ *
64
+ * Files that are not git-trackable are not considered inputs.
65
+ *
66
+ * Paths with a leading `/` are relative to the project root.
67
+ */
68
+ files?: string[];
69
+ /**
70
+ * Matched workspaces are treated as inputs for the script.
71
+ *
72
+ * For example, when workspaces are provided here, they will
73
+ * be treated like dependencies in the affected workspace resolution.
74
+ */
75
+ workspacePatterns?: string[];
76
+ /**
77
+ * Filters which of the workspace's declared external (non-workspace) deps
78
+ * participate in lockfile-change detection.
79
+ *
80
+ * - When omitted, every declared external dep participates (default).
81
+ * - When set to an empty array, no external deps participate (the workspace
82
+ * will not be flagged from a lockfile change unless something else makes it so).
83
+ * - When set to a non-empty list of package names, only the listed names
84
+ * participate. Names not present in the workspace's actual
85
+ * `externalDependencies` are silently ignored.
86
+ */
87
+ externalDependencies?: string[];
88
+ };
48
89
  /** Configuration that applies to a specific package.json script */
49
90
  export type ScriptConfig = {
50
91
  /**
@@ -54,6 +95,15 @@ export type ScriptConfig = {
54
95
  * of their relative path from the project root.
55
96
  */
56
97
  order?: number;
98
+ /**
99
+ * Inputs for the script.
100
+ *
101
+ * These can be used to specify the files and workspace patterns
102
+ * that should be considered inputs for the script.
103
+ *
104
+ * The default inputs when not provided are all git-trackable files in the workspace.
105
+ */
106
+ inputs?: WorkspaceInputsConfig;
57
107
  };
58
108
  /** Configuration that applies to a specific workspace */
59
109
  export type WorkspaceConfig = {
@@ -78,12 +128,18 @@ export type WorkspaceConfig = {
78
128
  * Rules that validate the workspace.
79
129
  */
80
130
  rules?: WorkspaceRules;
131
+ /**
132
+ * The default inputs for the workspace
133
+ * applied to all scripts that don't configure their own inputs.
134
+ */
135
+ defaultInputs?: WorkspaceInputsConfig;
81
136
  };
82
137
  export type ResolvedWorkspaceConfig = {
83
138
  aliases: string[];
84
139
  tags: string[];
85
140
  scripts: Record<string, ScriptConfig>;
86
141
  rules: WorkspaceRules;
142
+ defaultInputs?: WorkspaceInputsConfig;
87
143
  };
88
144
  /** Static workspace context passed to a {@link WorkspacePatternConfigFactory}.
89
145
  * Contains only the immutable, package.json-derived fields — not config-derived fields like aliases or tags. */
@@ -117,6 +173,8 @@ export type RootConfig = {
117
173
  shell?: ShellOption;
118
174
  /** Whether to include the root workspace in the workspaces list by default. (default: false) */
119
175
  includeRootWorkspace?: boolean;
176
+ /** The default base ref for affected workspace resolution. (default: "main") */
177
+ affectedBaseRef?: string;
120
178
  };
121
179
  /**
122
180
  * Workspace configs applied by pattern, in order, merging left to right,
@@ -133,6 +191,7 @@ export type ResolvedRootConfig = {
133
191
  shell: ScriptShellOption;
134
192
  /** `undefined` means the value was not set in the input config */
135
193
  includeRootWorkspace: boolean | undefined;
194
+ affectedBaseRef: string;
136
195
  };
137
196
  workspacePatternConfigs: WorkspacePatternConfigEntry[];
138
197
  };
@@ -164,6 +223,39 @@ export interface MultiProcessOutput<Metadata extends object = object> {
164
223
  bytes(): BytesOutput<Metadata>;
165
224
  text(): TextOutput<Metadata>;
166
225
  }
226
+ /** Catalog reference info attached to an `ExternalDependency` that uses a `catalog:` ref */
227
+ export type ExternalDependencyCatalog = {
228
+ /** Catalog name from the `catalog:<name>` ref. Empty string for the default catalog (`catalog:`). */
229
+ name: string;
230
+ };
231
+ declare const EXTERNAL_DEPENDENCY_SOURCES: readonly [
232
+ "dependencies",
233
+ "devDependencies",
234
+ "peerDependencies",
235
+ "optionalDependencies",
236
+ ];
237
+ export type ExternalDependencySource =
238
+ (typeof EXTERNAL_DEPENDENCY_SOURCES)[number];
239
+ /** A non-workspace package the workspace declares (resolved via package.json + catalogs) */
240
+ export type ExternalDependency = {
241
+ /** The package name as it appears in `node_modules` */
242
+ name: string;
243
+ /**
244
+ * Version specifier from `package.json`, with `catalog:`/`catalog:<name>` references
245
+ * resolved to the catalog's value. If the catalog reference cannot be resolved, the
246
+ * literal `catalog:` / `catalog:<name>` string is preserved.
247
+ */
248
+ version: string;
249
+ /**
250
+ * Which `package.json` dependency map this dep was declared in. When a dep
251
+ * appears in multiple maps, `dependencies` wins over the others, and any
252
+ * non-`devDependencies` source wins over `devDependencies`. One entry per
253
+ * unique name.
254
+ */
255
+ source: ExternalDependencySource;
256
+ /** Present when the dep was declared via a `catalog:` reference in `package.json` */
257
+ catalog?: ExternalDependencyCatalog;
258
+ };
167
259
  /** Metadata about a nested package within a Bun monorepo */
168
260
  export type Workspace = {
169
261
  /** The name of the workspace from its `package.json` */
@@ -184,6 +276,8 @@ export type Workspace = {
184
276
  dependencies: string[];
185
277
  /** Names of workspaces that depend on this workspace */
186
278
  dependents: string[];
279
+ /** Non-workspace package dependencies declared by this workspace */
280
+ externalDependencies: ExternalDependency[];
187
281
  };
188
282
  declare const WORKSPACE_SCRIPT_COMMAND_METHODS: readonly ["cd", "filter"];
189
283
  export type WorkspaceScriptCommandMethod =
@@ -316,6 +410,184 @@ declare abstract class ProjectBase implements Project {
316
410
  options: CreateProjectScriptCommandOptions,
317
411
  ): CreateProjectScriptCommandResult;
318
412
  }
413
+ declare const LOG_LEVELS: readonly ["debug", "info", "warn", "error"];
414
+ export type LogLevel = (typeof LOG_LEVELS)[number];
415
+ export type LogLevelSetting = LogLevel | "silent";
416
+ /**
417
+ * A version delta for a single workspace's external dependency between
418
+ * two reference points (typically `baseRef` vs `headRef`).
419
+ *
420
+ * `baseVersion`/`headVersion` are `null` when the dep was absent at that
421
+ * side of the comparison (added or removed). When both are non-null and
422
+ * differ, the version was upgraded/downgraded.
423
+ *
424
+ * All four `package.json` dependency map sources participate. For
425
+ * `optionalDependencies` and `peerDependencies`, lockfile presence is the
426
+ * effective gate — if bun didn't resolve a version (e.g. an optional native
427
+ * binding skipped on this platform), no change is emitted.
428
+ */
429
+ export type ExternalDependencyChange = {
430
+ /** The package name */
431
+ name: string;
432
+ /** Which `package.json` dependency map this dep was declared in */
433
+ source: ExternalDependencySource;
434
+ /** Version at the base point; `null` if absent */
435
+ baseVersion: string | null;
436
+ /** Version at the head point; `null` if absent */
437
+ headVersion: string | null;
438
+ };
439
+ export type AffectedDependencyEdgeSource = "input" | "package";
440
+ export interface AffectedDependencyChainEntry {
441
+ workspaceName: string;
442
+ /**
443
+ * The kind of edge that led to this workspace from the previous chain entry.
444
+ * Undefined for the starting workspace at the head of the chain.
445
+ *
446
+ * "package" means the dependency is a true package.json-resolved dependency.
447
+ *
448
+ * "input" means the dependency comes from the workspace's workspace pattern inputs,
449
+ * from defaultInputs or a script's inputs.
450
+ */
451
+ edgeSource?: AffectedDependencyEdgeSource;
452
+ }
453
+ declare const GIT_AFFECTED_FILE_REASONS: readonly [
454
+ "diff",
455
+ "staged",
456
+ "unstaged",
457
+ "untracked",
458
+ ];
459
+ export type GitAffectedFileReason = (typeof GIT_AFFECTED_FILE_REASONS)[number];
460
+ export type AffectedChangedFile = {
461
+ /** The path to the file, relative to the project root */
462
+ projectFilePath: string;
463
+ /** The matched input for the file */
464
+ inputMatch: string;
465
+ /** Present when `diffSource` is "git": the reasons for the file being affected */
466
+ gitReasons?: GitAffectedFileReason[];
467
+ };
468
+ export type AffectedDependency = {
469
+ /** The name of the dependency */
470
+ dependencyName: string;
471
+ /** The chain of dependencies that led to the affected workspace */
472
+ chain: AffectedDependencyChainEntry[];
473
+ };
474
+ export type AffectedWorkspaceResult = {
475
+ workspace: Workspace;
476
+ inputs: WorkspaceInputsConfig;
477
+ isAffected: boolean;
478
+ affectedReasons: {
479
+ changedFiles: AffectedChangedFile[];
480
+ dependencies: AffectedDependency[];
481
+ /**
482
+ * External (non-workspace) dependency version deltas. In `git` mode the
483
+ * `baseVersion`/`headVersion` carry resolved versions from `bun.lock` at
484
+ * each ref. In `fileList` mode where `bun.lock` was listed as changed,
485
+ * both fields are `null` since no version comparison is possible.
486
+ */
487
+ externalDependencies: ExternalDependencyChange[];
488
+ };
489
+ };
490
+ /** The source for changed files */
491
+ export type AffectedDiffSource = "git" | "fileList";
492
+ export type AffectedWorkspacesMetadata = {
493
+ /** The source for changed files */
494
+ diffSource: AffectedDiffSource;
495
+ /** When `diffSource` is "git" */
496
+ git?: {
497
+ /** The base ref as provided (or the resolved default) */
498
+ baseRef: string;
499
+ /** The head ref as provided (or the resolved default) */
500
+ headRef: string;
501
+ /** The full SHA `baseRef` resolves to */
502
+ baseSha: string;
503
+ /** The full SHA `headRef` resolves to */
504
+ headSha: string;
505
+ };
506
+ };
507
+ export type AffectedWorkspacesResult = {
508
+ /** Metadata based on the parameters given */
509
+ metadata: AffectedWorkspacesMetadata;
510
+ /** The workspaces and their affected reasons */
511
+ workspaceResults: AffectedWorkspaceResult[];
512
+ };
513
+ export type BaseAffectedWorkspacesOptions<
514
+ AcceptsScript extends boolean = true,
515
+ > = {
516
+ /** Skip cascading affected workspaces through `workspace:*` dependencies */
517
+ ignoreWorkspaceDependencies?: boolean;
518
+ /**
519
+ * Skip lockfile-based external dependency version tracking. In `git` mode
520
+ * this prevents reading `bun.lock` at base and head refs. In `fileList`
521
+ * mode this prevents `bun.lock` (when present in `changedFiles`) from
522
+ * triggering external-dep workspaces.
523
+ */
524
+ ignoreExternalDependencies?: boolean;
525
+ } & (AcceptsScript extends true
526
+ ? {
527
+ script?: string;
528
+ }
529
+ : object);
530
+ export type GitAffectedWorkspacesOptions<AcceptsScript extends boolean = true> =
531
+ BaseAffectedWorkspacesOptions<AcceptsScript> & {
532
+ /** Whether to use git to determine affected workspaces or a list of given files */
533
+ diffSource: "git";
534
+ diffOptions?: {
535
+ /**
536
+ * The base git ref to compare against.
537
+ *
538
+ * Default is "main" when not provided or
539
+ * when the default is not set by the
540
+ * root config or env var.
541
+ */
542
+ baseRef?: string;
543
+ /**
544
+ * The head git ref to compare against.
545
+ *
546
+ * Default is "HEAD" when not provided.
547
+ */
548
+ headRef?: string;
549
+ /** Exclude untracked files */
550
+ ignoreUntracked?: boolean;
551
+ /** Ignore staged files */
552
+ ignoreStaged?: boolean;
553
+ /** Ignore unstaged files */
554
+ ignoreUnstaged?: boolean;
555
+ /** Exclude any uncommitted files (ignores staged, unstaged, and untracked) */
556
+ ignoreUncommitted?: boolean;
557
+ };
558
+ };
559
+ export type FileListAffectedWorkspacesOptions<
560
+ AcceptsScript extends boolean = true,
561
+ > = BaseAffectedWorkspacesOptions<AcceptsScript> & {
562
+ /** Whether to use git or a list of given files to determine affected workspaces */
563
+ diffSource: "fileList";
564
+ /**
565
+ * File paths, directories, or glob patterns relative to the project root.
566
+ *
567
+ * - File paths are matched literally. Paths that don't exist on disk
568
+ * pass through as-is.
569
+ * - Directories are walked recursively into a flat file list. The
570
+ * `node_modules` and `.git` directories are skipped during the walk.
571
+ * - Globs are expanded via `bun.Glob` against the project root and
572
+ * only match files that currently exist.
573
+ * - Prefix with `!` to exclude. Exclusions are expanded the same way
574
+ * and removed from the include set.
575
+ */
576
+ changedFiles: string[];
577
+ };
578
+ export type DetermineAffectedWorkspacesOptions<
579
+ AcceptScript extends boolean = true,
580
+ > =
581
+ | GitAffectedWorkspacesOptions<AcceptScript>
582
+ | FileListAffectedWorkspacesOptions<AcceptScript>;
583
+ export declare const isOptionsForDiffSource: <
584
+ DiffSource extends AffectedDiffSource,
585
+ >(
586
+ options: DetermineAffectedWorkspacesOptions,
587
+ diffSource: DiffSource,
588
+ ) => options is DiffSource extends "git"
589
+ ? GitAffectedWorkspacesOptions
590
+ : FileListAffectedWorkspacesOptions;
319
591
  /** Arguments for {@link createFileSystemProject} */
320
592
  export type CreateFileSystemProjectOptions = {
321
593
  /** The directory containing the root package.json. Often the same root as a git repository. Relative to process.cwd(). The default is process.cwd(). */
@@ -423,6 +695,16 @@ export type RunScriptAcrossWorkspacesResult = {
423
695
  /** The workspaces targeted */
424
696
  workspaces: Workspace[];
425
697
  };
698
+ export type RunAffectedWorkspaceScriptOptions = {
699
+ /**
700
+ * Options for resolving the affected workspaces. The `script` field is
701
+ * intentionally omitted — it is derived from `scriptOptions` (the inline
702
+ * script name when running inline, the script name otherwise) so that
703
+ * inputs resolution always tracks the script being run.
704
+ */
705
+ affectedOptions: DetermineAffectedWorkspacesOptions<false>;
706
+ scriptOptions: Omit<RunScriptAcrossWorkspacesOptions, "workspacePatterns">;
707
+ };
426
708
  declare class _FileSystemProject extends ProjectBase implements Project {
427
709
  #private;
428
710
  readonly rootDirectory: string;
@@ -438,6 +720,24 @@ declare class _FileSystemProject extends ProjectBase implements Project {
438
720
  runScriptAcrossWorkspaces(
439
721
  options: RunScriptAcrossWorkspacesOptions,
440
722
  ): RunScriptAcrossWorkspacesResult;
723
+ /**
724
+ * Determine the affected workspaces based on the given options.
725
+ *
726
+ * Returns a summary of all workspaces, whether they are affected or not,
727
+ * and the reasons why they are affected.
728
+ */
729
+ determineAffectedWorkspaces(
730
+ options: DetermineAffectedWorkspacesOptions,
731
+ ): Promise<AffectedWorkspacesResult>;
732
+ /**
733
+ * Run the script across the affected workspaces.
734
+ *
735
+ * Similar to {@link runScriptAcrossWorkspaces}, but only runs the script across the affected workspaces.
736
+ */
737
+ runAffectedWorkspaceScript({
738
+ affectedOptions,
739
+ scriptOptions,
740
+ }: RunAffectedWorkspaceScriptOptions): Promise<RunScriptAcrossWorkspacesResult>;
441
741
  }
442
742
  /** An implementation of {@link Project} that is created from a root directory in the file system. */
443
743
  export type FileSystemProject = Simplify<_FileSystemProject>;
@@ -500,14 +800,16 @@ export declare const defineWorkspaceConfig: (
500
800
  ) => ResolvedWorkspaceConfig;
501
801
  export type WorkspaceConfigFactory = (prev: WorkspaceConfig) => WorkspaceConfig;
502
802
  export type WorkspaceConfigInput = WorkspaceConfig | WorkspaceConfigFactory;
503
- /** Merge two or more workspace configs left to right, with each subsequent config taking precedence.
504
- * Any argument may be a factory function receiving the accumulated config up to that point. */
803
+ /**
804
+ * Merge two or more workspace configs left to right, with each subsequent config taking precedence.
805
+ * Any argument may be a factory function receiving the accumulated config up to that point.
806
+ *
807
+ * Generally, objects are deeply merged, and arrays are concatenated and deduplicated,
808
+ * **except** for inputs (defaultInputs and script inputs), which are replaced entirely.
809
+ */
505
810
  export declare const mergeWorkspaceConfig: (
506
811
  ...configs: WorkspaceConfigInput[]
507
812
  ) => WorkspaceConfig;
508
- declare const LOG_LEVELS: readonly ["debug", "info", "warn", "error"];
509
- export type LogLevel = (typeof LOG_LEVELS)[number];
510
- export type LogLevelSetting = LogLevel | "silent";
511
813
  /** Set the global logging level. Defaults to "info" or "error" when `NODE_ENV` is "test" */
512
814
  export declare const setLogLevel: (level: LogLevelSetting) => void;
513
815
 
package/src/index.mjs CHANGED
@@ -3,6 +3,7 @@ export * from "./config/public.mjs";
3
3
  export {
4
4
  createFileSystemProject,
5
5
  createMemoryProject,
6
+ isOptionsForDiffSource,
6
7
  } from "./project/index.mjs";
7
8
  export { BunWorkspacesError } from "./internal/core/index.mjs";
8
9
  export { setLogLevel } from "./internal/logger/index.mjs";