bun-workspaces 1.0.0-alpha.8 → 1.0.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 (233) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +212 -19
  3. package/bin/cli.js +1 -1
  4. package/package.json +25 -9
  5. package/src/cli/commands/commandHandlerUtils.d.ts +45 -0
  6. package/src/cli/commands/commandHandlerUtils.mjs +81 -0
  7. package/src/cli/commands/commands.d.ts +10 -0
  8. package/src/cli/commands/commands.mjs +23 -0
  9. package/src/cli/commands/commandsConfig.d.ts +351 -0
  10. package/src/cli/commands/commandsConfig.mjs +183 -0
  11. package/src/cli/commands/handleSimpleCommands.d.ts +15 -0
  12. package/src/cli/commands/handleSimpleCommands.mjs +174 -0
  13. package/src/cli/commands/index.d.ts +3 -0
  14. package/src/cli/commands/index.mjs +3 -0
  15. package/src/cli/commands/runScript/handleRunScript.d.ts +3 -0
  16. package/src/cli/commands/runScript/handleRunScript.mjs +250 -0
  17. package/src/cli/commands/runScript/index.d.ts +2 -0
  18. package/src/cli/commands/runScript/index.mjs +2 -0
  19. package/src/cli/commands/runScript/output/index.d.ts +1 -0
  20. package/src/cli/commands/runScript/output/index.mjs +1 -0
  21. package/src/cli/commands/runScript/output/outputStyle.d.ts +8 -0
  22. package/src/cli/commands/runScript/output/outputStyle.mjs +17 -0
  23. package/src/cli/commands/runScript/output/renderGroupedOutput.d.ts +71 -0
  24. package/src/cli/commands/runScript/output/renderGroupedOutput.mjs +307 -0
  25. package/src/cli/commands/runScript/output/renderPlainOutput.d.ts +22 -0
  26. package/src/cli/commands/runScript/output/renderPlainOutput.mjs +43 -0
  27. package/src/cli/commands/runScript/output/sanitizeChunk.d.ts +4 -0
  28. package/src/cli/commands/runScript/output/sanitizeChunk.mjs +101 -0
  29. package/src/cli/createCli.d.ts +14 -8
  30. package/src/cli/createCli.mjs +94 -39
  31. package/src/cli/fatalErrorLogger.d.ts +1 -0
  32. package/src/cli/fatalErrorLogger.mjs +7 -0
  33. package/src/cli/globalOptions/globalOptions.d.ts +38 -2
  34. package/src/cli/globalOptions/globalOptions.mjs +96 -47
  35. package/src/cli/globalOptions/globalOptionsConfig.d.ts +37 -31
  36. package/src/cli/globalOptions/globalOptionsConfig.mjs +32 -30
  37. package/src/cli/globalOptions/index.mjs +1 -1
  38. package/src/cli/index.d.ts +3 -1
  39. package/src/cli/index.mjs +3 -2
  40. package/src/config/index.d.ts +3 -2
  41. package/src/config/index.mjs +3 -3
  42. package/src/config/rootConfig/errors.d.ts +1 -0
  43. package/src/config/rootConfig/errors.mjs +6 -0
  44. package/src/config/rootConfig/index.d.ts +5 -0
  45. package/src/config/rootConfig/index.mjs +5 -0
  46. package/src/config/rootConfig/loadRootConfig.d.ts +3 -0
  47. package/src/config/rootConfig/loadRootConfig.mjs +22 -0
  48. package/src/config/rootConfig/rootConfig.d.ts +17 -0
  49. package/src/config/rootConfig/rootConfig.mjs +43 -0
  50. package/src/config/rootConfig/rootConfigLocation.d.ts +2 -0
  51. package/src/config/rootConfig/rootConfigLocation.mjs +5 -0
  52. package/src/config/rootConfig/rootConfigSchema.d.ts +21 -0
  53. package/src/config/rootConfig/rootConfigSchema.mjs +24 -0
  54. package/src/config/userEnvVars/index.d.ts +1 -0
  55. package/src/config/userEnvVars/index.mjs +1 -0
  56. package/src/config/userEnvVars/userEnvVars.d.ts +13 -0
  57. package/src/config/userEnvVars/userEnvVars.mjs +10 -0
  58. package/src/config/util/ajvTypes.d.ts +10 -0
  59. package/src/config/util/ajvTypes.mjs +2 -0
  60. package/src/config/util/configLocation.d.ts +12 -0
  61. package/src/config/util/configLocation.mjs +11 -0
  62. package/src/config/util/index.d.ts +4 -0
  63. package/src/config/util/index.mjs +3 -0
  64. package/src/config/util/loadConfig.d.ts +16 -0
  65. package/src/config/util/loadConfig.mjs +118 -0
  66. package/src/config/util/validateConfig.d.ts +8 -0
  67. package/src/config/util/validateConfig.mjs +17 -0
  68. package/src/config/workspaceConfig/errors.d.ts +1 -0
  69. package/src/config/workspaceConfig/errors.mjs +6 -0
  70. package/src/config/workspaceConfig/index.d.ts +5 -0
  71. package/src/config/workspaceConfig/index.mjs +5 -0
  72. package/src/config/workspaceConfig/loadWorkspaceConfig.d.ts +3 -0
  73. package/src/config/workspaceConfig/loadWorkspaceConfig.mjs +25 -0
  74. package/src/config/workspaceConfig/workspaceConfig.d.ts +22 -0
  75. package/src/config/workspaceConfig/workspaceConfig.mjs +31 -0
  76. package/src/config/workspaceConfig/workspaceConfigLocation.d.ts +2 -0
  77. package/src/config/workspaceConfig/workspaceConfigLocation.mjs +5 -0
  78. package/src/config/workspaceConfig/workspaceConfigSchema.d.ts +25 -0
  79. package/src/config/workspaceConfig/workspaceConfigSchema.mjs +28 -0
  80. package/src/doctor/doctor.d.ts +35 -0
  81. package/src/doctor/doctor.mjs +52 -0
  82. package/src/doctor/index.d.ts +1 -0
  83. package/src/doctor/index.mjs +1 -0
  84. package/src/index.d.ts +37 -3
  85. package/src/index.mjs +16 -3
  86. package/src/internal/bun/bunLock.d.ts +20 -0
  87. package/src/internal/bun/bunLock.mjs +70 -0
  88. package/src/internal/bun/bunVersion.d.ts +21 -0
  89. package/src/internal/bun/bunVersion.mjs +43 -0
  90. package/src/internal/bun/index.d.ts +2 -0
  91. package/src/internal/bun/index.mjs +2 -0
  92. package/src/internal/core/error/error.d.ts +13 -0
  93. package/src/internal/core/error/error.mjs +36 -0
  94. package/src/internal/core/error/index.d.ts +1 -0
  95. package/src/internal/core/error/index.mjs +1 -0
  96. package/src/internal/core/index.d.ts +4 -0
  97. package/src/internal/core/index.mjs +4 -0
  98. package/src/internal/core/json/index.d.ts +2 -0
  99. package/src/internal/core/json/index.mjs +2 -0
  100. package/src/internal/core/json/json.d.ts +49 -0
  101. package/src/internal/core/json/json.mjs +12 -0
  102. package/src/internal/core/json/jsonc.d.ts +9 -0
  103. package/src/internal/core/json/jsonc.mjs +117 -0
  104. package/src/internal/core/language/array/index.d.ts +1 -0
  105. package/src/internal/core/language/array/index.mjs +1 -0
  106. package/src/internal/core/language/array/optionalArray.d.ts +15 -0
  107. package/src/internal/core/language/array/optionalArray.mjs +8 -0
  108. package/src/internal/core/language/asyncIterable/asyncIterableQueue.d.ts +16 -0
  109. package/src/internal/core/language/asyncIterable/asyncIterableQueue.mjs +81 -0
  110. package/src/internal/core/language/asyncIterable/index.d.ts +2 -0
  111. package/src/internal/core/language/asyncIterable/index.mjs +2 -0
  112. package/src/internal/core/language/asyncIterable/mergeAsyncIterables.d.ts +5 -0
  113. package/src/internal/core/language/asyncIterable/mergeAsyncIterables.mjs +27 -0
  114. package/src/internal/core/language/events/typedEventTarget.d.ts +50 -0
  115. package/src/internal/core/language/events/typedEventTarget.mjs +14 -0
  116. package/src/internal/core/language/index.d.ts +5 -0
  117. package/src/internal/core/language/index.mjs +5 -0
  118. package/src/internal/core/language/regex/index.d.ts +1 -0
  119. package/src/internal/core/language/regex/index.mjs +1 -0
  120. package/src/internal/{regex.d.ts → core/language/regex/regex.d.ts} +1 -0
  121. package/src/internal/core/language/regex/regex.mjs +10 -0
  122. package/src/internal/core/language/string/id.d.ts +1 -0
  123. package/src/internal/core/language/string/id.mjs +10 -0
  124. package/src/internal/core/language/string/index.d.ts +1 -0
  125. package/src/internal/core/language/string/index.mjs +1 -0
  126. package/src/internal/core/language/string/utf/eastAsianWidth.d.ts +16 -0
  127. package/src/internal/core/language/string/utf/eastAsianWidth.mjs +326 -0
  128. package/src/internal/core/language/string/utf/visibleLength.d.ts +5 -0
  129. package/src/internal/core/language/string/utf/visibleLength.mjs +29 -0
  130. package/src/internal/core/language/types/index.d.ts +2 -0
  131. package/src/internal/core/language/types/index.mjs +1 -0
  132. package/src/internal/core/language/types/typeof.d.ts +102 -0
  133. package/src/internal/core/language/types/typeof.mjs +123 -0
  134. package/src/internal/core/language/types/types.d.ts +14 -0
  135. package/src/internal/core/language/types/types.mjs +2 -0
  136. package/src/internal/{env.d.ts → core/runtime/env.d.ts} +1 -0
  137. package/src/internal/core/runtime/env.mjs +36 -0
  138. package/src/internal/core/runtime/index.d.ts +5 -0
  139. package/src/internal/core/runtime/index.mjs +5 -0
  140. package/src/internal/core/runtime/onExit.d.ts +4 -0
  141. package/src/internal/core/runtime/onExit.mjs +54 -0
  142. package/src/internal/core/runtime/os.d.ts +4 -0
  143. package/src/internal/core/runtime/os.mjs +7 -0
  144. package/src/internal/core/runtime/tempFile.d.ts +20 -0
  145. package/src/internal/core/runtime/tempFile.mjs +87 -0
  146. package/src/internal/core/runtime/terminal.d.ts +1 -0
  147. package/src/internal/core/runtime/terminal.mjs +4 -0
  148. package/src/internal/generated/ajv/validateRootConfig.mjs +1 -0
  149. package/src/internal/generated/ajv/validateWorkspaceConfig.mjs +1 -0
  150. package/src/internal/logger/index.d.ts +1 -0
  151. package/src/internal/logger/index.mjs +1 -0
  152. package/src/internal/logger/logger.d.ts +39 -0
  153. package/src/internal/logger/logger.mjs +116 -0
  154. package/src/internal/version.d.ts +1 -0
  155. package/src/internal/version.mjs +6 -0
  156. package/src/project/errors.d.ts +5 -1
  157. package/src/project/errors.mjs +10 -3
  158. package/src/project/implementations/fileSystemProject.d.ts +148 -0
  159. package/src/project/implementations/fileSystemProject.mjs +455 -0
  160. package/src/project/implementations/memoryProject.d.ts +41 -0
  161. package/src/project/implementations/memoryProject.mjs +148 -0
  162. package/src/project/implementations/projectBase.d.ts +35 -0
  163. package/src/project/implementations/projectBase.mjs +197 -0
  164. package/src/project/index.d.ts +5 -1
  165. package/src/project/index.mjs +4 -2
  166. package/src/project/project.d.ts +72 -28
  167. package/src/project/project.mjs +6 -72
  168. package/src/runScript/index.d.ts +7 -0
  169. package/src/runScript/index.mjs +7 -0
  170. package/src/runScript/output/index.d.ts +3 -0
  171. package/src/runScript/output/index.mjs +2 -0
  172. package/src/runScript/output/multiProcessOutput.d.ts +14 -0
  173. package/src/runScript/output/multiProcessOutput.mjs +21 -0
  174. package/src/runScript/output/outputStream.d.ts +1 -0
  175. package/src/runScript/output/outputStream.mjs +1 -0
  176. package/src/runScript/output/processOutput.d.ts +33 -0
  177. package/src/runScript/output/processOutput.mjs +124 -0
  178. package/src/runScript/parallel.d.ts +15 -0
  179. package/src/runScript/parallel.mjs +56 -0
  180. package/src/runScript/recursion.d.ts +4 -0
  181. package/src/runScript/recursion.mjs +17 -0
  182. package/src/runScript/runScript.d.ts +45 -0
  183. package/src/runScript/runScript.mjs +89 -0
  184. package/src/runScript/runScripts.d.ts +65 -0
  185. package/src/runScript/runScripts.mjs +263 -0
  186. package/src/runScript/scriptCommand.d.ts +33 -0
  187. package/src/runScript/scriptCommand.mjs +19 -0
  188. package/src/runScript/scriptExecution.d.ts +9 -0
  189. package/src/runScript/scriptExecution.mjs +50 -0
  190. package/src/runScript/scriptRuntimeMetadata.d.ts +73 -0
  191. package/src/runScript/scriptRuntimeMetadata.mjs +61 -0
  192. package/src/runScript/scriptShellOption.d.ts +8 -0
  193. package/src/runScript/scriptShellOption.mjs +39 -0
  194. package/src/runScript/subprocesses.d.ts +11 -0
  195. package/src/runScript/subprocesses.mjs +34 -0
  196. package/src/workspaces/dependencyGraph/cycles.d.ts +9 -0
  197. package/src/workspaces/dependencyGraph/cycles.mjs +91 -0
  198. package/src/workspaces/dependencyGraph/index.d.ts +2 -0
  199. package/src/workspaces/dependencyGraph/index.mjs +2 -0
  200. package/src/workspaces/dependencyGraph/resolveDependencies.d.ts +18 -0
  201. package/src/workspaces/dependencyGraph/resolveDependencies.mjs +52 -0
  202. package/src/workspaces/errors.d.ts +13 -1
  203. package/src/workspaces/errors.mjs +18 -3
  204. package/src/workspaces/findWorkspaces.d.ts +20 -13
  205. package/src/workspaces/findWorkspaces.mjs +208 -57
  206. package/src/workspaces/index.d.ts +4 -3
  207. package/src/workspaces/index.mjs +3 -2
  208. package/src/workspaces/packageJson.d.ts +28 -5
  209. package/src/workspaces/packageJson.mjs +177 -54
  210. package/src/workspaces/workspace.d.ts +19 -13
  211. package/src/workspaces/workspace.mjs +2 -0
  212. package/src/workspaces/workspacePattern.d.ts +21 -0
  213. package/src/workspaces/workspacePattern.mjs +104 -0
  214. package/src/cli/projectCommands/index.d.ts +0 -2
  215. package/src/cli/projectCommands/index.mjs +0 -2
  216. package/src/cli/projectCommands/projectCommandHandlers.d.ts +0 -8
  217. package/src/cli/projectCommands/projectCommandHandlers.mjs +0 -180
  218. package/src/cli/projectCommands/projectCommandsConfig.d.ts +0 -191
  219. package/src/cli/projectCommands/projectCommandsConfig.mjs +0 -100
  220. package/src/config/bunWorkspacesConfig.d.ts +0 -13
  221. package/src/config/bunWorkspacesConfig.mjs +0 -18
  222. package/src/config/configFile.d.ts +0 -3
  223. package/src/config/configFile.mjs +0 -21
  224. package/src/internal/bunVersion.d.ts +0 -14
  225. package/src/internal/bunVersion.mjs +0 -8
  226. package/src/internal/env.mjs +0 -15
  227. package/src/internal/error.d.ts +0 -7
  228. package/src/internal/error.mjs +0 -26
  229. package/src/internal/logger.d.ts +0 -21
  230. package/src/internal/logger.mjs +0 -85
  231. package/src/internal/regex.mjs +0 -3
  232. package/src/project/scriptCommand.d.ts +0 -15
  233. package/src/project/scriptCommand.mjs +0 -18
@@ -0,0 +1,56 @@
1
+ import os from "os";
2
+ import {
3
+ getUserEnvVar,
4
+ getUserEnvVarName,
5
+ } from "../config/userEnvVars/index.mjs";
6
+ import { BunWorkspacesError } from "../internal/core/index.mjs"; // CONCATENATED MODULE: external "os"
7
+ // CONCATENATED MODULE: external "../config/userEnvVars/index.mjs"
8
+ // CONCATENATED MODULE: external "../internal/core/index.mjs"
9
+ // CONCATENATED MODULE: ./src/runScript/parallel.ts
10
+
11
+ const PARALLEL_MAX_VALUES = ["auto", "unbounded", "default"];
12
+ /** Should always return at least 1 */ const determineParallelMax = (
13
+ value,
14
+ errorMessageSuffix = "",
15
+ ) => {
16
+ if (!isNaN(Number(value))) {
17
+ value = Math.floor(Number(value));
18
+ }
19
+ if (typeof value === "number") {
20
+ if (value < 1 || isNaN(value)) {
21
+ throw new BunWorkspacesError(
22
+ `Parallel max value must be at least 1${errorMessageSuffix}`,
23
+ );
24
+ }
25
+ return Math.floor(value);
26
+ }
27
+ if (value === "default") {
28
+ const defaultMax = getUserEnvVar("parallelMaxDefault")?.trim();
29
+ if (defaultMax === "default") return determineParallelMax("auto");
30
+ return determineParallelMax(
31
+ defaultMax ?? "auto",
32
+ ` (set by env var ${getUserEnvVarName("parallelMaxDefault")})`,
33
+ );
34
+ }
35
+ if (value === "unbounded") {
36
+ return Infinity;
37
+ }
38
+ const cpuCount = Math.max(1, os.availableParallelism());
39
+ if (value === "auto") {
40
+ return cpuCount;
41
+ }
42
+ if (value.endsWith("%")) {
43
+ const percentage = parseFloat(value.slice(0, -1));
44
+ if (isNaN(percentage) || percentage <= 0 || percentage > 100) {
45
+ throw new BunWorkspacesError(
46
+ `Parallel max value must be a number greater than 0 and less than or equal to 100${errorMessageSuffix}`,
47
+ );
48
+ }
49
+ return Math.max(1, Math.floor((cpuCount * percentage) / 100));
50
+ }
51
+ throw new BunWorkspacesError(
52
+ `Invalid parallel max value: ${JSON.stringify(value)}${errorMessageSuffix}`,
53
+ );
54
+ };
55
+
56
+ export { PARALLEL_MAX_VALUES, determineParallelMax };
@@ -0,0 +1,4 @@
1
+ export declare const checkIsRecursiveScript: (
2
+ workspaceName: string,
3
+ scriptName: string,
4
+ ) => boolean | undefined;
@@ -0,0 +1,17 @@
1
+ import { getScriptRuntimeMetadataConfig } from "./scriptRuntimeMetadata.mjs"; // CONCATENATED MODULE: external "./scriptRuntimeMetadata.mjs"
2
+ // CONCATENATED MODULE: ./src/runScript/recursion.ts
3
+
4
+ const checkIsRecursiveScript = (workspaceName, scriptName) => {
5
+ const parentWorkspace =
6
+ process.env[getScriptRuntimeMetadataConfig("workspaceName").envVarName];
7
+ const parentScript =
8
+ process.env[getScriptRuntimeMetadataConfig("scriptName").envVarName];
9
+ if (!parentWorkspace || !parentScript) {
10
+ return false;
11
+ }
12
+ if (parentWorkspace === workspaceName && parentScript === scriptName) {
13
+ return true;
14
+ }
15
+ };
16
+
17
+ export { checkIsRecursiveScript };
@@ -0,0 +1,45 @@
1
+ import { type MultiProcessOutput, type OutputStreamName } from "./output";
2
+ import type { ScriptCommand } from "./scriptCommand";
3
+ import type { ScriptShellOption } from "./scriptShellOption";
4
+ export type RunScriptExit<ScriptMetadata extends object = object> = {
5
+ exitCode: number;
6
+ signal: NodeJS.Signals | null;
7
+ success: boolean;
8
+ /** Whether the script was skipped due to a failed dependency */
9
+ skipped?: boolean;
10
+ startTimeISO: string;
11
+ endTimeISO: string;
12
+ durationMs: number;
13
+ metadata: ScriptMetadata;
14
+ };
15
+ export type RunScriptResult<ScriptMetadata extends object = object> = {
16
+ output: MultiProcessOutput<
17
+ ScriptMetadata & {
18
+ streamName: OutputStreamName;
19
+ }
20
+ >;
21
+ exit: Promise<RunScriptExit<ScriptMetadata>>;
22
+ metadata: ScriptMetadata;
23
+ kill: (exit?: number | NodeJS.Signals) => void;
24
+ };
25
+ export type RunScriptOptions<ScriptMetadata extends object = object> = {
26
+ scriptCommand: ScriptCommand;
27
+ metadata: ScriptMetadata;
28
+ env: Record<string, string>;
29
+ /** The shell to use to run the script. Defaults to "system". */
30
+ shell?: ScriptShellOption;
31
+ /** Set to `true` to ignore all output from the script. This saves memory when you don't need script output. */
32
+ ignoreOutput?: boolean;
33
+ };
34
+ /**
35
+ * Run some script and get an async output stream of
36
+ * stdout and stderr chunks and a result object
37
+ * containing exit details.
38
+ */
39
+ export declare const runScript: <ScriptMetadata extends object = object>({
40
+ scriptCommand,
41
+ metadata,
42
+ env,
43
+ shell,
44
+ ignoreOutput,
45
+ }: RunScriptOptions<ScriptMetadata>) => RunScriptResult<ScriptMetadata>;
@@ -0,0 +1,89 @@
1
+ import {
2
+ createMultiProcessOutput,
3
+ createProcessOutput,
4
+ } from "./output/index.mjs";
5
+ import { createScriptExecutor } from "./scriptExecution.mjs";
6
+ import { createSubprocess } from "./subprocesses.mjs"; // CONCATENATED MODULE: external "./output/index.mjs"
7
+ // CONCATENATED MODULE: external "./scriptExecution.mjs"
8
+ // CONCATENATED MODULE: external "./subprocesses.mjs"
9
+ // CONCATENATED MODULE: ./src/runScript/runScript.ts
10
+
11
+ const SIGNAL_MAP = {
12
+ 130: "SIGINT",
13
+ 143: "SIGTERM",
14
+ 129: "SIGHUP",
15
+ 131: "SIGQUIT",
16
+ 138: "SIGUSR1",
17
+ 140: "SIGUSR2",
18
+ };
19
+ /**
20
+ * Run some script and get an async output stream of
21
+ * stdout and stderr chunks and a result object
22
+ * containing exit details.
23
+ */ const runScript = ({
24
+ scriptCommand,
25
+ metadata,
26
+ env,
27
+ shell = "system",
28
+ ignoreOutput = false,
29
+ }) => {
30
+ const startTime = new Date();
31
+ const { argv, cleanup } = createScriptExecutor(scriptCommand.command, shell);
32
+ const proc = createSubprocess(argv, {
33
+ cwd: scriptCommand.workingDirectory || process.cwd(),
34
+ env: {
35
+ ...process.env,
36
+ ...env,
37
+ _BW_SCRIPT_SHELL_OPTION: shell,
38
+ FORCE_COLOR: "1",
39
+ },
40
+ stdout: ignoreOutput ? "ignore" : "pipe",
41
+ stderr: ignoreOutput ? "ignore" : "pipe",
42
+ stdin: "ignore",
43
+ });
44
+ proc.exited.finally(cleanup);
45
+ const processOutput = createMultiProcessOutput([
46
+ createProcessOutput(
47
+ proc.stdout
48
+ ? proc.stdout
49
+ : (async function* () {
50
+ /* empty */
51
+ })(),
52
+ {
53
+ ...metadata,
54
+ streamName: "stdout",
55
+ },
56
+ ),
57
+ createProcessOutput(
58
+ proc.stderr
59
+ ? proc.stderr
60
+ : (async function* () {
61
+ /* empty */
62
+ })(),
63
+ {
64
+ ...metadata,
65
+ streamName: "stderr",
66
+ },
67
+ ),
68
+ ]);
69
+ const exit = proc.exited.then((exitCode) => {
70
+ const endTime = new Date();
71
+ return {
72
+ exitCode,
73
+ signal: proc.signalCode ?? SIGNAL_MAP[exitCode] ?? null,
74
+ success: exitCode === 0,
75
+ startTimeISO: startTime.toISOString(),
76
+ endTimeISO: endTime.toISOString(),
77
+ durationMs: endTime.getTime() - startTime.getTime(),
78
+ metadata,
79
+ };
80
+ });
81
+ return {
82
+ output: processOutput,
83
+ exit,
84
+ metadata,
85
+ kill: (exit) => proc.kill(exit),
86
+ };
87
+ };
88
+
89
+ export { runScript };
@@ -0,0 +1,65 @@
1
+ import { type MultiProcessOutput, type OutputStreamName } from "./output";
2
+ import { type ParallelMaxValue } from "./parallel";
3
+ import { type RunScriptExit, type RunScriptResult } from "./runScript";
4
+ import { type ScriptCommand } from "./scriptCommand";
5
+ import { type ScriptShellOption } from "./scriptShellOption";
6
+ export type RunScriptsScript<ScriptMetadata extends object = object> = {
7
+ scriptCommand: ScriptCommand;
8
+ metadata: ScriptMetadata;
9
+ env: Record<string, string>;
10
+ /** The shell to use to run the script */
11
+ shell?: ScriptShellOption;
12
+ /** Indices of other scripts in the array that must complete before this one starts */
13
+ dependsOn?: number[];
14
+ /** Set to `true` to ignore all output from the script. This saves memory when you don't need script output. */
15
+ ignoreOutput?: boolean;
16
+ };
17
+ export type RunScriptsScriptResult<ScriptMetadata extends object = object> = {
18
+ /** The result of running the script */
19
+ result: RunScriptResult<ScriptMetadata>;
20
+ };
21
+ export type RunScriptsSummary<ScriptMetadata extends object = object> = {
22
+ totalCount: number;
23
+ successCount: number;
24
+ failureCount: number;
25
+ allSuccess: boolean;
26
+ startTimeISO: string;
27
+ endTimeISO: string;
28
+ durationMs: number;
29
+ scriptResults: RunScriptExit<ScriptMetadata>[];
30
+ };
31
+ export type ScriptEventName = "start" | "skip" | "exit";
32
+ export type RunScriptsResult<ScriptMetadata extends object = object> = {
33
+ output: MultiProcessOutput<
34
+ ScriptMetadata & {
35
+ streamName: OutputStreamName;
36
+ }
37
+ >;
38
+ /** Resolves with a results summary after all scripts have exited */
39
+ summary: Promise<RunScriptsSummary<ScriptMetadata>>;
40
+ };
41
+ export type RunScriptsParallelOptions = {
42
+ max: ParallelMaxValue;
43
+ };
44
+ export type RunScriptsOptions<ScriptMetadata extends object = object> = {
45
+ scripts: RunScriptsScript<ScriptMetadata>[];
46
+ parallel: boolean | RunScriptsParallelOptions;
47
+ /** When true, run scripts even if a dependency failed. Default: false (skip them). */
48
+ ignoreDependencyFailure?: boolean;
49
+ /** Set to `true` to ignore all output from the scripts. This saves memory when you don't need script output. */
50
+ ignoreOutput?: boolean;
51
+ /** Callback to invoke when a script event occurs */
52
+ onScriptEvent?: (
53
+ event: ScriptEventName,
54
+ scriptIndex: number,
55
+ result: RunScriptExit<ScriptMetadata> | null,
56
+ ) => void;
57
+ };
58
+ /** Run a list of scripts */
59
+ export declare const runScripts: <ScriptMetadata extends object = object>({
60
+ scripts,
61
+ parallel,
62
+ ignoreDependencyFailure,
63
+ ignoreOutput,
64
+ onScriptEvent,
65
+ }: RunScriptsOptions<ScriptMetadata>) => RunScriptsResult<ScriptMetadata>;
@@ -0,0 +1,263 @@
1
+ import { createAsyncIterableQueue } from "../internal/core/index.mjs";
2
+ import { logger } from "../internal/logger/index.mjs";
3
+ import {
4
+ createMultiProcessOutput,
5
+ createProcessOutput,
6
+ } from "./output/index.mjs";
7
+ import { determineParallelMax } from "./parallel.mjs";
8
+ import { runScript } from "./runScript.mjs"; // CONCATENATED MODULE: external "../internal/core/index.mjs"
9
+ // CONCATENATED MODULE: external "../internal/logger/index.mjs"
10
+ // CONCATENATED MODULE: external "./output/index.mjs"
11
+ // CONCATENATED MODULE: external "./parallel.mjs"
12
+ // CONCATENATED MODULE: external "./runScript.mjs"
13
+ // CONCATENATED MODULE: ./src/runScript/runScripts.ts
14
+
15
+ /** Validate dependency indices and detect cycles via DFS */ const validateScriptDependencies =
16
+ (scripts) => {
17
+ const scriptCount = scripts.length;
18
+ for (let i = 0; i < scriptCount; i++) {
19
+ const deps = scripts[i].dependsOn;
20
+ if (!deps) continue;
21
+ for (const dep of deps) {
22
+ if (dep === i) {
23
+ throw new Error(
24
+ `Script at index ${i} has a self-referencing dependency`,
25
+ );
26
+ }
27
+ if (dep < 0 || dep >= scriptCount) {
28
+ throw new Error(
29
+ `Script at index ${i} depends on invalid index ${dep} (valid range: 0-${scriptCount - 1})`,
30
+ );
31
+ }
32
+ }
33
+ }
34
+ const WHITE = 0;
35
+ const GRAY = 1;
36
+ const BLACK = 2;
37
+ const colors = new Array(scriptCount).fill(WHITE);
38
+ const visit = (node, path) => {
39
+ colors[node] = GRAY;
40
+ const deps = scripts[node].dependsOn;
41
+ if (deps) {
42
+ for (const dep of deps) {
43
+ if (colors[dep] === GRAY) {
44
+ const cycleStart = path.indexOf(dep);
45
+ const cycle = path.slice(cycleStart);
46
+ throw new Error(
47
+ `Dependency cycle detected: ${[...cycle, dep].join(" -> ")}`,
48
+ );
49
+ }
50
+ if (colors[dep] === WHITE) {
51
+ visit(dep, [...path, dep]);
52
+ }
53
+ }
54
+ }
55
+ colors[node] = BLACK;
56
+ };
57
+ for (let i = 0; i < scriptCount; i++) {
58
+ if (colors[i] === WHITE) {
59
+ visit(i, [i]);
60
+ }
61
+ }
62
+ };
63
+ /** Run a list of scripts */ const runScripts = ({
64
+ scripts,
65
+ parallel,
66
+ ignoreDependencyFailure = false,
67
+ ignoreOutput = false,
68
+ onScriptEvent,
69
+ }) => {
70
+ validateScriptDependencies(scripts);
71
+ const startTime = new Date();
72
+ const scriptTriggers = scripts.map((_, index) => {
73
+ let trigger = () => {
74
+ void 0;
75
+ };
76
+ const promise = new Promise((res) => {
77
+ trigger = () => res(result);
78
+ });
79
+ const result = {
80
+ promise,
81
+ trigger,
82
+ index,
83
+ };
84
+ return result;
85
+ });
86
+ const scriptResults = scripts.map(() => null);
87
+ const parallelMax =
88
+ parallel === false
89
+ ? 1
90
+ : determineParallelMax(
91
+ typeof parallel === "boolean" ? "default" : parallel.max,
92
+ );
93
+ const parallelBatchSize = Math.min(parallelMax, scripts.length);
94
+ const recommendedParallelMax = determineParallelMax("auto");
95
+ if (
96
+ parallel &&
97
+ parallelBatchSize > recommendedParallelMax &&
98
+ process.env._BW_IS_INTERNAL_TEST !== "true"
99
+ ) {
100
+ logger.warn(
101
+ `Number of scripts to run in parallel (${parallelBatchSize}) is greater than the available CPUs (${recommendedParallelMax})`,
102
+ );
103
+ }
104
+ const pendingScripts = new Set(scripts.map((_, i) => i));
105
+ const runningScripts = new Set();
106
+ const completedScripts = new Set();
107
+ const exitResults = scripts.map(() => null);
108
+ const scriptProcessBytes = scripts.map(() => null);
109
+ const createSkippedExit = (index) => {
110
+ const now = new Date().toISOString();
111
+ return {
112
+ exitCode: -1,
113
+ signal: null,
114
+ success: false,
115
+ skipped: true,
116
+ startTimeISO: now,
117
+ endTimeISO: now,
118
+ durationMs: 0,
119
+ metadata: scripts[index].metadata,
120
+ };
121
+ };
122
+ const createSkippedResult = (index) => {
123
+ const skippedExit = createSkippedExit(index);
124
+ exitResults[index] = skippedExit;
125
+ return {
126
+ result: {
127
+ output: createMultiProcessOutput([]),
128
+ exit: Promise.resolve(skippedExit),
129
+ metadata: scripts[index].metadata,
130
+ kill: () => {
131
+ /* empty */
132
+ },
133
+ },
134
+ };
135
+ };
136
+ const hasDependencyFailure = (index) => {
137
+ const deps = scripts[index].dependsOn;
138
+ if (!deps) return false;
139
+ return deps.some(
140
+ (dep) => exitResults[dep] !== null && !exitResults[dep].success,
141
+ );
142
+ };
143
+ const areDependenciesMet = (index) => {
144
+ const deps = scripts[index].dependsOn;
145
+ if (!deps) return true;
146
+ return deps.every((dep) => completedScripts.has(dep));
147
+ };
148
+ const scriptOutputQueues = scripts.map(() => ({
149
+ stdout: createAsyncIterableQueue(),
150
+ stderr: createAsyncIterableQueue(),
151
+ }));
152
+ const scheduleReadyScripts = () => {
153
+ let changed = true;
154
+ while (changed) {
155
+ changed = false;
156
+ for (const index of [...pendingScripts]) {
157
+ if (runningScripts.size >= parallelMax) return;
158
+ if (!areDependenciesMet(index)) continue;
159
+ if (!ignoreDependencyFailure && hasDependencyFailure(index)) {
160
+ pendingScripts.delete(index);
161
+ completedScripts.add(index);
162
+ scriptResults[index] = createSkippedResult(index);
163
+ scriptProcessBytes[index] = (async function* () {
164
+ /* empty */
165
+ })();
166
+ scriptOutputQueues[index].stdout.close();
167
+ scriptOutputQueues[index].stderr.close();
168
+ onScriptEvent?.("skip", index, null);
169
+ scriptTriggers[index].trigger();
170
+ changed = true;
171
+ continue;
172
+ }
173
+ pendingScripts.delete(index);
174
+ runningScripts.add(index);
175
+ const scriptResult = {
176
+ ...scripts[index],
177
+ result: runScript({
178
+ ...scripts[index],
179
+ env: {
180
+ ...scripts[index].env,
181
+ _BW_PARALLEL_MAX: parallelMax.toString(),
182
+ },
183
+ ignoreOutput,
184
+ }),
185
+ };
186
+ scriptResults[index] = scriptResult;
187
+ const bytesOutput = scriptResult.result.output.bytes();
188
+ scriptProcessBytes[index] = bytesOutput;
189
+ (async () => {
190
+ for await (const { chunk, metadata } of bytesOutput) {
191
+ scriptOutputQueues[index][metadata.streamName].push(chunk);
192
+ }
193
+ scriptOutputQueues[index].stdout.close();
194
+ scriptOutputQueues[index].stderr.close();
195
+ })();
196
+ onScriptEvent?.("start", index, null);
197
+ scriptTriggers[index].trigger();
198
+ scriptResult.result.exit.then((exit) => {
199
+ runningScripts.delete(index);
200
+ completedScripts.add(index);
201
+ exitResults[index] = exit;
202
+ onScriptEvent?.("exit", index, exit);
203
+ scheduleReadyScripts();
204
+ });
205
+ }
206
+ }
207
+ };
208
+ const multiProcessOutput = createMultiProcessOutput(
209
+ scriptOutputQueues.flatMap(({ stdout, stderr }, index) => [
210
+ createProcessOutput(stdout, {
211
+ ...scripts[index].metadata,
212
+ streamName: "stdout",
213
+ }),
214
+ createProcessOutput(stderr, {
215
+ ...scripts[index].metadata,
216
+ streamName: "stderr",
217
+ }),
218
+ ]),
219
+ );
220
+ const handleScriptProcesses = async () => {
221
+ let pendingScriptCount = scripts.length;
222
+ while (pendingScriptCount > 0) {
223
+ const { index } = await Promise.race(
224
+ scriptTriggers.map((trigger) => trigger.promise),
225
+ );
226
+ pendingScriptCount--;
227
+ scriptTriggers[index].promise = new Promise(() => {
228
+ void 0;
229
+ });
230
+ }
231
+ await Promise.all(
232
+ scriptOutputQueues.flatMap(({ stdout, stderr }) => [
233
+ stdout.closed,
234
+ stderr.closed,
235
+ ]),
236
+ );
237
+ await Promise.all(scriptResults.map(({ result }) => result.exit));
238
+ };
239
+ const awaitSummary = async () => {
240
+ scheduleReadyScripts();
241
+ await handleScriptProcesses();
242
+ const scriptExitResults = await Promise.all(
243
+ scripts.map((_, index) => scriptResults[index].result.exit),
244
+ );
245
+ const endTime = new Date();
246
+ return {
247
+ totalCount: scriptExitResults.length,
248
+ successCount: scriptExitResults.filter((exit) => exit.success).length,
249
+ failureCount: scriptExitResults.filter((exit) => !exit.success).length,
250
+ allSuccess: scriptExitResults.every((exit) => exit.success),
251
+ startTimeISO: startTime.toISOString(),
252
+ endTimeISO: endTime.toISOString(),
253
+ durationMs: endTime.getTime() - startTime.getTime(),
254
+ scriptResults: scriptExitResults,
255
+ };
256
+ };
257
+ return {
258
+ output: multiProcessOutput,
259
+ summary: awaitSummary(),
260
+ };
261
+ };
262
+
263
+ export { runScripts };
@@ -0,0 +1,33 @@
1
+ import type { Workspace } from "../workspaces";
2
+ export declare const WORKSPACE_SCRIPT_COMMAND_METHODS: readonly [
3
+ "cd",
4
+ "filter",
5
+ ];
6
+ export type WorkspaceScriptCommandMethod =
7
+ (typeof WORKSPACE_SCRIPT_COMMAND_METHODS)[number];
8
+ /** Basic metadata to run a script, the command string and the directory to run it in */
9
+ export interface ScriptCommand {
10
+ /** The command string to run */
11
+ command: string;
12
+ /** The directory to run the command in */
13
+ workingDirectory: string;
14
+ }
15
+ export interface CreateWorkspaceScriptCommandOptions {
16
+ /**
17
+ * The method to use to run the script.
18
+ * Either run in the workspace directory or use bun's --filter option.
19
+ * Defaults to "cd".
20
+ */
21
+ method?: WorkspaceScriptCommandMethod;
22
+ /** The name of the script to run */
23
+ scriptName: string;
24
+ /** The arguments to append to the command */
25
+ args: string;
26
+ /** The workspace that the script belongs to */
27
+ workspace: Workspace;
28
+ /** The root directory of the project */
29
+ rootDirectory: string;
30
+ }
31
+ export declare const createWorkspaceScriptCommand: (
32
+ options: CreateWorkspaceScriptCommandOptions,
33
+ ) => ScriptCommand;
@@ -0,0 +1,19 @@
1
+ import path from "path"; // CONCATENATED MODULE: external "path"
2
+ // CONCATENATED MODULE: ./src/runScript/scriptCommand.ts
3
+
4
+ const WORKSPACE_SCRIPT_COMMAND_METHODS = ["cd", "filter"];
5
+ const spaceArgs = (args) => (args ? ` ${args.trim()}` : "");
6
+ const METHODS = {
7
+ cd: ({ scriptName, workspace, rootDirectory, args }) => ({
8
+ workingDirectory: path.resolve(rootDirectory, workspace.path),
9
+ command: `bun --silent run ${scriptName}${spaceArgs(args)}`,
10
+ }),
11
+ filter: ({ scriptName, workspace, args, rootDirectory }) => ({
12
+ workingDirectory: rootDirectory,
13
+ command: `bun --silent run --filter=${JSON.stringify(workspace.name)} ${scriptName}${spaceArgs(args)}`,
14
+ }),
15
+ };
16
+ const createWorkspaceScriptCommand = (options) =>
17
+ METHODS[options.method ?? "cd"](options);
18
+
19
+ export { WORKSPACE_SCRIPT_COMMAND_METHODS, createWorkspaceScriptCommand };
@@ -0,0 +1,9 @@
1
+ import { type ScriptShellOption } from "./scriptShellOption";
2
+ export type ScriptExecutor = {
3
+ argv: string[];
4
+ cleanup: () => void;
5
+ };
6
+ export declare const createScriptExecutor: (
7
+ command: string,
8
+ shell: ScriptShellOption,
9
+ ) => ScriptExecutor;
@@ -0,0 +1,50 @@
1
+ import {
2
+ BunWorkspacesError,
3
+ DEFAULT_TEMP_DIR,
4
+ IS_WINDOWS,
5
+ createShortId,
6
+ } from "../internal/core/index.mjs";
7
+ import { resolveScriptShell } from "./scriptShellOption.mjs"; // CONCATENATED MODULE: external "../internal/core/index.mjs"
8
+ // CONCATENATED MODULE: external "./scriptShellOption.mjs"
9
+ // CONCATENATED MODULE: ./src/runScript/scriptExecution.ts
10
+
11
+ const createWindowsBatchFile = (command) => {
12
+ const fileName = `${createShortId(6)}.cmd`;
13
+ const fileContent = `@echo off\r\n${command}\r\n`;
14
+ return DEFAULT_TEMP_DIR.createFile({
15
+ name: fileName,
16
+ content: fileContent,
17
+ });
18
+ };
19
+ const createShellScript = (command) => {
20
+ const fileName = `${createShortId(6)}.sh`;
21
+ return DEFAULT_TEMP_DIR.createFile({
22
+ name: fileName,
23
+ content: command,
24
+ mode: 493,
25
+ });
26
+ };
27
+ const createScriptExecutor = (command, shell) => {
28
+ shell = resolveScriptShell(shell);
29
+ if (shell === "bun") {
30
+ const { filePath, cleanup } = createShellScript(command);
31
+ return {
32
+ argv: ["bun", filePath],
33
+ cleanup,
34
+ };
35
+ }
36
+ if (shell === "system") {
37
+ const { filePath, cleanup } = IS_WINDOWS
38
+ ? createWindowsBatchFile(command)
39
+ : createShellScript(command);
40
+ return {
41
+ argv: IS_WINDOWS
42
+ ? ["cmd", "/d", "/s", "/c", "call", filePath]
43
+ : ["sh", "-c", filePath],
44
+ cleanup,
45
+ };
46
+ }
47
+ throw new BunWorkspacesError(`Invalid shell option: ${shell}`);
48
+ };
49
+
50
+ export { createScriptExecutor };