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
@@ -1,8 +1,8 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { loadRootConfig } from "../../config/index.mjs";
4
- import { getUserEnvVar } from "../../config/userEnvVars/index.mjs";
5
- import { parse, quote } from "../../internal/bundledDeps/shellQuote.mjs";
3
+ import { loadRootConfig } from "../../../config/index.mjs";
4
+ import { getUserEnvVar } from "../../../config/userEnvVars/index.mjs";
5
+ import { parse, quote } from "../../../internal/bundledDeps/shellQuote.mjs";
6
6
  import {
7
7
  DEFAULT_TEMP_DIR,
8
8
  IS_WINDOWS,
@@ -11,25 +11,55 @@ import {
11
11
  isPlainObject,
12
12
  validateJSArray,
13
13
  validateJSTypes,
14
- } from "../../internal/core/index.mjs";
15
- import { logger } from "../../internal/logger/index.mjs";
14
+ } from "../../../internal/core/index.mjs";
15
+ import { logger } from "../../../internal/logger/index.mjs";
16
16
  import {
17
17
  createScriptRuntimeEnvVars,
18
18
  interpolateWorkspaceScriptMetadata,
19
19
  runScript,
20
20
  runScripts,
21
- } from "../../runScript/index.mjs";
22
- import { checkIsRecursiveScript } from "../../runScript/recursion.mjs";
23
- import { resolveScriptShell } from "../../runScript/scriptShellOption.mjs";
24
- import { findWorkspaces, sortWorkspaces } from "../../workspaces/index.mjs";
25
- import { preventDependencyCycles } from "../../workspaces/dependencyGraph/index.mjs";
26
- import { PROJECT_ERRORS } from "../errors.mjs";
21
+ } from "../../../runScript/index.mjs";
22
+ import { createMultiProcessOutput } from "../../../runScript/output/multiProcessOutput.mjs";
23
+ import { checkIsRecursiveScript } from "../../../runScript/recursion.mjs";
24
+ import { resolveScriptShell } from "../../../runScript/scriptShellOption.mjs";
25
+ import { findWorkspaces, sortWorkspaces } from "../../../workspaces/index.mjs";
26
+ import { preventDependencyCycles } from "../../../workspaces/dependencyGraph/index.mjs";
27
+ import { PROJECT_ERRORS } from "../../errors.mjs";
27
28
  import {
28
29
  ProjectBase,
29
30
  resolveRootWorkspaceSelector,
30
31
  resolveWorkspacePath,
31
- } from "./projectBase.mjs";
32
+ } from "../projectBase.mjs";
33
+ import { determineAffectedWorkspaces } from "./affectedWorkspaces.mjs";
32
34
 
35
+ /**
36
+ * Resolves the script name used to look up script-level inputs in
37
+ * `runAffectedWorkspaceScript`. Uses the inline-script name when running
38
+ * an inline command, or the script name otherwise.
39
+ */ const resolveInputsLookupScriptName = (scriptOptions) => {
40
+ if (!scriptOptions.inline) return scriptOptions.script;
41
+ if (typeof scriptOptions.inline === "object") {
42
+ return scriptOptions.inline.scriptName;
43
+ }
44
+ return undefined;
45
+ };
46
+ const createEmptyAffectedRunResult = () => {
47
+ const now = new Date().toISOString();
48
+ return {
49
+ output: createMultiProcessOutput([]),
50
+ summary: Promise.resolve({
51
+ totalCount: 0,
52
+ successCount: 0,
53
+ failureCount: 0,
54
+ allSuccess: true,
55
+ startTimeISO: now,
56
+ endTimeISO: now,
57
+ durationMs: 0,
58
+ scriptResults: [],
59
+ }),
60
+ workspaces: [],
61
+ };
62
+ };
33
63
  const quoteArg = (arg, shell) =>
34
64
  IS_WINDOWS && shell === "system"
35
65
  ? `"${arg.replace(/"/g, '""')}"`
@@ -497,6 +527,133 @@ class _FileSystemProject extends ProjectBase {
497
527
  workspaces,
498
528
  };
499
529
  }
530
+ /**
531
+ * Determine the affected workspaces based on the given options.
532
+ *
533
+ * Returns a summary of all workspaces, whether they are affected or not,
534
+ * and the reasons why they are affected.
535
+ */ async determineAffectedWorkspaces(options) {
536
+ validateJSTypes(
537
+ {
538
+ "diffSource option": {
539
+ value: options.diffSource,
540
+ typeofName: "string",
541
+ },
542
+ "ignoreWorkspaceDependencies option": {
543
+ value: options.ignoreWorkspaceDependencies,
544
+ typeofName: "boolean",
545
+ optional: true,
546
+ },
547
+ "ignoreExternalDependencies option": {
548
+ value: options.ignoreExternalDependencies,
549
+ typeofName: "boolean",
550
+ optional: true,
551
+ },
552
+ "script option": {
553
+ value: options.script,
554
+ typeofName: "string",
555
+ optional: true,
556
+ },
557
+ },
558
+ {
559
+ throw: true,
560
+ },
561
+ );
562
+ if (options.diffSource !== "git" && options.diffSource !== "fileList") {
563
+ throw new InvalidJSTypeError(
564
+ `Type error: diffSource option expects "git" | "fileList", received ${JSON.stringify(options.diffSource)}`,
565
+ );
566
+ }
567
+ if (options.diffSource === "git") {
568
+ validateJSTypes(
569
+ {
570
+ "diffOptions option": {
571
+ value: options.diffOptions,
572
+ typeofName: "object",
573
+ optional: true,
574
+ },
575
+ },
576
+ {
577
+ throw: true,
578
+ },
579
+ );
580
+ if (options.diffOptions !== undefined) {
581
+ validateJSTypes(
582
+ {
583
+ "diffOptions.baseRef option": {
584
+ value: options.diffOptions.baseRef,
585
+ typeofName: "string",
586
+ optional: true,
587
+ },
588
+ "diffOptions.headRef option": {
589
+ value: options.diffOptions.headRef,
590
+ typeofName: "string",
591
+ optional: true,
592
+ },
593
+ "diffOptions.ignoreUntracked option": {
594
+ value: options.diffOptions.ignoreUntracked,
595
+ typeofName: "boolean",
596
+ optional: true,
597
+ },
598
+ "diffOptions.ignoreStaged option": {
599
+ value: options.diffOptions.ignoreStaged,
600
+ typeofName: "boolean",
601
+ optional: true,
602
+ },
603
+ "diffOptions.ignoreUnstaged option": {
604
+ value: options.diffOptions.ignoreUnstaged,
605
+ typeofName: "boolean",
606
+ optional: true,
607
+ },
608
+ "diffOptions.ignoreUncommitted option": {
609
+ value: options.diffOptions.ignoreUncommitted,
610
+ typeofName: "boolean",
611
+ optional: true,
612
+ },
613
+ },
614
+ {
615
+ throw: true,
616
+ },
617
+ );
618
+ }
619
+ } else {
620
+ validateJSTypes(
621
+ {
622
+ "changedFiles option": {
623
+ value: options.changedFiles,
624
+ array: true,
625
+ itemOptions: {
626
+ typeofName: "string",
627
+ },
628
+ },
629
+ },
630
+ {
631
+ throw: true,
632
+ },
633
+ );
634
+ }
635
+ return determineAffectedWorkspaces(this, options);
636
+ }
637
+ /**
638
+ * Run the script across the affected workspaces.
639
+ *
640
+ * Similar to {@link runScriptAcrossWorkspaces}, but only runs the script across the affected workspaces.
641
+ */ async runAffectedWorkspaceScript({ affectedOptions, scriptOptions }) {
642
+ const { workspaceResults } = await this.determineAffectedWorkspaces({
643
+ ...affectedOptions,
644
+ script: resolveInputsLookupScriptName(scriptOptions),
645
+ });
646
+ const affectedNames = workspaceResults
647
+ .filter(({ isAffected }) => isAffected)
648
+ .map(({ workspace }) => workspace.name);
649
+ if (affectedNames.length === 0) {
650
+ return createEmptyAffectedRunResult();
651
+ }
652
+ return this.runScriptAcrossWorkspaces({
653
+ ...scriptOptions,
654
+ workspacePatterns: affectedNames,
655
+ });
656
+ }
500
657
  static #initialized = false;
501
658
  }
502
659
  /**
@@ -0,0 +1,4 @@
1
+ export * from "./fileSystemProject.mjs";
2
+ export * from "./affectedWorkspaces.mjs";
3
+
4
+ export {};
@@ -112,6 +112,7 @@ class _MemoryProject extends ProjectBase {
112
112
  tags: [],
113
113
  dependencies: [],
114
114
  dependents: [],
115
+ externalDependencies: [],
115
116
  };
116
117
  validateWorkspace(this.rootWorkspace);
117
118
  for (const workspace of this.workspaces) {
@@ -1,6 +1,6 @@
1
1
  export * from "./errors.mjs";
2
2
  export * from "./implementations/projectBase.mjs";
3
- export * from "./implementations/fileSystemProject.mjs";
3
+ export * from "./implementations/fileSystemProject/index.mjs";
4
4
  export * from "./implementations/memoryProject.mjs";
5
5
 
6
6
  export {};
@@ -21,42 +21,11 @@ function __webpack_require__(moduleId) {
21
21
  // expose the modules object (__webpack_modules__)
22
22
  __webpack_require__.m = __webpack_modules__;
23
23
 
24
- // webpack/runtime/compat_get_default_export
25
- (() => {
26
- // getDefaultExport function for compatibility with non-ESM modules
27
- __webpack_require__.n = (module) => {
28
- var getter =
29
- module && module.__esModule ? () => module["default"] : () => module;
30
- __webpack_require__.d(getter, { a: getter });
31
- return getter;
32
- };
33
- })();
34
- // webpack/runtime/define_property_getters
35
- (() => {
36
- __webpack_require__.d = (exports, definition) => {
37
- for (var key in definition) {
38
- if (
39
- __webpack_require__.o(definition, key) &&
40
- !__webpack_require__.o(exports, key)
41
- ) {
42
- Object.defineProperty(exports, key, {
43
- enumerable: true,
44
- get: definition[key],
45
- });
46
- }
47
- }
48
- };
49
- })();
50
24
  // webpack/runtime/esm_register_module
51
25
  (() => {
52
26
  __webpack_require__.add = function registerModules(modules) {
53
27
  Object.assign(__webpack_require__.m, modules);
54
28
  };
55
29
  })();
56
- // webpack/runtime/has_own_property
57
- (() => {
58
- __webpack_require__.o = (obj, prop) =>
59
- Object.prototype.hasOwnProperty.call(obj, prop);
60
- })();
61
30
 
62
31
  export { __webpack_require__ };
@@ -4,11 +4,20 @@ import {
4
4
  } from "../config/index.mjs";
5
5
  import { matchWorkspacesByPatterns } from "./workspacePattern.mjs";
6
6
 
7
- const resolvedToWorkspaceConfig = ({ aliases, tags, scripts, rules }) => ({
7
+ const resolvedToWorkspaceConfig = ({
8
+ aliases,
9
+ tags,
10
+ scripts,
11
+ rules,
12
+ defaultInputs,
13
+ }) => ({
8
14
  alias: aliases,
9
15
  tags,
10
16
  scripts,
11
17
  rules,
18
+ ...(defaultInputs && {
19
+ defaultInputs,
20
+ }),
12
21
  });
13
22
  const makeContext = (workspace) => ({
14
23
  name: workspace.name,
@@ -1,5 +1,11 @@
1
1
  import { resolveCatalogDependencyVersion } from "../packageJson.mjs";
2
2
 
3
+ const parseCatalogRef = (rawVersion) => {
4
+ if (!rawVersion.startsWith("catalog:")) return undefined;
5
+ return {
6
+ name: rawVersion.slice("catalog:".length),
7
+ };
8
+ };
3
9
  const resolveWorkspaceDependencies = (
4
10
  workspaceMap,
5
11
  includeRootWorkspace,
@@ -10,34 +16,78 @@ const resolveWorkspaceDependencies = (
10
16
  );
11
17
  const workspacesWithDependencies = workspacePackages.map(
12
18
  ({ workspace, packageJson }) => {
13
- for (const dependencyMap of [
14
- packageJson.dependencies,
15
- packageJson.devDependencies,
16
- packageJson.peerDependencies,
17
- packageJson.optionalDependencies,
18
- ]) {
19
- for (const [dependencyName, dependencyVersion] of Object.entries(
20
- dependencyMap,
21
- )) {
19
+ const externalAccumulator = new Map();
20
+ const dependencyMaps = [
21
+ {
22
+ map: packageJson.dependencies,
23
+ source: "dependencies",
24
+ },
25
+ {
26
+ map: packageJson.devDependencies,
27
+ source: "devDependencies",
28
+ },
29
+ {
30
+ map: packageJson.peerDependencies,
31
+ source: "peerDependencies",
32
+ },
33
+ {
34
+ map: packageJson.optionalDependencies,
35
+ source: "optionalDependencies",
36
+ },
37
+ ];
38
+ for (const { map, source } of dependencyMaps) {
39
+ for (const [dependencyName, dependencyVersion] of Object.entries(map)) {
40
+ const catalog = parseCatalogRef(dependencyVersion);
22
41
  const resolvedVersion =
23
- catalogs && dependencyVersion.startsWith("catalog:")
42
+ catalogs && catalog
24
43
  ? (resolveCatalogDependencyVersion(
25
44
  dependencyName,
26
45
  dependencyVersion,
27
46
  catalogs,
28
47
  ) ?? dependencyVersion)
29
48
  : dependencyVersion;
30
- if (
31
- resolvedVersion.startsWith("workspace:") &&
32
- workspaceMap[dependencyName]
33
- ) {
34
- workspace.dependencies.push(dependencyName);
35
- workspaceMap[dependencyName].workspace.dependents.push(
36
- workspace.name,
37
- );
49
+ if (resolvedVersion.startsWith("workspace:")) {
50
+ if (workspaceMap[dependencyName]) {
51
+ workspace.dependencies.push(dependencyName);
52
+ workspaceMap[dependencyName].workspace.dependents.push(
53
+ workspace.name,
54
+ );
55
+ }
56
+ continue;
57
+ }
58
+ // External dep — record. Source precedence: a non-`devDependencies`
59
+ // source overrides `devDependencies`; otherwise the first source
60
+ // seen wins. Version/catalog reflect the last entry seen for the name.
61
+ const existing = externalAccumulator.get(dependencyName);
62
+ if (!existing) {
63
+ externalAccumulator.set(dependencyName, {
64
+ source,
65
+ version: resolvedVersion,
66
+ catalog,
67
+ });
68
+ } else {
69
+ existing.version = resolvedVersion;
70
+ existing.catalog = catalog;
71
+ if (
72
+ existing.source === "devDependencies" &&
73
+ source !== "devDependencies"
74
+ ) {
75
+ existing.source = source;
76
+ }
38
77
  }
39
78
  }
40
79
  }
80
+ workspace.externalDependencies = [...externalAccumulator.entries()]
81
+ .map(([name, { source, version, catalog }]) => {
82
+ const entry = {
83
+ name,
84
+ version,
85
+ source,
86
+ };
87
+ if (catalog) entry.catalog = catalog;
88
+ return entry;
89
+ })
90
+ .sort((a, b) => a.name.localeCompare(b.name));
41
91
  return workspace;
42
92
  },
43
93
  );
@@ -144,6 +144,7 @@ const findWorkspaces = ({
144
144
  tags: workspaceConfig?.tags ?? [],
145
145
  dependencies: [],
146
146
  dependents: [],
147
+ externalDependencies: [],
147
148
  };
148
149
  if (workspace.isRoot) {
149
150
  logger.debug(`Found root workspace: ${workspace.name}`);
@@ -1,3 +1,9 @@
1
- /** Metadata about a nested package within a Bun monorepo */
1
+ /** Catalog reference info attached to an `ExternalDependency` that uses a `catalog:` ref */ /** The four `package.json` dependency maps a dep can be declared in */ const EXTERNAL_DEPENDENCY_SOURCES =
2
+ [
3
+ "dependencies",
4
+ "devDependencies",
5
+ "peerDependencies",
6
+ "optionalDependencies",
7
+ ];
2
8
 
3
- export {};
9
+ export { EXTERNAL_DEPENDENCY_SOURCES };