workspace-utils 1.0.3 → 1.0.5

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 pnpmono
3
+ Copyright (c) 2024 wsu
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/index.js CHANGED
@@ -14751,6 +14751,7 @@ class ProcessRunner {
14751
14751
  ];
14752
14752
  static assignedColors = new Map;
14753
14753
  static colorIndex = 0;
14754
+ static activeChildren = new Set;
14754
14755
  static getPackageColor(packageName) {
14755
14756
  if (!this.assignedColors.has(packageName)) {
14756
14757
  const colorIndex2 = this.colorIndex % this.colorPalette.length;
@@ -14804,6 +14805,7 @@ class ProcessRunner {
14804
14805
  env: { ...process.env, ...options.env },
14805
14806
  stdio: ["inherit", "pipe", "pipe"]
14806
14807
  });
14808
+ ProcessRunner.activeChildren.add(childProcess);
14807
14809
  if (childProcess.stdout) {
14808
14810
  childProcess.stdout.on("data", (data) => {
14809
14811
  const lines = data.toString().split(`
@@ -14827,6 +14829,7 @@ class ProcessRunner {
14827
14829
  });
14828
14830
  }
14829
14831
  childProcess.on("close", (exitCode) => {
14832
+ ProcessRunner.activeChildren.delete(childProcess);
14830
14833
  const duration = Date.now() - startTime;
14831
14834
  const code = exitCode || 0;
14832
14835
  const result = {
@@ -14845,6 +14848,7 @@ class ProcessRunner {
14845
14848
  resolve2(result);
14846
14849
  });
14847
14850
  childProcess.on("error", (error) => {
14851
+ ProcessRunner.activeChildren.delete(childProcess);
14848
14852
  const duration = Date.now() - startTime;
14849
14853
  const colorFn2 = this.getColorFn(logOptions.color);
14850
14854
  console.error(`[${colorFn2(logOptions.prefix)}] ` + import_picocolors.default.red(`\uD83D\uDCA5 Error: ${error.message}`));
@@ -14858,6 +14862,37 @@ class ProcessRunner {
14858
14862
  });
14859
14863
  });
14860
14864
  }
14865
+ static async terminateAll(signal = "SIGTERM", graceMs = 5000) {
14866
+ const children = Array.from(this.activeChildren);
14867
+ if (children.length === 0)
14868
+ return;
14869
+ for (const child of children) {
14870
+ try {
14871
+ child.kill(signal);
14872
+ } catch {}
14873
+ }
14874
+ await Promise.all(children.map((child) => {
14875
+ return new Promise((resolve2) => {
14876
+ let settled = false;
14877
+ const onClose = () => {
14878
+ if (settled)
14879
+ return;
14880
+ settled = true;
14881
+ resolve2();
14882
+ };
14883
+ child.once("close", onClose);
14884
+ const timer = setTimeout(() => {
14885
+ if (settled)
14886
+ return;
14887
+ try {
14888
+ child.kill("SIGKILL");
14889
+ } catch {}
14890
+ settled = true;
14891
+ resolve2();
14892
+ }, graceMs);
14893
+ });
14894
+ }));
14895
+ }
14861
14896
  static logLine(line, logOptions, isError = false) {
14862
14897
  const timestamp = logOptions.showTimestamp ? import_picocolors.default.dim(`[${new Date().toISOString()}] `) : "";
14863
14898
  const colorFn = this.getColorFn(logOptions.color);
@@ -15136,13 +15171,6 @@ async function runCommand(scriptName, options) {
15136
15171
  Output.log(`Filtered to ${targetPackages.length} packages matching "${options.filter}"`, "magnifying", "yellow");
15137
15172
  }
15138
15173
  const { valid: packagesWithScript, invalid: packagesWithoutScript } = validatePackagesHaveScript(targetPackages, scriptName);
15139
- if (packagesWithoutScript.length > 0) {
15140
- Output.warning(`The following packages don't have the "${scriptName}" script:`);
15141
- packagesWithoutScript.forEach((pkg) => {
15142
- Output.listItem(pkg.name);
15143
- });
15144
- console.log();
15145
- }
15146
15174
  if (packagesWithScript.length === 0) {
15147
15175
  Output.error(`No packages found with the "${scriptName}" script.`);
15148
15176
  process.exit(1);
@@ -15191,6 +15219,24 @@ Failed packages:`));
15191
15219
 
15192
15220
  // src/commands/build.ts
15193
15221
  var import_picocolors4 = __toESM(require_picocolors(), 1);
15222
+ function collectPackagesWithDependencies(packages, packageMap) {
15223
+ const queue = [...packages];
15224
+ const collected = new Map;
15225
+ while (queue.length > 0) {
15226
+ const pkg = queue.shift();
15227
+ if (!pkg || collected.has(pkg.name))
15228
+ continue;
15229
+ collected.set(pkg.name, pkg);
15230
+ const dependencies = [...pkg.dependencies, ...pkg.devDependencies];
15231
+ for (const depName of dependencies) {
15232
+ const depPackage = packageMap.get(depName);
15233
+ if (depPackage && !collected.has(depName)) {
15234
+ queue.push(depPackage);
15235
+ }
15236
+ }
15237
+ }
15238
+ return Array.from(collected.values());
15239
+ }
15194
15240
  async function buildCommand(options) {
15195
15241
  try {
15196
15242
  Output.build(`Building packages in dependency order...
@@ -15205,18 +15251,24 @@ async function buildCommand(options) {
15205
15251
  targetPackages = parser2.filterPackages(workspace.packages, options.filter);
15206
15252
  Output.log(`Filtered to ${targetPackages.length} packages matching "${options.filter}"`, "magnifying", "yellow");
15207
15253
  }
15208
- const { valid: packagesWithBuild, invalid: packagesWithoutBuild } = validatePackagesHaveScript(targetPackages, "build");
15209
- if (packagesWithoutBuild.length > 0) {
15254
+ const { valid: buildableTargets, invalid: targetPackagesWithoutBuild } = validatePackagesHaveScript(targetPackages, "build");
15255
+ if (buildableTargets.length === 0) {
15256
+ Output.error('No packages found with a "build" script.');
15257
+ process.exit(1);
15258
+ }
15259
+ const packagesWithDependencies = collectPackagesWithDependencies(buildableTargets, workspace.packageMap);
15260
+ const { valid: packagesWithBuild, invalid: packagesWithoutBuild } = validatePackagesHaveScript(packagesWithDependencies, "build");
15261
+ const missingBuildScriptPackages = new Map;
15262
+ [...targetPackagesWithoutBuild, ...packagesWithoutBuild].forEach((pkg) => {
15263
+ missingBuildScriptPackages.set(pkg.name, pkg);
15264
+ });
15265
+ if (missingBuildScriptPackages.size > 0) {
15210
15266
  Output.warning(`The following packages don't have a "build" script:`);
15211
- packagesWithoutBuild.forEach((pkg) => {
15267
+ Array.from(missingBuildScriptPackages.values()).forEach((pkg) => {
15212
15268
  Output.listItem(pkg.name);
15213
15269
  });
15214
15270
  console.log();
15215
15271
  }
15216
- if (packagesWithBuild.length === 0) {
15217
- Output.error('No packages found with a "build" script.');
15218
- process.exit(1);
15219
- }
15220
15272
  Output.log("Building dependency graph...", "chart", "blue");
15221
15273
  const dependencyGraph = buildDependencyGraph(packagesWithBuild);
15222
15274
  const packageNames = packagesWithBuild.map((pkg) => pkg.name);
@@ -15375,10 +15427,15 @@ async function devCommand(options) {
15375
15427
  Shutting down development servers...`, "warning", "yellow");
15376
15428
  Output.dim(`This may take a moment to gracefully stop all processes.
15377
15429
  `);
15430
+ ProcessRunner.terminateAll("SIGTERM", 5000).then(() => {
15431
+ process.exit(0);
15432
+ }).catch(() => {
15433
+ process.exit(0);
15434
+ });
15378
15435
  setTimeout(() => {
15379
15436
  Output.log("Timeout reached, forcing exit...", "clock", "red");
15380
15437
  process.exit(0);
15381
- }, 5000);
15438
+ }, 6000);
15382
15439
  };
15383
15440
  process.on("SIGINT", shutdown);
15384
15441
  process.on("SIGTERM", shutdown);
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workspace-utils",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A CLI tool to orchestrate scripts across monorepo workspaces (Bun, pnpm, npm) with parallel execution and dependency-aware builds.",
5
5
  "module": "index.ts",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workspace-utils",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A CLI tool to orchestrate scripts across monorepo workspaces (Bun, pnpm, npm) with parallel execution and dependency-aware builds.",
5
5
  "module": "index.ts",
6
6
  "type": "module",