1import { assert, describe } from "@effect/vitest";
2
3import { createOxlintRuleHarness } from "../test/utils.ts";
4
5const rule = createOxlintRuleHarness("t3code/prefer-catch-tags");
6
7describe("t3code/prefer-catch-tags", () => {
8 rule.valid(
9 "allows Effect.catchTags",
10 `
11 import * as Effect from "effect/Effect";
12
13 export const program = Effect.fail({ _tag: "A" } as const).pipe(
14 Effect.catchTags({ A: () => Effect.void }),
15 );
16 `,
17 );
18
19 rule.valid(
20 "ignores catchTag on other modules",
21 `
22 import * as Stream from "effect/Stream";
23
24 export const recover = Stream.catchTag("A", () => Stream.empty);
25 `,
26 );
27
28 rule.valid(
29 "ignores a local that shadows the namespace",
30 `
31 import * as Effect from "effect/Effect";
32
33 export const program = Effect.void;
34 export function recover(Effect: { catchTag: (tag: string) => void }) {
35 Effect.catchTag("A");
36 }
37 `,
38 );
39
40 rule.invalid(
41 "reports Effect.catchTag",
42 `
43 import * as Effect from "effect/Effect";
44
45 export const program = Effect.fail({ _tag: "A" } as const).pipe(
46 Effect.catchTag("A", () => Effect.void),
47 );
48 `,
49 (output) => {
50 assert.match(output, /Effect\.catchTags\(\{ Tag: handler \}\)/);
51 },
52 );
53
54 rule.invalid(
55 "reports catchTag through an aliased namespace",
56 `
57 import * as Eff from "effect/Effect";
58
59 export const recover = Eff.catchTag("A", () => Eff.void);
60 `,
61 );
62
63 rule.invalid("reports a named catchTag import", `import { catchTag } from "effect/Effect";`);
64});