bun-workspaces 0.2.0 → 1.0.0-alpha
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.
- package/README.md +44 -2
- package/bun.lock +576 -0
- package/package.json +14 -14
- package/src/cli/cli.ts +3 -8
- package/src/cli/globalOptions.ts +61 -23
- package/src/cli/projectCommands.ts +232 -130
- package/src/config/bunWorkspacesConfig.ts +62 -0
- package/src/config/configFile.ts +33 -0
- package/src/config/index.ts +7 -0
- package/src/internal/bunVersion.ts +4 -2
- package/src/internal/env.ts +25 -1
- package/src/internal/logger.ts +143 -15
- package/src/project/project.ts +25 -1
- package/src/workspaces/errors.ts +3 -0
- package/src/workspaces/findWorkspaces.ts +37 -11
- package/src/workspaces/index.ts +0 -1
- package/src/workspaces/packageJson.ts +16 -8
- package/src/workspaces/workspace.ts +2 -0
- package/tsconfig.json +1 -1
- package/.vscode/extensions.json +0 -12
- package/.vscode/settings.json +0 -23
- package/bun-workspaces-0.1.0-alpha-test-publish-2.tgz +0 -0
- package/eslint.config.mjs +0 -45
- package/src/cli/output.ts +0 -6
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { type Command } from "commander";
|
|
2
|
-
import {
|
|
2
|
+
import { BunWorkspacesError } from "../internal/error";
|
|
3
|
+
import { logger, createLogger } from "../internal/logger";
|
|
3
4
|
import type { Project } from "../project";
|
|
4
5
|
import type { Workspace } from "../workspaces";
|
|
5
6
|
|
|
6
7
|
export interface ProjectCommandsContext {
|
|
7
8
|
project: Project;
|
|
8
9
|
program: Command;
|
|
9
|
-
printLines: (...lines: string[]) => void;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const createWorkspaceInfoLines = (workspace: Workspace) => [
|
|
13
13
|
`Workspace: ${workspace.name}`,
|
|
14
|
+
` - Aliases: ${workspace.aliases.join(", ")}`,
|
|
14
15
|
` - Path: ${workspace.path}`,
|
|
15
16
|
` - Glob Match: ${workspace.matchPattern}`,
|
|
16
17
|
` - Scripts: ${Object.keys(workspace.packageJson.scripts).sort().join(", ")}`,
|
|
@@ -21,132 +22,194 @@ const createScriptInfoLines = (script: string, workspaces: Workspace[]) => [
|
|
|
21
22
|
...workspaces.map((workspace) => ` - ${workspace.name}`),
|
|
22
23
|
];
|
|
23
24
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
const createJsonLines = (data: unknown, options: { pretty: boolean }) =>
|
|
26
|
+
JSON.stringify(data, null, options.pretty ? 2 : undefined).split("\n");
|
|
27
|
+
|
|
28
|
+
export const commandOutputLogger = createLogger("");
|
|
29
|
+
commandOutputLogger.printLevel = "info";
|
|
30
|
+
|
|
31
|
+
const listWorkspaces = ({ program, project }: ProjectCommandsContext) => {
|
|
29
32
|
program
|
|
30
33
|
.command("list-workspaces [pattern]")
|
|
31
34
|
.aliases(["ls", "list"])
|
|
32
35
|
.description("List all workspaces")
|
|
33
36
|
.option("--name-only", "Only show workspace names")
|
|
34
|
-
.
|
|
35
|
-
|
|
37
|
+
.option("--json", "Output as JSON")
|
|
38
|
+
.option("--pretty", "Pretty print JSON")
|
|
39
|
+
.action(
|
|
40
|
+
(
|
|
41
|
+
pattern,
|
|
42
|
+
options: { nameOnly: boolean; json: boolean; pretty: boolean },
|
|
43
|
+
) => {
|
|
44
|
+
logger.debug(
|
|
45
|
+
`Command: List workspaces (options: ${JSON.stringify(options)})`,
|
|
46
|
+
);
|
|
36
47
|
|
|
37
|
-
|
|
38
|
-
logger.debug("Showing more metadata");
|
|
39
|
-
}
|
|
48
|
+
const lines: string[] = [];
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
const workspaces = pattern
|
|
51
|
+
? project.findWorkspacesByPattern(pattern)
|
|
52
|
+
: project.workspaces;
|
|
53
|
+
|
|
54
|
+
if (options.json) {
|
|
55
|
+
lines.push(
|
|
56
|
+
...createJsonLines(
|
|
57
|
+
options.nameOnly
|
|
58
|
+
? workspaces.map(({ name }) => name)
|
|
59
|
+
: workspaces,
|
|
60
|
+
options,
|
|
61
|
+
),
|
|
62
|
+
);
|
|
48
63
|
} else {
|
|
49
|
-
|
|
64
|
+
workspaces.forEach((workspace) => {
|
|
65
|
+
if (options.nameOnly) {
|
|
66
|
+
lines.push(workspace.name);
|
|
67
|
+
} else {
|
|
68
|
+
lines.push(...createWorkspaceInfoLines(workspace));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
50
71
|
}
|
|
51
|
-
});
|
|
52
72
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
if (!lines.length) {
|
|
74
|
+
logger.info("No workspaces found");
|
|
75
|
+
}
|
|
56
76
|
|
|
57
|
-
|
|
58
|
-
|
|
77
|
+
if (lines.length) commandOutputLogger.info(lines.join("\n"));
|
|
78
|
+
},
|
|
79
|
+
);
|
|
59
80
|
};
|
|
60
81
|
|
|
61
|
-
const listScripts = ({
|
|
62
|
-
program,
|
|
63
|
-
project,
|
|
64
|
-
printLines,
|
|
65
|
-
}: ProjectCommandsContext) => {
|
|
82
|
+
const listScripts = ({ program, project }: ProjectCommandsContext) => {
|
|
66
83
|
program
|
|
67
84
|
.command("list-scripts")
|
|
68
85
|
.description("List all scripts available with their workspaces")
|
|
69
86
|
.option("--name-only", "Only show script names")
|
|
70
|
-
.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.forEach(({ name, workspaces }) => {
|
|
78
|
-
if (options.nameOnly) {
|
|
79
|
-
lines.push(name);
|
|
80
|
-
} else {
|
|
81
|
-
lines.push(...createScriptInfoLines(name, workspaces));
|
|
82
|
-
}
|
|
83
|
-
});
|
|
87
|
+
.option("--json", "Output as JSON")
|
|
88
|
+
.option("--pretty", "Pretty print JSON")
|
|
89
|
+
.action(
|
|
90
|
+
(options: { nameOnly: boolean; json: boolean; pretty: boolean }) => {
|
|
91
|
+
logger.debug(
|
|
92
|
+
`Command: List scripts (options: ${JSON.stringify(options)})`,
|
|
93
|
+
);
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
lines
|
|
87
|
-
|
|
95
|
+
const scripts = project.listScriptsWithWorkspaces();
|
|
96
|
+
const lines: string[] = [];
|
|
97
|
+
|
|
98
|
+
if (options.json) {
|
|
99
|
+
lines.push(
|
|
100
|
+
...createJsonLines(
|
|
101
|
+
options.nameOnly
|
|
102
|
+
? Object.keys(scripts)
|
|
103
|
+
: Object.values(scripts).map(({ workspaces, ...rest }) => ({
|
|
104
|
+
...rest,
|
|
105
|
+
workspaces: workspaces.map(({ name }) => name),
|
|
106
|
+
})),
|
|
107
|
+
options,
|
|
108
|
+
),
|
|
109
|
+
);
|
|
110
|
+
} else {
|
|
111
|
+
Object.values(scripts)
|
|
112
|
+
.sort(({ name: nameA }, { name: nameB }) =>
|
|
113
|
+
nameA.localeCompare(nameB),
|
|
114
|
+
)
|
|
115
|
+
.forEach(({ name, workspaces }) => {
|
|
116
|
+
if (options.nameOnly) {
|
|
117
|
+
lines.push(name);
|
|
118
|
+
} else {
|
|
119
|
+
lines.push(...createScriptInfoLines(name, workspaces));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (!lines.length) {
|
|
124
|
+
logger.info("No scripts found");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
88
127
|
|
|
89
|
-
|
|
90
|
-
|
|
128
|
+
if (lines.length) commandOutputLogger.info(lines.join("\n"));
|
|
129
|
+
},
|
|
130
|
+
);
|
|
91
131
|
};
|
|
92
132
|
|
|
93
|
-
const workspaceInfo = ({
|
|
94
|
-
program,
|
|
95
|
-
project,
|
|
96
|
-
printLines,
|
|
97
|
-
}: ProjectCommandsContext) => {
|
|
133
|
+
const workspaceInfo = ({ program, project }: ProjectCommandsContext) => {
|
|
98
134
|
program
|
|
99
135
|
.command("workspace-info <workspace>")
|
|
100
136
|
.aliases(["info"])
|
|
101
137
|
.description("Show information about a workspace")
|
|
102
|
-
.
|
|
103
|
-
|
|
138
|
+
.option("--json", "Output as JSON")
|
|
139
|
+
.option("--pretty", "Pretty print JSON")
|
|
140
|
+
.action(
|
|
141
|
+
(workspaceName: string, options: { json: boolean; pretty: boolean }) => {
|
|
142
|
+
logger.debug(
|
|
143
|
+
`Command: Workspace info for ${workspaceName} (options: ${JSON.stringify(options)})`,
|
|
144
|
+
);
|
|
104
145
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
146
|
+
const workspace = project.findWorkspaceByName(workspaceName);
|
|
147
|
+
if (!workspace) {
|
|
148
|
+
logger.error(
|
|
149
|
+
`Workspace not found: (options: ${JSON.stringify(workspaceName)})`,
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
110
153
|
|
|
111
|
-
|
|
112
|
-
|
|
154
|
+
commandOutputLogger.info(
|
|
155
|
+
(options.json
|
|
156
|
+
? createJsonLines(workspace, options)
|
|
157
|
+
: createWorkspaceInfoLines(workspace)
|
|
158
|
+
).join("\n"),
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
);
|
|
113
162
|
};
|
|
114
163
|
|
|
115
|
-
const scriptInfo = ({
|
|
116
|
-
program,
|
|
117
|
-
project,
|
|
118
|
-
printLines,
|
|
119
|
-
}: ProjectCommandsContext) => {
|
|
164
|
+
const scriptInfo = ({ program, project }: ProjectCommandsContext) => {
|
|
120
165
|
program
|
|
121
166
|
.command("script-info <script>")
|
|
122
167
|
.description("Show information about a script")
|
|
123
168
|
.option("--workspaces-only", "Only show script's workspace names")
|
|
124
|
-
.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
)} (available: ${Object.keys(scripts).join(", ")})`,
|
|
169
|
+
.option("--json", "Output as JSON")
|
|
170
|
+
.option("--pretty", "Pretty print JSON")
|
|
171
|
+
.action(
|
|
172
|
+
(
|
|
173
|
+
script,
|
|
174
|
+
options: { workspacesOnly: boolean; json: boolean; pretty: boolean },
|
|
175
|
+
) => {
|
|
176
|
+
logger.debug(
|
|
177
|
+
`Command: Script info for ${script} (options: ${JSON.stringify(options)})`,
|
|
134
178
|
);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
179
|
+
|
|
180
|
+
const scripts = project.listScriptsWithWorkspaces();
|
|
181
|
+
const scriptMetadata = scripts[script];
|
|
182
|
+
if (!scriptMetadata) {
|
|
183
|
+
logger.error(
|
|
184
|
+
`Script not found: ${JSON.stringify(
|
|
185
|
+
script,
|
|
186
|
+
)} (available: ${Object.keys(scripts).join(", ")})`,
|
|
187
|
+
);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
commandOutputLogger.info(
|
|
191
|
+
(options.json
|
|
192
|
+
? createJsonLines(
|
|
193
|
+
options.workspacesOnly
|
|
194
|
+
? scriptMetadata.workspaces.map(({ name }) => name)
|
|
195
|
+
: {
|
|
196
|
+
name: scriptMetadata.name,
|
|
197
|
+
workspaces: scriptMetadata.workspaces.map(
|
|
198
|
+
({ name }) => name,
|
|
199
|
+
),
|
|
200
|
+
},
|
|
201
|
+
options,
|
|
202
|
+
)
|
|
203
|
+
: options.workspacesOnly
|
|
204
|
+
? scriptMetadata.workspaces.map(({ name }) => name)
|
|
205
|
+
: createScriptInfoLines(script, scriptMetadata.workspaces)
|
|
206
|
+
).join("\n"),
|
|
207
|
+
);
|
|
208
|
+
},
|
|
209
|
+
);
|
|
143
210
|
};
|
|
144
211
|
|
|
145
|
-
const runScript = ({
|
|
146
|
-
program,
|
|
147
|
-
project,
|
|
148
|
-
printLines,
|
|
149
|
-
}: ProjectCommandsContext) => {
|
|
212
|
+
const runScript = ({ program, project }: ProjectCommandsContext) => {
|
|
150
213
|
program
|
|
151
214
|
.command("run <script> [workspaces...]")
|
|
152
215
|
.description("Run a script in all workspaces")
|
|
@@ -201,31 +264,45 @@ const runScript = ({
|
|
|
201
264
|
scriptName,
|
|
202
265
|
workspace,
|
|
203
266
|
}: (typeof scriptCommands)[number]) => {
|
|
267
|
+
const commandLogger = createLogger(`${workspace.name}:${scriptName}`);
|
|
268
|
+
|
|
204
269
|
const splitCommand = command.command.split(/\s+/g);
|
|
205
270
|
|
|
206
|
-
|
|
271
|
+
commandLogger.debug(
|
|
207
272
|
`Running script ${scriptName} in workspace ${workspace.name} (cwd: ${
|
|
208
273
|
command.cwd
|
|
209
274
|
}): ${splitCommand.join(" ")}`,
|
|
210
275
|
);
|
|
211
276
|
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
if (!silent) {
|
|
215
|
-
printLines(
|
|
216
|
-
`Running script ${JSON.stringify(
|
|
217
|
-
scriptName,
|
|
218
|
-
)} in workspace ${JSON.stringify(workspace.name)}`,
|
|
219
|
-
);
|
|
220
|
-
}
|
|
277
|
+
const isSilent = logger.printLevel === "silent";
|
|
221
278
|
|
|
222
279
|
const proc = Bun.spawn(command.command.split(/\s+/g), {
|
|
223
280
|
cwd: command.cwd,
|
|
224
281
|
env: process.env,
|
|
225
|
-
stdout:
|
|
226
|
-
stderr:
|
|
282
|
+
stdout: isSilent ? "ignore" : "pipe",
|
|
283
|
+
stderr: isSilent ? "ignore" : "pipe",
|
|
227
284
|
});
|
|
228
285
|
|
|
286
|
+
const linePrefix = `[${workspace.name}:${scriptName}] `;
|
|
287
|
+
|
|
288
|
+
if (proc.stdout) {
|
|
289
|
+
for await (const chunk of proc.stdout) {
|
|
290
|
+
const line = new TextDecoder().decode(chunk).trim();
|
|
291
|
+
line.split("\n").forEach((line) => {
|
|
292
|
+
commandLogger.info(linePrefix + line);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (proc.stderr) {
|
|
298
|
+
for await (const chunk of proc.stderr) {
|
|
299
|
+
const line = new TextDecoder().decode(chunk).trim();
|
|
300
|
+
line.split("\n").forEach((line) => {
|
|
301
|
+
commandLogger.error(linePrefix + line);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
229
306
|
await proc.exited;
|
|
230
307
|
|
|
231
308
|
return {
|
|
@@ -233,30 +310,20 @@ const runScript = ({
|
|
|
233
310
|
workspace,
|
|
234
311
|
command,
|
|
235
312
|
success: proc.exitCode === 0,
|
|
313
|
+
error:
|
|
314
|
+
proc.exitCode === 0
|
|
315
|
+
? null
|
|
316
|
+
: new BunWorkspacesError(
|
|
317
|
+
`Script exited with code ${proc.exitCode}`,
|
|
318
|
+
),
|
|
236
319
|
};
|
|
237
320
|
};
|
|
238
321
|
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const handleResult = ({
|
|
247
|
-
scriptName,
|
|
248
|
-
workspace,
|
|
249
|
-
success,
|
|
250
|
-
}: (typeof scriptCommands)[number] & { success: boolean }) => {
|
|
251
|
-
logger.info(
|
|
252
|
-
`${success ? "✅" : "❌"} ${workspace.name}: ${scriptName}`,
|
|
253
|
-
);
|
|
254
|
-
if (!success) {
|
|
255
|
-
program.error(
|
|
256
|
-
`Script ${scriptName} failed in workspace ${workspace.name}`,
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
};
|
|
322
|
+
const results = [] as {
|
|
323
|
+
success: boolean;
|
|
324
|
+
workspaceName: string;
|
|
325
|
+
error: Error | null;
|
|
326
|
+
}[];
|
|
260
327
|
|
|
261
328
|
if (options.parallel) {
|
|
262
329
|
let i = 0;
|
|
@@ -264,9 +331,17 @@ const runScript = ({
|
|
|
264
331
|
scriptCommands.map(runCommand),
|
|
265
332
|
)) {
|
|
266
333
|
if (result.status === "rejected") {
|
|
267
|
-
|
|
334
|
+
results.push({
|
|
335
|
+
success: false,
|
|
336
|
+
workspaceName: workspaces[i],
|
|
337
|
+
error: result.reason,
|
|
338
|
+
});
|
|
268
339
|
} else {
|
|
269
|
-
|
|
340
|
+
results.push({
|
|
341
|
+
success: result.value.success,
|
|
342
|
+
workspaceName: workspaces[i],
|
|
343
|
+
error: result.value.error,
|
|
344
|
+
});
|
|
270
345
|
}
|
|
271
346
|
i++;
|
|
272
347
|
}
|
|
@@ -275,12 +350,39 @@ const runScript = ({
|
|
|
275
350
|
for (const command of scriptCommands) {
|
|
276
351
|
try {
|
|
277
352
|
const result = await runCommand(command);
|
|
278
|
-
|
|
353
|
+
results.push({
|
|
354
|
+
success: result.success,
|
|
355
|
+
workspaceName: workspaces[i],
|
|
356
|
+
error: result.error,
|
|
357
|
+
});
|
|
279
358
|
} catch (error) {
|
|
280
|
-
|
|
359
|
+
results.push({
|
|
360
|
+
success: false,
|
|
361
|
+
workspaceName: workspaces[i],
|
|
362
|
+
error: error as Error,
|
|
363
|
+
});
|
|
281
364
|
}
|
|
365
|
+
i++;
|
|
282
366
|
}
|
|
283
|
-
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
let failCount = 0;
|
|
370
|
+
results.forEach(({ success, workspaceName }) => {
|
|
371
|
+
if (!success) failCount++;
|
|
372
|
+
commandOutputLogger.info(
|
|
373
|
+
`${success ? "✅" : "❌"} ${workspaceName}: ${script}`,
|
|
374
|
+
);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const s = results.length === 1 ? "" : "s";
|
|
378
|
+
if (failCount) {
|
|
379
|
+
const message = `${failCount} of ${results.length} script${s} failed`;
|
|
380
|
+
commandOutputLogger.info(message);
|
|
381
|
+
process.exit(1);
|
|
382
|
+
} else {
|
|
383
|
+
commandOutputLogger.info(
|
|
384
|
+
`${results.length} script${s} ran successfully`,
|
|
385
|
+
);
|
|
284
386
|
}
|
|
285
387
|
});
|
|
286
388
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { validateLogLevel, type LogLevelSetting } from "../internal/logger";
|
|
2
|
+
|
|
3
|
+
export interface CliConfig {
|
|
4
|
+
logLevel?: LogLevelSetting;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ProjectConfig {
|
|
8
|
+
/** A map of aliases to a workspace name */
|
|
9
|
+
workspaceAliases?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface BunWorkspacesConfig {
|
|
13
|
+
cli?: CliConfig;
|
|
14
|
+
project?: ProjectConfig;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const validateCliConfig = (cliConfig: CliConfig) => {
|
|
18
|
+
if (typeof cliConfig !== "object" || Array.isArray(cliConfig)) {
|
|
19
|
+
throw new Error(`Config file: "cli" must be an object`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (cliConfig?.logLevel) {
|
|
23
|
+
validateLogLevel(cliConfig.logLevel);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const validateProjectConfig = (projectConfig: ProjectConfig) => {
|
|
28
|
+
if (typeof projectConfig !== "object" || Array.isArray(projectConfig)) {
|
|
29
|
+
throw new Error(`Config file: "project" must be an object`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (projectConfig?.workspaceAliases) {
|
|
33
|
+
if (
|
|
34
|
+
typeof projectConfig.workspaceAliases !== "object" ||
|
|
35
|
+
Array.isArray(projectConfig.workspaceAliases)
|
|
36
|
+
) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Config file: project.workspaceAliases must be an object`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
for (const alias of Object.values(projectConfig.workspaceAliases)) {
|
|
42
|
+
if (typeof alias !== "string") {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Config file: project.workspaceAliases must be an object with string keys and values`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const validateBunWorkspacesConfig = (config: BunWorkspacesConfig) => {
|
|
52
|
+
if (typeof config !== "object" || Array.isArray(config)) {
|
|
53
|
+
throw new Error(`Config file: must be an object`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (typeof config.cli !== "undefined") {
|
|
57
|
+
validateCliConfig(config.cli);
|
|
58
|
+
}
|
|
59
|
+
if (typeof config.project !== "undefined") {
|
|
60
|
+
validateProjectConfig(config.project);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import {
|
|
4
|
+
validateBunWorkspacesConfig,
|
|
5
|
+
type BunWorkspacesConfig,
|
|
6
|
+
} from "./bunWorkspacesConfig";
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_CONFIG_FILE_PATH = "bw.json";
|
|
9
|
+
|
|
10
|
+
export const loadConfigFile = (filePath?: string, rootDir = ".") => {
|
|
11
|
+
if (!filePath) {
|
|
12
|
+
const defaultFilePath = path.resolve(rootDir, DEFAULT_CONFIG_FILE_PATH);
|
|
13
|
+
if (fs.existsSync(defaultFilePath)) {
|
|
14
|
+
filePath = defaultFilePath;
|
|
15
|
+
} else {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
filePath = path.resolve(rootDir, filePath);
|
|
21
|
+
|
|
22
|
+
const configFile = fs.readFileSync(filePath, "utf8");
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const json = JSON.parse(configFile);
|
|
26
|
+
validateBunWorkspacesConfig(json);
|
|
27
|
+
return json as BunWorkspacesConfig;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Config file: "${filePath}" is not a valid JSON file: ${error}`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -8,12 +8,14 @@ export const BUILD_BUN_VERSION = rootPackageJson.custom.bunVersion.build;
|
|
|
8
8
|
export const getRequiredBunVersion = (build?: boolean) =>
|
|
9
9
|
build ? BUILD_BUN_VERSION : LIBRARY_CONSUMER_BUN_VERSION;
|
|
10
10
|
|
|
11
|
+
const _Bun = typeof Bun === "undefined" ? ({} as typeof Bun) : Bun;
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Validates that the provided version satisfies the required Bun version
|
|
13
15
|
* specified in the root `package.json`.
|
|
14
16
|
*/
|
|
15
17
|
export const validateBunVersion = (version: string, build?: boolean) =>
|
|
16
|
-
|
|
18
|
+
_Bun ? _Bun.semver.satisfies(version, getRequiredBunVersion(build)) : true;
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
*
|
|
@@ -21,4 +23,4 @@ export const validateBunVersion = (version: string, build?: boolean) =>
|
|
|
21
23
|
* required Bun version specified in the root `package.json`.
|
|
22
24
|
*/
|
|
23
25
|
export const validateCurrentBunVersion = (build?: boolean) =>
|
|
24
|
-
validateBunVersion(
|
|
26
|
+
validateBunVersion(_Bun?.version, build);
|
package/src/internal/env.ts
CHANGED
|
@@ -1 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
const RUNTIME_MODE_VALUES = ["development", "production", "test"] as const;
|
|
2
|
+
|
|
3
|
+
export type RuntimeMode = "development" | "production" | "test";
|
|
4
|
+
|
|
5
|
+
const _RUNTIME_MODE: RuntimeMode = ((process.env
|
|
6
|
+
._BW_RUNTIME_MODE as RuntimeMode) ||
|
|
7
|
+
(process.env.NODE_ENV?.match(/test(ing)?/)
|
|
8
|
+
? "test"
|
|
9
|
+
: process.env.NODE_ENV === "development"
|
|
10
|
+
? "development"
|
|
11
|
+
: "production")) as RuntimeMode;
|
|
12
|
+
|
|
13
|
+
export const RUNTIME_MODE = RUNTIME_MODE_VALUES.includes(_RUNTIME_MODE)
|
|
14
|
+
? _RUNTIME_MODE
|
|
15
|
+
: "production";
|
|
16
|
+
|
|
17
|
+
if (RUNTIME_MODE !== _RUNTIME_MODE) {
|
|
18
|
+
console.error(
|
|
19
|
+
`Env var RUNTIME_MODE has an invalid value: "${_RUNTIME_MODE}". Defaulting to "${RUNTIME_MODE}". Accepted values: ${RUNTIME_MODE_VALUES.join(", ")}.`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const IS_TEST = RUNTIME_MODE === "test";
|
|
24
|
+
export const IS_PRODUCTION = RUNTIME_MODE === "production";
|
|
25
|
+
export const IS_DEVELOPMENT = RUNTIME_MODE === "development";
|