Skip to content

Commit c3900a8

Browse files
committed
refactor(@probitas/probitas): move reporter implementations from external package
Reporter implementations (ListReporter, JSONReporter, Writer) are only consumed by the CLI in this repository. Moving them from the external @probitas/reporter package simplifies the dependency graph and enables direct modification without cross-repository releases. Changes: - Moved reporter source files to src/cli/reporter/ - Updated imports in CLI utils to use local reporter modules - Removed @probitas/reporter dependency from deno.json - Added @std/testing/snapshot for reporter tests - Updated custom reporter example in development.md to show self-contained implementation without external Writer dependency - All 45 tests passing with migrated code
1 parent ee76da7 commit c3900a8

14 files changed

Lines changed: 2809 additions & 73 deletions

.claude/rules/development.md

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,41 @@ Key exports:
4141

4242
## Custom Reporter Implementation
4343

44-
Custom reporters should implement the `Reporter` interface and compose a
45-
`Writer` for output. The interface uses `Metadata` types (serializable) instead
44+
Custom reporters should implement the `Reporter` interface from
45+
`@probitas/runner`. The interface uses `Metadata` types (serializable) instead
4646
of `Definition` types:
4747

4848
```ts
49-
import { Writer, type WriterOptions } from "@probitas/reporter";
5049
import type { Reporter, RunResult, StepResult } from "@probitas/runner";
5150
import type { ScenarioMetadata, StepMetadata } from "@probitas/core";
52-
import { defaultTheme, type Theme } from "@probitas/reporter";
51+
import { defaultTheme, type Theme } from "@probitas/core/theme";
5352

54-
export interface CustomReporterOptions extends WriterOptions {
53+
export interface CustomReporterOptions {
54+
output?: WritableStream;
5555
theme?: Theme;
5656
}
5757

5858
export class CustomReporter implements Reporter {
59-
#writer: Writer;
59+
#output: WritableStream;
6060
#theme: Theme;
61+
#encoder: TextEncoder = new TextEncoder();
6162

6263
constructor(options: CustomReporterOptions = {}) {
63-
this.#writer = new Writer(options);
64+
this.#output = options.output ?? Deno.stderr.writable;
6465
this.#theme = options.theme ?? defaultTheme;
6566
}
6667

68+
async #write(text: string): Promise<void> {
69+
const writer = this.#output.getWriter();
70+
try {
71+
await writer.write(this.#encoder.encode(text));
72+
} finally {
73+
writer.releaseLock();
74+
}
75+
}
76+
6777
async onRunStart(scenarios: readonly ScenarioMetadata[]): Promise<void> {
68-
await this.#writer.write(`Running ${scenarios.length} scenarios\n`);
78+
await this.#write(`Running ${scenarios.length} scenarios\n`);
6979
}
7080

7181
async onStepEnd(
@@ -75,28 +85,27 @@ export class CustomReporter implements Reporter {
7585
): Promise<void> {
7686
// result is a discriminated union - access status-specific fields safely
7787
if (result.status === "passed") {
78-
await this.#writer.write(`✓ ${step.name}\n`);
88+
await this.#write(`✓ ${step.name}\n`);
7989
} else if (result.status === "failed") {
80-
await this.#writer.write(`✗ ${step.name}: ${result.error}\n`);
90+
await this.#write(`✗ ${step.name}: ${result.error}\n`);
8191
} else if (result.status === "skipped") {
82-
await this.#writer.write(`⊘ ${step.name}: ${result.error}\n`);
92+
await this.#write(`⊘ ${step.name}: ${result.error}\n`);
8393
}
8494
}
8595

8696
async onRunEnd(
8797
scenarios: readonly ScenarioMetadata[],
8898
result: RunResult,
8999
): Promise<void> {
90-
await this.#writer.write(`\nCompleted: ${result.passed}/${result.total}\n`);
100+
await this.#write(`\nCompleted: ${result.passed}/${result.total}\n`);
91101
}
92102
}
93103
```
94104

95105
### Key Points
96106

97107
1. **Implement `Reporter` interface** - All methods are optional
98-
2. **Compose `Writer`** - For serialized, buffered output
99-
3. **Use `Theme`** - For semantic coloring
108+
2. **Use `Theme`** from `@probitas/core/theme` - For semantic coloring
100109
4. **Access discriminated unions safely** - Check `result.status` before
101110
accessing fields
102111
5. **Support options** - Allow users to customize output stream and theme

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@
9090
"@probitas/core": "jsr:@probitas/core@^0.3.2",
9191
"@probitas/discover": "jsr:@probitas/discover@^0.4.0",
9292
"@probitas/expect": "jsr:@probitas/expect@^0.4.1",
93-
"@probitas/reporter": "jsr:@probitas/reporter@^0.7.1",
9493
"@probitas/runner": "jsr:@probitas/runner@^0.5.6",
9594
"@std/assert": "jsr:@std/assert@^1.0.16",
9695
"@std/cbor": "jsr:@std/cbor@^0.1.9",
@@ -103,6 +102,7 @@
103102
"@std/jsonc": "jsr:@std/jsonc@^1.0.2",
104103
"@std/path": "jsr:@std/path@^1.1.4",
105104
"@std/streams": "jsr:@std/streams@^1.0.16",
105+
"@std/testing/snapshot": "jsr:@std/testing@^1.0.16/snapshot",
106106
"@std/testing/bdd": "jsr:@std/testing@^1.0.16/bdd",
107107
"@std/testing/mock": "jsr:@std/testing@^1.0.16/mock",
108108
"@std/testing/time": "jsr:@std/testing@^1.0.16/time",

deno.lock

Lines changed: 13 additions & 55 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)