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.
Files changed (258) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +13 -0
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.js +4 -0
  4. package/dist/plugin.d.ts +5 -0
  5. package/dist/plugin.js +18 -0
  6. package/dist/presets/core.d.ts +43 -0
  7. package/dist/presets/core.js +43 -0
  8. package/dist/presets/effect-native.d.ts +28 -0
  9. package/dist/presets/effect-native.js +28 -0
  10. package/dist/presets/full.d.ts +60 -0
  11. package/dist/presets/full.js +60 -0
  12. package/dist/presets/functional.d.ts +21 -0
  13. package/dist/presets/functional.js +21 -0
  14. package/dist/presets/index.d.ts +14 -0
  15. package/dist/presets/index.js +20 -0
  16. package/dist/presets/strict.d.ts +64 -0
  17. package/dist/presets/strict.js +64 -0
  18. package/dist/presets/v3-strict.d.ts +16 -0
  19. package/dist/presets/v3-strict.js +16 -0
  20. package/dist/presets/v3.d.ts +18 -0
  21. package/dist/presets/v3.js +18 -0
  22. package/dist/rules/_effect-context.d.ts +19 -0
  23. package/dist/rules/_effect-context.js +22 -0
  24. package/dist/rules/index.d.ts +66 -0
  25. package/dist/rules/index.js +124 -0
  26. package/dist/rules/no-arrow-ladder.d.ts +6 -0
  27. package/dist/rules/no-arrow-ladder.js +61 -0
  28. package/dist/rules/no-async-function.d.ts +6 -0
  29. package/dist/rules/no-async-function.js +46 -0
  30. package/dist/rules/no-catch-all-to-map-error.d.ts +6 -0
  31. package/dist/rules/no-catch-all-to-map-error.js +67 -0
  32. package/dist/rules/no-effect-as.d.ts +6 -0
  33. package/dist/rules/no-effect-as.js +16 -0
  34. package/dist/rules/no-effect-async.d.ts +6 -0
  35. package/dist/rules/no-effect-async.js +16 -0
  36. package/dist/rules/no-effect-bind.d.ts +6 -0
  37. package/dist/rules/no-effect-bind.js +16 -0
  38. package/dist/rules/no-effect-do.d.ts +6 -0
  39. package/dist/rules/no-effect-do.js +16 -0
  40. package/dist/rules/no-effect-fn-generator.d.ts +6 -0
  41. package/dist/rules/no-effect-fn-generator.js +30 -0
  42. package/dist/rules/no-effect-gen-adapter.d.ts +6 -0
  43. package/dist/rules/no-effect-gen-adapter.js +30 -0
  44. package/dist/rules/no-effect-map-flatten.d.ts +6 -0
  45. package/dist/rules/no-effect-map-flatten.js +53 -0
  46. package/dist/rules/no-effect-map-void.d.ts +6 -0
  47. package/dist/rules/no-effect-map-void.js +40 -0
  48. package/dist/rules/no-effect-never.d.ts +6 -0
  49. package/dist/rules/no-effect-never.js +16 -0
  50. package/dist/rules/no-effect-orElse-ladder.d.ts +6 -0
  51. package/dist/rules/no-effect-orElse-ladder.js +53 -0
  52. package/dist/rules/no-effect-succeed-string.d.ts +6 -0
  53. package/dist/rules/no-effect-succeed-string.js +30 -0
  54. package/dist/rules/no-effect-succeed-variable.d.ts +6 -0
  55. package/dist/rules/no-effect-succeed-variable.js +30 -0
  56. package/dist/rules/no-effect-succeed-void.d.ts +6 -0
  57. package/dist/rules/no-effect-succeed-void.js +33 -0
  58. package/dist/rules/no-effect-sync-console.d.ts +6 -0
  59. package/dist/rules/no-effect-sync-console.js +63 -0
  60. package/dist/rules/no-effect-sync-wrapper.d.ts +6 -0
  61. package/dist/rules/no-effect-sync-wrapper.js +37 -0
  62. package/dist/rules/no-effect-type-alias.d.ts +6 -0
  63. package/dist/rules/no-effect-type-alias.js +52 -0
  64. package/dist/rules/no-effect-wrapper-alias.d.ts +6 -0
  65. package/dist/rules/no-effect-wrapper-alias.js +69 -0
  66. package/dist/rules/no-extends-native-error.d.ts +6 -0
  67. package/dist/rules/no-extends-native-error.js +41 -0
  68. package/dist/rules/no-flatmap-ladder.d.ts +6 -0
  69. package/dist/rules/no-flatmap-ladder.js +48 -0
  70. package/dist/rules/no-fromnullable-coalesce.d.ts +6 -0
  71. package/dist/rules/no-fromnullable-coalesce.js +36 -0
  72. package/dist/rules/no-global-error-in-catch.d.ts +6 -0
  73. package/dist/rules/no-global-error-in-catch.js +75 -0
  74. package/dist/rules/no-global-error-in-failure.d.ts +6 -0
  75. package/dist/rules/no-global-error-in-failure.js +54 -0
  76. package/dist/rules/no-globals.d.ts +6 -0
  77. package/dist/rules/no-globals.js +164 -0
  78. package/dist/rules/no-if-statement.d.ts +6 -0
  79. package/dist/rules/no-if-statement.js +18 -0
  80. package/dist/rules/no-iife-wrapper.d.ts +6 -0
  81. package/dist/rules/no-iife-wrapper.js +37 -0
  82. package/dist/rules/no-inline-provide.d.ts +6 -0
  83. package/dist/rules/no-inline-provide.js +31 -0
  84. package/dist/rules/no-instanceof-schema.d.ts +6 -0
  85. package/dist/rules/no-instanceof-schema.js +35 -0
  86. package/dist/rules/no-manual-effect-channels.d.ts +6 -0
  87. package/dist/rules/no-manual-effect-channels.js +40 -0
  88. package/dist/rules/no-match-effect-branch.d.ts +6 -0
  89. package/dist/rules/no-match-effect-branch.js +64 -0
  90. package/dist/rules/no-match-void-branch.d.ts +6 -0
  91. package/dist/rules/no-match-void-branch.js +50 -0
  92. package/dist/rules/no-multiple-effect-provide.d.ts +6 -0
  93. package/dist/rules/no-multiple-effect-provide.js +45 -0
  94. package/dist/rules/no-nested-effect-call.d.ts +6 -0
  95. package/dist/rules/no-nested-effect-call.js +97 -0
  96. package/dist/rules/no-nested-effect-gen.d.ts +6 -0
  97. package/dist/rules/no-nested-effect-gen.js +46 -0
  98. package/dist/rules/no-nested-pipe.d.ts +6 -0
  99. package/dist/rules/no-nested-pipe.js +38 -0
  100. package/dist/rules/no-new-error.d.ts +6 -0
  101. package/dist/rules/no-new-error.js +39 -0
  102. package/dist/rules/no-new-promise.d.ts +6 -0
  103. package/dist/rules/no-new-promise.js +38 -0
  104. package/dist/rules/no-node-builtin-import.d.ts +6 -0
  105. package/dist/rules/no-node-builtin-import.js +61 -0
  106. package/dist/rules/no-option-as.d.ts +6 -0
  107. package/dist/rules/no-option-as.js +16 -0
  108. package/dist/rules/no-option-boolean-normalization.d.ts +6 -0
  109. package/dist/rules/no-option-boolean-normalization.js +50 -0
  110. package/dist/rules/no-positional-log-error.d.ts +6 -0
  111. package/dist/rules/no-positional-log-error.js +52 -0
  112. package/dist/rules/no-redundant-schema-tag-identifier.d.ts +6 -0
  113. package/dist/rules/no-redundant-schema-tag-identifier.js +46 -0
  114. package/dist/rules/no-return-in-arrow.d.ts +6 -0
  115. package/dist/rules/no-return-in-arrow.js +41 -0
  116. package/dist/rules/no-return-nullish.d.ts +6 -0
  117. package/dist/rules/no-return-nullish.js +47 -0
  118. package/dist/rules/no-run-in-effect-gen.d.ts +6 -0
  119. package/dist/rules/no-run-in-effect-gen.js +48 -0
  120. package/dist/rules/no-runtime-run-fork.d.ts +6 -0
  121. package/dist/rules/no-runtime-run-fork.js +19 -0
  122. package/dist/rules/no-schema-struct-with-tag.d.ts +6 -0
  123. package/dist/rules/no-schema-struct-with-tag.js +48 -0
  124. package/dist/rules/no-schema-union-of-literals.d.ts +6 -0
  125. package/dist/rules/no-schema-union-of-literals.js +35 -0
  126. package/dist/rules/no-string-sentinel-const.d.ts +6 -0
  127. package/dist/rules/no-string-sentinel-const.js +38 -0
  128. package/dist/rules/no-switch-statement.d.ts +6 -0
  129. package/dist/rules/no-switch-statement.js +16 -0
  130. package/dist/rules/no-ternary.d.ts +6 -0
  131. package/dist/rules/no-ternary.js +30 -0
  132. package/dist/rules/no-throw-statement.d.ts +6 -0
  133. package/dist/rules/no-throw-statement.js +34 -0
  134. package/dist/rules/no-try-catch.d.ts +6 -0
  135. package/dist/rules/no-try-catch.js +34 -0
  136. package/dist/rules/no-unnecessary-arrow-block.d.ts +6 -0
  137. package/dist/rules/no-unnecessary-arrow-block.js +34 -0
  138. package/dist/rules/no-unnecessary-effect-gen.d.ts +6 -0
  139. package/dist/rules/no-unnecessary-effect-gen.js +35 -0
  140. package/dist/rules/no-unnecessary-pipe-chain.d.ts +6 -0
  141. package/dist/rules/no-unnecessary-pipe-chain.js +36 -0
  142. package/dist/rules/no-unnecessary-pipe.d.ts +6 -0
  143. package/dist/rules/no-unnecessary-pipe.js +29 -0
  144. package/dist/vendor/effect-oxlint/AST.d.ts +199 -0
  145. package/dist/vendor/effect-oxlint/AST.js +214 -0
  146. package/dist/vendor/effect-oxlint/Comment.d.ts +55 -0
  147. package/dist/vendor/effect-oxlint/Comment.js +67 -0
  148. package/dist/vendor/effect-oxlint/Diagnostic.d.ts +86 -0
  149. package/dist/vendor/effect-oxlint/Diagnostic.js +115 -0
  150. package/dist/vendor/effect-oxlint/Plugin.d.ts +38 -0
  151. package/dist/vendor/effect-oxlint/Plugin.js +45 -0
  152. package/dist/vendor/effect-oxlint/Rule.d.ts +218 -0
  153. package/dist/vendor/effect-oxlint/Rule.js +309 -0
  154. package/dist/vendor/effect-oxlint/RuleContext.d.ts +77 -0
  155. package/dist/vendor/effect-oxlint/RuleContext.js +74 -0
  156. package/dist/vendor/effect-oxlint/Scope.d.ts +100 -0
  157. package/dist/vendor/effect-oxlint/Scope.js +110 -0
  158. package/dist/vendor/effect-oxlint/SourceCode.d.ts +180 -0
  159. package/dist/vendor/effect-oxlint/SourceCode.js +203 -0
  160. package/dist/vendor/effect-oxlint/Testing.d.ts +510 -0
  161. package/dist/vendor/effect-oxlint/Testing.js +963 -0
  162. package/dist/vendor/effect-oxlint/Token.d.ts +98 -0
  163. package/dist/vendor/effect-oxlint/Token.js +103 -0
  164. package/dist/vendor/effect-oxlint/Visitor.d.ts +166 -0
  165. package/dist/vendor/effect-oxlint/Visitor.js +138 -0
  166. package/dist/vendor/effect-oxlint/index.d.ts +13 -0
  167. package/dist/vendor/effect-oxlint/index.js +12 -0
  168. package/package.json +24 -5
  169. package/.effect-lsp.json +0 -60
  170. package/.oxlintrc.json +0 -33
  171. package/CHANGELOG.md +0 -55
  172. package/scripts/add-rule.ts +0 -87
  173. package/scripts/codegen.ts +0 -108
  174. package/src/index.ts +0 -9
  175. package/src/plugin.ts +0 -16
  176. package/src/presets/core.ts +0 -47
  177. package/src/presets/effect-native.ts +0 -34
  178. package/src/presets/full.ts +0 -70
  179. package/src/presets/functional.ts +0 -18
  180. package/src/presets/index.ts +0 -5
  181. package/src/presets/strict.ts +0 -77
  182. package/src/rules/_effect-context.ts +0 -28
  183. package/src/rules/index.ts +0 -72
  184. package/src/rules/no-arrow-ladder.ts +0 -70
  185. package/src/rules/no-async-function.ts +0 -47
  186. package/src/rules/no-catch-all-to-map-error.ts +0 -90
  187. package/src/rules/no-effect-as.ts +0 -14
  188. package/src/rules/no-effect-async.ts +0 -14
  189. package/src/rules/no-effect-bind.ts +0 -13
  190. package/src/rules/no-effect-do.ts +0 -14
  191. package/src/rules/no-effect-fn-generator.ts +0 -58
  192. package/src/rules/no-effect-gen-adapter.ts +0 -51
  193. package/src/rules/no-effect-map-flatten.ts +0 -82
  194. package/src/rules/no-effect-map-void.ts +0 -80
  195. package/src/rules/no-effect-never.ts +0 -14
  196. package/src/rules/no-effect-orElse-ladder.ts +0 -79
  197. package/src/rules/no-effect-succeed-string.ts +0 -52
  198. package/src/rules/no-effect-succeed-variable.ts +0 -50
  199. package/src/rules/no-effect-succeed-void.ts +0 -63
  200. package/src/rules/no-effect-sync-console.ts +0 -91
  201. package/src/rules/no-effect-sync-wrapper.ts +0 -67
  202. package/src/rules/no-effect-type-alias.ts +0 -71
  203. package/src/rules/no-effect-wrapper-alias.ts +0 -95
  204. package/src/rules/no-extends-native-error.ts +0 -54
  205. package/src/rules/no-flatmap-ladder.ts +0 -77
  206. package/src/rules/no-fromnullable-coalesce.ts +0 -62
  207. package/src/rules/no-global-error-in-catch.ts +0 -104
  208. package/src/rules/no-global-error-in-failure.ts +0 -83
  209. package/src/rules/no-globals.ts +0 -178
  210. package/src/rules/no-if-statement.ts +0 -16
  211. package/src/rules/no-iife-wrapper.ts +0 -51
  212. package/src/rules/no-inline-provide.ts +0 -41
  213. package/src/rules/no-instanceof-schema.ts +0 -42
  214. package/src/rules/no-manual-effect-channels.ts +0 -58
  215. package/src/rules/no-match-effect-branch.ts +0 -82
  216. package/src/rules/no-match-void-branch.ts +0 -72
  217. package/src/rules/no-multiple-effect-provide.ts +0 -75
  218. package/src/rules/no-nested-effect-call.ts +0 -57
  219. package/src/rules/no-nested-effect-gen.ts +0 -43
  220. package/src/rules/no-nested-pipe.ts +0 -73
  221. package/src/rules/no-new-error.ts +0 -53
  222. package/src/rules/no-new-promise.ts +0 -50
  223. package/src/rules/no-node-builtin-import.ts +0 -68
  224. package/src/rules/no-option-as.ts +0 -13
  225. package/src/rules/no-option-boolean-normalization.ts +0 -88
  226. package/src/rules/no-positional-log-error.ts +0 -76
  227. package/src/rules/no-redundant-schema-tag-identifier.ts +0 -62
  228. package/src/rules/no-return-in-arrow.ts +0 -76
  229. package/src/rules/no-return-nullish.ts +0 -80
  230. package/src/rules/no-run-in-effect-gen.ts +0 -66
  231. package/src/rules/no-runtime-run-fork.ts +0 -14
  232. package/src/rules/no-schema-struct-with-tag.ts +0 -64
  233. package/src/rules/no-schema-union-of-literals.ts +0 -48
  234. package/src/rules/no-string-sentinel-const.ts +0 -49
  235. package/src/rules/no-switch-statement.ts +0 -13
  236. package/src/rules/no-ternary.ts +0 -30
  237. package/src/rules/no-throw-statement.ts +0 -39
  238. package/src/rules/no-try-catch.ts +0 -39
  239. package/src/rules/no-unnecessary-arrow-block.ts +0 -51
  240. package/src/rules/no-unnecessary-effect-gen.ts +0 -83
  241. package/src/rules/no-unnecessary-pipe-chain.ts +0 -47
  242. package/src/rules/no-unnecessary-pipe.ts +0 -45
  243. package/src/vendor/effect-oxlint/AST.ts +0 -516
  244. package/src/vendor/effect-oxlint/Comment.ts +0 -86
  245. package/src/vendor/effect-oxlint/Diagnostic.ts +0 -199
  246. package/src/vendor/effect-oxlint/Plugin.ts +0 -71
  247. package/src/vendor/effect-oxlint/Rule.ts +0 -548
  248. package/src/vendor/effect-oxlint/RuleContext.ts +0 -144
  249. package/src/vendor/effect-oxlint/Scope.ts +0 -177
  250. package/src/vendor/effect-oxlint/SourceCode.ts +0 -377
  251. package/src/vendor/effect-oxlint/Testing.ts +0 -1227
  252. package/src/vendor/effect-oxlint/Token.ts +0 -131
  253. package/src/vendor/effect-oxlint/Visitor.ts +0 -287
  254. package/src/vendor/effect-oxlint/index.ts +0 -88
  255. package/tests/ban-rules.test.ts +0 -68
  256. package/tests/context-rules.test.ts +0 -263
  257. package/tests/pattern-rules.test.ts +0 -247
  258. package/tsconfig.json +0 -15
@@ -1,70 +0,0 @@
1
- /**
2
- * Ban nested IIFE chains — `((x) => ((y) => ...)(arg2))(arg1)`.
3
- *
4
- * Use named const bindings + flat pipeline.
5
- *
6
- * Source: biome-effect-linting-rules/no-arrow-ladder
7
- */
8
- import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
9
- import * as Effect from "effect/Effect"
10
-
11
- const isIife = (node: unknown): boolean => {
12
- if (node == null || typeof node !== "object") return false
13
- const n = node as unknown as Record<string, unknown>
14
- if (n["type"] !== "CallExpression") return false
15
- const callee = n["callee"]
16
- if (callee == null || typeof callee !== "object") return false
17
- const c = callee as unknown as Record<string, unknown>
18
- return c["type"] === "ArrowFunctionExpression" || c["type"] === "FunctionExpression"
19
- }
20
-
21
- const containsIife = (node: unknown): boolean => {
22
- if (node == null || typeof node !== "object") return false
23
- const n = node as unknown as Record<string, unknown>
24
- if (isIife(n)) return true
25
- if ("body" in n) {
26
- if (Array.isArray(n["body"])) {
27
- for (const child of n["body"]) {
28
- if (containsIife(child)) return true
29
- }
30
- } else if (containsIife(n["body"])) return true
31
- }
32
- if ("argument" in n && containsIife(n["argument"])) return true
33
- if ("arguments" in n && Array.isArray(n["arguments"])) {
34
- for (const arg of n["arguments"]) {
35
- if (containsIife(arg)) return true
36
- }
37
- }
38
- if ("expression" in n && containsIife(n["expression"])) return true
39
- return false
40
- }
41
-
42
- export const noArrowLadder = Rule.define({
43
- name: "no-arrow-ladder",
44
- meta: Rule.meta({
45
- type: "suggestion",
46
- description: "Avoid nested IIFE chains. Use named const bindings + flat pipeline.",
47
- }),
48
- create: function* () {
49
- const ctx = yield* RuleContext
50
- return {
51
- CallExpression: (node) => {
52
- if (!isIife(node)) return Effect.void
53
-
54
- // Check if the body of the IIFE itself contains another IIFE
55
- const callee = (node as unknown as Record<string, unknown>)["callee"]
56
- if (callee == null || typeof callee !== "object") return Effect.void
57
- const c = callee as unknown as Record<string, unknown>
58
- if ("body" in c && containsIife(c["body"])) {
59
- return ctx.report(
60
- Diagnostic.make({
61
- node,
62
- message: "Nested IIFE chain detected. Use named const bindings + flat pipeline.",
63
- }),
64
- )
65
- }
66
- return Effect.void
67
- },
68
- }
69
- },
70
- })
@@ -1,47 +0,0 @@
1
- /**
2
- * Ban `async` functions.
3
- *
4
- * Use Effect.promise, Effect.tryPromise, or Effect.gen instead.
5
- *
6
- * Source: language-service/asyncFunction
7
- *
8
- * Note: This is an effectNative rule — off by default.
9
- * Only enable in codebases fully committed to Effect.
10
- */
11
- import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
12
- import * as Effect from "effect/Effect"
13
-
14
- export const noAsyncFunction = Rule.define({
15
- name: "no-async-function",
16
- meta: Rule.meta({
17
- type: "suggestion",
18
- description:
19
- "Avoid async functions. Use Effect.promise or Effect.tryPromise.",
20
- }),
21
- create: function* () {
22
- const ctx = yield* RuleContext
23
- const report = (node: Parameters<typeof Diagnostic.make>[0]["node"]) =>
24
- ctx.report(
25
- Diagnostic.make({
26
- node,
27
- message:
28
- "Avoid async functions. Use Effect.promise, Effect.tryPromise, or Effect.gen.",
29
- }),
30
- )
31
-
32
- return {
33
- FunctionDeclaration: (node) => {
34
- if ("async" in node && node.async === true) return report(node)
35
- return Effect.void
36
- },
37
- FunctionExpression: (node) => {
38
- if ("async" in node && node.async === true) return report(node)
39
- return Effect.void
40
- },
41
- ArrowFunctionExpression: (node) => {
42
- if ("async" in node && node.async === true) return report(node)
43
- return Effect.void
44
- },
45
- }
46
- },
47
- })
@@ -1,90 +0,0 @@
1
- /**
2
- * Ban `Effect.catchAll(e => Effect.fail(f(e)))` — use `Effect.mapError(f)`.
3
- *
4
- * Source: language-service/catchAllToMapError
5
- */
6
- import type { ESTree } from "@oxlint/plugins"
7
- import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
8
- import * as Effect from "effect/Effect"
9
- import * as Option from "effect/Option"
10
-
11
- const catchNames = new Set(["catchAll", "catchAllCause"])
12
-
13
- /**
14
- * Check if a node is `Effect.fail(...)` or `Effect.failCause(...)`.
15
- */
16
- const isEffectFailCall = (node: ESTree.Node): boolean => {
17
- if (node.type !== "CallExpression") return false
18
- const call = node as ESTree.CallExpression
19
- return (
20
- Option.isSome(AST.matchCallOf(call, "Effect", "fail")) ||
21
- Option.isSome(AST.matchCallOf(call, "Effect", "failCause"))
22
- )
23
- }
24
-
25
- /**
26
- * Check if a function body is a single `Effect.fail(...)` expression.
27
- * Handles: `(e) => Effect.fail(f(e))` and `(e) => { return Effect.fail(f(e)) }`
28
- */
29
- const bodyIsEffectFail = (fn: ESTree.Node): boolean => {
30
- const body = (fn as unknown as Record<string, unknown>)["body"]
31
- if (body == null || typeof body !== "object") return false
32
- const bodyNode = body as ESTree.Node
33
- // Arrow with expression body: (e) => Effect.fail(f(e))
34
- if (bodyNode.type !== "BlockStatement") {
35
- return isEffectFailCall(bodyNode)
36
- }
37
- // Block body with single return: (e) => { return Effect.fail(f(e)) }
38
- const stmts = (bodyNode as unknown as Record<string, unknown>)["body"]
39
- if (!Array.isArray(stmts) || stmts.length !== 1) return false
40
- const stmt = stmts[0] as ESTree.Node
41
- if (stmt.type !== "ReturnStatement") return false
42
- const arg = (stmt as unknown as Record<string, unknown>)["argument"]
43
- return arg != null && typeof arg === "object" && isEffectFailCall(arg as ESTree.Node)
44
- }
45
-
46
- export const noCatchAllToMapError = Rule.define({
47
- name: "no-catch-all-to-map-error",
48
- meta: Rule.meta({
49
- type: "suggestion",
50
- description:
51
- "Use Effect.mapError instead of Effect.catchAll(e => Effect.fail(f(e))).",
52
- effectVersion: "v3",
53
- }),
54
- create: function* () {
55
- const ctx = yield* RuleContext
56
- return {
57
- CallExpression: (node) => {
58
- const call = node as ESTree.CallExpression
59
- const names = Option.getOrUndefined(AST.memberNames(call.callee as ESTree.MemberExpression))
60
- if (names === undefined) return Effect.void
61
- const [obj, prop] = names
62
- if (obj !== "Effect" && obj !== "_") return Effect.void
63
- if (!catchNames.has(prop)) return Effect.void
64
-
65
- // The callback is the last argument
66
- const args = call.arguments
67
- if (args.length === 0) return Effect.void
68
- const callback = args[args.length - 1]
69
- if (callback === undefined) return Effect.void
70
- if (
71
- callback.type !== "ArrowFunctionExpression" &&
72
- callback.type !== "FunctionExpression"
73
- ) {
74
- return Effect.void
75
- }
76
-
77
- if (bodyIsEffectFail(callback as ESTree.Node)) {
78
- const replacement = prop === "catchAllCause" ? "mapErrorCause" : "mapError"
79
- return ctx.report(
80
- Diagnostic.make({
81
- node,
82
- message: `Use Effect.${replacement} instead of Effect.${prop}(e => Effect.fail(...)).`,
83
- }),
84
- )
85
- }
86
- return Effect.void
87
- },
88
- }
89
- },
90
- })
@@ -1,14 +0,0 @@
1
- /**
2
- * Ban `Effect.as`.
3
- *
4
- * Use `Effect.map` for value mapping or `Effect.asVoid` after explicit steps.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-as
7
- */
8
- import { Rule } from "../vendor/effect-oxlint/index.js"
9
-
10
- export const noEffectAs = Rule.banMember("Effect", "as", {
11
- message:
12
- "Avoid Effect.as. Use Effect.map for value mapping or Effect.asVoid.",
13
- meta: { type: "suggestion" },
14
- })
@@ -1,14 +0,0 @@
1
- /**
2
- * Ban `Effect.async`.
3
- *
4
- * Use `Stream` or structured Effect lifecycles (acquire/use/release).
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-async
7
- */
8
- import { Rule } from "../vendor/effect-oxlint/index.js"
9
-
10
- export const noEffectAsync = Rule.banMember("Effect", "async", {
11
- message:
12
- "Avoid Effect.async. Use Stream or structured Effect lifecycles.",
13
- meta: { type: "suggestion" },
14
- })
@@ -1,13 +0,0 @@
1
- /**
2
- * Ban `Effect.bind`.
3
- *
4
- * Use flat pipe or direct top-level `Effect.gen` with yields.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-bind
7
- */
8
- import { Rule } from "../vendor/effect-oxlint/index.js"
9
-
10
- export const noEffectBind = Rule.banMember("Effect", "bind", {
11
- message: "Avoid Effect.bind. Use flat pipe or Effect.gen with yields.",
12
- meta: { type: "suggestion" },
13
- })
@@ -1,14 +0,0 @@
1
- /**
2
- * Ban `Effect.Do` — the builder/do-notation entry point.
3
- *
4
- * Use flat pipe-based flow or `Effect.gen` instead.
5
- *
6
- * Sources: biome-effect-linting-rules/no-effect-do, language-service/effectDoNotation
7
- */
8
- import { Rule } from "../vendor/effect-oxlint/index.js"
9
-
10
- export const noEffectDo = Rule.banMember("Effect", "Do", {
11
- message:
12
- "Avoid Effect.Do builder notation. Use flat pipe-based flow or Effect.gen.",
13
- meta: { type: "suggestion" },
14
- })
@@ -1,58 +0,0 @@
1
- /**
2
- * Ban `Effect.fn(function* () { ... })` called with a generator argument.
3
- *
4
- * Effect.fn should wrap a plain function or arrow that builds a pipeline,
5
- * not a generator (use Effect.gen for generators).
6
- *
7
- * Source: biome-effect-linting-rules/no-effect-fn-generator
8
- *
9
- * Note: This rule may be too aggressive. In Effect v4, `Effect.fn("name")(function*() {...})`
10
- * is actually the idiomatic pattern. This rule targets `Effect.fn(function*() {...})` without
11
- * a name span, which is the discouraged pattern from the biome rules.
12
- */
13
- import type { ESTree } from "@oxlint/plugins"
14
- import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
15
- import * as Effect from "effect/Effect"
16
-
17
- export const noEffectFnGenerator = Rule.define({
18
- name: "no-effect-fn-generator",
19
- meta: Rule.meta({
20
- type: "suggestion",
21
- description:
22
- "Effect.fn should not directly wrap a generator. Use Effect.fn('name')(function*() {...}) with a span name.",
23
- }),
24
- create: function* () {
25
- const ctx = yield* RuleContext
26
- return {
27
- CallExpression: (node) => {
28
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "fn")) return Effect.void
29
-
30
- // Effect.fn(function*() {...}) — single arg that's a generator
31
- if (
32
- "arguments" in node &&
33
- Array.isArray(node.arguments) &&
34
- node.arguments.length === 1
35
- ) {
36
- const arg = node.arguments[0]
37
- if (
38
- arg != null &&
39
- typeof arg === "object" &&
40
- "type" in arg &&
41
- arg.type === "FunctionExpression" &&
42
- "generator" in arg &&
43
- arg.generator === true
44
- ) {
45
- return ctx.report(
46
- Diagnostic.make({
47
- node,
48
- message:
49
- "Use Effect.fn('spanName')(function*() {...}) — provide a trace span name.",
50
- }),
51
- )
52
- }
53
- }
54
- return Effect.void
55
- },
56
- }
57
- },
58
- })
@@ -1,51 +0,0 @@
1
- /**
2
- * Ban deprecated adapter parameter in `Effect.gen(function*(adapter) {...})`.
3
- *
4
- * The adapter parameter is deprecated — just use `yield*` directly.
5
- *
6
- * Source: language-service/effectGenUsesAdapter
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
-
12
- export const noEffectGenAdapter = Rule.define({
13
- name: "no-effect-gen-adapter",
14
- meta: Rule.meta({
15
- type: "suggestion",
16
- description: "Deprecated adapter parameter in Effect.gen. Use `yield*` directly.",
17
- effectVersion: "v3",
18
- }),
19
- create: function* () {
20
- const ctx = yield* RuleContext
21
- return {
22
- CallExpression: (node) => {
23
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "gen")) return Effect.void
24
-
25
- if (!("arguments" in node) || !Array.isArray(node.arguments) || node.arguments.length < 1)
26
- return Effect.void
27
-
28
- const arg = node.arguments[0]
29
- if (
30
- arg != null &&
31
- typeof arg === "object" &&
32
- "type" in arg &&
33
- arg.type === "FunctionExpression" &&
34
- "generator" in arg &&
35
- arg.generator === true &&
36
- "params" in arg &&
37
- Array.isArray(arg.params) &&
38
- arg.params.length > 0
39
- ) {
40
- return ctx.report(
41
- Diagnostic.make({
42
- node,
43
- message: "Deprecated adapter parameter in Effect.gen. Remove the parameter and use `yield*` directly.",
44
- }),
45
- )
46
- }
47
- return Effect.void
48
- },
49
- }
50
- },
51
- })
@@ -1,82 +0,0 @@
1
- /**
2
- * Ban `.map(f).flatMap(g)` — use `.flatMap(x => g(f(x)))` or refactor.
3
- *
4
- * Detects `.pipe(Effect.map(f), Effect.flatMap(g))` chains where
5
- * the map + flatMap can be fused.
6
- *
7
- * Source: language-service/effectMapFlatten
8
- */
9
- import type { ESTree } from "@oxlint/plugins"
10
- import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
11
- import * as Effect from "effect/Effect"
12
- import * as Option from "effect/Option"
13
-
14
- const isEffectMap = (node: ESTree.Node): boolean => {
15
- if (node.type !== "CallExpression") return false
16
- return Option.isSome(AST.matchCallOf(node as ESTree.CallExpression, "Effect", "map"))
17
- }
18
-
19
- const isEffectFlatMap = (node: ESTree.Node): boolean => {
20
- if (node.type !== "CallExpression") return false
21
- return Option.isSome(AST.matchCallOf(node as ESTree.CallExpression, "Effect", "flatMap"))
22
- }
23
-
24
- const hasMapFlatMapSequence = (args: ReadonlyArray<ESTree.Node>): boolean => {
25
- for (let i = 0; i < args.length - 1; i++) {
26
- const a = args[i]; const b = args[i + 1]; if (a && b && isEffectMap(a) && isEffectFlatMap(b)) return true
27
- }
28
- return false
29
- }
30
-
31
- export const noEffectMapFlatten = Rule.define({
32
- name: "no-effect-map-flatten",
33
- meta: Rule.meta({
34
- type: "suggestion",
35
- description:
36
- "Avoid Effect.map followed by Effect.flatMap in pipe. Fuse into a single Effect.flatMap.",
37
- }),
38
- create: function* () {
39
- const ctx = yield* RuleContext
40
- return {
41
- CallExpression: (node) => {
42
- const call = node as ESTree.CallExpression
43
- const args = call.arguments
44
-
45
- // Bare pipe(value, Effect.map(f), Effect.flatMap(g))
46
- const calleeName = Option.getOrUndefined(AST.calleeName(call))
47
- if (calleeName === "pipe" && hasMapFlatMapSequence(args as ReadonlyArray<ESTree.Node>)) {
48
- return ctx.report(
49
- Diagnostic.make({
50
- node,
51
- message:
52
- "Effect.map followed by Effect.flatMap can be fused into a single Effect.flatMap.",
53
- }),
54
- )
55
- }
56
-
57
- // .pipe(Effect.map(f), Effect.flatMap(g))
58
- const calleeNode = call.callee
59
- if (calleeNode.type === "MemberExpression") {
60
- const prop = (calleeNode as unknown as Record<string, unknown>)["property"]
61
- if (
62
- prop != null &&
63
- typeof prop === "object" &&
64
- "name" in prop &&
65
- prop.name === "pipe" &&
66
- hasMapFlatMapSequence(args as ReadonlyArray<ESTree.Node>)
67
- ) {
68
- return ctx.report(
69
- Diagnostic.make({
70
- node,
71
- message:
72
- "Effect.map followed by Effect.flatMap can be fused into a single Effect.flatMap.",
73
- }),
74
- )
75
- }
76
- }
77
-
78
- return Effect.void
79
- },
80
- }
81
- },
82
- })
@@ -1,80 +0,0 @@
1
- /**
2
- * Ban `Effect.map(() => undefined)` / `Effect.map(() => void 0)` / `Effect.map(() => {})`.
3
- *
4
- * Use `Effect.asVoid` instead.
5
- *
6
- * Source: language-service/effectMapVoid
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
-
12
- const isVoidCallback = (arg: unknown): boolean => {
13
- if (arg == null || typeof arg !== "object" || !("type" in arg)) return false
14
-
15
- // Arrow function: () => undefined, () => void 0, () => {}
16
- if (arg.type === "ArrowFunctionExpression" && "body" in arg) {
17
- const body = arg.body
18
- if (body == null || typeof body !== "object" || !("type" in body)) return false
19
-
20
- // () => undefined
21
- if (body.type === "Identifier" && "name" in body && body.name === "undefined") return true
22
-
23
- // () => void 0
24
- if (
25
- body.type === "UnaryExpression" &&
26
- "operator" in body &&
27
- body.operator === "void"
28
- )
29
- return true
30
-
31
- // () => {} (empty block)
32
- if (
33
- body.type === "BlockStatement" &&
34
- "body" in body &&
35
- Array.isArray(body.body) &&
36
- body.body.length === 0
37
- )
38
- return true
39
- }
40
-
41
- return false
42
- }
43
-
44
- export const noEffectMapVoid = Rule.define({
45
- name: "no-effect-map-void",
46
- meta: Rule.meta({
47
- type: "suggestion",
48
- description:
49
- "Avoid Effect.map(() => undefined). Use Effect.asVoid instead.",
50
- }),
51
- create: function* () {
52
- const ctx = yield* RuleContext
53
- return {
54
- CallExpression: (node) => {
55
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "map")) return Effect.void
56
-
57
- if (
58
- "arguments" in node &&
59
- Array.isArray(node.arguments) &&
60
- node.arguments.length >= 1
61
- ) {
62
- // Effect.map(effect, fn) or as pipe arg Effect.map(fn)
63
- const fn =
64
- node.arguments.length === 2
65
- ? node.arguments[1]
66
- : node.arguments[0]
67
- if (isVoidCallback(fn)) {
68
- return ctx.report(
69
- Diagnostic.make({
70
- node,
71
- message: "Use Effect.asVoid instead of Effect.map(() => undefined).",
72
- }),
73
- )
74
- }
75
- }
76
- return Effect.void
77
- },
78
- }
79
- },
80
- })
@@ -1,14 +0,0 @@
1
- /**
2
- * Ban `Effect.never`.
3
- *
4
- * Use `Stream` or explicit acquire/release lifecycles instead.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-never
7
- */
8
- import { Rule } from "../vendor/effect-oxlint/index.js"
9
-
10
- export const noEffectNever = Rule.banMember("Effect", "never", {
11
- message:
12
- "Avoid Effect.never. Use Stream or explicit acquire/release lifecycles.",
13
- meta: { type: "suggestion" },
14
- })
@@ -1,79 +0,0 @@
1
- /**
2
- * Ban `Effect.orElse` wrapping chains with sequencing combinators.
3
- *
4
- * Move error handling to a single terminal decision after the pipeline.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-orElse-ladder
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
-
12
- const sequencingCombinators = ["flatMap", "zipRight", "as", "tap", "andThen"]
13
-
14
- const containsSequencing = (node: unknown): boolean => {
15
- if (node == null || typeof node !== "object") return false
16
- const n = node as Record<string, unknown>
17
- if (n["type"] === "CallExpression" && "callee" in n) {
18
- const callee = n["callee"] as Record<string, unknown> | null
19
- if (
20
- callee != null &&
21
- callee["type"] === "MemberExpression" &&
22
- "object" in callee &&
23
- "property" in callee
24
- ) {
25
- const obj = callee["object"] as Record<string, unknown> | null
26
- const prop = callee["property"] as Record<string, unknown> | null
27
- if (
28
- obj != null &&
29
- obj["type"] === "Identifier" &&
30
- obj["name"] === "Effect" &&
31
- prop != null &&
32
- prop["type"] === "Identifier" &&
33
- typeof prop["name"] === "string" &&
34
- sequencingCombinators.includes(prop["name"])
35
- ) {
36
- return true
37
- }
38
- }
39
- if ("arguments" in n && Array.isArray(n["arguments"])) {
40
- for (const arg of n["arguments"]) {
41
- if (containsSequencing(arg)) return true
42
- }
43
- }
44
- }
45
- if ("body" in n) return containsSequencing(n["body"])
46
- return false
47
- }
48
-
49
- export const noEffectOrElseLadder = Rule.define({
50
- name: "no-effect-orElse-ladder",
51
- meta: Rule.meta({
52
- type: "suggestion",
53
- description:
54
- "Avoid Effect.orElse wrapping sequencing chains. Handle errors at a single terminal decision.",
55
- }),
56
- create: function* () {
57
- const ctx = yield* RuleContext
58
- return {
59
- CallExpression: (node) => {
60
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "orElse")) return Effect.void
61
-
62
- if ("arguments" in node && Array.isArray(node.arguments)) {
63
- for (const arg of node.arguments) {
64
- if (containsSequencing(arg)) {
65
- return ctx.report(
66
- Diagnostic.make({
67
- node,
68
- message:
69
- "Effect.orElse wrapping sequencing chain. Move error handling to a terminal decision after the pipeline.",
70
- }),
71
- )
72
- }
73
- }
74
- }
75
- return Effect.void
76
- },
77
- }
78
- },
79
- })