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,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
- })
@@ -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
- })