bun-workspaces 1.3.0 → 1.4.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 (28) hide show
  1. package/README.md +5 -2
  2. package/package.json +1 -1
  3. package/src/cli/commands/commandHandlerUtils.mjs +1 -0
  4. package/src/cli/commands/commands.mjs +4 -0
  5. package/src/cli/commands/commandsConfig.d.ts +72 -0
  6. package/src/cli/commands/commandsConfig.mjs +36 -0
  7. package/src/cli/commands/handleSimpleCommands.d.ts +6 -0
  8. package/src/cli/commands/handleSimpleCommands.mjs +62 -1
  9. package/src/cli/globalOptions/globalOptions.d.ts +2 -0
  10. package/src/config/public.d.ts +7 -10
  11. package/src/config/rootConfig/defineRootConfig.d.ts +1 -8
  12. package/src/config/rootConfig/rootConfig.d.ts +12 -4
  13. package/src/config/rootConfig/rootConfigSchema.mjs +1 -0
  14. package/src/config/workspaceConfig/defineWorkspaceConfig.d.ts +1 -5
  15. package/src/config/workspaceConfig/workspaceConfig.d.ts +32 -11
  16. package/src/config/workspaceConfig/workspaceConfig.mjs +1 -0
  17. package/src/config/workspaceConfig/workspaceConfigSchema.d.ts +23 -16
  18. package/src/config/workspaceConfig/workspaceConfigSchema.mjs +8 -0
  19. package/src/internal/generated/ajv/validateWorkspaceConfig.mjs +1 -1
  20. package/src/project/implementations/memoryProject.mjs +1 -0
  21. package/src/project/implementations/projectBase.d.ts +2 -0
  22. package/src/project/implementations/projectBase.mjs +18 -0
  23. package/src/project/project.d.ts +4 -0
  24. package/src/runScript/parallel.d.ts +9 -0
  25. package/src/workspaces/findWorkspaces.mjs +1 -0
  26. package/src/workspaces/workspace.d.ts +3 -1
  27. package/src/workspaces/workspacePattern.d.ts +1 -1
  28. package/src/workspaces/workspacePattern.mjs +8 -1
package/README.md CHANGED
@@ -80,7 +80,7 @@ bw run lint --dep-order
80
80
  bw run lint --dep-order --ignore-dep-failure
81
81
 
82
82
  bw run lint "my-workspace-*" # Run for matching workspace names
83
- bw run lint "alias:my-alias-pattern-*" "path:my-glob/**/*" # Use matching specifiers
83
+ bw run lint "alias:my-alias-*" "path:my-glob/**/*" "tag:my-tag" # Use matching specifiers
84
84
 
85
85
  bw run lint --args="--my-appended-args" # Add args to each script call
86
86
  bw run lint --args="--my-arg=<workspaceName>" # Use the workspace name in args
@@ -106,6 +106,9 @@ bw run my-script --output-style=prefixed
106
106
  # Use the plain output style (no workspace prefixes)
107
107
  bw run my-script --output-style=plain
108
108
 
109
+ # Silence all output of the run command
110
+ bw --log-level=silent run my-script --output-style=none
111
+
109
112
  # Show usage (you can pass --help to any command)
110
113
  bw help
111
114
  bw --help
@@ -118,7 +121,7 @@ bw --cwd=/path/to/your/project ls
118
121
  bw --cwd=/path/to/your/project run my-script
119
122
 
120
123
  # Pass --log-level to any command (debug, info, warn, error, or silent)
121
- bw --log-level=silent run my-script
124
+ bw --log-level=debug ls
122
125
  ```
123
126
 
124
127
  ### API
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bun-workspaces",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "A monorepo management tool for Bun, with a CLI and API to enhance Bun's native workspaces.",
5
5
  "license": "MIT",
6
6
  "exports": {
@@ -19,6 +19,7 @@ const createWorkspaceInfoLines = (workspace) => [
19
19
  ` - Path: ${workspace.path}`,
20
20
  ` - Glob Match: ${workspace.matchPattern}`,
21
21
  ` - Scripts: ${workspace.scripts.join(", ")}`,
22
+ ` - Tags: ${workspace.tags.join(", ")}`,
22
23
  ` - Dependencies: ${workspace.dependencies.join(", ")}`,
23
24
  ` - Dependents: ${workspace.dependents.join(", ")}`,
24
25
  ];
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  doctor,
3
3
  listScripts,
4
+ listTags,
4
5
  listWorkspaces,
5
6
  scriptInfo,
7
+ tagInfo,
6
8
  workspaceInfo,
7
9
  } from "./handleSimpleCommands.mjs";
8
10
  import { runScript } from "./runScript/index.mjs"; // CONCATENATED MODULE: external "./handleSimpleCommands.mjs"
@@ -17,6 +19,8 @@ const defineProjectCommands = (context) => {
17
19
  listScripts(context);
18
20
  workspaceInfo(context);
19
21
  scriptInfo(context);
22
+ listTags(context);
23
+ tagInfo(context);
20
24
  runScript(context);
21
25
  };
22
26
 
@@ -123,6 +123,42 @@ export declare const CLI_COMMANDS_CONFIG: {
123
123
  };
124
124
  };
125
125
  };
126
+ readonly listTags: {
127
+ readonly command: "list-tags";
128
+ readonly isGlobal: false;
129
+ readonly aliases: ["ls-tags"];
130
+ readonly description: "List all tags available with their workspaces";
131
+ readonly options: {
132
+ readonly nameOnly: {
133
+ readonly flags: ["-n", "--name-only"];
134
+ readonly description: "Only show tag names";
135
+ };
136
+ readonly json: {
137
+ readonly flags: readonly ["-j", "--json"];
138
+ readonly description: "Output as JSON";
139
+ };
140
+ readonly pretty: {
141
+ readonly flags: ["-p", "--pretty"];
142
+ readonly description: "Pretty print JSON";
143
+ };
144
+ };
145
+ };
146
+ readonly tagInfo: {
147
+ readonly command: "tag-info <tag>";
148
+ readonly isGlobal: false;
149
+ readonly aliases: [];
150
+ readonly description: "Show information about a tag";
151
+ readonly options: {
152
+ readonly json: {
153
+ readonly flags: readonly ["-j", "--json"];
154
+ readonly description: "Output as JSON";
155
+ };
156
+ readonly pretty: {
157
+ readonly flags: ["-p", "--pretty"];
158
+ readonly description: "Pretty print JSON";
159
+ };
160
+ };
161
+ };
126
162
  readonly runScript: {
127
163
  readonly command: "run-script [script] [workspacePatterns...]";
128
164
  readonly isGlobal: false;
@@ -284,6 +320,42 @@ export declare const getCliCommandConfig: (commandName: CliCommandName) =>
284
320
  };
285
321
  };
286
322
  }
323
+ | {
324
+ readonly command: "list-tags";
325
+ readonly isGlobal: false;
326
+ readonly aliases: ["ls-tags"];
327
+ readonly description: "List all tags available with their workspaces";
328
+ readonly options: {
329
+ readonly nameOnly: {
330
+ readonly flags: ["-n", "--name-only"];
331
+ readonly description: "Only show tag names";
332
+ };
333
+ readonly json: {
334
+ readonly flags: readonly ["-j", "--json"];
335
+ readonly description: "Output as JSON";
336
+ };
337
+ readonly pretty: {
338
+ readonly flags: ["-p", "--pretty"];
339
+ readonly description: "Pretty print JSON";
340
+ };
341
+ };
342
+ }
343
+ | {
344
+ readonly command: "tag-info <tag>";
345
+ readonly isGlobal: false;
346
+ readonly aliases: [];
347
+ readonly description: "Show information about a tag";
348
+ readonly options: {
349
+ readonly json: {
350
+ readonly flags: readonly ["-j", "--json"];
351
+ readonly description: "Output as JSON";
352
+ };
353
+ readonly pretty: {
354
+ readonly flags: ["-p", "--pretty"];
355
+ readonly description: "Pretty print JSON";
356
+ };
357
+ };
358
+ }
287
359
  | {
288
360
  readonly command: "run-script [script] [workspacePatterns...]";
289
361
  readonly isGlobal: false;
@@ -101,6 +101,42 @@ const CLI_COMMANDS_CONFIG = {
101
101
  },
102
102
  },
103
103
  },
104
+ listTags: {
105
+ command: "list-tags",
106
+ isGlobal: false,
107
+ aliases: ["ls-tags"],
108
+ description: "List all tags available with their workspaces",
109
+ options: {
110
+ nameOnly: {
111
+ flags: ["-n", "--name-only"],
112
+ description: "Only show tag names",
113
+ },
114
+ json: {
115
+ flags: JSON_FLAGS,
116
+ description: "Output as JSON",
117
+ },
118
+ pretty: {
119
+ flags: ["-p", "--pretty"],
120
+ description: "Pretty print JSON",
121
+ },
122
+ },
123
+ },
124
+ tagInfo: {
125
+ command: "tag-info <tag>",
126
+ isGlobal: false,
127
+ aliases: [],
128
+ description: "Show information about a tag",
129
+ options: {
130
+ json: {
131
+ flags: JSON_FLAGS,
132
+ description: "Output as JSON",
133
+ },
134
+ pretty: {
135
+ flags: ["-p", "--pretty"],
136
+ description: "Pretty print JSON",
137
+ },
138
+ },
139
+ },
104
140
  runScript: {
105
141
  command: "run-script [script] [workspacePatterns...]",
106
142
  isGlobal: false,
@@ -13,3 +13,9 @@ export declare const workspaceInfo: (
13
13
  export declare const scriptInfo: (
14
14
  context: import("./commandHandlerUtils").ProjectCommandContext,
15
15
  ) => import("commander").Command;
16
+ export declare const listTags: (
17
+ context: import("./commandHandlerUtils").ProjectCommandContext,
18
+ ) => import("commander").Command;
19
+ export declare const tagInfo: (
20
+ context: import("./commandHandlerUtils").ProjectCommandContext,
21
+ ) => import("commander").Command;
@@ -170,5 +170,66 @@ const scriptInfo = handleProjectCommand(
170
170
  );
171
171
  },
172
172
  );
173
+ const listTags = handleProjectCommand("listTags", ({ project }, options) => {
174
+ logger.debug(`Options: ${JSON.stringify(options)}`);
175
+ const tagMap = project.mapTagsToWorkspaces();
176
+ const tags = Object.entries(tagMap).map(([tag, workspaces]) => ({
177
+ tag,
178
+ workspaces: workspaces.map(({ name }) => name),
179
+ }));
180
+ const lines = [];
181
+ if (options.json) {
182
+ lines.push(
183
+ ...createJsonLines(
184
+ options.nameOnly ? tags.map(({ tag }) => tag) : tags,
185
+ options,
186
+ ),
187
+ );
188
+ } else {
189
+ if (!Object.keys(tagMap).length && !options.nameOnly) {
190
+ logger.info("No tags found");
191
+ return;
192
+ }
193
+ tags.forEach(({ tag, workspaces }) => {
194
+ if (options.nameOnly) {
195
+ lines.push(tag);
196
+ } else {
197
+ lines.push(
198
+ `Tag: ${tag}\n${workspaces.map((name) => ` - ${name}`).join("\n")}`,
199
+ );
200
+ }
201
+ });
202
+ }
203
+ if (lines.length) commandOutputLogger.info(lines.join("\n"));
204
+ });
205
+ const handleSimpleCommands_tagInfo = handleProjectCommand(
206
+ "tagInfo",
207
+ ({ project }, tag, options) => {
208
+ logger.debug(`Options: ${JSON.stringify(options)}`);
209
+ const tagMap = project.mapTagsToWorkspaces();
210
+ const tagMetadata = tagMap[tag];
211
+ if (!tagMetadata) {
212
+ logger.error(`Tag not found: ${JSON.stringify(tag)}`);
213
+ process.exit(1);
214
+ }
215
+ const tagInfo = {
216
+ name: tag,
217
+ workspaces: tagMetadata.map(({ name }) => name),
218
+ };
219
+ commandOutputLogger.info(
220
+ options.json
221
+ ? createJsonLines(tagInfo, options).join("\n")
222
+ : `Tag: ${tagInfo.name}\n${tagInfo.workspaces.map((name) => ` - ${name}`).join("\n")}`,
223
+ );
224
+ },
225
+ );
173
226
 
174
- export { doctor, listScripts, listWorkspaces, scriptInfo, workspaceInfo };
227
+ export {
228
+ doctor,
229
+ listScripts,
230
+ listTags,
231
+ listWorkspaces,
232
+ scriptInfo,
233
+ handleSimpleCommands_tagInfo as tagInfo,
234
+ workspaceInfo,
235
+ };
@@ -23,6 +23,7 @@ export declare const initializeWithGlobalOptions: (
23
23
  string,
24
24
  import("../..").WorkspaceScriptMetadata
25
25
  >;
26
+ mapTagsToWorkspaces(): Record<string, import("../..").Workspace[]>;
26
27
  findWorkspaceByName(
27
28
  workspaceName: string,
28
29
  ): import("../..").Workspace | null;
@@ -30,6 +31,7 @@ export declare const initializeWithGlobalOptions: (
30
31
  findWorkspaceByNameOrAlias(
31
32
  nameOrAlias: string,
32
33
  ): import("../..").Workspace | null;
34
+ listWorkspacesWithTag(tag: string): import("../..").Workspace[];
33
35
  findWorkspacesByPattern(
34
36
  ...workspacePatterns: string[]
35
37
  ): import("../..").Workspace[];
@@ -1,10 +1,7 @@
1
- export type { ResolvedRootConfig } from "./rootConfig";
2
- export type { ResolvedWorkspaceConfig } from "./workspaceConfig";
3
- export {
4
- type RootConfig,
5
- defineRootConfig,
6
- } from "./rootConfig/defineRootConfig";
7
- export {
8
- type WorkspaceConfig,
9
- defineWorkspaceConfig,
10
- } from "./workspaceConfig/defineWorkspaceConfig";
1
+ export type { RootConfig, ResolvedRootConfig } from "./rootConfig";
2
+ export type {
3
+ WorkspaceConfig,
4
+ ResolvedWorkspaceConfig,
5
+ } from "./workspaceConfig";
6
+ export { defineRootConfig } from "./rootConfig/defineRootConfig";
7
+ export { defineWorkspaceConfig } from "./workspaceConfig/defineWorkspaceConfig";
@@ -1,11 +1,4 @@
1
- import { type ResolvedRootConfig } from "./rootConfig";
2
- export type RootConfig = {
3
- defaults?: {
4
- parallelMax?: number | string;
5
- shell?: string;
6
- includeRootWorkspace?: boolean;
7
- };
8
- };
1
+ import { type RootConfig, type ResolvedRootConfig } from "./rootConfig";
9
2
  export declare const defineRootConfig: (
10
3
  config: RootConfig,
11
4
  ) => ResolvedRootConfig;
@@ -1,7 +1,15 @@
1
- import { type FromSchema } from "json-schema-to-ts";
2
- import { type ScriptShellOption } from "../../runScript";
3
- import type { ROOT_CONFIG_JSON_SCHEMA } from "./rootConfigSchema";
4
- export type RootConfig = FromSchema<typeof ROOT_CONFIG_JSON_SCHEMA>;
1
+ import type { ShellOption } from "../../project";
2
+ import { type ParallelMaxValue, type ScriptShellOption } from "../../runScript";
3
+ export type RootConfig = {
4
+ defaults?: {
5
+ /** The maximum number of scripts that can run in parallel. (default: "auto") */
6
+ parallelMax?: ParallelMaxValue;
7
+ /** The shell to use for inline scripts. (default: "bun") */
8
+ shell?: ShellOption;
9
+ /** Whether to include the root workspace in the workspaces list by default. (default: false) */
10
+ includeRootWorkspace?: boolean;
11
+ };
12
+ };
5
13
  export type ResolvedRootConfig = {
6
14
  defaults: {
7
15
  parallelMax: number;
@@ -20,5 +20,6 @@ const ROOT_CONFIG_JSON_SCHEMA = {
20
20
  },
21
21
  },
22
22
  };
23
+ let _validateSchemaType;
23
24
 
24
25
  export { ROOT_CONFIG_JSON_SCHEMA };
@@ -1,11 +1,7 @@
1
1
  import {
2
2
  type ResolvedWorkspaceConfig,
3
- type ScriptConfig,
3
+ type WorkspaceConfig,
4
4
  } from "./workspaceConfig";
5
- export type WorkspaceConfig = {
6
- alias?: string | string[];
7
- scripts?: Record<string, ScriptConfig>;
8
- };
9
5
  export declare const defineWorkspaceConfig: (
10
6
  config: WorkspaceConfig,
11
7
  ) => ResolvedWorkspaceConfig;
@@ -1,20 +1,41 @@
1
- import { type FromSchema } from "json-schema-to-ts";
2
- import type { WORKSPACE_CONFIG_JSON_SCHEMA } from "./workspaceConfigSchema";
3
- /**
4
- * @todo json-schema-to-ts doesn't support the union type for alias as it is,
5
- * but AJV error messaging for oneOf is not good
6
- */
7
- export type WorkspaceConfig = Omit<
8
- FromSchema<typeof WORKSPACE_CONFIG_JSON_SCHEMA>,
9
- "alias"
10
- > & {
1
+ /** Configuration that applies to a specific package.json script */
2
+ export type ScriptConfig = {
3
+ /**
4
+ * The order in which the script should be executed.
5
+ *
6
+ * This is used to sort the scripts in the workspace.
7
+ *
8
+ * Scripts with no `order` set will be executed in alphanumerical order
9
+ * of their relative path from the project root.
10
+ */
11
+ order?: number;
12
+ };
13
+ /** Configuration that applies to a specific workspace */
14
+ export type WorkspaceConfig = {
15
+ /**
16
+ * An alias or list of aliases for the workspace.
17
+ *
18
+ * These must be unique to other workspaces' aliases
19
+ * and package.json names.
20
+ */
11
21
  alias?: string | string[];
22
+ /**
23
+ * Tags for the workspace.
24
+ *
25
+ * These can be used to group workspaces
26
+ * by a common tag.
27
+ */
28
+ tags?: string[];
29
+ /**
30
+ * Configuration that maps to a script name in the workspace's package.json.
31
+ */
32
+ scripts?: Record<string, ScriptConfig>;
12
33
  };
13
34
  export type ResolvedWorkspaceConfig = {
14
35
  aliases: string[];
36
+ tags: string[];
15
37
  scripts: Record<string, ScriptConfig>;
16
38
  };
17
- export type ScriptConfig = NonNullable<WorkspaceConfig["scripts"]>[string];
18
39
  export declare const validateWorkspaceConfig: (config: WorkspaceConfig) => void;
19
40
  export declare const resolveWorkspaceConfig: (
20
41
  config: WorkspaceConfig,
@@ -32,6 +32,7 @@ const resolveWorkspaceConfig = (config) => {
32
32
  workspaceConfig_validateWorkspaceConfig(config);
33
33
  return {
34
34
  aliases: resolveOptionalArray(config.alias ?? []),
35
+ tags: config.tags ?? [],
35
36
  scripts: config.scripts ?? {},
36
37
  };
37
38
  };
@@ -1,24 +1,31 @@
1
1
  export declare const WORKSPACE_CONFIG_JSON_SCHEMA: {
2
- type: "object";
3
- additionalProperties: false;
4
- properties: {
5
- alias: {
6
- type: ("string" | "array")[];
7
- items: {
8
- type: "string";
2
+ readonly type: "object";
3
+ readonly additionalProperties: false;
4
+ readonly properties: {
5
+ readonly alias: {
6
+ readonly type: readonly ["string", "array"];
7
+ readonly items: {
8
+ readonly type: "string";
9
9
  };
10
- uniqueItems: true;
10
+ readonly uniqueItems: true;
11
11
  };
12
- scripts: {
13
- type: "object";
14
- additionalProperties: {
15
- type: "object";
16
- properties: {
17
- order: {
18
- type: "number";
12
+ readonly tags: {
13
+ readonly type: "array";
14
+ readonly items: {
15
+ readonly type: "string";
16
+ };
17
+ readonly uniqueItems: true;
18
+ };
19
+ readonly scripts: {
20
+ readonly type: "object";
21
+ readonly additionalProperties: {
22
+ readonly type: "object";
23
+ readonly properties: {
24
+ readonly order: {
25
+ readonly type: "number";
19
26
  };
20
27
  };
21
- additionalProperties: false;
28
+ readonly additionalProperties: false;
22
29
  };
23
30
  };
24
31
  };
@@ -10,6 +10,13 @@ const WORKSPACE_CONFIG_JSON_SCHEMA = {
10
10
  },
11
11
  uniqueItems: true,
12
12
  },
13
+ tags: {
14
+ type: "array",
15
+ items: {
16
+ type: "string",
17
+ },
18
+ uniqueItems: true,
19
+ },
13
20
  scripts: {
14
21
  type: "object",
15
22
  additionalProperties: {
@@ -24,5 +31,6 @@ const WORKSPACE_CONFIG_JSON_SCHEMA = {
24
31
  },
25
32
  },
26
33
  };
34
+ let _validateSchemaType;
27
35
 
28
36
  export { WORKSPACE_CONFIG_JSON_SCHEMA };
@@ -1 +1 @@
1
- "use strict";module.exports = validate10;module.exports.default = validate10;const schema11 = {"type":"object","additionalProperties":false,"properties":{"alias":{"type":["string","array"],"items":{"type":"string"},"uniqueItems":true},"scripts":{"type":"object","additionalProperties":{"type":"object","properties":{"order":{"type":"number"}},"additionalProperties":false}}}};function validate10(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if(errors === 0){if(data && typeof data == "object" && !Array.isArray(data)){const _errs1 = errors;for(const key0 in data){if(!((key0 === "alias") || (key0 === "scripts"))){validate10.errors = [{instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"}];return false;break;}}if(_errs1 === errors){if(data.alias !== undefined){let data0 = data.alias;const _errs2 = errors;if((typeof data0 !== "string") && (!(Array.isArray(data0)))){validate10.errors = [{instancePath:instancePath+"/alias",schemaPath:"#/properties/alias/type",keyword:"type",params:{type: schema11.properties.alias.type},message:"must be string,array"}];return false;}if(errors === _errs2){if(Array.isArray(data0)){var valid1 = true;const len0 = data0.length;for(let i0=0; i0<len0; i0++){const _errs4 = errors;if(typeof data0[i0] !== "string"){validate10.errors = [{instancePath:instancePath+"/alias/" + i0,schemaPath:"#/properties/alias/items/type",keyword:"type",params:{type: "string"},message:"must be string"}];return false;}var valid1 = _errs4 === errors;if(!valid1){break;}}if(valid1){let i1 = data0.length;let j0;if(i1 > 1){const indices0 = {};for(;i1--;){let item0 = data0[i1];if(typeof item0 !== "string"){continue;}if(typeof indices0[item0] == "number"){j0 = indices0[item0];validate10.errors = [{instancePath:instancePath+"/alias",schemaPath:"#/properties/alias/uniqueItems",keyword:"uniqueItems",params:{i: i1, j: j0},message:"must NOT have duplicate items (items ## "+j0+" and "+i1+" are identical)"}];return false;break;}indices0[item0] = i1;}}}}}var valid0 = _errs2 === errors;}else {var valid0 = true;}if(valid0){if(data.scripts !== undefined){let data2 = data.scripts;const _errs6 = errors;if(errors === _errs6){if(data2 && typeof data2 == "object" && !Array.isArray(data2)){for(const key1 in data2){let data3 = data2[key1];const _errs9 = errors;if(errors === _errs9){if(data3 && typeof data3 == "object" && !Array.isArray(data3)){const _errs11 = errors;for(const key2 in data3){if(!(key2 === "order")){validate10.errors = [{instancePath:instancePath+"/scripts/" + key1.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/scripts/additionalProperties/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key2},message:"must NOT have additional properties"}];return false;break;}}if(_errs11 === errors){if(data3.order !== undefined){let data4 = data3.order;if(!((typeof data4 == "number") && (isFinite(data4)))){validate10.errors = [{instancePath:instancePath+"/scripts/" + key1.replace(/~/g, "~0").replace(/\//g, "~1")+"/order",schemaPath:"#/properties/scripts/additionalProperties/properties/order/type",keyword:"type",params:{type: "number"},message:"must be number"}];return false;}}}}else {validate10.errors = [{instancePath:instancePath+"/scripts/" + key1.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/scripts/additionalProperties/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}var valid3 = _errs9 === errors;if(!valid3){break;}}}else {validate10.errors = [{instancePath:instancePath+"/scripts",schemaPath:"#/properties/scripts/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}var valid0 = _errs6 === errors;}else {var valid0 = true;}}}}else {validate10.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}validate10.errors = vErrors;return errors === 0;}
1
+ "use strict";module.exports = validate10;module.exports.default = validate10;const schema11 = {"type":"object","additionalProperties":false,"properties":{"alias":{"type":["string","array"],"items":{"type":"string"},"uniqueItems":true},"tags":{"type":"array","items":{"type":"string"},"uniqueItems":true},"scripts":{"type":"object","additionalProperties":{"type":"object","properties":{"order":{"type":"number"}},"additionalProperties":false}}}};function validate10(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if(errors === 0){if(data && typeof data == "object" && !Array.isArray(data)){const _errs1 = errors;for(const key0 in data){if(!(((key0 === "alias") || (key0 === "tags")) || (key0 === "scripts"))){validate10.errors = [{instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"}];return false;break;}}if(_errs1 === errors){if(data.alias !== undefined){let data0 = data.alias;const _errs2 = errors;if((typeof data0 !== "string") && (!(Array.isArray(data0)))){validate10.errors = [{instancePath:instancePath+"/alias",schemaPath:"#/properties/alias/type",keyword:"type",params:{type: schema11.properties.alias.type},message:"must be string,array"}];return false;}if(errors === _errs2){if(Array.isArray(data0)){var valid1 = true;const len0 = data0.length;for(let i0=0; i0<len0; i0++){const _errs4 = errors;if(typeof data0[i0] !== "string"){validate10.errors = [{instancePath:instancePath+"/alias/" + i0,schemaPath:"#/properties/alias/items/type",keyword:"type",params:{type: "string"},message:"must be string"}];return false;}var valid1 = _errs4 === errors;if(!valid1){break;}}if(valid1){let i1 = data0.length;let j0;if(i1 > 1){const indices0 = {};for(;i1--;){let item0 = data0[i1];if(typeof item0 !== "string"){continue;}if(typeof indices0[item0] == "number"){j0 = indices0[item0];validate10.errors = [{instancePath:instancePath+"/alias",schemaPath:"#/properties/alias/uniqueItems",keyword:"uniqueItems",params:{i: i1, j: j0},message:"must NOT have duplicate items (items ## "+j0+" and "+i1+" are identical)"}];return false;break;}indices0[item0] = i1;}}}}}var valid0 = _errs2 === errors;}else {var valid0 = true;}if(valid0){if(data.tags !== undefined){let data2 = data.tags;const _errs6 = errors;if(errors === _errs6){if(Array.isArray(data2)){var valid3 = true;const len1 = data2.length;for(let i2=0; i2<len1; i2++){const _errs8 = errors;if(typeof data2[i2] !== "string"){validate10.errors = [{instancePath:instancePath+"/tags/" + i2,schemaPath:"#/properties/tags/items/type",keyword:"type",params:{type: "string"},message:"must be string"}];return false;}var valid3 = _errs8 === errors;if(!valid3){break;}}if(valid3){let i3 = data2.length;let j1;if(i3 > 1){const indices1 = {};for(;i3--;){let item1 = data2[i3];if(typeof item1 !== "string"){continue;}if(typeof indices1[item1] == "number"){j1 = indices1[item1];validate10.errors = [{instancePath:instancePath+"/tags",schemaPath:"#/properties/tags/uniqueItems",keyword:"uniqueItems",params:{i: i3, j: j1},message:"must NOT have duplicate items (items ## "+j1+" and "+i3+" are identical)"}];return false;break;}indices1[item1] = i3;}}}}else {validate10.errors = [{instancePath:instancePath+"/tags",schemaPath:"#/properties/tags/type",keyword:"type",params:{type: "array"},message:"must be array"}];return false;}}var valid0 = _errs6 === errors;}else {var valid0 = true;}if(valid0){if(data.scripts !== undefined){let data4 = data.scripts;const _errs10 = errors;if(errors === _errs10){if(data4 && typeof data4 == "object" && !Array.isArray(data4)){for(const key1 in data4){let data5 = data4[key1];const _errs13 = errors;if(errors === _errs13){if(data5 && typeof data5 == "object" && !Array.isArray(data5)){const _errs15 = errors;for(const key2 in data5){if(!(key2 === "order")){validate10.errors = [{instancePath:instancePath+"/scripts/" + key1.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/scripts/additionalProperties/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key2},message:"must NOT have additional properties"}];return false;break;}}if(_errs15 === errors){if(data5.order !== undefined){let data6 = data5.order;if(!((typeof data6 == "number") && (isFinite(data6)))){validate10.errors = [{instancePath:instancePath+"/scripts/" + key1.replace(/~/g, "~0").replace(/\//g, "~1")+"/order",schemaPath:"#/properties/scripts/additionalProperties/properties/order/type",keyword:"type",params:{type: "number"},message:"must be number"}];return false;}}}}else {validate10.errors = [{instancePath:instancePath+"/scripts/" + key1.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/scripts/additionalProperties/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}var valid5 = _errs13 === errors;if(!valid5){break;}}}else {validate10.errors = [{instancePath:instancePath+"/scripts",schemaPath:"#/properties/scripts/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}var valid0 = _errs10 === errors;}else {var valid0 = true;}}}}}else {validate10.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}];return false;}}validate10.errors = vErrors;return errors === 0;}
@@ -113,6 +113,7 @@ class _MemoryProject extends ProjectBase {
113
113
  path: "",
114
114
  scripts: [],
115
115
  aliases: [],
116
+ tags: [],
116
117
  dependencies: [],
117
118
  dependents: [],
118
119
  };
@@ -25,9 +25,11 @@ export declare abstract class ProjectBase implements Project {
25
25
  constructor(_ignoreBunVersion?: boolean);
26
26
  listWorkspacesWithScript(scriptName: string): Workspace[];
27
27
  mapScriptsToWorkspaces(): Record<string, WorkspaceScriptMetadata>;
28
+ mapTagsToWorkspaces(): Record<string, Workspace[]>;
28
29
  findWorkspaceByName(workspaceName: string): Workspace | null;
29
30
  findWorkspaceByAlias(alias: string): Workspace | null;
30
31
  findWorkspaceByNameOrAlias(nameOrAlias: string): Workspace | null;
32
+ listWorkspacesWithTag(tag: string): Workspace[];
31
33
  findWorkspacesByPattern(...workspacePatterns: string[]): Workspace[];
32
34
  createScriptCommand(
33
35
  options: CreateProjectScriptCommandOptions,
@@ -69,6 +69,21 @@ class ProjectBase {
69
69
  {},
70
70
  );
71
71
  }
72
+ mapTagsToWorkspaces() {
73
+ const tags = new Set();
74
+ this.workspaces.forEach((workspace) => {
75
+ workspace.tags.forEach((tag) => tags.add(tag));
76
+ });
77
+ return Array.from(tags)
78
+ .sort((a, b) => a.localeCompare(b))
79
+ .reduce(
80
+ (acc, tag) => ({
81
+ ...acc,
82
+ [tag]: this.listWorkspacesWithTag(tag),
83
+ }),
84
+ {},
85
+ );
86
+ }
72
87
  findWorkspaceByName(workspaceName) {
73
88
  validateJSTypes(
74
89
  {
@@ -120,6 +135,9 @@ class ProjectBase {
120
135
  this.findWorkspaceByAlias(nameOrAlias)
121
136
  );
122
137
  }
138
+ listWorkspacesWithTag(tag) {
139
+ return this.workspaces.filter((workspace) => workspace.tags.includes(tag));
140
+ }
123
141
  findWorkspacesByPattern(...workspacePatterns) {
124
142
  const workspaces = [];
125
143
  if (workspacePatterns.includes(ROOT_WORKSPACE_SELECTOR)) {
@@ -62,12 +62,16 @@ export interface Project {
62
62
  findWorkspaceByAlias(alias: string): Workspace | null;
63
63
  /** Find a workspace that matches a workspace's name or an alias if no name matches. */
64
64
  findWorkspaceByNameOrAlias(nameOrAlias: string): Workspace | null;
65
+ /** Find a list of workspaces that have a given tag in their configuration */
66
+ listWorkspacesWithTag(tag: string): Workspace[];
65
67
  /** Accepts a wildcard pattern for finding a list of workspaces by their name*/
66
68
  findWorkspacesByPattern(workspacePattern: string): Workspace[];
67
69
  /** Get an array of all workspaces that have a given script in their package.json */
68
70
  listWorkspacesWithScript(scriptName: string): Workspace[];
69
71
  /** Get a mapping of all scripts to the workspaces that have them in their package.json */
70
72
  mapScriptsToWorkspaces(): Record<string, WorkspaceScriptMetadata>;
73
+ /** Get a mapping of all tags to the workspaces that have them in their config */
74
+ mapTagsToWorkspaces(): Record<string, Workspace[]>;
71
75
  /** Create metadata that can be used to run a workspace's script */
72
76
  createScriptCommand(
73
77
  options: CreateProjectScriptCommandOptions,
@@ -4,6 +4,15 @@ export declare const PARALLEL_MAX_VALUES: readonly [
4
4
  "default",
5
5
  ];
6
6
  export type PercentageValue = `${number}%`;
7
+ /**
8
+ * The maximum number of scripts that can run in parallel.
9
+ *
10
+ * - `number`: The exact number of scripts that can run in parallel.
11
+ * - `"auto"`: The number of available logical CPU threads.
12
+ * - `"unbounded"`: No limit.
13
+ * - `"default"`: The default value, either "auto" or the value of the root config's "parallelMax" option.
14
+ * - `"${number}%"`: A percentage of the available logical CPU threads (e.g. "50%").
15
+ */
7
16
  export type ParallelMaxValue =
8
17
  | number
9
18
  | (typeof PARALLEL_MAX_VALUES)[number]
@@ -146,6 +146,7 @@ const findWorkspaces = ({
146
146
  .concat(workspaceConfig?.aliases ?? []),
147
147
  ),
148
148
  ],
149
+ tags: workspaceConfig?.tags ?? [],
149
150
  dependencies: [],
150
151
  dependents: [],
151
152
  };
@@ -10,8 +10,10 @@ export type Workspace = {
10
10
  matchPattern: string;
11
11
  /** The scripts available in package.json */
12
12
  scripts: string[];
13
- /** Aliases assigned to the workspace via the `"workspaceAliases"` field in the config */
13
+ /** Aliases assigned via the `"alias"` field in the workspace's config */
14
14
  aliases: string[];
15
+ /** Tags assigned via the `"tags"` field in the workspace's config */
16
+ tags: string[];
15
17
  /** Names of workspaces that this workspace depends on */
16
18
  dependencies: string[];
17
19
  /** Names of workspaces that depend on this workspace */
@@ -1,5 +1,5 @@
1
1
  import type { Workspace } from "./workspace";
2
- declare const TARGETS: readonly ["path", "alias", "name"];
2
+ declare const TARGETS: readonly ["path", "alias", "name", "tag"];
3
3
  export declare const WORKSPACE_PATTERN_ERRORS: import("../internal/core").DefinedErrors<"InvalidWorkspacePattern">;
4
4
  export type WorkspacePatternTarget = (typeof TARGETS)[number];
5
5
  export type WorkspacePattern = {
@@ -3,7 +3,7 @@ import { createWildcardRegex, defineErrors } from "../internal/core/index.mjs";
3
3
  // CONCATENATED MODULE: external "../internal/core/index.mjs"
4
4
  // CONCATENATED MODULE: ./src/workspaces/workspacePattern.ts
5
5
 
6
- const TARGETS = ["path", "alias", "name"];
6
+ const TARGETS = ["path", "alias", "name", "tag"];
7
7
  const WORKSPACE_PATTERN_ERRORS = defineErrors("InvalidWorkspacePattern");
8
8
  const WORKSPACE_PATTERN_SEPARATOR = ":";
9
9
  const parseWorkspacePattern = (pattern) => {
@@ -65,6 +65,13 @@ const PATTERN_TARGET_HANDLERS = {
65
65
  new bun.Glob(pattern.value).match(workspace.path),
66
66
  );
67
67
  },
68
+ tag: (pattern, workspaces, wildcardRegex) => {
69
+ return workspaces.filter((workspace) =>
70
+ pattern.value.includes("*")
71
+ ? workspace.tags.some((tag) => wildcardRegex.test(tag))
72
+ : workspace.tags.includes(pattern.value),
73
+ );
74
+ },
68
75
  };
69
76
  const matchWorkspacesByPattern = (pattern, workspaces) =>
70
77
  PATTERN_TARGET_HANDLERS[pattern.target](