Skip to content
This repository was archived by the owner on Dec 27, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions assets/usage-check.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
probitas check - Type-check scenario files

Usage: probitas check [options] [paths...]

Arguments:
[paths...] Scenario files or directories
Defaults to current directory

Options:
-h, --help Show help message
--include <pattern> Include pattern for file discovery
--exclude <pattern> Exclude pattern for file discovery
--config <path> Path to probitas config file
-v, --verbose Verbose output
-q, --quiet Suppress output
-d, --debug Debug output

Note:
Runs `deno check --no-config` on discovered scenario files.
Uses includes/excludes from probitas config (same as run/list).

Examples:
probitas check # Check all scenario files
probitas check api/ # Check scenarios in api directory
probitas check --include "e2e/**/*.probitas.ts"

Documentation: https://jsr-probitas.github.io/documents/
27 changes: 27 additions & 0 deletions assets/usage-fmt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
probitas fmt - Format scenario files

Usage: probitas fmt [options] [paths...]

Arguments:
[paths...] Scenario files or directories
Defaults to current directory

Options:
-h, --help Show help message
--include <pattern> Include pattern for file discovery
--exclude <pattern> Exclude pattern for file discovery
--config <path> Path to probitas config file
-v, --verbose Verbose output
-q, --quiet Suppress output
-d, --debug Debug output

Note:
Runs `deno fmt --no-config` on discovered scenario files.
Uses includes/excludes from probitas config (same as run/list).

Examples:
probitas fmt # Format all scenario files
probitas fmt api/ # Format scenarios in api directory
probitas fmt --include "e2e/**/*.probitas.ts"

Documentation: https://jsr-probitas.github.io/documents/
28 changes: 28 additions & 0 deletions assets/usage-lint.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
probitas lint - Lint scenario files

Usage: probitas lint [options] [paths...]

Arguments:
[paths...] Scenario files or directories
Defaults to current directory

Options:
-h, --help Show help message
--include <pattern> Include pattern for file discovery
--exclude <pattern> Exclude pattern for file discovery
--config <path> Path to probitas config file
-v, --verbose Verbose output
-q, --quiet Suppress output
-d, --debug Debug output

Note:
Runs `deno lint --no-config` on discovered scenario files.
Uses includes/excludes from probitas config (same as run/list).
Automatically excludes rules: no-import-prefix, no-unversioned-import

Examples:
probitas lint # Lint all scenario files
probitas lint api/ # Lint scenarios in api directory
probitas lint --include "e2e/**/*.probitas.ts"

Documentation: https://jsr-probitas.github.io/documents/
3 changes: 3 additions & 0 deletions assets/usage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Commands:
init Initialize a new probitas project
run Run scenarios
list List available scenarios
fmt Format scenario files (runs deno fmt)
lint Lint scenario files (runs deno lint)
check Type-check scenario files (runs deno check)

Options:
-h, --help Show help message
Expand Down
135 changes: 135 additions & 0 deletions src/commands/_deno.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/**
* Shared helper for Deno subcommand execution
*
* Used by fmt, lint, and check commands to run corresponding deno commands
* on discovered scenario files.
*
* @module
*/

import { parseArgs } from "@std/cli";
import { resolve } from "@std/path";
import { configureLogging, getLogger, type LogLevel } from "@probitas/logger";
import { discoverScenarioFiles } from "@probitas/discover";
import { EXIT_CODE } from "../constants.ts";
import { findProbitasConfigFile, loadConfig } from "../config.ts";
import { createDiscoveryProgress } from "../progress.ts";
import { readAsset } from "../utils.ts";

const logger = getLogger("probitas", "cli", "deno");

/**
* Options for running a Deno subcommand
*/
export interface DenoSubcommandOptions {
/** Asset file name for help text */
usageAsset: string;
/** Extra arguments to pass to the deno command */
extraArgs?: readonly string[];
}

/**
* Run a Deno subcommand on discovered scenario files
*
* @param subcommand - Deno subcommand to run (fmt, lint, check)
* @param args - Command-line arguments
* @param cwd - Current working directory
* @param options - Subcommand options
* @returns Exit code from the deno command
*/
export async function runDenoSubcommand(
subcommand: string,
args: string[],
cwd: string,
options: DenoSubcommandOptions,
): Promise<number> {
try {
const parsed = parseArgs(args, {
string: ["config", "include", "exclude"],
boolean: ["help", "quiet", "verbose", "debug"],
collect: ["include", "exclude"],
alias: {
h: "help",
v: "verbose",
q: "quiet",
d: "debug",
},
default: {
include: undefined,
exclude: undefined,
},
});

if (parsed.help) {
const helpText = await readAsset(options.usageAsset);
console.log(helpText);
return EXIT_CODE.SUCCESS;
}

// Determine log level
const logLevel: LogLevel = parsed.debug
? "debug"
: parsed.verbose
? "info"
: parsed.quiet
? "fatal"
: "warning";

try {
await configureLogging(logLevel);
} catch {
// Ignore - logging may already be configured
}

// Load probitas config (NOT deno.json)
const configPath = parsed.config ??
await findProbitasConfigFile(cwd, { parentLookup: true });
const config = configPath ? await loadConfig(configPath) : {};

// CLI > config
const includes = parsed.include ?? config?.includes;
const excludes = parsed.exclude ?? config?.excludes;

// Discover scenario files
const paths = parsed._.map(String).map((p) => resolve(cwd, p));
const discoveryProgress = parsed.quiet ? null : createDiscoveryProgress();
const scenarioFiles = await discoverScenarioFiles(
paths.length ? paths : [cwd],
{ includes, excludes, onProgress: discoveryProgress?.onProgress },
);
discoveryProgress?.complete(scenarioFiles.length);

if (scenarioFiles.length === 0) {
console.warn("No scenario files found");
return EXIT_CODE.NOT_FOUND;
}

logger.debug(`Running deno ${subcommand}`, {
fileCount: scenarioFiles.length,
});

// Run deno command with --no-config
const denoArgs = [
subcommand,
"--no-config",
...(options.extraArgs ?? []),
...scenarioFiles,
];

const command = new Deno.Command("deno", {
args: denoArgs,
cwd,
stdin: "inherit",
stdout: "inherit",
stderr: "inherit",
});

const { code } = await command.output();
return code;
} catch (err: unknown) {
logger.error(`deno ${subcommand} failed`, { error: err });
const m = err instanceof Error ? err.message : String(err);
console.error(`Error: ${m}`);
return EXIT_CODE.FAILURE;
}
}
25 changes: 25 additions & 0 deletions src/commands/check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Type-check command for Probitas CLI
*
* Runs `deno check --no-config` on discovered scenario files.
*
* @module
*/

import { runDenoSubcommand } from "./_deno.ts";

/**
* Run the check command
*
* @param args - Command-line arguments
* @param cwd - Current working directory
* @returns Exit code
*/
export async function checkCommand(
args: string[],
cwd: string,
): Promise<number> {
return await runDenoSubcommand("check", args, cwd, {
usageAsset: "usage-check.txt",
});
}
25 changes: 25 additions & 0 deletions src/commands/fmt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Format command for Probitas CLI
*
* Runs `deno fmt --no-config` on discovered scenario files.
*
* @module
*/

import { runDenoSubcommand } from "./_deno.ts";

/**
* Run the fmt command
*
* @param args - Command-line arguments
* @param cwd - Current working directory
* @returns Exit code
*/
export async function fmtCommand(
args: string[],
cwd: string,
): Promise<number> {
return await runDenoSubcommand("fmt", args, cwd, {
usageAsset: "usage-fmt.txt",
});
}
27 changes: 27 additions & 0 deletions src/commands/lint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Lint command for Probitas CLI
*
* Runs `deno lint --no-config` on discovered scenario files.
* Automatically excludes rules that conflict with scenario imports.
*
* @module
*/

import { runDenoSubcommand } from "./_deno.ts";

/**
* Run the lint command
*
* @param args - Command-line arguments
* @param cwd - Current working directory
* @returns Exit code
*/
export async function lintCommand(
args: string[],
cwd: string,
): Promise<number> {
return await runDenoSubcommand("lint", args, cwd, {
usageAsset: "usage-lint.txt",
extraArgs: ["--rules-exclude=no-import-prefix,no-unversioned-import"],
});
}
3 changes: 3 additions & 0 deletions src/commands/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
* @module
*/

export { checkCommand } from "./check.ts";
export { fmtCommand } from "./fmt.ts";
export { initCommand } from "./init.ts";
export { lintCommand } from "./lint.ts";
export { listCommand } from "./list.ts";
export { runCommand } from "./run.ts";
12 changes: 12 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import { parseArgs } from "@std/cli";
import { getLogger } from "@probitas/logger";
import { EXIT_CODE } from "./constants.ts";
import { checkCommand } from "./commands/check.ts";
import { fmtCommand } from "./commands/fmt.ts";
import { initCommand } from "./commands/init.ts";
import { lintCommand } from "./commands/lint.ts";
import { listCommand } from "./commands/list.ts";
import { runCommand } from "./commands/run.ts";
import { getVersionInfo, readAsset } from "./utils.ts";
Expand Down Expand Up @@ -78,6 +81,15 @@ export async function main(args: string[]): Promise<number> {
case "list":
return await listCommand(commandArgs, cwd);

case "fmt":
return await fmtCommand(commandArgs, cwd);

case "lint":
return await lintCommand(commandArgs, cwd);

case "check":
return await checkCommand(commandArgs, cwd);

default:
console.warn(`Unknown command: ${command}`);
console.warn("Run 'probitas --help' for usage information");
Expand Down