oxlint-plugin-effect 0.2.0 → 0.2.2
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/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.js +18 -0
- package/dist/presets/core.d.ts +43 -0
- package/dist/presets/core.js +43 -0
- package/dist/presets/effect-native.d.ts +28 -0
- package/dist/presets/effect-native.js +28 -0
- package/dist/presets/full.d.ts +60 -0
- package/dist/presets/full.js +60 -0
- package/dist/presets/functional.d.ts +21 -0
- package/dist/presets/functional.js +21 -0
- package/dist/presets/index.d.ts +14 -0
- package/dist/presets/index.js +20 -0
- package/dist/presets/strict.d.ts +64 -0
- package/dist/presets/strict.js +64 -0
- package/dist/presets/v3-strict.d.ts +16 -0
- package/dist/presets/v3-strict.js +16 -0
- package/dist/presets/v3.d.ts +18 -0
- package/dist/presets/v3.js +18 -0
- package/dist/rules/_effect-context.d.ts +19 -0
- package/dist/rules/_effect-context.js +22 -0
- package/dist/rules/index.d.ts +66 -0
- package/dist/rules/index.js +124 -0
- package/dist/rules/no-arrow-ladder.d.ts +6 -0
- package/dist/rules/no-arrow-ladder.js +61 -0
- package/dist/rules/no-async-function.d.ts +6 -0
- package/dist/rules/no-async-function.js +46 -0
- package/dist/rules/no-catch-all-to-map-error.d.ts +6 -0
- package/dist/rules/no-catch-all-to-map-error.js +67 -0
- package/dist/rules/no-effect-as.d.ts +6 -0
- package/dist/rules/no-effect-as.js +16 -0
- package/dist/rules/no-effect-async.d.ts +6 -0
- package/dist/rules/no-effect-async.js +16 -0
- package/dist/rules/no-effect-bind.d.ts +6 -0
- package/dist/rules/no-effect-bind.js +16 -0
- package/dist/rules/no-effect-do.d.ts +6 -0
- package/dist/rules/no-effect-do.js +16 -0
- package/dist/rules/no-effect-fn-generator.d.ts +6 -0
- package/dist/rules/no-effect-fn-generator.js +30 -0
- package/dist/rules/no-effect-gen-adapter.d.ts +6 -0
- package/dist/rules/no-effect-gen-adapter.js +30 -0
- package/dist/rules/no-effect-map-flatten.d.ts +6 -0
- package/dist/rules/no-effect-map-flatten.js +53 -0
- package/dist/rules/no-effect-map-void.d.ts +6 -0
- package/dist/rules/no-effect-map-void.js +40 -0
- package/dist/rules/no-effect-never.d.ts +6 -0
- package/dist/rules/no-effect-never.js +16 -0
- package/dist/rules/no-effect-orElse-ladder.d.ts +6 -0
- package/dist/rules/no-effect-orElse-ladder.js +53 -0
- package/dist/rules/no-effect-succeed-string.d.ts +6 -0
- package/dist/rules/no-effect-succeed-string.js +30 -0
- package/dist/rules/no-effect-succeed-variable.d.ts +6 -0
- package/dist/rules/no-effect-succeed-variable.js +30 -0
- package/dist/rules/no-effect-succeed-void.d.ts +6 -0
- package/dist/rules/no-effect-succeed-void.js +33 -0
- package/dist/rules/no-effect-sync-console.d.ts +6 -0
- package/dist/rules/no-effect-sync-console.js +63 -0
- package/dist/rules/no-effect-sync-wrapper.d.ts +6 -0
- package/dist/rules/no-effect-sync-wrapper.js +37 -0
- package/dist/rules/no-effect-type-alias.d.ts +6 -0
- package/dist/rules/no-effect-type-alias.js +52 -0
- package/dist/rules/no-effect-wrapper-alias.d.ts +6 -0
- package/dist/rules/no-effect-wrapper-alias.js +69 -0
- package/dist/rules/no-extends-native-error.d.ts +6 -0
- package/dist/rules/no-extends-native-error.js +41 -0
- package/dist/rules/no-flatmap-ladder.d.ts +6 -0
- package/dist/rules/no-flatmap-ladder.js +48 -0
- package/dist/rules/no-fromnullable-coalesce.d.ts +6 -0
- package/dist/rules/no-fromnullable-coalesce.js +36 -0
- package/dist/rules/no-global-error-in-catch.d.ts +6 -0
- package/dist/rules/no-global-error-in-catch.js +75 -0
- package/dist/rules/no-global-error-in-failure.d.ts +6 -0
- package/dist/rules/no-global-error-in-failure.js +54 -0
- package/dist/rules/no-globals.d.ts +6 -0
- package/dist/rules/no-globals.js +164 -0
- package/dist/rules/no-if-statement.d.ts +6 -0
- package/dist/rules/no-if-statement.js +18 -0
- package/dist/rules/no-iife-wrapper.d.ts +6 -0
- package/dist/rules/no-iife-wrapper.js +37 -0
- package/dist/rules/no-inline-provide.d.ts +6 -0
- package/dist/rules/no-inline-provide.js +31 -0
- package/dist/rules/no-instanceof-schema.d.ts +6 -0
- package/dist/rules/no-instanceof-schema.js +35 -0
- package/dist/rules/no-manual-effect-channels.d.ts +6 -0
- package/dist/rules/no-manual-effect-channels.js +40 -0
- package/dist/rules/no-match-effect-branch.d.ts +6 -0
- package/dist/rules/no-match-effect-branch.js +64 -0
- package/dist/rules/no-match-void-branch.d.ts +6 -0
- package/dist/rules/no-match-void-branch.js +50 -0
- package/dist/rules/no-multiple-effect-provide.d.ts +6 -0
- package/dist/rules/no-multiple-effect-provide.js +45 -0
- package/dist/rules/no-nested-effect-call.d.ts +6 -0
- package/dist/rules/no-nested-effect-call.js +97 -0
- package/dist/rules/no-nested-effect-gen.d.ts +6 -0
- package/dist/rules/no-nested-effect-gen.js +46 -0
- package/dist/rules/no-nested-pipe.d.ts +6 -0
- package/dist/rules/no-nested-pipe.js +38 -0
- package/dist/rules/no-new-error.d.ts +6 -0
- package/dist/rules/no-new-error.js +39 -0
- package/dist/rules/no-new-promise.d.ts +6 -0
- package/dist/rules/no-new-promise.js +38 -0
- package/dist/rules/no-node-builtin-import.d.ts +6 -0
- package/dist/rules/no-node-builtin-import.js +61 -0
- package/dist/rules/no-option-as.d.ts +6 -0
- package/dist/rules/no-option-as.js +16 -0
- package/dist/rules/no-option-boolean-normalization.d.ts +6 -0
- package/dist/rules/no-option-boolean-normalization.js +50 -0
- package/dist/rules/no-positional-log-error.d.ts +6 -0
- package/dist/rules/no-positional-log-error.js +52 -0
- package/dist/rules/no-redundant-schema-tag-identifier.d.ts +6 -0
- package/dist/rules/no-redundant-schema-tag-identifier.js +46 -0
- package/dist/rules/no-return-in-arrow.d.ts +6 -0
- package/dist/rules/no-return-in-arrow.js +41 -0
- package/dist/rules/no-return-nullish.d.ts +6 -0
- package/dist/rules/no-return-nullish.js +47 -0
- package/dist/rules/no-run-in-effect-gen.d.ts +6 -0
- package/dist/rules/no-run-in-effect-gen.js +48 -0
- package/dist/rules/no-runtime-run-fork.d.ts +6 -0
- package/dist/rules/no-runtime-run-fork.js +19 -0
- package/dist/rules/no-schema-struct-with-tag.d.ts +6 -0
- package/dist/rules/no-schema-struct-with-tag.js +48 -0
- package/dist/rules/no-schema-union-of-literals.d.ts +6 -0
- package/dist/rules/no-schema-union-of-literals.js +35 -0
- package/dist/rules/no-string-sentinel-const.d.ts +6 -0
- package/dist/rules/no-string-sentinel-const.js +38 -0
- package/dist/rules/no-switch-statement.d.ts +6 -0
- package/dist/rules/no-switch-statement.js +16 -0
- package/dist/rules/no-ternary.d.ts +6 -0
- package/dist/rules/no-ternary.js +30 -0
- package/dist/rules/no-throw-statement.d.ts +6 -0
- package/dist/rules/no-throw-statement.js +34 -0
- package/dist/rules/no-try-catch.d.ts +6 -0
- package/dist/rules/no-try-catch.js +34 -0
- package/dist/rules/no-unnecessary-arrow-block.d.ts +6 -0
- package/dist/rules/no-unnecessary-arrow-block.js +34 -0
- package/dist/rules/no-unnecessary-effect-gen.d.ts +6 -0
- package/dist/rules/no-unnecessary-effect-gen.js +35 -0
- package/dist/rules/no-unnecessary-pipe-chain.d.ts +6 -0
- package/dist/rules/no-unnecessary-pipe-chain.js +36 -0
- package/dist/rules/no-unnecessary-pipe.d.ts +6 -0
- package/dist/rules/no-unnecessary-pipe.js +29 -0
- package/dist/vendor/effect-oxlint/AST.d.ts +199 -0
- package/dist/vendor/effect-oxlint/AST.js +214 -0
- package/dist/vendor/effect-oxlint/Comment.d.ts +55 -0
- package/dist/vendor/effect-oxlint/Comment.js +67 -0
- package/dist/vendor/effect-oxlint/Diagnostic.d.ts +86 -0
- package/dist/vendor/effect-oxlint/Diagnostic.js +115 -0
- package/dist/vendor/effect-oxlint/Plugin.d.ts +38 -0
- package/dist/vendor/effect-oxlint/Plugin.js +45 -0
- package/dist/vendor/effect-oxlint/Rule.d.ts +218 -0
- package/dist/vendor/effect-oxlint/Rule.js +309 -0
- package/dist/vendor/effect-oxlint/RuleContext.d.ts +77 -0
- package/dist/vendor/effect-oxlint/RuleContext.js +74 -0
- package/dist/vendor/effect-oxlint/Scope.d.ts +100 -0
- package/dist/vendor/effect-oxlint/Scope.js +110 -0
- package/dist/vendor/effect-oxlint/SourceCode.d.ts +180 -0
- package/dist/vendor/effect-oxlint/SourceCode.js +203 -0
- package/dist/vendor/effect-oxlint/Testing.d.ts +510 -0
- package/dist/vendor/effect-oxlint/Testing.js +963 -0
- package/dist/vendor/effect-oxlint/Token.d.ts +98 -0
- package/dist/vendor/effect-oxlint/Token.js +103 -0
- package/dist/vendor/effect-oxlint/Visitor.d.ts +166 -0
- package/dist/vendor/effect-oxlint/Visitor.js +138 -0
- package/dist/vendor/effect-oxlint/index.d.ts +13 -0
- package/dist/vendor/effect-oxlint/index.js +12 -0
- package/package.json +24 -5
- package/.effect-lsp.json +0 -60
- package/.oxlintrc.json +0 -33
- package/CHANGELOG.md +0 -55
- package/scripts/add-rule.ts +0 -87
- package/scripts/codegen.ts +0 -108
- package/src/index.ts +0 -9
- package/src/plugin.ts +0 -16
- package/src/presets/core.ts +0 -47
- package/src/presets/effect-native.ts +0 -34
- package/src/presets/full.ts +0 -70
- package/src/presets/functional.ts +0 -18
- package/src/presets/index.ts +0 -5
- package/src/presets/strict.ts +0 -77
- package/src/rules/_effect-context.ts +0 -28
- package/src/rules/index.ts +0 -72
- package/src/rules/no-arrow-ladder.ts +0 -70
- package/src/rules/no-async-function.ts +0 -47
- package/src/rules/no-catch-all-to-map-error.ts +0 -90
- package/src/rules/no-effect-as.ts +0 -14
- package/src/rules/no-effect-async.ts +0 -14
- package/src/rules/no-effect-bind.ts +0 -13
- package/src/rules/no-effect-do.ts +0 -14
- package/src/rules/no-effect-fn-generator.ts +0 -58
- package/src/rules/no-effect-gen-adapter.ts +0 -51
- package/src/rules/no-effect-map-flatten.ts +0 -82
- package/src/rules/no-effect-map-void.ts +0 -80
- package/src/rules/no-effect-never.ts +0 -14
- package/src/rules/no-effect-orElse-ladder.ts +0 -79
- package/src/rules/no-effect-succeed-string.ts +0 -52
- package/src/rules/no-effect-succeed-variable.ts +0 -50
- package/src/rules/no-effect-succeed-void.ts +0 -63
- package/src/rules/no-effect-sync-console.ts +0 -91
- package/src/rules/no-effect-sync-wrapper.ts +0 -67
- package/src/rules/no-effect-type-alias.ts +0 -71
- package/src/rules/no-effect-wrapper-alias.ts +0 -95
- package/src/rules/no-extends-native-error.ts +0 -54
- package/src/rules/no-flatmap-ladder.ts +0 -77
- package/src/rules/no-fromnullable-coalesce.ts +0 -62
- package/src/rules/no-global-error-in-catch.ts +0 -104
- package/src/rules/no-global-error-in-failure.ts +0 -83
- package/src/rules/no-globals.ts +0 -178
- package/src/rules/no-if-statement.ts +0 -16
- package/src/rules/no-iife-wrapper.ts +0 -51
- package/src/rules/no-inline-provide.ts +0 -41
- package/src/rules/no-instanceof-schema.ts +0 -42
- package/src/rules/no-manual-effect-channels.ts +0 -58
- package/src/rules/no-match-effect-branch.ts +0 -82
- package/src/rules/no-match-void-branch.ts +0 -72
- package/src/rules/no-multiple-effect-provide.ts +0 -75
- package/src/rules/no-nested-effect-call.ts +0 -57
- package/src/rules/no-nested-effect-gen.ts +0 -43
- package/src/rules/no-nested-pipe.ts +0 -73
- package/src/rules/no-new-error.ts +0 -53
- package/src/rules/no-new-promise.ts +0 -50
- package/src/rules/no-node-builtin-import.ts +0 -68
- package/src/rules/no-option-as.ts +0 -13
- package/src/rules/no-option-boolean-normalization.ts +0 -88
- package/src/rules/no-positional-log-error.ts +0 -76
- package/src/rules/no-redundant-schema-tag-identifier.ts +0 -62
- package/src/rules/no-return-in-arrow.ts +0 -76
- package/src/rules/no-return-nullish.ts +0 -80
- package/src/rules/no-run-in-effect-gen.ts +0 -66
- package/src/rules/no-runtime-run-fork.ts +0 -14
- package/src/rules/no-schema-struct-with-tag.ts +0 -64
- package/src/rules/no-schema-union-of-literals.ts +0 -48
- package/src/rules/no-string-sentinel-const.ts +0 -49
- package/src/rules/no-switch-statement.ts +0 -13
- package/src/rules/no-ternary.ts +0 -30
- package/src/rules/no-throw-statement.ts +0 -39
- package/src/rules/no-try-catch.ts +0 -39
- package/src/rules/no-unnecessary-arrow-block.ts +0 -51
- package/src/rules/no-unnecessary-effect-gen.ts +0 -83
- package/src/rules/no-unnecessary-pipe-chain.ts +0 -47
- package/src/rules/no-unnecessary-pipe.ts +0 -45
- package/src/vendor/effect-oxlint/AST.ts +0 -516
- package/src/vendor/effect-oxlint/Comment.ts +0 -86
- package/src/vendor/effect-oxlint/Diagnostic.ts +0 -199
- package/src/vendor/effect-oxlint/Plugin.ts +0 -71
- package/src/vendor/effect-oxlint/Rule.ts +0 -548
- package/src/vendor/effect-oxlint/RuleContext.ts +0 -144
- package/src/vendor/effect-oxlint/Scope.ts +0 -177
- package/src/vendor/effect-oxlint/SourceCode.ts +0 -377
- package/src/vendor/effect-oxlint/Testing.ts +0 -1227
- package/src/vendor/effect-oxlint/Token.ts +0 -131
- package/src/vendor/effect-oxlint/Visitor.ts +0 -287
- package/src/vendor/effect-oxlint/index.ts +0 -88
- package/tests/ban-rules.test.ts +0 -68
- package/tests/context-rules.test.ts +0 -263
- package/tests/pattern-rules.test.ts +0 -247
- package/tsconfig.json +0 -15
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban redundant `_tag` in `Schema.TaggedStruct("Foo", { _tag: Schema.Literal("Foo") })`.
|
|
3
|
-
*
|
|
4
|
-
* `TaggedStruct` already provides `_tag` automatically.
|
|
5
|
-
*
|
|
6
|
-
* Source: language-service/redundantSchemaTagIdentifier
|
|
7
|
-
*/
|
|
8
|
-
import type { ESTree } from "@oxlint/plugins"
|
|
9
|
-
import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
10
|
-
import * as Effect from "effect/Effect"
|
|
11
|
-
import * as Option from "effect/Option"
|
|
12
|
-
|
|
13
|
-
const isTagKey = (key: ESTree.Node): boolean => {
|
|
14
|
-
if (key.type === "Identifier" && "name" in key && key.name === "_tag") return true
|
|
15
|
-
if (key.type === "Literal" && "value" in key && key.value === "_tag") return true
|
|
16
|
-
return false
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const noRedundantSchemaTagIdentifier = Rule.define({
|
|
20
|
-
name: "no-redundant-schema-tag-identifier",
|
|
21
|
-
meta: Rule.meta({
|
|
22
|
-
type: "suggestion",
|
|
23
|
-
description:
|
|
24
|
-
"Redundant _tag in TaggedStruct. TaggedStruct already provides _tag automatically.",
|
|
25
|
-
}),
|
|
26
|
-
create: function* () {
|
|
27
|
-
const ctx = yield* RuleContext
|
|
28
|
-
return {
|
|
29
|
-
CallExpression: (node) => {
|
|
30
|
-
const call = node as ESTree.CallExpression
|
|
31
|
-
if (Option.isNone(AST.matchCallOf(call, "Schema", "TaggedStruct"))) return Effect.void
|
|
32
|
-
|
|
33
|
-
// TaggedStruct("tag", { fields })
|
|
34
|
-
const args = call.arguments
|
|
35
|
-
if (args.length < 2) return Effect.void
|
|
36
|
-
const fieldsArg = args[1]
|
|
37
|
-
if (fieldsArg === undefined) return Effect.void
|
|
38
|
-
if (fieldsArg.type !== "ObjectExpression") return Effect.void
|
|
39
|
-
|
|
40
|
-
const props = (fieldsArg as unknown as Record<string, unknown>)["properties"]
|
|
41
|
-
if (!Array.isArray(props)) return Effect.void
|
|
42
|
-
|
|
43
|
-
for (const prop of props) {
|
|
44
|
-
const p = prop as ESTree.Node
|
|
45
|
-
if (p.type !== "Property") continue
|
|
46
|
-
const key = (p as unknown as Record<string, unknown>)["key"] as ESTree.Node
|
|
47
|
-
if (isTagKey(key)) {
|
|
48
|
-
return ctx.report(
|
|
49
|
-
Diagnostic.make({
|
|
50
|
-
node: p,
|
|
51
|
-
message:
|
|
52
|
-
"Redundant _tag property. Schema.TaggedStruct already provides _tag automatically.",
|
|
53
|
-
}),
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return Effect.void
|
|
59
|
-
},
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
})
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban explicit `return` in arrow function callbacks (info severity).
|
|
3
|
-
*
|
|
4
|
-
* Use expression-only callbacks + pipeline logic.
|
|
5
|
-
* Excludes Schema.filter callbacks where return is required.
|
|
6
|
-
*
|
|
7
|
-
* Source: biome-effect-linting-rules/no-return-in-arrow
|
|
8
|
-
*/
|
|
9
|
-
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
10
|
-
import * as Effect from "effect/Effect"
|
|
11
|
-
|
|
12
|
-
export const noReturnInArrow = Rule.define({
|
|
13
|
-
name: "no-return-in-arrow",
|
|
14
|
-
meta: Rule.meta({
|
|
15
|
-
type: "suggestion",
|
|
16
|
-
description: "Prefer expression-only arrow callbacks. Avoid explicit return in arrow functions.",
|
|
17
|
-
}),
|
|
18
|
-
create: function* () {
|
|
19
|
-
const ctx = yield* RuleContext
|
|
20
|
-
return {
|
|
21
|
-
ArrowFunctionExpression: (node) => {
|
|
22
|
-
if (
|
|
23
|
-
"body" in node &&
|
|
24
|
-
node.body != null &&
|
|
25
|
-
typeof node.body === "object" &&
|
|
26
|
-
"type" in node.body &&
|
|
27
|
-
node.body.type === "BlockStatement" &&
|
|
28
|
-
"body" in node.body &&
|
|
29
|
-
Array.isArray(node.body.body)
|
|
30
|
-
) {
|
|
31
|
-
for (const stmt of node.body.body) {
|
|
32
|
-
if (
|
|
33
|
-
stmt != null &&
|
|
34
|
-
typeof stmt === "object" &&
|
|
35
|
-
"type" in stmt &&
|
|
36
|
-
stmt.type === "ReturnStatement"
|
|
37
|
-
) {
|
|
38
|
-
// Check if parent is a Schema.filter call — skip those
|
|
39
|
-
if (
|
|
40
|
-
"parent" in node &&
|
|
41
|
-
node.parent != null &&
|
|
42
|
-
typeof node.parent === "object" &&
|
|
43
|
-
"type" in node.parent &&
|
|
44
|
-
node.parent.type === "CallExpression" &&
|
|
45
|
-
"callee" in node.parent
|
|
46
|
-
) {
|
|
47
|
-
const callee = node.parent.callee
|
|
48
|
-
if (
|
|
49
|
-
callee != null &&
|
|
50
|
-
typeof callee === "object" &&
|
|
51
|
-
"type" in callee &&
|
|
52
|
-
callee.type === "MemberExpression" &&
|
|
53
|
-
"property" in callee &&
|
|
54
|
-
callee.property != null &&
|
|
55
|
-
typeof callee.property === "object" &&
|
|
56
|
-
"name" in callee.property &&
|
|
57
|
-
(callee.property.name === "filter" || callee.property.name === "check")
|
|
58
|
-
) {
|
|
59
|
-
return Effect.void
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return ctx.report(
|
|
64
|
-
Diagnostic.make({
|
|
65
|
-
node: stmt,
|
|
66
|
-
message: "Prefer expression-only arrow callbacks over explicit return.",
|
|
67
|
-
}),
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return Effect.void
|
|
73
|
-
},
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
})
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `return null`, `return undefined`, `return void 0`. Context-aware messaging.
|
|
3
|
-
*
|
|
4
|
-
* Inside Effect.gen/fn: "Use Option.none() or Effect.void"
|
|
5
|
-
* Outside: "Use Option.none() — convert nullish at system boundaries with Option.fromNullable"
|
|
6
|
-
*
|
|
7
|
-
* Source: biome-effect-linting-rules/no-return-null (extended)
|
|
8
|
-
*/
|
|
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"
|
|
12
|
-
|
|
13
|
-
import { makeEffectContextTracker } from "./_effect-context.js"
|
|
14
|
-
|
|
15
|
-
export const noReturnNullish = Rule.define({
|
|
16
|
-
name: "no-return-nullish",
|
|
17
|
-
meta: Rule.meta({
|
|
18
|
-
type: "suggestion",
|
|
19
|
-
description:
|
|
20
|
-
"Avoid returning null/undefined. Use Option.none() for absence or Effect.void for void effects.",
|
|
21
|
-
}),
|
|
22
|
-
create: function* () {
|
|
23
|
-
const ctx = yield* RuleContext
|
|
24
|
-
const [depth, tracker] = yield* makeEffectContextTracker
|
|
25
|
-
|
|
26
|
-
return Visitor.merge(tracker, {
|
|
27
|
-
ReturnStatement: (node) =>
|
|
28
|
-
Effect.flatMap(Ref.get(depth), (d) => {
|
|
29
|
-
if (
|
|
30
|
-
node.type !== "ReturnStatement" ||
|
|
31
|
-
!("argument" in node) ||
|
|
32
|
-
node.argument === null ||
|
|
33
|
-
node.argument === undefined
|
|
34
|
-
) {
|
|
35
|
-
return Effect.void
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const arg = node.argument as unknown as Record<string, unknown>
|
|
39
|
-
|
|
40
|
-
// return null
|
|
41
|
-
if (arg["type"] === "Literal" && arg["value"] === null) {
|
|
42
|
-
return ctx.report(
|
|
43
|
-
Diagnostic.make({
|
|
44
|
-
node,
|
|
45
|
-
message: d > 0
|
|
46
|
-
? "Avoid returning null inside Effect.gen/fn. Use Option.none() for absence, or yield* Effect.fail(new MyError()) for errors."
|
|
47
|
-
: "Avoid returning null. Use Option.none() for absence — convert nullish values at system boundaries with Option.fromNullable().",
|
|
48
|
-
}),
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// return undefined
|
|
53
|
-
if (arg["type"] === "Identifier" && arg["name"] === "undefined") {
|
|
54
|
-
return ctx.report(
|
|
55
|
-
Diagnostic.make({
|
|
56
|
-
node,
|
|
57
|
-
message: d > 0
|
|
58
|
-
? "Avoid returning undefined inside Effect.gen/fn. Use Effect.void for void effects, or Option.none() for absence."
|
|
59
|
-
: "Avoid returning undefined. Use Option.none() for absence, or restructure as an Effect returning void.",
|
|
60
|
-
}),
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// return void 0
|
|
65
|
-
if (arg["type"] === "UnaryExpression" && arg["operator"] === "void") {
|
|
66
|
-
return ctx.report(
|
|
67
|
-
Diagnostic.make({
|
|
68
|
-
node,
|
|
69
|
-
message: d > 0
|
|
70
|
-
? "Avoid returning void inside Effect.gen/fn. Use Effect.void for void effects."
|
|
71
|
-
: "Avoid returning void expression. Use Option.none() for absence.",
|
|
72
|
-
}),
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return Effect.void
|
|
77
|
-
}),
|
|
78
|
-
})
|
|
79
|
-
},
|
|
80
|
-
})
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `Effect.run*` and `Runtime.run*` calls inside `Effect.gen`/`Effect.fn`.
|
|
3
|
-
*
|
|
4
|
-
* Running an effect inside a generator drops the ambient context — fibers,
|
|
5
|
-
* services, tracing, and memoized layers. Just `yield*` the child effect;
|
|
6
|
-
* for callback boundaries use `Effect.async`, for fork use `Effect.fork`.
|
|
7
|
-
*
|
|
8
|
-
* Explicitly allowed inside gen: `Effect.runForkWith`, `Effect.runPromiseWith`,
|
|
9
|
-
* `Effect.runSyncWith` (they take services explicitly — legitimate at
|
|
10
|
-
* callback boundaries) and `managedRuntime.runX` on identifier callees
|
|
11
|
-
* (can't be discriminated syntactically).
|
|
12
|
-
*
|
|
13
|
-
* Source: language-service/runEffectInsideEffect, extended for v4.
|
|
14
|
-
*/
|
|
15
|
-
import type { ESTree } from "@oxlint/plugins"
|
|
16
|
-
import { AST, Diagnostic, Rule, Visitor, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
17
|
-
import * as Effect from "effect/Effect"
|
|
18
|
-
import * as Ref from "effect/Ref"
|
|
19
|
-
|
|
20
|
-
import { makeEffectContextTracker } from "./_effect-context.js"
|
|
21
|
-
|
|
22
|
-
const effectRunMethods = ["runSync", "runPromise", "runFork", "runCallback"]
|
|
23
|
-
const runtimeRunMethods = ["runSync", "runPromise", "runFork", "runCallback"]
|
|
24
|
-
|
|
25
|
-
export const noRunInEffectGen = Rule.define({
|
|
26
|
-
name: "no-run-in-effect-gen",
|
|
27
|
-
meta: Rule.meta({
|
|
28
|
-
type: "problem",
|
|
29
|
-
description:
|
|
30
|
-
"Running effects inside Effect.gen/fn drops the ambient context. Use yield* instead.",
|
|
31
|
-
}),
|
|
32
|
-
create: function* () {
|
|
33
|
-
const ctx = yield* RuleContext
|
|
34
|
-
const [depth, tracker] = yield* makeEffectContextTracker
|
|
35
|
-
|
|
36
|
-
return Visitor.merge(tracker, {
|
|
37
|
-
CallExpression: (node) =>
|
|
38
|
-
Effect.flatMap(Ref.get(depth), (d) => {
|
|
39
|
-
if (d <= 0) return Effect.void
|
|
40
|
-
const call = node as ESTree.CallExpression
|
|
41
|
-
|
|
42
|
-
if (AST.isCallOf(call, "Effect", effectRunMethods)) {
|
|
43
|
-
return ctx.report(
|
|
44
|
-
Diagnostic.make({
|
|
45
|
-
node,
|
|
46
|
-
message:
|
|
47
|
-
"Avoid Effect.run* inside Effect.gen/fn. `yield*` the child effect, or use Effect.fork for concurrency.",
|
|
48
|
-
}),
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (AST.isCallOf(call, "Runtime", runtimeRunMethods)) {
|
|
53
|
-
return ctx.report(
|
|
54
|
-
Diagnostic.make({
|
|
55
|
-
node,
|
|
56
|
-
message:
|
|
57
|
-
"Avoid Runtime.run* inside Effect.gen/fn. The ambient context already has your services — `yield*` the child effect.",
|
|
58
|
-
}),
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return Effect.void
|
|
63
|
-
}),
|
|
64
|
-
})
|
|
65
|
-
},
|
|
66
|
-
})
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `Runtime.runFork`.
|
|
3
|
-
*
|
|
4
|
-
* Use `forkScoped`, `Stream`, or runtime-provided layers.
|
|
5
|
-
*
|
|
6
|
-
* Source: biome-effect-linting-rules/no-runtime-runfork
|
|
7
|
-
*/
|
|
8
|
-
import { Rule } from "../vendor/effect-oxlint/index.js"
|
|
9
|
-
|
|
10
|
-
export const noRuntimeRunFork = Rule.banMember("Runtime", "runFork", {
|
|
11
|
-
message:
|
|
12
|
-
"Avoid Runtime.runFork. Use forkScoped, Stream, or runtime-provided layers.",
|
|
13
|
-
meta: { type: "problem", effectVersion: "v3" },
|
|
14
|
-
})
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `Schema.Struct({ _tag: Schema.Literal("Foo"), ... })`.
|
|
3
|
-
* Use `Schema.TaggedStruct("Foo", { ... })` instead.
|
|
4
|
-
*
|
|
5
|
-
* Source: language-service/schemaStructWithTag
|
|
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 isTagKey = (key: ESTree.Node): boolean => {
|
|
13
|
-
if (key.type === "Identifier" && "name" in key && key.name === "_tag") return true
|
|
14
|
-
if (key.type === "Literal" && "value" in key && key.value === "_tag") return true
|
|
15
|
-
return false
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const noSchemaStructWithTag = Rule.define({
|
|
19
|
-
name: "no-schema-struct-with-tag",
|
|
20
|
-
meta: Rule.meta({
|
|
21
|
-
type: "suggestion",
|
|
22
|
-
description:
|
|
23
|
-
'Use Schema.TaggedStruct("Tag", { ... }) instead of Schema.Struct({ _tag: Schema.Literal("Tag"), ... }).',
|
|
24
|
-
}),
|
|
25
|
-
create: function* () {
|
|
26
|
-
const ctx = yield* RuleContext
|
|
27
|
-
return {
|
|
28
|
-
CallExpression: (node) => {
|
|
29
|
-
const call = node as ESTree.CallExpression
|
|
30
|
-
if (Option.isNone(AST.matchCallOf(call, "Schema", "Struct"))) return Effect.void
|
|
31
|
-
|
|
32
|
-
const args = call.arguments
|
|
33
|
-
if (args.length !== 1) return Effect.void
|
|
34
|
-
const arg = args[0]
|
|
35
|
-
if (arg === undefined) return Effect.void
|
|
36
|
-
if (arg.type !== "ObjectExpression") return Effect.void
|
|
37
|
-
|
|
38
|
-
const props = (arg as unknown as Record<string, unknown>)["properties"]
|
|
39
|
-
if (!Array.isArray(props)) return Effect.void
|
|
40
|
-
|
|
41
|
-
for (const prop of props) {
|
|
42
|
-
const p = prop as ESTree.Node
|
|
43
|
-
if (p.type !== "Property") continue
|
|
44
|
-
const key = (p as unknown as Record<string, unknown>)["key"] as ESTree.Node
|
|
45
|
-
if (!isTagKey(key)) continue
|
|
46
|
-
|
|
47
|
-
// Check value is Schema.Literal(...)
|
|
48
|
-
const value = (p as unknown as Record<string, unknown>)["value"] as ESTree.Node
|
|
49
|
-
if (value.type === "CallExpression" && Option.isSome(AST.matchCallOf(value as ESTree.CallExpression, "Schema", "Literal"))) {
|
|
50
|
-
return ctx.report(
|
|
51
|
-
Diagnostic.make({
|
|
52
|
-
node,
|
|
53
|
-
message:
|
|
54
|
-
'Use Schema.TaggedStruct("Tag", { ... }) instead of Schema.Struct({ _tag: Schema.Literal(...), ... }).',
|
|
55
|
-
}),
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return Effect.void
|
|
61
|
-
},
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
})
|
|
@@ -1,48 +0,0 @@
|
|
|
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
|
-
})
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `const x = "some-string"` string literal const declarations.
|
|
3
|
-
*
|
|
4
|
-
* Use tagged unions, Option, or meaningful domain values.
|
|
5
|
-
*
|
|
6
|
-
* Source: biome-effect-linting-rules/no-string-sentinel-const
|
|
7
|
-
*
|
|
8
|
-
* Note: Very aggressive — should probably be off by default or in a strict preset only.
|
|
9
|
-
*/
|
|
10
|
-
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
11
|
-
import * as Effect from "effect/Effect"
|
|
12
|
-
|
|
13
|
-
export const noStringSentinelConst = Rule.define({
|
|
14
|
-
name: "no-string-sentinel-const",
|
|
15
|
-
meta: Rule.meta({
|
|
16
|
-
type: "suggestion",
|
|
17
|
-
description: "Avoid string literal const declarations. Use tagged unions or domain values.",
|
|
18
|
-
}),
|
|
19
|
-
create: function* () {
|
|
20
|
-
const ctx = yield* RuleContext
|
|
21
|
-
return {
|
|
22
|
-
VariableDeclarator: (node) => {
|
|
23
|
-
if (!("init" in node) || node.init == null) return Effect.void
|
|
24
|
-
const init = node.init as unknown as Record<string, unknown>
|
|
25
|
-
|
|
26
|
-
if (init["type"] === "Literal" && typeof init["value"] === "string") {
|
|
27
|
-
// Check parent is const declaration
|
|
28
|
-
if (
|
|
29
|
-
"parent" in node &&
|
|
30
|
-
node.parent != null &&
|
|
31
|
-
typeof node.parent === "object" &&
|
|
32
|
-
"type" in node.parent &&
|
|
33
|
-
node.parent.type === "VariableDeclaration" &&
|
|
34
|
-
"kind" in node.parent &&
|
|
35
|
-
node.parent.kind === "const"
|
|
36
|
-
) {
|
|
37
|
-
return ctx.report(
|
|
38
|
-
Diagnostic.make({
|
|
39
|
-
node,
|
|
40
|
-
message: "Avoid string literal const. Use tagged unions, Option, or domain values.",
|
|
41
|
-
}),
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return Effect.void
|
|
46
|
-
},
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
})
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `switch` statements.
|
|
3
|
-
*
|
|
4
|
-
* Use `Match.value`, `Option.match`, `Either.match` instead.
|
|
5
|
-
*
|
|
6
|
-
* Source: biome-effect-linting-rules/no-switch-statement
|
|
7
|
-
*/
|
|
8
|
-
import { Rule } from "../vendor/effect-oxlint/index.js"
|
|
9
|
-
|
|
10
|
-
export const noSwitchStatement = Rule.banStatement("SwitchStatement", {
|
|
11
|
-
message: "Avoid switch statements. Use Match.value, Option.match, or Either.match.",
|
|
12
|
-
meta: { type: "suggestion" },
|
|
13
|
-
})
|
package/src/rules/no-ternary.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban ternary expressions in Effect codebases.
|
|
3
|
-
*
|
|
4
|
-
* Use `Option.match`, `Either.match`, `Match.value` instead.
|
|
5
|
-
*
|
|
6
|
-
* Source: biome-effect-linting-rules/no-ternary
|
|
7
|
-
*
|
|
8
|
-
* Note: Very opinionated — recommended for strict functional presets only.
|
|
9
|
-
*/
|
|
10
|
-
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
11
|
-
|
|
12
|
-
export const noTernary = Rule.define({
|
|
13
|
-
name: "no-ternary",
|
|
14
|
-
meta: Rule.meta({
|
|
15
|
-
type: "suggestion",
|
|
16
|
-
description: "Avoid ternary expressions. Use Option.match, Either.match, or Match.value.",
|
|
17
|
-
}),
|
|
18
|
-
create: function* () {
|
|
19
|
-
const ctx = yield* RuleContext
|
|
20
|
-
return {
|
|
21
|
-
ConditionalExpression: (node) =>
|
|
22
|
-
ctx.report(
|
|
23
|
-
Diagnostic.make({
|
|
24
|
-
node,
|
|
25
|
-
message: "Avoid ternary expressions. Use Option.match, Either.match, or Match.value.",
|
|
26
|
-
}),
|
|
27
|
-
),
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
})
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `throw` statements. Context-aware messaging.
|
|
3
|
-
*
|
|
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"
|
|
6
|
-
*
|
|
7
|
-
* Source: effect convention — errors should be in the type system
|
|
8
|
-
*/
|
|
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"
|
|
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
|
-
},
|
|
39
|
-
})
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `try/catch` statements. Context-aware messaging.
|
|
3
|
-
*
|
|
4
|
-
* Inside Effect.gen/fn: "Use Effect.try or Effect.tryPromise"
|
|
5
|
-
* Outside: "Wrap with Effect.fn and use Effect.try for error handling"
|
|
6
|
-
*
|
|
7
|
-
* Source: biome-effect-linting-rules/no-try-catch, language-service/tryCatchInEffectGen
|
|
8
|
-
*/
|
|
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"
|
|
12
|
-
|
|
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
|
-
},
|
|
39
|
-
})
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ban `() => { return x }` — use `() => x` instead.
|
|
3
|
-
*
|
|
4
|
-
* Source: language-service/unnecessaryArrowBlock
|
|
5
|
-
*/
|
|
6
|
-
import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
|
|
7
|
-
import * as Effect from "effect/Effect"
|
|
8
|
-
|
|
9
|
-
export const noUnnecessaryArrowBlock = Rule.define({
|
|
10
|
-
name: "no-unnecessary-arrow-block",
|
|
11
|
-
meta: Rule.meta({
|
|
12
|
-
type: "suggestion",
|
|
13
|
-
description: "Unnecessary arrow block body. Use concise arrow `() => expr`.",
|
|
14
|
-
fixable: "code",
|
|
15
|
-
}),
|
|
16
|
-
create: function* () {
|
|
17
|
-
const ctx = yield* RuleContext
|
|
18
|
-
return {
|
|
19
|
-
ArrowFunctionExpression: (node) => {
|
|
20
|
-
if (
|
|
21
|
-
"body" in node &&
|
|
22
|
-
node.body != null &&
|
|
23
|
-
typeof node.body === "object" &&
|
|
24
|
-
"type" in node.body &&
|
|
25
|
-
node.body.type === "BlockStatement" &&
|
|
26
|
-
"body" in node.body &&
|
|
27
|
-
Array.isArray(node.body.body) &&
|
|
28
|
-
node.body.body.length === 1
|
|
29
|
-
) {
|
|
30
|
-
const stmt = node.body.body[0]
|
|
31
|
-
if (
|
|
32
|
-
stmt != null &&
|
|
33
|
-
typeof stmt === "object" &&
|
|
34
|
-
"type" in stmt &&
|
|
35
|
-
stmt.type === "ReturnStatement" &&
|
|
36
|
-
"argument" in stmt &&
|
|
37
|
-
stmt.argument != null
|
|
38
|
-
) {
|
|
39
|
-
return ctx.report(
|
|
40
|
-
Diagnostic.make({
|
|
41
|
-
node,
|
|
42
|
-
message: "Unnecessary arrow block body. Use `() => expr` instead of `() => { return expr }`.",
|
|
43
|
-
}),
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return Effect.void
|
|
48
|
-
},
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
})
|