oxlint-plugin-effect 0.0.0 → 0.2.0
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 +55 -0
- package/package.json +6 -7
- package/src/presets/core.ts +24 -13
- package/src/presets/effect-native.ts +18 -25
- package/src/presets/full.ts +33 -47
- package/src/presets/functional.ts +18 -0
- package/src/presets/index.ts +2 -0
- package/src/presets/strict.ts +77 -0
- package/src/rules/index.ts +18 -29
- package/src/rules/no-arrow-ladder.ts +1 -2
- package/src/rules/no-async-function.ts +1 -2
- package/src/rules/no-catch-all-to-map-error.ts +90 -0
- package/src/rules/no-effect-fn-generator.ts +1 -2
- package/src/rules/no-effect-gen-adapter.ts +2 -2
- package/src/rules/no-effect-map-flatten.ts +82 -0
- package/src/rules/no-effect-map-void.ts +1 -2
- package/src/rules/no-effect-orElse-ladder.ts +1 -2
- package/src/rules/no-effect-succeed-string.ts +1 -2
- package/src/rules/no-effect-succeed-variable.ts +1 -2
- package/src/rules/no-effect-succeed-void.ts +1 -2
- package/src/rules/no-effect-sync-console.ts +1 -2
- package/src/rules/no-effect-sync-wrapper.ts +1 -2
- package/src/rules/no-effect-type-alias.ts +1 -2
- package/src/rules/no-effect-wrapper-alias.ts +1 -4
- package/src/rules/no-extends-native-error.ts +1 -2
- package/src/rules/no-flatmap-ladder.ts +1 -3
- package/src/rules/no-fromnullable-coalesce.ts +1 -2
- package/src/rules/no-global-error-in-catch.ts +104 -0
- package/src/rules/no-global-error-in-failure.ts +83 -0
- package/src/rules/no-globals.ts +178 -0
- package/src/rules/no-iife-wrapper.ts +1 -2
- package/src/rules/{no-inline-runtime-provide.ts → no-inline-provide.ts} +3 -4
- package/src/rules/no-instanceof-schema.ts +2 -3
- package/src/rules/no-manual-effect-channels.ts +1 -2
- package/src/rules/no-match-effect-branch.ts +1 -2
- package/src/rules/no-match-void-branch.ts +1 -2
- package/src/rules/no-multiple-effect-provide.ts +75 -0
- package/src/rules/no-nested-effect-call.ts +1 -3
- package/src/rules/no-nested-effect-gen.ts +1 -2
- package/src/rules/no-nested-pipe.ts +1 -4
- package/src/rules/no-new-error.ts +46 -10
- package/src/rules/no-new-promise.ts +43 -7
- package/src/rules/no-node-builtin-import.ts +1 -3
- package/src/rules/no-option-boolean-normalization.ts +1 -2
- package/src/rules/no-positional-log-error.ts +76 -0
- package/src/rules/no-redundant-schema-tag-identifier.ts +62 -0
- package/src/rules/no-return-in-arrow.ts +1 -2
- package/src/rules/no-return-nullish.ts +80 -0
- package/src/rules/no-run-in-effect-gen.ts +66 -0
- package/src/rules/no-runtime-run-fork.ts +1 -1
- package/src/rules/no-schema-struct-with-tag.ts +64 -0
- package/src/rules/no-schema-union-of-literals.ts +48 -0
- package/src/rules/no-string-sentinel-const.ts +1 -2
- package/src/rules/no-ternary.ts +1 -3
- package/src/rules/no-throw-statement.ts +32 -6
- package/src/rules/no-try-catch.ts +32 -7
- package/src/rules/no-unnecessary-arrow-block.ts +1 -2
- package/src/rules/no-unnecessary-effect-gen.ts +1 -3
- package/src/rules/no-unnecessary-pipe-chain.ts +47 -0
- package/src/rules/no-unnecessary-pipe.ts +1 -2
- package/src/vendor/effect-oxlint/Rule.ts +141 -183
- package/tests/ban-rules.test.ts +0 -184
- package/tests/context-rules.test.ts +127 -145
- package/tests/pattern-rules.test.ts +39 -50
- package/src/rules/no-console-in-effect.ts +0 -46
- package/src/rules/no-date-in-effect.ts +0 -61
- package/src/rules/no-dynamic-import.ts +0 -13
- package/src/rules/no-fetch-in-effect.ts +0 -47
- package/src/rules/no-global-console.ts +0 -17
- package/src/rules/no-global-date.ts +0 -20
- package/src/rules/no-global-fetch.ts +0 -14
- package/src/rules/no-global-random.ts +0 -13
- package/src/rules/no-global-timers.ts +0 -17
- package/src/rules/no-json-in-effect.ts +0 -45
- package/src/rules/no-json-parse.ts +0 -18
- package/src/rules/no-platform-globals.ts +0 -117
- package/src/rules/no-process-env-in-effect.ts +0 -39
- package/src/rules/no-process-env.ts +0 -13
- package/src/rules/no-random-in-effect.ts +0 -39
- package/src/rules/no-return-null.ts +0 -47
- package/src/rules/no-run-in-effect.ts +0 -18
- package/src/rules/no-throw-in-effect-gen.ts +0 -42
- package/src/rules/no-timers-in-effect.ts +0 -47
- package/src/rules/no-try-catch-in-effect-gen.ts +0 -42
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ban `Schema.Union(Schema.Literal("a"), Schema.Literal("b"))`.
|
|
3
|
+
* Use `Schema.Literal("a", "b")` instead.
|
|
4
|
+
*
|
|
5
|
+
* Source: language-service/schemaUnionOfLiterals
|
|
6
|
+
*/
|
|
7
|
+
import type { ESTree } from "@oxlint/plugins"
|
|
8
|
+
import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
9
|
+
import * as Effect from "effect/Effect"
|
|
10
|
+
import * as Option from "effect/Option"
|
|
11
|
+
|
|
12
|
+
const isSchemaLiteral = (node: ESTree.Node): boolean => {
|
|
13
|
+
if (node.type !== "CallExpression") return false
|
|
14
|
+
return Option.isSome(AST.matchCallOf(node as ESTree.CallExpression, "Schema", "Literal"))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const noSchemaUnionOfLiterals = Rule.define({
|
|
18
|
+
name: "no-schema-union-of-literals",
|
|
19
|
+
meta: Rule.meta({
|
|
20
|
+
type: "suggestion",
|
|
21
|
+
description:
|
|
22
|
+
"Use Schema.Literal('a', 'b') instead of Schema.Union(Schema.Literal('a'), Schema.Literal('b')).",
|
|
23
|
+
}),
|
|
24
|
+
create: function* () {
|
|
25
|
+
const ctx = yield* RuleContext
|
|
26
|
+
return {
|
|
27
|
+
CallExpression: (node) => {
|
|
28
|
+
const call = node as ESTree.CallExpression
|
|
29
|
+
if (Option.isNone(AST.matchCallOf(call, "Schema", "Union"))) return Effect.void
|
|
30
|
+
|
|
31
|
+
const args = call.arguments
|
|
32
|
+
if (args.length < 2) return Effect.void
|
|
33
|
+
|
|
34
|
+
// Check if all arguments are Schema.Literal calls
|
|
35
|
+
const allLiterals = args.every((arg) => isSchemaLiteral(arg as ESTree.Node))
|
|
36
|
+
if (!allLiterals) return Effect.void
|
|
37
|
+
|
|
38
|
+
return ctx.report(
|
|
39
|
+
Diagnostic.make({
|
|
40
|
+
node,
|
|
41
|
+
message:
|
|
42
|
+
"Use Schema.Literal('a', 'b') instead of Schema.Union(Schema.Literal('a'), Schema.Literal('b')).",
|
|
43
|
+
}),
|
|
44
|
+
)
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
})
|
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Note: Very aggressive — should probably be off by default or in a strict preset only.
|
|
9
9
|
*/
|
|
10
|
-
import { Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
|
|
11
|
-
import { RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
10
|
+
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
12
11
|
import * as Effect from "effect/Effect"
|
|
13
12
|
|
|
14
13
|
export const noStringSentinelConst = Rule.define({
|
package/src/rules/no-ternary.ts
CHANGED
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Note: Very opinionated — recommended for strict functional presets only.
|
|
9
9
|
*/
|
|
10
|
-
import { Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
|
|
11
|
-
import { RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
12
|
-
import * as Effect from "effect/Effect"
|
|
10
|
+
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
13
11
|
|
|
14
12
|
export const noTernary = Rule.define({
|
|
15
13
|
name: "no-ternary",
|
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ban `throw` statements.
|
|
2
|
+
* Ban `throw` statements. Context-aware messaging.
|
|
3
3
|
*
|
|
4
|
-
* Use Effect.fail or
|
|
4
|
+
* Inside Effect.gen/fn: "Use yield* Effect.fail() or yield* new MyError()"
|
|
5
|
+
* Outside: "Model errors with Effect.fail() — wrap this function with Effect.fn"
|
|
5
6
|
*
|
|
6
7
|
* Source: effect convention — errors should be in the type system
|
|
7
8
|
*/
|
|
8
|
-
import { Rule } from "../vendor/effect-oxlint/index.js"
|
|
9
|
+
import { Diagnostic, Rule, Visitor, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
10
|
+
import * as Effect from "effect/Effect"
|
|
11
|
+
import * as Ref from "effect/Ref"
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
import { makeEffectContextTracker } from "./_effect-context.js"
|
|
14
|
+
|
|
15
|
+
export const noThrowStatement = Rule.define({
|
|
16
|
+
name: "no-throw-statement",
|
|
17
|
+
meta: Rule.meta({
|
|
18
|
+
type: "problem",
|
|
19
|
+
description: "Avoid throw. Use Effect.fail with tagged errors.",
|
|
20
|
+
}),
|
|
21
|
+
create: function* () {
|
|
22
|
+
const ctx = yield* RuleContext
|
|
23
|
+
const [depth, tracker] = yield* makeEffectContextTracker
|
|
24
|
+
|
|
25
|
+
return Visitor.merge(tracker, {
|
|
26
|
+
ThrowStatement: (node) =>
|
|
27
|
+
Effect.flatMap(Ref.get(depth), (d) =>
|
|
28
|
+
ctx.report(
|
|
29
|
+
Diagnostic.make({
|
|
30
|
+
node,
|
|
31
|
+
message: d > 0
|
|
32
|
+
? "Avoid throw inside Effect.gen/fn. Use yield* Effect.fail(new MyError()) or yield* new MyError() for yieldable errors."
|
|
33
|
+
: "Avoid throw. Model errors with Effect — wrap this function with Effect.fn and use Effect.fail with tagged errors.",
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
})
|
|
38
|
+
},
|
|
13
39
|
})
|
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ban `try/catch` statements.
|
|
2
|
+
* Ban `try/catch` statements. Context-aware messaging.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Inside Effect.gen/fn: "Use Effect.try or Effect.tryPromise"
|
|
5
|
+
* Outside: "Wrap with Effect.fn and use Effect.try for error handling"
|
|
5
6
|
*
|
|
6
7
|
* Source: biome-effect-linting-rules/no-try-catch, language-service/tryCatchInEffectGen
|
|
7
8
|
*/
|
|
8
|
-
import { Rule } from "../vendor/effect-oxlint/index.js"
|
|
9
|
+
import { Diagnostic, Rule, Visitor, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
10
|
+
import * as Effect from "effect/Effect"
|
|
11
|
+
import * as Ref from "effect/Ref"
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
import { makeEffectContextTracker } from "./_effect-context.js"
|
|
14
|
+
|
|
15
|
+
export const noTryCatch = Rule.define({
|
|
16
|
+
name: "no-try-catch",
|
|
17
|
+
meta: Rule.meta({
|
|
18
|
+
type: "suggestion",
|
|
19
|
+
description: "Avoid try/catch. Use Effect.try or Effect.tryPromise.",
|
|
20
|
+
}),
|
|
21
|
+
create: function* () {
|
|
22
|
+
const ctx = yield* RuleContext
|
|
23
|
+
const [depth, tracker] = yield* makeEffectContextTracker
|
|
24
|
+
|
|
25
|
+
return Visitor.merge(tracker, {
|
|
26
|
+
TryStatement: (node) =>
|
|
27
|
+
Effect.flatMap(Ref.get(depth), (d) =>
|
|
28
|
+
ctx.report(
|
|
29
|
+
Diagnostic.make({
|
|
30
|
+
node,
|
|
31
|
+
message: d > 0
|
|
32
|
+
? "Avoid try/catch inside Effect.gen/fn. Use Effect.try({ try: () => ..., catch: (e) => new MyError({ cause: e }) })."
|
|
33
|
+
: "Avoid try/catch. Wrap this function with Effect.fn and use Effect.try or Effect.tryPromise for error handling.",
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
})
|
|
38
|
+
},
|
|
14
39
|
})
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Source: language-service/unnecessaryArrowBlock
|
|
5
5
|
*/
|
|
6
|
-
import { Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
|
|
7
|
-
import { RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
6
|
+
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
8
7
|
import * as Effect from "effect/Effect"
|
|
9
8
|
|
|
10
9
|
export const noUnnecessaryArrowBlock = Rule.define({
|
|
@@ -12,10 +12,8 @@
|
|
|
12
12
|
* Source: language-service/unnecessaryEffectGen
|
|
13
13
|
*/
|
|
14
14
|
import type { ESTree } from "@oxlint/plugins"
|
|
15
|
-
import { AST, Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
|
|
16
|
-
import { RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
15
|
+
import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
17
16
|
import * as Effect from "effect/Effect"
|
|
18
|
-
import * as Option from "effect/Option"
|
|
19
17
|
|
|
20
18
|
export const noUnnecessaryEffectGen = Rule.define({
|
|
21
19
|
name: "no-unnecessary-effect-gen",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ban `x.pipe(f).pipe(g)` — merge into `x.pipe(f, g)`.
|
|
3
|
+
*
|
|
4
|
+
* Source: language-service/unnecessaryPipeChain
|
|
5
|
+
*/
|
|
6
|
+
import type { ESTree } from "@oxlint/plugins"
|
|
7
|
+
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
8
|
+
import * as Effect from "effect/Effect"
|
|
9
|
+
|
|
10
|
+
const isMethodPipe = (node: ESTree.Node): boolean => {
|
|
11
|
+
if (node.type !== "CallExpression") return false
|
|
12
|
+
const callee = (node as unknown as Record<string, unknown>)["callee"]
|
|
13
|
+
if (callee == null || typeof callee !== "object" || !("type" in callee)) return false
|
|
14
|
+
if (callee.type !== "MemberExpression") return false
|
|
15
|
+
const prop = (callee as unknown as Record<string, unknown>)["property"]
|
|
16
|
+
if (prop == null || typeof prop !== "object" || !("type" in prop)) return false
|
|
17
|
+
return prop.type === "Identifier" && "name" in prop && prop.name === "pipe"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const noUnnecessaryPipeChain = Rule.define({
|
|
21
|
+
name: "no-unnecessary-pipe-chain",
|
|
22
|
+
meta: Rule.meta({
|
|
23
|
+
type: "suggestion",
|
|
24
|
+
description:
|
|
25
|
+
"Avoid chaining .pipe().pipe(). Merge into a single .pipe() call.",
|
|
26
|
+
}),
|
|
27
|
+
create: function* () {
|
|
28
|
+
const ctx = yield* RuleContext
|
|
29
|
+
return {
|
|
30
|
+
CallExpression: (node) => {
|
|
31
|
+
if (!isMethodPipe(node)) return Effect.void
|
|
32
|
+
const callee = (node as unknown as Record<string, unknown>)["callee"] as Record<string, unknown>
|
|
33
|
+
const obj = callee["object"]
|
|
34
|
+
if (obj != null && typeof obj === "object" && isMethodPipe(obj as ESTree.Node)) {
|
|
35
|
+
return ctx.report(
|
|
36
|
+
Diagnostic.make({
|
|
37
|
+
node,
|
|
38
|
+
message:
|
|
39
|
+
"Unnecessary .pipe() chain. Merge into a single .pipe() call.",
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
return Effect.void
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
})
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* Source: language-service/unnecessaryPipe
|
|
7
7
|
*/
|
|
8
8
|
import type { ESTree } from "@oxlint/plugins"
|
|
9
|
-
import { AST, Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
|
|
10
|
-
import { RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
9
|
+
import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
11
10
|
import * as Effect from "effect/Effect"
|
|
12
11
|
import * as Option from "effect/Option"
|
|
13
12
|
|