@autometa/cli 1.0.0-rc.3 → 1.0.0-rc.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/dist/index.d.cts CHANGED
@@ -60,6 +60,11 @@ interface RunCommandOptions {
60
60
  * When omitted, the CLI will choose a sensible default (preferring node_modules/.cache).
61
61
  */
62
62
  readonly cacheDir?: string;
63
+ /**
64
+ * Explicit path to the Autometa config file. If omitted, the CLI will search upward
65
+ * from the current working directory for autometa.config.* or autometa.<name>.config.* files.
66
+ */
67
+ readonly configPath?: string;
63
68
  readonly patterns?: readonly string[];
64
69
  /**
65
70
  * Extra args to pass directly to the detected native runner.
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { builtinModules, createRequire } from 'node:module';
2
2
  import { Command } from 'commander';
3
3
  import fs, { promises, constants, existsSync } from 'node:fs';
4
- import path2, { resolve, extname, relative, join, isAbsolute } from 'node:path';
4
+ import path2, { resolve, extname, relative, join, isAbsolute, dirname } from 'node:path';
5
5
  import { pathToFileURL } from 'node:url';
6
6
  import { HTTP, createLoggingPlugin } from '@autometa/http';
7
7
  import { CucumberRunner, STEPS_ENVIRONMENT_META } from '@autometa/runner';
8
8
  import { parseGherkin } from '@autometa/gherkin';
9
- import { rm, mkdir, writeFile, access } from 'node:fs/promises';
9
+ import { rm, mkdir, writeFile, access, readdir } from 'node:fs/promises';
10
10
  import { build } from 'esbuild';
11
11
  import 'source-map-support/register';
12
12
  import pc5 from 'picocolors';
@@ -17,7 +17,7 @@ import { Config } from '@autometa/config';
17
17
  import { createHash as createHash$1 } from 'crypto';
18
18
  import { promises as promises$1 } from 'fs';
19
19
  import { builtinModules as builtinModules$1 } from 'module';
20
- import { resolve as resolve$1, extname as extname$1, isAbsolute as isAbsolute$1, dirname, join as join$1 } from 'path';
20
+ import { resolve as resolve$1, extname as extname$1, isAbsolute as isAbsolute$1, dirname as dirname$1, join as join$1 } from 'path';
21
21
  import { pathToFileURL as pathToFileURL$1 } from 'url';
22
22
  import { createHash } from 'node:crypto';
23
23
  import { homedir } from 'node:os';
@@ -1735,7 +1735,7 @@ async function resolveFilePath(pathCandidate) {
1735
1735
  if (await pathExists2(pathCandidate)) {
1736
1736
  return pathCandidate;
1737
1737
  }
1738
- const directory = dirname(pathCandidate);
1738
+ const directory = dirname$1(pathCandidate);
1739
1739
  const fileName = pathCandidate.slice(directory.length + 1);
1740
1740
  for (const extension of TS_EXTENSIONS) {
1741
1741
  const candidate = join$1(directory, `${fileName}${extension}`);
@@ -1790,14 +1790,39 @@ async function pathExists2(path3) {
1790
1790
  }
1791
1791
 
1792
1792
  // src/loaders/config.ts
1793
- var CONFIG_CANDIDATES = [
1794
- "autometa.config.ts",
1795
- "autometa.config.mts",
1796
- "autometa.config.cts",
1797
- "autometa.config.js",
1798
- "autometa.config.mjs",
1799
- "autometa.config.cjs"
1800
- ];
1793
+ var CONFIG_EXTENSIONS = ["ts", "mts", "cts", "js", "mjs", "cjs"];
1794
+ async function findConfigInDir(dir) {
1795
+ for (const ext of CONFIG_EXTENSIONS) {
1796
+ const candidate = resolve(dir, `autometa.config.${ext}`);
1797
+ if (await fileExists(candidate)) {
1798
+ return candidate;
1799
+ }
1800
+ }
1801
+ try {
1802
+ const entries = await readdir(dir, { withFileTypes: true });
1803
+ const matches = [];
1804
+ const pattern = /^autometa\.[A-Za-z0-9_-]+\.config\.(?:ts|mts|cts|js|mjs|cjs)$/u;
1805
+ for (const entry of entries) {
1806
+ if (!entry.isFile())
1807
+ continue;
1808
+ if (pattern.test(entry.name)) {
1809
+ matches.push(resolve(dir, entry.name));
1810
+ }
1811
+ }
1812
+ if (matches.length > 0) {
1813
+ matches.sort((a, b) => {
1814
+ const an = a.split("/").pop() ?? a;
1815
+ const bn = b.split("/").pop() ?? b;
1816
+ const alen = an.length;
1817
+ const blen = bn.length;
1818
+ return alen === blen ? an.localeCompare(bn) : alen - blen;
1819
+ });
1820
+ return matches[0];
1821
+ }
1822
+ } catch {
1823
+ }
1824
+ return void 0;
1825
+ }
1801
1826
  async function loadExecutorConfig(cwd, options = {}) {
1802
1827
  const configPath = await resolveConfigPath(cwd, options.configPath);
1803
1828
  const module = await loadModule(configPath, createModuleLoadOptions(cwd, options));
@@ -1827,14 +1852,24 @@ async function resolveConfigPath(cwd, explicitPath) {
1827
1852
  await ensureFileExists(absolutePath);
1828
1853
  return absolutePath;
1829
1854
  }
1830
- for (const candidate of CONFIG_CANDIDATES) {
1831
- const absoluteCandidate = resolve(cwd, candidate);
1832
- if (await fileExists(absoluteCandidate)) {
1833
- return absoluteCandidate;
1855
+ let current = cwd;
1856
+ for (let depth = 0; depth < 50; depth += 1) {
1857
+ const found = await findConfigInDir(current);
1858
+ if (found) {
1859
+ return found;
1860
+ }
1861
+ const parent = dirname(current);
1862
+ if (parent === current) {
1863
+ break;
1834
1864
  }
1865
+ current = parent;
1835
1866
  }
1867
+ const expected = [
1868
+ ...CONFIG_EXTENSIONS.map((ext) => `autometa.config.${ext}`),
1869
+ "autometa.<name>.config.{ts,mts,cts,js,mjs,cjs}"
1870
+ ];
1836
1871
  throw new Error(
1837
- `Unable to locate an Autometa config file in "${cwd}". Expected one of: ${CONFIG_CANDIDATES.join(
1872
+ `Unable to locate an Autometa config file starting from "${cwd}". Expected one of: ${expected.join(
1838
1873
  ", "
1839
1874
  )}`
1840
1875
  );
@@ -2265,7 +2300,7 @@ function registerRunCommand(program) {
2265
2300
  ).option(
2266
2301
  "--cache-dir <dir>",
2267
2302
  "Directory for Autometa CLI cache (defaults to node_modules/.cache/autometa when available)"
2268
- ).option("--dry-run", "Collect scenarios without executing steps").option("--watch", "Run in watch mode (vitest/jest only)").option("--verbose", "Show detailed output including runner detection").option("--standalone", "Force standalone runtime instead of native runner").option("-e, --environment <environment>", "Select config environment").option(
2303
+ ).option("--dry-run", "Collect scenarios without executing steps").option("--watch", "Run in watch mode (vitest/jest only)").option("--verbose", "Show detailed output including runner detection").option("--standalone", "Force standalone runtime instead of native runner").option("-c, --config <path>", "Path to Autometa config file (e.g. autometa.config.ts)").option("-e, --environment <environment>", "Select config environment").option(
2269
2304
  "-g, --group <group>",
2270
2305
  "Filter module groups to include (affects module/step loading; patterns are not auto-scoped)",
2271
2306
  collectRepeatedString,
@@ -2281,6 +2316,7 @@ function registerRunCommand(program) {
2281
2316
  const summary = await runFeatures({
2282
2317
  cwd: process.cwd(),
2283
2318
  ...typeof flags?.cacheDir === "string" && flags.cacheDir.trim().length > 0 ? { cacheDir: flags.cacheDir } : {},
2319
+ ...typeof flags?.config === "string" && flags.config.trim().length > 0 ? { configPath: flags.config } : {},
2284
2320
  ...split.patterns.length > 0 ? { patterns: split.patterns } : {},
2285
2321
  ...split.runnerArgs.length > 0 ? { runnerArgs: split.runnerArgs } : {},
2286
2322
  ...typeof flags?.dryRun === "boolean" ? { dryRun: flags.dryRun } : {},
@@ -2426,6 +2462,7 @@ async function runFeatures(options = {}) {
2426
2462
  const summaryFormatter = options.summaryFormatter ?? formatSummary;
2427
2463
  const { resolved } = await loadExecutorConfig(cwd, {
2428
2464
  cacheDir,
2465
+ ...typeof options.configPath === "string" && options.configPath.trim().length > 0 ? { configPath: options.configPath } : {},
2429
2466
  ...typeof options.environment === "string" && options.environment.trim().length > 0 ? { environment: options.environment } : {},
2430
2467
  ...options.modules ? { modules: [...options.modules] } : {},
2431
2468
  ...options.groups ? { groups: [...options.groups] } : {}