as-test 1.0.3 → 1.0.4

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/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Change Log
2
2
 
3
- ## 2026-03-27 - 1.0.3
3
+ ## 2026-03-27 - v1.0.4
4
+
5
+ ### Build Command
6
+
7
+ - fix: make `ast build` exit cleanly instead of hanging after work completes.
8
+ - feat: make `ast build` print per-mode build results and a final summary.
9
+ - feat: make `ast build` support `--parallel`, `--jobs`, and `--build-jobs`.
4
10
 
5
11
  ### Parallel Execution
6
12
 
@@ -102,6 +102,13 @@ function getSerialBuildWorkerPool() {
102
102
  }
103
103
  return serialBuildWorkerPool;
104
104
  }
105
+ export async function closeSerialBuildWorkerPool() {
106
+ if (!serialBuildWorkerPool)
107
+ return;
108
+ const pool = serialBuildWorkerPool;
109
+ serialBuildWorkerPool = null;
110
+ await pool.close();
111
+ }
105
112
  export async function getBuildInvocationPreview(configPath = DEFAULT_CONFIG_PATH, file, modeName, featureToggles = {}, overrides = {}) {
106
113
  const loadedConfig = loadConfig(configPath, false);
107
114
  const mode = applyMode(loadedConfig, modeName);
@@ -1,9 +1,11 @@
1
+ import { closeSerialBuildWorkerPool, } from "./build-core.js";
1
2
  export { build } from "./build-core.js";
2
3
  export { formatInvocation, getBuildInvocationPreview } from "./build-core.js";
3
4
  export async function executeBuildCommand(rawArgs, configPath, selectedModes, deps) {
4
5
  const commandArgs = deps.resolveCommandArgs(rawArgs, "build");
5
6
  const listFlags = deps.resolveListFlags(rawArgs, "build");
6
7
  const featureToggles = deps.resolveFeatureToggles(rawArgs, "build");
8
+ const parallel = deps.resolveBuildParallelJobs(rawArgs);
7
9
  const buildFeatureToggles = {
8
10
  tryAs: featureToggles.tryAs,
9
11
  coverage: featureToggles.coverage,
@@ -13,5 +15,18 @@ export async function executeBuildCommand(rawArgs, configPath, selectedModes, de
13
15
  await deps.listExecutionPlan("build", configPath, commandArgs, modeTargets, listFlags);
14
16
  return;
15
17
  }
16
- await deps.runBuildModes(configPath, commandArgs, modeTargets, buildFeatureToggles);
18
+ const previousBuildApi = process.env.AS_TEST_BUILD_API;
19
+ process.env.AS_TEST_BUILD_API = "1";
20
+ try {
21
+ await deps.runBuildModes(configPath, commandArgs, modeTargets, buildFeatureToggles, parallel);
22
+ }
23
+ finally {
24
+ if (previousBuildApi == undefined) {
25
+ delete process.env.AS_TEST_BUILD_API;
26
+ }
27
+ else {
28
+ process.env.AS_TEST_BUILD_API = previousBuildApi;
29
+ }
30
+ await closeSerialBuildWorkerPool();
31
+ }
17
32
  }
package/bin/index.js CHANGED
@@ -9,7 +9,7 @@ import { executeFuzzCommand } from "./commands/fuzz.js";
9
9
  import { executeInitCommand } from "./commands/init.js";
10
10
  import { executeDoctorCommand } from "./commands/doctor.js";
11
11
  import { fuzz } from "./commands/fuzz-core.js";
12
- import { applyMode, getCliVersion, loadConfig, resolveModeNames, } from "./util.js";
12
+ import { applyMode, formatTime, getCliVersion, loadConfig, resolveModeNames, } from "./util.js";
13
13
  import * as path from "path";
14
14
  import { spawnSync } from "child_process";
15
15
  import { glob } from "glob";
@@ -50,6 +50,7 @@ else if (COMMANDS.includes(args[0])) {
50
50
  resolveCommandArgs,
51
51
  resolveListFlags,
52
52
  resolveFeatureToggles,
53
+ resolveBuildParallelJobs,
53
54
  resolveExecutionModes,
54
55
  listExecutionPlan,
55
56
  runBuildModes,
@@ -226,6 +227,9 @@ function printCommandHelp(command) {
226
227
  process.stdout.write(" --mode <name[,name...]> Run one or multiple named config modes\n");
227
228
  process.stdout.write(" --enable <feature> Enable build feature (coverage|try-as)\n");
228
229
  process.stdout.write(" --disable <feature> Disable build feature (coverage|try-as)\n");
230
+ process.stdout.write(" --parallel Run files through an ordered worker pool using an automatic worker count\n");
231
+ process.stdout.write(" --jobs <n> Run files through an ordered worker pool\n");
232
+ process.stdout.write(" --build-jobs <n> Limit concurrent build tasks (defaults to --jobs)\n");
229
233
  process.stdout.write(" --list Preview resolved files/artifacts without building\n");
230
234
  process.stdout.write(" --list-modes Preview configured and selected mode names\n");
231
235
  process.stdout.write(" --help, -h Show this help\n");
@@ -597,6 +601,29 @@ function resolveJobs(rawArgs, command) {
597
601
  }
598
602
  return parallel ? 0 : 1;
599
603
  }
604
+ function resolveBuildParallelJobs(rawArgs) {
605
+ const baseJobs = resolveJobs(rawArgs, "build");
606
+ let buildJobs = baseJobs;
607
+ let seenCommand = false;
608
+ for (let i = 0; i < rawArgs.length; i++) {
609
+ const arg = rawArgs[i];
610
+ if (!seenCommand) {
611
+ if (arg == "build")
612
+ seenCommand = true;
613
+ continue;
614
+ }
615
+ const buildParsed = parseNumberFlag(rawArgs, i, "--build-jobs");
616
+ if (buildParsed) {
617
+ if (buildParsed.number < 1) {
618
+ throw new Error("--build-jobs requires a positive integer");
619
+ }
620
+ buildJobs = buildParsed.number;
621
+ continue;
622
+ }
623
+ }
624
+ const jobs = Math.max(baseJobs, buildJobs);
625
+ return { jobs, buildJobs };
626
+ }
600
627
  function resolveParallelJobs(rawArgs, command) {
601
628
  const baseJobs = resolveJobs(rawArgs, command);
602
629
  let buildJobs = baseJobs;
@@ -922,10 +949,46 @@ async function runTestSequential(runFlags, configPath, selectors, buildFeatureTo
922
949
  },
923
950
  };
924
951
  }
925
- async function runBuildModes(configPath, selectors, modes, buildFeatureToggles) {
952
+ async function runBuildModes(configPath, selectors, modes, buildFeatureToggles, parallel) {
953
+ const files = await resolveSelectedFiles(configPath, selectors);
954
+ if (!files.length) {
955
+ throw await buildNoTestFilesMatchedError(configPath, selectors);
956
+ }
957
+ const effective = resolveEffectiveParallelJobs({
958
+ jobs: parallel.jobs,
959
+ buildJobs: parallel.buildJobs,
960
+ runJobs: parallel.buildJobs,
961
+ }, files.length);
962
+ const resolvedConfigPath = configPath ?? path.join(process.cwd(), "./as-test.config.json");
963
+ const loadedConfig = loadConfig(resolvedConfigPath, true);
964
+ const allStartedAt = Date.now();
965
+ let builtCount = 0;
926
966
  for (const modeName of modes) {
927
- await build(configPath, selectors, modeName, buildFeatureToggles);
967
+ const startedAt = Date.now();
968
+ if (effective.buildJobs > 1) {
969
+ const pool = new BuildWorkerPool(effective.buildJobs);
970
+ try {
971
+ await runOrderedPool(files, effective.buildJobs, async (file) => {
972
+ await pool.buildFileMode({
973
+ configPath,
974
+ file,
975
+ modeName,
976
+ featureToggles: buildFeatureToggles,
977
+ });
978
+ });
979
+ }
980
+ finally {
981
+ await pool.close();
982
+ }
983
+ }
984
+ else {
985
+ await build(configPath, selectors, modeName, buildFeatureToggles);
986
+ }
987
+ builtCount += files.length;
988
+ const active = applyMode(loadedConfig, modeName).config;
989
+ process.stdout.write(`${chalk.bgGreenBright.black(" BUILT ")} ${modeName ?? "default"} ${chalk.dim(`(${active.buildOptions.target})`)} ${files.length} file(s) -> ${active.outDir} ${chalk.dim(formatTime(Date.now() - startedAt))}\n`);
928
990
  }
991
+ process.stdout.write(`${chalk.bold("Summary:")} built ${builtCount} file(s) across ${modes.length || 1} mode(s) in ${formatTime(Date.now() - allStartedAt)}\n`);
929
992
  }
930
993
  async function runRuntimeModes(runFlags, configPath, selectors, modes) {
931
994
  await ensureWebBrowsersReady(configPath, modes, runFlags.browser);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "as-test",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "author": "Jairus Tanaka",
5
5
  "repository": {
6
6
  "type": "git",