oxlint-plugin-effect 0.2.0 → 0.2.1

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 (256) 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 +13 -0
  15. package/dist/presets/index.js +18 -0
  16. package/dist/presets/strict.d.ts +69 -0
  17. package/dist/presets/strict.js +69 -0
  18. package/dist/presets/v3.d.ts +15 -0
  19. package/dist/presets/v3.js +15 -0
  20. package/dist/rules/_effect-context.d.ts +19 -0
  21. package/dist/rules/_effect-context.js +22 -0
  22. package/dist/rules/index.d.ts +66 -0
  23. package/dist/rules/index.js +124 -0
  24. package/dist/rules/no-arrow-ladder.d.ts +6 -0
  25. package/dist/rules/no-arrow-ladder.js +61 -0
  26. package/dist/rules/no-async-function.d.ts +6 -0
  27. package/dist/rules/no-async-function.js +46 -0
  28. package/dist/rules/no-catch-all-to-map-error.d.ts +6 -0
  29. package/dist/rules/no-catch-all-to-map-error.js +67 -0
  30. package/dist/rules/no-effect-as.d.ts +6 -0
  31. package/dist/rules/no-effect-as.js +16 -0
  32. package/dist/rules/no-effect-async.d.ts +6 -0
  33. package/dist/rules/no-effect-async.js +16 -0
  34. package/dist/rules/no-effect-bind.d.ts +6 -0
  35. package/dist/rules/no-effect-bind.js +16 -0
  36. package/dist/rules/no-effect-do.d.ts +6 -0
  37. package/dist/rules/no-effect-do.js +16 -0
  38. package/dist/rules/no-effect-fn-generator.d.ts +6 -0
  39. package/dist/rules/no-effect-fn-generator.js +30 -0
  40. package/dist/rules/no-effect-gen-adapter.d.ts +6 -0
  41. package/dist/rules/no-effect-gen-adapter.js +30 -0
  42. package/dist/rules/no-effect-map-flatten.d.ts +6 -0
  43. package/dist/rules/no-effect-map-flatten.js +53 -0
  44. package/dist/rules/no-effect-map-void.d.ts +6 -0
  45. package/dist/rules/no-effect-map-void.js +40 -0
  46. package/dist/rules/no-effect-never.d.ts +6 -0
  47. package/dist/rules/no-effect-never.js +16 -0
  48. package/dist/rules/no-effect-orElse-ladder.d.ts +6 -0
  49. package/dist/rules/no-effect-orElse-ladder.js +53 -0
  50. package/dist/rules/no-effect-succeed-string.d.ts +6 -0
  51. package/dist/rules/no-effect-succeed-string.js +30 -0
  52. package/dist/rules/no-effect-succeed-variable.d.ts +6 -0
  53. package/dist/rules/no-effect-succeed-variable.js +30 -0
  54. package/dist/rules/no-effect-succeed-void.d.ts +6 -0
  55. package/dist/rules/no-effect-succeed-void.js +33 -0
  56. package/dist/rules/no-effect-sync-console.d.ts +6 -0
  57. package/dist/rules/no-effect-sync-console.js +63 -0
  58. package/dist/rules/no-effect-sync-wrapper.d.ts +6 -0
  59. package/dist/rules/no-effect-sync-wrapper.js +37 -0
  60. package/dist/rules/no-effect-type-alias.d.ts +6 -0
  61. package/dist/rules/no-effect-type-alias.js +52 -0
  62. package/dist/rules/no-effect-wrapper-alias.d.ts +6 -0
  63. package/dist/rules/no-effect-wrapper-alias.js +69 -0
  64. package/dist/rules/no-extends-native-error.d.ts +6 -0
  65. package/dist/rules/no-extends-native-error.js +41 -0
  66. package/dist/rules/no-flatmap-ladder.d.ts +6 -0
  67. package/dist/rules/no-flatmap-ladder.js +48 -0
  68. package/dist/rules/no-fromnullable-coalesce.d.ts +6 -0
  69. package/dist/rules/no-fromnullable-coalesce.js +36 -0
  70. package/dist/rules/no-global-error-in-catch.d.ts +6 -0
  71. package/dist/rules/no-global-error-in-catch.js +75 -0
  72. package/dist/rules/no-global-error-in-failure.d.ts +6 -0
  73. package/dist/rules/no-global-error-in-failure.js +54 -0
  74. package/dist/rules/no-globals.d.ts +6 -0
  75. package/dist/rules/no-globals.js +164 -0
  76. package/dist/rules/no-if-statement.d.ts +6 -0
  77. package/dist/rules/no-if-statement.js +18 -0
  78. package/dist/rules/no-iife-wrapper.d.ts +6 -0
  79. package/dist/rules/no-iife-wrapper.js +37 -0
  80. package/dist/rules/no-inline-provide.d.ts +6 -0
  81. package/dist/rules/no-inline-provide.js +31 -0
  82. package/dist/rules/no-instanceof-schema.d.ts +6 -0
  83. package/dist/rules/no-instanceof-schema.js +35 -0
  84. package/dist/rules/no-manual-effect-channels.d.ts +6 -0
  85. package/dist/rules/no-manual-effect-channels.js +40 -0
  86. package/dist/rules/no-match-effect-branch.d.ts +6 -0
  87. package/dist/rules/no-match-effect-branch.js +64 -0
  88. package/dist/rules/no-match-void-branch.d.ts +6 -0
  89. package/dist/rules/no-match-void-branch.js +50 -0
  90. package/dist/rules/no-multiple-effect-provide.d.ts +6 -0
  91. package/dist/rules/no-multiple-effect-provide.js +45 -0
  92. package/dist/rules/no-nested-effect-call.d.ts +6 -0
  93. package/dist/rules/no-nested-effect-call.js +97 -0
  94. package/dist/rules/no-nested-effect-gen.d.ts +6 -0
  95. package/dist/rules/no-nested-effect-gen.js +46 -0
  96. package/dist/rules/no-nested-pipe.d.ts +6 -0
  97. package/dist/rules/no-nested-pipe.js +38 -0
  98. package/dist/rules/no-new-error.d.ts +6 -0
  99. package/dist/rules/no-new-error.js +39 -0
  100. package/dist/rules/no-new-promise.d.ts +6 -0
  101. package/dist/rules/no-new-promise.js +38 -0
  102. package/dist/rules/no-node-builtin-import.d.ts +6 -0
  103. package/dist/rules/no-node-builtin-import.js +61 -0
  104. package/dist/rules/no-option-as.d.ts +6 -0
  105. package/dist/rules/no-option-as.js +16 -0
  106. package/dist/rules/no-option-boolean-normalization.d.ts +6 -0
  107. package/dist/rules/no-option-boolean-normalization.js +50 -0
  108. package/dist/rules/no-positional-log-error.d.ts +6 -0
  109. package/dist/rules/no-positional-log-error.js +52 -0
  110. package/dist/rules/no-redundant-schema-tag-identifier.d.ts +6 -0
  111. package/dist/rules/no-redundant-schema-tag-identifier.js +46 -0
  112. package/dist/rules/no-return-in-arrow.d.ts +6 -0
  113. package/dist/rules/no-return-in-arrow.js +41 -0
  114. package/dist/rules/no-return-nullish.d.ts +6 -0
  115. package/dist/rules/no-return-nullish.js +47 -0
  116. package/dist/rules/no-run-in-effect-gen.d.ts +6 -0
  117. package/dist/rules/no-run-in-effect-gen.js +48 -0
  118. package/dist/rules/no-runtime-run-fork.d.ts +6 -0
  119. package/dist/rules/no-runtime-run-fork.js +19 -0
  120. package/dist/rules/no-schema-struct-with-tag.d.ts +6 -0
  121. package/dist/rules/no-schema-struct-with-tag.js +48 -0
  122. package/dist/rules/no-schema-union-of-literals.d.ts +6 -0
  123. package/dist/rules/no-schema-union-of-literals.js +35 -0
  124. package/dist/rules/no-string-sentinel-const.d.ts +6 -0
  125. package/dist/rules/no-string-sentinel-const.js +38 -0
  126. package/dist/rules/no-switch-statement.d.ts +6 -0
  127. package/dist/rules/no-switch-statement.js +16 -0
  128. package/dist/rules/no-ternary.d.ts +6 -0
  129. package/dist/rules/no-ternary.js +30 -0
  130. package/dist/rules/no-throw-statement.d.ts +6 -0
  131. package/dist/rules/no-throw-statement.js +34 -0
  132. package/dist/rules/no-try-catch.d.ts +6 -0
  133. package/dist/rules/no-try-catch.js +34 -0
  134. package/dist/rules/no-unnecessary-arrow-block.d.ts +6 -0
  135. package/dist/rules/no-unnecessary-arrow-block.js +34 -0
  136. package/dist/rules/no-unnecessary-effect-gen.d.ts +6 -0
  137. package/dist/rules/no-unnecessary-effect-gen.js +35 -0
  138. package/dist/rules/no-unnecessary-pipe-chain.d.ts +6 -0
  139. package/dist/rules/no-unnecessary-pipe-chain.js +36 -0
  140. package/dist/rules/no-unnecessary-pipe.d.ts +6 -0
  141. package/dist/rules/no-unnecessary-pipe.js +29 -0
  142. package/dist/vendor/effect-oxlint/AST.d.ts +199 -0
  143. package/dist/vendor/effect-oxlint/AST.js +214 -0
  144. package/dist/vendor/effect-oxlint/Comment.d.ts +55 -0
  145. package/dist/vendor/effect-oxlint/Comment.js +67 -0
  146. package/dist/vendor/effect-oxlint/Diagnostic.d.ts +86 -0
  147. package/dist/vendor/effect-oxlint/Diagnostic.js +115 -0
  148. package/dist/vendor/effect-oxlint/Plugin.d.ts +38 -0
  149. package/dist/vendor/effect-oxlint/Plugin.js +45 -0
  150. package/dist/vendor/effect-oxlint/Rule.d.ts +218 -0
  151. package/dist/vendor/effect-oxlint/Rule.js +309 -0
  152. package/dist/vendor/effect-oxlint/RuleContext.d.ts +77 -0
  153. package/dist/vendor/effect-oxlint/RuleContext.js +74 -0
  154. package/dist/vendor/effect-oxlint/Scope.d.ts +100 -0
  155. package/dist/vendor/effect-oxlint/Scope.js +110 -0
  156. package/dist/vendor/effect-oxlint/SourceCode.d.ts +180 -0
  157. package/dist/vendor/effect-oxlint/SourceCode.js +203 -0
  158. package/dist/vendor/effect-oxlint/Testing.d.ts +510 -0
  159. package/dist/vendor/effect-oxlint/Testing.js +963 -0
  160. package/dist/vendor/effect-oxlint/Token.d.ts +98 -0
  161. package/dist/vendor/effect-oxlint/Token.js +103 -0
  162. package/dist/vendor/effect-oxlint/Visitor.d.ts +166 -0
  163. package/dist/vendor/effect-oxlint/Visitor.js +138 -0
  164. package/dist/vendor/effect-oxlint/index.d.ts +13 -0
  165. package/dist/vendor/effect-oxlint/index.js +12 -0
  166. package/package.json +24 -5
  167. package/.effect-lsp.json +0 -60
  168. package/.oxlintrc.json +0 -33
  169. package/CHANGELOG.md +0 -55
  170. package/scripts/add-rule.ts +0 -87
  171. package/scripts/codegen.ts +0 -108
  172. package/src/index.ts +0 -9
  173. package/src/plugin.ts +0 -16
  174. package/src/presets/core.ts +0 -47
  175. package/src/presets/effect-native.ts +0 -34
  176. package/src/presets/full.ts +0 -70
  177. package/src/presets/functional.ts +0 -18
  178. package/src/presets/index.ts +0 -5
  179. package/src/presets/strict.ts +0 -77
  180. package/src/rules/_effect-context.ts +0 -28
  181. package/src/rules/index.ts +0 -72
  182. package/src/rules/no-arrow-ladder.ts +0 -70
  183. package/src/rules/no-async-function.ts +0 -47
  184. package/src/rules/no-catch-all-to-map-error.ts +0 -90
  185. package/src/rules/no-effect-as.ts +0 -14
  186. package/src/rules/no-effect-async.ts +0 -14
  187. package/src/rules/no-effect-bind.ts +0 -13
  188. package/src/rules/no-effect-do.ts +0 -14
  189. package/src/rules/no-effect-fn-generator.ts +0 -58
  190. package/src/rules/no-effect-gen-adapter.ts +0 -51
  191. package/src/rules/no-effect-map-flatten.ts +0 -82
  192. package/src/rules/no-effect-map-void.ts +0 -80
  193. package/src/rules/no-effect-never.ts +0 -14
  194. package/src/rules/no-effect-orElse-ladder.ts +0 -79
  195. package/src/rules/no-effect-succeed-string.ts +0 -52
  196. package/src/rules/no-effect-succeed-variable.ts +0 -50
  197. package/src/rules/no-effect-succeed-void.ts +0 -63
  198. package/src/rules/no-effect-sync-console.ts +0 -91
  199. package/src/rules/no-effect-sync-wrapper.ts +0 -67
  200. package/src/rules/no-effect-type-alias.ts +0 -71
  201. package/src/rules/no-effect-wrapper-alias.ts +0 -95
  202. package/src/rules/no-extends-native-error.ts +0 -54
  203. package/src/rules/no-flatmap-ladder.ts +0 -77
  204. package/src/rules/no-fromnullable-coalesce.ts +0 -62
  205. package/src/rules/no-global-error-in-catch.ts +0 -104
  206. package/src/rules/no-global-error-in-failure.ts +0 -83
  207. package/src/rules/no-globals.ts +0 -178
  208. package/src/rules/no-if-statement.ts +0 -16
  209. package/src/rules/no-iife-wrapper.ts +0 -51
  210. package/src/rules/no-inline-provide.ts +0 -41
  211. package/src/rules/no-instanceof-schema.ts +0 -42
  212. package/src/rules/no-manual-effect-channels.ts +0 -58
  213. package/src/rules/no-match-effect-branch.ts +0 -82
  214. package/src/rules/no-match-void-branch.ts +0 -72
  215. package/src/rules/no-multiple-effect-provide.ts +0 -75
  216. package/src/rules/no-nested-effect-call.ts +0 -57
  217. package/src/rules/no-nested-effect-gen.ts +0 -43
  218. package/src/rules/no-nested-pipe.ts +0 -73
  219. package/src/rules/no-new-error.ts +0 -53
  220. package/src/rules/no-new-promise.ts +0 -50
  221. package/src/rules/no-node-builtin-import.ts +0 -68
  222. package/src/rules/no-option-as.ts +0 -13
  223. package/src/rules/no-option-boolean-normalization.ts +0 -88
  224. package/src/rules/no-positional-log-error.ts +0 -76
  225. package/src/rules/no-redundant-schema-tag-identifier.ts +0 -62
  226. package/src/rules/no-return-in-arrow.ts +0 -76
  227. package/src/rules/no-return-nullish.ts +0 -80
  228. package/src/rules/no-run-in-effect-gen.ts +0 -66
  229. package/src/rules/no-runtime-run-fork.ts +0 -14
  230. package/src/rules/no-schema-struct-with-tag.ts +0 -64
  231. package/src/rules/no-schema-union-of-literals.ts +0 -48
  232. package/src/rules/no-string-sentinel-const.ts +0 -49
  233. package/src/rules/no-switch-statement.ts +0 -13
  234. package/src/rules/no-ternary.ts +0 -30
  235. package/src/rules/no-throw-statement.ts +0 -39
  236. package/src/rules/no-try-catch.ts +0 -39
  237. package/src/rules/no-unnecessary-arrow-block.ts +0 -51
  238. package/src/rules/no-unnecessary-effect-gen.ts +0 -83
  239. package/src/rules/no-unnecessary-pipe-chain.ts +0 -47
  240. package/src/rules/no-unnecessary-pipe.ts +0 -45
  241. package/src/vendor/effect-oxlint/AST.ts +0 -516
  242. package/src/vendor/effect-oxlint/Comment.ts +0 -86
  243. package/src/vendor/effect-oxlint/Diagnostic.ts +0 -199
  244. package/src/vendor/effect-oxlint/Plugin.ts +0 -71
  245. package/src/vendor/effect-oxlint/Rule.ts +0 -548
  246. package/src/vendor/effect-oxlint/RuleContext.ts +0 -144
  247. package/src/vendor/effect-oxlint/Scope.ts +0 -177
  248. package/src/vendor/effect-oxlint/SourceCode.ts +0 -377
  249. package/src/vendor/effect-oxlint/Testing.ts +0 -1227
  250. package/src/vendor/effect-oxlint/Token.ts +0 -131
  251. package/src/vendor/effect-oxlint/Visitor.ts +0 -287
  252. package/src/vendor/effect-oxlint/index.ts +0 -88
  253. package/tests/ban-rules.test.ts +0 -68
  254. package/tests/context-rules.test.ts +0 -263
  255. package/tests/pattern-rules.test.ts +0 -247
  256. package/tsconfig.json +0 -15
@@ -1,52 +0,0 @@
1
- /**
2
- * Ban `Effect.succeed("...")` with string literal arguments.
3
- *
4
- * Return domain values (Option/Either/tagged unions) instead.
5
- *
6
- * Source: biome-effect-linting-rules/no-string-sentinel-return
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 noEffectSucceedString = Rule.define({
13
- name: "no-effect-succeed-string",
14
- meta: Rule.meta({
15
- type: "suggestion",
16
- description:
17
- "Avoid Effect.succeed with string literals. Return domain values (tagged unions, Option, Either).",
18
- }),
19
- create: function* () {
20
- const ctx = yield* RuleContext
21
- return {
22
- CallExpression: (node) => {
23
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "succeed")) return Effect.void
24
-
25
- if (
26
- "arguments" in node &&
27
- Array.isArray(node.arguments) &&
28
- node.arguments.length === 1
29
- ) {
30
- const arg = node.arguments[0]
31
- if (
32
- arg != null &&
33
- typeof arg === "object" &&
34
- "type" in arg &&
35
- arg.type === "Literal" &&
36
- "value" in arg &&
37
- typeof arg.value === "string"
38
- ) {
39
- return ctx.report(
40
- Diagnostic.make({
41
- node,
42
- message:
43
- "Avoid Effect.succeed with string literals. Use tagged unions, Option, or Either.",
44
- }),
45
- )
46
- }
47
- }
48
- return Effect.void
49
- },
50
- }
51
- },
52
- })
@@ -1,50 +0,0 @@
1
- /**
2
- * Ban `Effect.succeed(someVariable)` where the argument is a plain identifier.
3
- *
4
- * Suggests selecting a plain value (Option/Match), then running one Effect pipeline.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-succeed-variable
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 noEffectSucceedVariable = Rule.define({
13
- name: "no-effect-succeed-variable",
14
- meta: Rule.meta({
15
- type: "suggestion",
16
- description:
17
- "Avoid Effect.succeed with a plain variable. Select value with Option/Match, then run one Effect pipeline.",
18
- }),
19
- create: function* () {
20
- const ctx = yield* RuleContext
21
- return {
22
- CallExpression: (node) => {
23
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "succeed")) return Effect.void
24
-
25
- if (
26
- "arguments" in node &&
27
- Array.isArray(node.arguments) &&
28
- node.arguments.length === 1
29
- ) {
30
- const arg = node.arguments[0]
31
- if (
32
- arg != null &&
33
- typeof arg === "object" &&
34
- "type" in arg &&
35
- arg.type === "Identifier"
36
- ) {
37
- return ctx.report(
38
- Diagnostic.make({
39
- node,
40
- message:
41
- "Avoid Effect.succeed(variable). Select value with Option/Match, then run one Effect pipeline.",
42
- }),
43
- )
44
- }
45
- }
46
- return Effect.void
47
- },
48
- }
49
- },
50
- })
@@ -1,63 +0,0 @@
1
- /**
2
- * Ban `Effect.succeed(undefined)` and `Effect.succeed(void 0)`.
3
- *
4
- * Use `Effect.void` instead.
5
- *
6
- * Source: language-service/effectSucceedWithVoid
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 isUndefinedLike = (node: unknown): boolean => {
13
- if (node == null || typeof node !== "object" || !("type" in node)) return false
14
- // undefined identifier
15
- if (node.type === "Identifier" && "name" in node && node.name === "undefined") return true
16
- // void 0
17
- if (
18
- node.type === "UnaryExpression" &&
19
- "operator" in node &&
20
- node.operator === "void" &&
21
- "argument" in node &&
22
- node.argument != null &&
23
- typeof node.argument === "object" &&
24
- "type" in node.argument &&
25
- node.argument.type === "Literal" &&
26
- "value" in node.argument &&
27
- node.argument.value === 0
28
- )
29
- return true
30
- return false
31
- }
32
-
33
- export const noEffectSucceedVoid = Rule.define({
34
- name: "no-effect-succeed-void",
35
- meta: Rule.meta({
36
- type: "suggestion",
37
- description:
38
- "Avoid Effect.succeed(undefined). Use Effect.void instead.",
39
- }),
40
- create: function* () {
41
- const ctx = yield* RuleContext
42
- return {
43
- CallExpression: (node) => {
44
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "succeed")) return Effect.void
45
-
46
- if (
47
- "arguments" in node &&
48
- Array.isArray(node.arguments) &&
49
- node.arguments.length === 1 &&
50
- isUndefinedLike(node.arguments[0])
51
- ) {
52
- return ctx.report(
53
- Diagnostic.make({
54
- node,
55
- message: "Use Effect.void instead of Effect.succeed(undefined).",
56
- }),
57
- )
58
- }
59
- return Effect.void
60
- },
61
- }
62
- },
63
- })
@@ -1,91 +0,0 @@
1
- /**
2
- * Ban `console.*` inside `Effect.sync(...)`.
3
- *
4
- * Use Effect.log* instead.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-sync-console
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 consoleMethods = new Set(["log", "warn", "error", "info", "debug", "trace"])
13
-
14
- const containsConsoleCall = (node: unknown): boolean => {
15
- if (node == null || typeof node !== "object") return false
16
- const n = node as Record<string, unknown>
17
- if (
18
- n["type"] === "CallExpression" &&
19
- "callee" in n &&
20
- n["callee"] != null &&
21
- typeof n["callee"] === "object"
22
- ) {
23
- const callee = n["callee"] as Record<string, unknown>
24
- if (
25
- callee["type"] === "MemberExpression" &&
26
- "object" in callee &&
27
- "property" in callee
28
- ) {
29
- const obj = callee["object"] as Record<string, unknown> | null
30
- const prop = callee["property"] as Record<string, unknown> | null
31
- if (
32
- obj != null && obj["type"] === "Identifier" && obj["name"] === "console" &&
33
- prop != null && prop["type"] === "Identifier" && typeof prop["name"] === "string" &&
34
- consoleMethods.has(prop["name"])
35
- ) {
36
- return true
37
- }
38
- }
39
- }
40
- // Recurse into body/arguments
41
- if ("body" in n) {
42
- if (Array.isArray(n["body"])) {
43
- for (const child of n["body"]) {
44
- if (containsConsoleCall(child)) return true
45
- }
46
- } else if (containsConsoleCall(n["body"])) return true
47
- }
48
- if ("argument" in n && containsConsoleCall(n["argument"])) return true
49
- if ("arguments" in n && Array.isArray(n["arguments"])) {
50
- for (const arg of n["arguments"]) {
51
- if (containsConsoleCall(arg)) return true
52
- }
53
- }
54
- if ("expression" in n && containsConsoleCall(n["expression"])) return true
55
- if ("expressions" in n && Array.isArray(n["expressions"])) {
56
- for (const expr of n["expressions"]) {
57
- if (containsConsoleCall(expr)) return true
58
- }
59
- }
60
- return false
61
- }
62
-
63
- export const noEffectSyncConsole = Rule.define({
64
- name: "no-effect-sync-console",
65
- meta: Rule.meta({
66
- type: "suggestion",
67
- description: "Avoid console.* inside Effect.sync. Use Effect.log* instead.",
68
- }),
69
- create: function* () {
70
- const ctx = yield* RuleContext
71
- return {
72
- CallExpression: (node) => {
73
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "sync")) return Effect.void
74
-
75
- if ("arguments" in node && Array.isArray(node.arguments)) {
76
- for (const arg of node.arguments) {
77
- if (containsConsoleCall(arg)) {
78
- return ctx.report(
79
- Diagnostic.make({
80
- node,
81
- message: "Avoid console.* inside Effect.sync. Use Effect.log, Effect.logWarning, etc.",
82
- }),
83
- )
84
- }
85
- }
86
- }
87
- return Effect.void
88
- },
89
- }
90
- },
91
- })
@@ -1,67 +0,0 @@
1
- /**
2
- * Warn on `Effect.sync(() => someCall(...))` wrapping a plain function call.
3
- *
4
- * Consider whether the wrapped call truly needs to be in Effect.sync.
5
- *
6
- * Source: biome-effect-linting-rules/warn-effect-sync-wrapper
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 noEffectSyncWrapper = Rule.define({
13
- name: "no-effect-sync-wrapper",
14
- meta: Rule.meta({
15
- type: "suggestion",
16
- description: "Effect.sync wrapping a plain call. Consider if Effect.sync is necessary.",
17
- }),
18
- create: function* () {
19
- const ctx = yield* RuleContext
20
- return {
21
- CallExpression: (node) => {
22
- if (!AST.isCallOf(node as ESTree.CallExpression, "Effect", "sync")) return Effect.void
23
-
24
- if (!("arguments" in node) || !Array.isArray(node.arguments) || node.arguments.length < 1)
25
- return Effect.void
26
-
27
- const arg = node.arguments[0]
28
- if (arg == null || typeof arg !== "object" || !("type" in arg)) return Effect.void
29
-
30
- // () => someCall(...)
31
- if (arg.type === "ArrowFunctionExpression" && "body" in arg) {
32
- const body = arg.body
33
- if (
34
- body != null &&
35
- typeof body === "object" &&
36
- "type" in body &&
37
- body.type === "CallExpression"
38
- ) {
39
- // Exclude console.* (handled by no-effect-sync-console)
40
- const callee = (body as unknown as Record<string, unknown>)["callee"]
41
- if (
42
- callee != null &&
43
- typeof callee === "object" &&
44
- "type" in callee &&
45
- callee.type === "MemberExpression" &&
46
- "object" in callee &&
47
- callee.object != null &&
48
- typeof callee.object === "object" &&
49
- "name" in callee.object &&
50
- callee.object.name === "console"
51
- ) {
52
- return Effect.void
53
- }
54
-
55
- return ctx.report(
56
- Diagnostic.make({
57
- node,
58
- message: "Effect.sync wrapping a plain function call. Consider if Effect.sync is necessary.",
59
- }),
60
- )
61
- }
62
- }
63
- return Effect.void
64
- },
65
- }
66
- },
67
- })
@@ -1,71 +0,0 @@
1
- /**
2
- * Ban `type X = Effect.Effect<...>` type aliases.
3
- *
4
- * Keep Effect types on service methods or inline at call site.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-type-alias
7
- */
8
- import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
9
- import * as Effect from "effect/Effect"
10
-
11
- const containsEffectType = (node: unknown): boolean => {
12
- if (node == null || typeof node !== "object") return false
13
- const n = node as Record<string, unknown>
14
- // TSTypeReference with Effect.Effect
15
- if (
16
- n["type"] === "TSTypeReference" &&
17
- "typeName" in n &&
18
- n["typeName"] != null &&
19
- typeof n["typeName"] === "object"
20
- ) {
21
- const typeName = n["typeName"] as Record<string, unknown>
22
- if (
23
- typeName["type"] === "TSQualifiedName" &&
24
- "left" in typeName && "right" in typeName
25
- ) {
26
- const left = typeName["left"] as Record<string, unknown> | null
27
- const right = typeName["right"] as Record<string, unknown> | null
28
- if (
29
- left != null && left["type"] === "Identifier" && left["name"] === "Effect" &&
30
- right != null && right["type"] === "Identifier" && right["name"] === "Effect"
31
- ) {
32
- return true
33
- }
34
- }
35
- }
36
- // Recurse into typeAnnotation, typeParameters
37
- if ("typeAnnotation" in n && containsEffectType(n["typeAnnotation"])) return true
38
- if ("typeParameters" in n && n["typeParameters"] != null && typeof n["typeParameters"] === "object") {
39
- const tp = n["typeParameters"] as Record<string, unknown>
40
- if ("params" in tp && Array.isArray(tp["params"])) {
41
- for (const p of tp["params"]) {
42
- if (containsEffectType(p)) return true
43
- }
44
- }
45
- }
46
- return false
47
- }
48
-
49
- export const noEffectTypeAlias = Rule.define({
50
- name: "no-effect-type-alias",
51
- meta: Rule.meta({
52
- type: "suggestion",
53
- description: "Avoid Effect type aliases. Keep Effect types on service methods or inline.",
54
- }),
55
- create: function* () {
56
- const ctx = yield* RuleContext
57
- return {
58
- TSTypeAliasDeclaration: (node) => {
59
- if ("typeAnnotation" in node && containsEffectType(node.typeAnnotation)) {
60
- return ctx.report(
61
- Diagnostic.make({
62
- node,
63
- message: "Avoid type alias wrapping Effect.Effect. Let Effect types flow from service methods.",
64
- }),
65
- )
66
- }
67
- return Effect.void
68
- },
69
- }
70
- },
71
- })
@@ -1,95 +0,0 @@
1
- /**
2
- * Ban wrapper functions that just alias an Effect.fn or pipe(Effect.fn(...)).
3
- *
4
- * Inline the pipeline at the call site or define a real domain function.
5
- *
6
- * Source: biome-effect-linting-rules/no-effect-wrapper-alias
7
- */
8
- import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
9
- import * as Effect from "effect/Effect"
10
-
11
- const isEffectFnCall = (node: unknown): boolean => {
12
- if (node == null || typeof node !== "object") return false
13
- const n = node 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 Record<string, unknown>
18
- if (c["type"] !== "MemberExpression") return false
19
- const obj = c["object"] as Record<string, unknown> | null
20
- const prop = c["property"] as Record<string, unknown> | null
21
- return (
22
- obj != null && obj["type"] === "Identifier" && obj["name"] === "Effect" &&
23
- prop != null && prop["type"] === "Identifier" && prop["name"] === "fn"
24
- )
25
- }
26
-
27
- const isPipeWrappingEffectFn = (node: unknown): boolean => {
28
- if (node == null || typeof node !== "object") return false
29
- const n = node as Record<string, unknown>
30
- if (n["type"] !== "CallExpression") return false
31
- const callee = n["callee"]
32
- if (callee == null || typeof callee !== "object") return false
33
- const c = callee as Record<string, unknown>
34
- if (!(c["type"] === "Identifier" && c["name"] === "pipe")) return false
35
- const args = n["arguments"]
36
- if (!Array.isArray(args) || args.length === 0) return false
37
- return isEffectFnCall(args[0])
38
- }
39
-
40
- export const noEffectWrapperAlias = Rule.define({
41
- name: "no-effect-wrapper-alias",
42
- meta: Rule.meta({
43
- type: "suggestion",
44
- description: "Avoid wrapper functions aliasing Effect.fn. Inline or define a real domain function.",
45
- }),
46
- create: function* () {
47
- const ctx = yield* RuleContext
48
- return {
49
- VariableDeclarator: (node) => {
50
- if (!("init" in node) || node.init == null) return Effect.void
51
- const init = node.init
52
-
53
- // const x = Effect.fn(...)
54
- if (isEffectFnCall(init)) {
55
- return ctx.report(
56
- Diagnostic.make({
57
- node,
58
- message: "Avoid aliasing Effect.fn. Inline the pipeline or define a real domain function.",
59
- }),
60
- )
61
- }
62
-
63
- // const x = pipe(Effect.fn(...), ...)
64
- if (isPipeWrappingEffectFn(init)) {
65
- return ctx.report(
66
- Diagnostic.make({
67
- node,
68
- message: "Avoid wrapping Effect.fn in pipe. Inline the pipeline or define a real domain function.",
69
- }),
70
- )
71
- }
72
-
73
- // const x = () => Effect.fn(...) or const x = () => pipe(Effect.fn(...))
74
- if (
75
- typeof init === "object" &&
76
- "type" in init &&
77
- (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression") &&
78
- "body" in init
79
- ) {
80
- const body = init.body
81
- if (isEffectFnCall(body) || isPipeWrappingEffectFn(body)) {
82
- return ctx.report(
83
- Diagnostic.make({
84
- node,
85
- message: "Avoid wrapper function aliasing Effect.fn. Inline or define a real domain function.",
86
- }),
87
- )
88
- }
89
- }
90
-
91
- return Effect.void
92
- },
93
- }
94
- },
95
- })
@@ -1,54 +0,0 @@
1
- /**
2
- * Ban `class Foo extends Error`.
3
- *
4
- * Use Schema.TaggedErrorClass or Data.TaggedError instead.
5
- *
6
- * Source: language-service/extendsNativeError
7
- */
8
- import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
9
- import * as Effect from "effect/Effect"
10
-
11
- const nativeErrors = new Set([
12
- "Error",
13
- "TypeError",
14
- "RangeError",
15
- "ReferenceError",
16
- "SyntaxError",
17
- "URIError",
18
- "EvalError",
19
- ])
20
-
21
- export const noExtendsNativeError = Rule.define({
22
- name: "no-extends-native-error",
23
- meta: Rule.meta({
24
- type: "suggestion",
25
- description:
26
- "Avoid extending native Error. Use Schema.TaggedErrorClass or Data.TaggedError.",
27
- }),
28
- create: function* () {
29
- const ctx = yield* RuleContext
30
- return {
31
- ClassDeclaration: (node) => {
32
- if (
33
- "superClass" in node &&
34
- node.superClass != null &&
35
- typeof node.superClass === "object" &&
36
- "type" in node.superClass &&
37
- node.superClass.type === "Identifier" &&
38
- "name" in node.superClass &&
39
- typeof node.superClass.name === "string" &&
40
- nativeErrors.has(node.superClass.name)
41
- ) {
42
- return ctx.report(
43
- Diagnostic.make({
44
- node,
45
- message:
46
- "Avoid extending native Error. Use Schema.TaggedErrorClass or Data.TaggedError.",
47
- }),
48
- )
49
- }
50
- return Effect.void
51
- },
52
- }
53
- },
54
- })
@@ -1,77 +0,0 @@
1
- /**
2
- * Ban nested `Effect.flatMap` calls (flatMap ladder).
3
- *
4
- * Build context once with `Effect.all`/`Effect.map` and run a single flatMap.
5
- *
6
- * Source: biome-effect-linting-rules/no-flatmap-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 isEffectFlatMap = (node: ESTree.CallExpression): boolean =>
13
- AST.isCallOf(node, "Effect", "flatMap")
14
-
15
- const containsEffectFlatMap = (node: unknown): boolean => {
16
- if (node == null || typeof node !== "object") return false
17
- const n = node as Record<string, unknown>
18
- if (n["type"] === "CallExpression" && "callee" in n && "arguments" in n) {
19
- if (isEffectFlatMap(node as ESTree.CallExpression)) return true
20
- }
21
- if ("arguments" in n && Array.isArray(n["arguments"])) {
22
- for (const arg of n["arguments"]) {
23
- if (containsEffectFlatMap(arg)) return true
24
- }
25
- }
26
- if ("body" in n) return containsEffectFlatMap(n["body"])
27
- return false
28
- }
29
-
30
- export const noFlatmapLadder = Rule.define({
31
- name: "no-flatmap-ladder",
32
- meta: Rule.meta({
33
- type: "suggestion",
34
- description:
35
- "Avoid nested Effect.flatMap (flatMap ladder). Build context once with Effect.all and run a single flatMap.",
36
- }),
37
- create: function* () {
38
- const ctx = yield* RuleContext
39
- return {
40
- CallExpression: (node) => {
41
- const ce = node as ESTree.CallExpression
42
- if (!isEffectFlatMap(ce)) return Effect.void
43
- if (!("arguments" in ce) || !Array.isArray(ce.arguments)) return Effect.void
44
-
45
- // Check if any argument's subtree contains another Effect.flatMap
46
- for (const arg of ce.arguments) {
47
- if (arg != null && typeof arg === "object" && "type" in arg) {
48
- if (arg.type === "CallExpression" && isEffectFlatMap(arg as ESTree.CallExpression)) {
49
- return ctx.report(
50
- Diagnostic.make({
51
- node,
52
- message:
53
- "Nested Effect.flatMap detected. Build context with Effect.all, then single flatMap.",
54
- }),
55
- )
56
- }
57
- // Check inside arrow/function body
58
- if (
59
- (arg.type === "ArrowFunctionExpression" || arg.type === "FunctionExpression") &&
60
- "body" in arg &&
61
- containsEffectFlatMap(arg.body)
62
- ) {
63
- return ctx.report(
64
- Diagnostic.make({
65
- node,
66
- message:
67
- "Nested Effect.flatMap detected. Build context with Effect.all, then single flatMap.",
68
- }),
69
- )
70
- }
71
- }
72
- }
73
- return Effect.void
74
- },
75
- }
76
- },
77
- })
@@ -1,62 +0,0 @@
1
- /**
2
- * Ban `Option.fromNullable(x ?? null)` / `Option.fromNullable(x ?? undefined)`.
3
- *
4
- * The nullish coalescing is redundant — pass the source directly.
5
- *
6
- * Source: biome-effect-linting-rules/no-fromnullable-nullish-coalesce
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 noFromNullableCoalesce = Rule.define({
13
- name: "no-fromnullable-coalesce",
14
- meta: Rule.meta({
15
- type: "suggestion",
16
- description:
17
- "Redundant nullish coalescing in Option.fromNullable. Pass the value directly.",
18
- }),
19
- create: function* () {
20
- const ctx = yield* RuleContext
21
- return {
22
- CallExpression: (node) => {
23
- // Match Option.fromNullable(...) or Option.fromNullishOr(...)
24
- const ce = node as ESTree.CallExpression
25
- const isFromNullable =
26
- AST.isCallOf(ce, "Option", "fromNullable") ||
27
- AST.isCallOf(ce, "Option", "fromNullishOr")
28
- if (!isFromNullable) return Effect.void
29
-
30
- if ("arguments" in node && Array.isArray(node.arguments) && node.arguments.length >= 1) {
31
- const arg = node.arguments[0]
32
- if (
33
- arg != null &&
34
- typeof arg === "object" &&
35
- "type" in arg &&
36
- arg.type === "LogicalExpression" &&
37
- "operator" in arg &&
38
- arg.operator === "??"
39
- ) {
40
- // Check RHS is null or undefined
41
- if ("right" in arg && arg.right != null && typeof arg.right === "object" && "type" in arg.right) {
42
- const rhs = arg.right
43
- const isNullish =
44
- (rhs.type === "Literal" && "value" in rhs && rhs.value === null) ||
45
- (rhs.type === "Identifier" && "name" in rhs && rhs.name === "undefined")
46
- if (isNullish) {
47
- return ctx.report(
48
- Diagnostic.make({
49
- node,
50
- message:
51
- "Redundant ?? null/undefined in Option.fromNullable. Pass the value directly.",
52
- }),
53
- )
54
- }
55
- }
56
- }
57
- }
58
- return Effect.void
59
- },
60
- }
61
- },
62
- })