oxlint-plugin-effect 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/package.json +6 -7
  3. package/src/presets/core.ts +23 -12
  4. package/src/presets/effect-native.ts +18 -25
  5. package/src/presets/full.ts +32 -46
  6. package/src/presets/functional.ts +18 -0
  7. package/src/presets/index.ts +2 -0
  8. package/src/presets/strict.ts +77 -0
  9. package/src/rules/index.ts +17 -28
  10. package/src/rules/no-arrow-ladder.ts +1 -2
  11. package/src/rules/no-async-function.ts +1 -2
  12. package/src/rules/no-catch-all-to-map-error.ts +89 -0
  13. package/src/rules/no-effect-fn-generator.ts +1 -2
  14. package/src/rules/no-effect-gen-adapter.ts +1 -2
  15. package/src/rules/no-effect-map-flatten.ts +82 -0
  16. package/src/rules/no-effect-map-void.ts +1 -2
  17. package/src/rules/no-effect-orElse-ladder.ts +1 -2
  18. package/src/rules/no-effect-succeed-string.ts +1 -2
  19. package/src/rules/no-effect-succeed-variable.ts +1 -2
  20. package/src/rules/no-effect-succeed-void.ts +1 -2
  21. package/src/rules/no-effect-sync-console.ts +1 -2
  22. package/src/rules/no-effect-sync-wrapper.ts +1 -2
  23. package/src/rules/no-effect-type-alias.ts +1 -2
  24. package/src/rules/no-effect-wrapper-alias.ts +1 -4
  25. package/src/rules/no-extends-native-error.ts +1 -2
  26. package/src/rules/no-flatmap-ladder.ts +1 -3
  27. package/src/rules/no-fromnullable-coalesce.ts +1 -2
  28. package/src/rules/no-global-error-in-catch.ts +104 -0
  29. package/src/rules/no-global-error-in-failure.ts +83 -0
  30. package/src/rules/no-globals.ts +178 -0
  31. package/src/rules/no-iife-wrapper.ts +1 -2
  32. package/src/rules/{no-inline-runtime-provide.ts → no-inline-provide.ts} +3 -4
  33. package/src/rules/no-instanceof-schema.ts +2 -3
  34. package/src/rules/no-manual-effect-channels.ts +1 -2
  35. package/src/rules/no-match-effect-branch.ts +1 -2
  36. package/src/rules/no-match-void-branch.ts +1 -2
  37. package/src/rules/no-multiple-effect-provide.ts +75 -0
  38. package/src/rules/no-nested-effect-call.ts +1 -3
  39. package/src/rules/no-nested-effect-gen.ts +1 -2
  40. package/src/rules/no-nested-pipe.ts +1 -4
  41. package/src/rules/no-new-error.ts +46 -10
  42. package/src/rules/no-new-promise.ts +43 -7
  43. package/src/rules/no-node-builtin-import.ts +1 -3
  44. package/src/rules/no-option-boolean-normalization.ts +1 -2
  45. package/src/rules/no-positional-log-error.ts +76 -0
  46. package/src/rules/no-redundant-schema-tag-identifier.ts +62 -0
  47. package/src/rules/no-return-in-arrow.ts +1 -2
  48. package/src/rules/no-return-nullish.ts +80 -0
  49. package/src/rules/no-schema-struct-with-tag.ts +64 -0
  50. package/src/rules/no-schema-union-of-literals.ts +48 -0
  51. package/src/rules/no-string-sentinel-const.ts +1 -2
  52. package/src/rules/no-ternary.ts +1 -3
  53. package/src/rules/no-throw-statement.ts +32 -6
  54. package/src/rules/no-try-catch.ts +32 -7
  55. package/src/rules/no-unnecessary-arrow-block.ts +1 -2
  56. package/src/rules/no-unnecessary-effect-gen.ts +1 -3
  57. package/src/rules/no-unnecessary-pipe-chain.ts +47 -0
  58. package/src/rules/no-unnecessary-pipe.ts +1 -2
  59. package/src/vendor/effect-oxlint/Rule.ts +111 -173
  60. package/tests/ban-rules.test.ts +0 -167
  61. package/tests/context-rules.test.ts +75 -158
  62. package/tests/pattern-rules.test.ts +39 -50
  63. package/src/rules/no-console-in-effect.ts +0 -46
  64. package/src/rules/no-date-in-effect.ts +0 -61
  65. package/src/rules/no-dynamic-import.ts +0 -13
  66. package/src/rules/no-fetch-in-effect.ts +0 -47
  67. package/src/rules/no-global-console.ts +0 -17
  68. package/src/rules/no-global-date.ts +0 -20
  69. package/src/rules/no-global-fetch.ts +0 -14
  70. package/src/rules/no-global-random.ts +0 -13
  71. package/src/rules/no-global-timers.ts +0 -17
  72. package/src/rules/no-json-in-effect.ts +0 -45
  73. package/src/rules/no-json-parse.ts +0 -18
  74. package/src/rules/no-platform-globals.ts +0 -117
  75. package/src/rules/no-process-env-in-effect.ts +0 -39
  76. package/src/rules/no-process-env.ts +0 -13
  77. package/src/rules/no-random-in-effect.ts +0 -39
  78. package/src/rules/no-return-null.ts +0 -47
  79. package/src/rules/no-throw-in-effect-gen.ts +0 -42
  80. package/src/rules/no-timers-in-effect.ts +0 -47
  81. package/src/rules/no-try-catch-in-effect-gen.ts +0 -42
package/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ # oxlint-plugin-effect
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`e1c49ed`](https://github.com/cevr/effect-oxlint/commit/e1c49ed4195de9df24c0e30196285ec29cfe5748) Thanks [@cevr](https://github.com/cevr)! - Major rule overhaul: add 16 Go type-aware rules, consolidate JS rules, enforce Effect model.
8
+
9
+ **JS plugin (59 rules, was 66):**
10
+
11
+ New rules:
12
+
13
+ - noCatchAllToMapError, noUnnecessaryPipeChain, noMultipleEffectProvide
14
+ - noSchemaUnionOfLiterals, noSchemaStructWithTag, noRedundantSchemaTagIdentifier
15
+ - noEffectMapFlatten, noGlobalErrorInFailure, noGlobalErrorInCatch
16
+ - noPositionalLogError (from agent session analysis — 57 violations)
17
+ - noReturnNullish (catches null, undefined, void 0 → points to Option.none())
18
+ - noGlobals (consolidated context rule — console, fetch, Date, Math.random, crypto, timers, JSON, process/Bun/Deno with per-API Effect alternative hints)
19
+
20
+ Removed 14 generic global bans (no-console, no-date, no-fetch, etc.) — these belong in oxlint built-in config, not an Effect plugin. Every removed rule has an Effect-context counterpart in noGlobals.
21
+
22
+ Restored 5 Effect-enforcing rules that prevent escaping the Effect model:
23
+
24
+ - noThrowStatement → "Use yield* Effect.fail() or yield* new MyError()"
25
+ - noTryCatch → "Use Effect.try / Effect.tryPromise"
26
+ - noNewPromise → "Use Effect.async / Effect.tryPromise / Effect.promise"
27
+ - noNewError → "Define class MyError extends Schema.TaggedErrorClass..."
28
+ - noReturnNullish → "Use Option.none() / Effect.void"
29
+
30
+ Redesigned Rule.banMultiple API with per-spec BanSpec discriminated union.
31
+ Promoted high-frequency agent violations from warn to error in core/full presets.
32
+
33
+ **Go binary (24 rules, was 8):**
34
+
35
+ - Layer/leak detection: missingEffectContext, missingEffectError, missingLayerContext, leakingRequirements, layerMergeAllWithDependencies
36
+ - Error hygiene: anyUnknownInError, unknownInEffectCatch
37
+ - Code quality: effectFnOpportunity, classSelfMismatch, fnImplicitAny, scopeInLayerEffect, strictProvide, unnecessaryFailYieldable, genericServices, overriddenSchemaConstructor, nonObjectServiceType
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "oxlint-plugin-effect",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "type": "module",
5
5
  "description": "oxlint plugin with Effect-specific lint rules",
6
6
  "license": "MIT",
7
- "repository": { "type": "git", "url": "https://github.com/cevr/effect-oxlint" },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/cevr/effect-oxlint"
10
+ },
8
11
  "exports": {
9
12
  ".": "./src/index.ts",
10
13
  "./plugin": "./src/plugin.ts",
@@ -23,9 +26,7 @@
23
26
  "test": "bun test",
24
27
  "gate": "concurrently -n type,style,test -c blue,yellow,green \"bun run typecheck\" \"bun run lint\" \"bun run test\"",
25
28
  "codegen": "bun run scripts/codegen.ts",
26
- "add-rule": "bun run scripts/add-rule.ts",
27
- "version": "changeset version",
28
- "release": "changeset publish"
29
+ "add-rule": "bun run scripts/add-rule.ts"
29
30
  },
30
31
  "dependencies": {
31
32
  "@oxlint/plugins": "^1.60.0"
@@ -34,8 +35,6 @@
34
35
  "effect": ">=4.0.0-beta.49"
35
36
  },
36
37
  "devDependencies": {
37
- "@changesets/changelog-github": "^0.6.0",
38
- "@changesets/cli": "^2.30.0",
39
38
  "@effect/language-service": "latest",
40
39
  "@effect/vitest": "latest",
41
40
  "@types/bun": "latest",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Core preset — essential Effect rules without global bans.
2
+ * Core preset — essential Effect rules.
3
3
  * Good starting point for projects transitioning to Effect.
4
4
  */
5
5
  export const core = {
@@ -13,9 +13,9 @@ export const core = {
13
13
  // AST pattern rules
14
14
  "effect/noNestedPipe": "error",
15
15
  "effect/noNestedEffectGen": "error",
16
- "effect/noUnnecessaryEffectGen": "warn",
17
- "effect/noEffectSucceedVoid": "warn",
18
- "effect/noEffectMapVoid": "warn",
16
+ "effect/noUnnecessaryEffectGen": "error",
17
+ "effect/noEffectSucceedVoid": "error",
18
+ "effect/noEffectMapVoid": "error",
19
19
  "effect/noUnnecessaryPipe": "warn",
20
20
  "effect/noEffectFnGenerator": "warn",
21
21
  "effect/noFlatmapLadder": "error",
@@ -23,14 +23,25 @@ export const core = {
23
23
  "effect/noIifeWrapper": "warn",
24
24
  "effect/noFromNullableCoalesce": "warn",
25
25
  "effect/noUnnecessaryArrowBlock": "warn",
26
- "effect/noEffectGenAdapter": "warn",
26
+ "effect/noEffectGenAdapter": "error",
27
27
  "effect/noEffectSyncConsole": "error",
28
- "effect/noArrowLadder": "warn",
28
+ "effect/noCatchAllToMapError": "error",
29
+ "effect/noUnnecessaryPipeChain": "error",
30
+ "effect/noMultipleEffectProvide": "error",
31
+ "effect/noSchemaUnionOfLiterals": "warn",
32
+ "effect/noSchemaStructWithTag": "warn",
33
+ "effect/noRedundantSchemaTagIdentifier": "warn",
34
+ "effect/noEffectMapFlatten": "warn",
35
+ "effect/noPositionalLogError": "error",
29
36
 
30
- // Effect-context rules
31
- "effect/noThrowInEffectGen": "error",
32
- "effect/noTryCatchInEffectGen": "warn",
33
- "effect/noConsoleInEffect": "warn",
34
- "effect/noInlineRuntimeProvide": "warn",
35
- "effect/noPlatformGlobals": "warn",
37
+ // Effect-enforcing bans (prevent escaping Effect model)
38
+ "effect/noThrowStatement": "error",
39
+ "effect/noTryCatch": "error",
40
+ "effect/noNewPromise": "error",
41
+ "effect/noNewError": "error",
42
+ "effect/noReturnNullish": "warn",
43
+
44
+ // Effect-context rules (inside Effect.gen/fn)
45
+ "effect/noGlobals": "error",
46
+ "effect/noInlineProvide": "error",
36
47
  } as const
@@ -1,37 +1,30 @@
1
1
  /**
2
2
  * Effect-native preset — for codebases fully committed to Effect.
3
- * Bans all globals and builtins in favor of Effect platform services.
3
+ * All Effect-context rules at error. Enforces Effect platform services
4
+ * and tagged errors inside generators.
4
5
  */
5
6
  export const effectNative = {
6
- // Global bans (everywhere)
7
- "effect/noGlobalFetch": "error",
8
- "effect/noGlobalConsole": "error",
9
- "effect/noGlobalDate": "error",
10
- "effect/noGlobalRandom": "error",
11
- "effect/noGlobalTimers": "error",
12
- "effect/noNewPromise": "error",
13
- "effect/noNewError": "error",
14
- "effect/noProcessEnv": "error",
7
+ // Global bans (everywhere, not just Effect context)
8
+ "effect/noAsyncFunction": "error",
15
9
  "effect/noNodeBuiltinImport": "error",
10
+
11
+ // Effect-enforcing bans
16
12
  "effect/noThrowStatement": "error",
17
13
  "effect/noTryCatch": "error",
18
- "effect/noReturnNull": "error",
19
- "effect/noJsonParse": "error",
14
+ "effect/noNewPromise": "error",
15
+ "effect/noNewError": "error",
16
+ "effect/noReturnNullish": "error",
17
+
18
+ // Effect-context
19
+ "effect/noGlobals": "error",
20
+ "effect/noInlineProvide": "error",
21
+
22
+ // Error hygiene
23
+ "effect/noGlobalErrorInFailure": "error",
24
+ "effect/noGlobalErrorInCatch": "error",
20
25
  "effect/noExtendsNativeError": "error",
21
- "effect/noAsyncFunction": "error",
22
26
  "effect/noInstanceofSchema": "error",
23
- "effect/noRuntimeRunFork": "error",
24
- "effect/noDynamicImport": "error",
25
- "effect/noSwitchStatement": "error",
26
-
27
- // Effect-context (inside Effect.gen/fn)
28
- "effect/noFetchInEffect": "error",
29
- "effect/noDateInEffect": "error",
30
- "effect/noRandomInEffect": "error",
31
- "effect/noTimersInEffect": "error",
32
- "effect/noJsonInEffect": "error",
33
- "effect/noProcessEnvInEffect": "error",
34
- "effect/noPlatformGlobals": "error",
27
+ "effect/noPositionalLogError": "error",
35
28
 
36
29
  // Type hygiene
37
30
  "effect/noEffectTypeAlias": "error",
@@ -1,5 +1,8 @@
1
1
  /**
2
- * Full preset — all rules enabled.
2
+ * Full preset — all Effect-specific rules enabled.
3
+ *
4
+ * Does NOT include generic JS rules (no-console, no-throw, etc.) —
5
+ * configure those via oxlint's built-in rules in .oxlintrc.json.
3
6
  */
4
7
  export const full = {
5
8
  // API bans
@@ -12,42 +15,20 @@ export const full = {
12
15
  "effect/noRuntimeRunFork": "error",
13
16
  "effect/noRunInEffect": "error",
14
17
 
15
- // Global bans
16
- "effect/noGlobalFetch": "warn",
17
- "effect/noGlobalConsole": "warn",
18
- "effect/noGlobalDate": "warn",
19
- "effect/noGlobalRandom": "warn",
20
- "effect/noGlobalTimers": "warn",
21
- "effect/noNewPromise": "warn",
22
- "effect/noNewError": "warn",
23
- "effect/noProcessEnv": "warn",
24
-
25
- // Import bans
18
+ // Global bans (everywhere, not just Effect context)
19
+ "effect/noAsyncFunction": "warn",
26
20
  "effect/noNodeBuiltinImport": "warn",
27
- "effect/noDynamicImport": "error",
28
-
29
- // Statement bans
30
- "effect/noThrowStatement": "error",
31
- "effect/noTryCatch": "warn",
32
- "effect/noReturnNull": "warn",
33
- "effect/noSwitchStatement": "warn",
34
- "effect/noIfStatement": "off",
35
- "effect/noTernary": "off",
36
-
37
- // JSON
38
- "effect/noJsonParse": "warn",
39
21
 
40
22
  // AST pattern rules
41
23
  "effect/noNestedPipe": "error",
42
24
  "effect/noNestedEffectGen": "error",
43
- "effect/noUnnecessaryEffectGen": "warn",
44
- "effect/noEffectSucceedVoid": "warn",
45
- "effect/noEffectMapVoid": "warn",
25
+ "effect/noUnnecessaryEffectGen": "error",
26
+ "effect/noEffectSucceedVoid": "error",
27
+ "effect/noEffectMapVoid": "error",
46
28
  "effect/noUnnecessaryPipe": "warn",
47
- "effect/noExtendsNativeError": "warn",
29
+ "effect/noExtendsNativeError": "error",
48
30
  "effect/noEffectFnGenerator": "warn",
49
- "effect/noInstanceofSchema": "warn",
50
- "effect/noAsyncFunction": "warn",
31
+ "effect/noInstanceofSchema": "error",
51
32
  "effect/noFlatmapLadder": "error",
52
33
  "effect/noNestedEffectCall": "error",
53
34
  "effect/noIifeWrapper": "warn",
@@ -55,7 +36,7 @@ export const full = {
55
36
  "effect/noEffectOrElseLadder": "warn",
56
37
  "effect/noFromNullableCoalesce": "warn",
57
38
  "effect/noUnnecessaryArrowBlock": "warn",
58
- "effect/noEffectGenAdapter": "warn",
39
+ "effect/noEffectGenAdapter": "error",
59
40
  "effect/noEffectSyncConsole": "error",
60
41
  "effect/noEffectTypeAlias": "warn",
61
42
  "effect/noEffectWrapperAlias": "warn",
@@ -63,22 +44,27 @@ export const full = {
63
44
  "effect/noManualEffectChannels": "warn",
64
45
  "effect/noMatchVoidBranch": "warn",
65
46
  "effect/noOptionBooleanNormalization": "warn",
66
- "effect/noReturnInArrow": "off",
67
- "effect/noStringSentinelConst": "off",
68
47
  "effect/noEffectSyncWrapper": "off",
69
- "effect/noArrowLadder": "warn",
70
48
  "effect/noMatchEffectBranch": "warn",
49
+ "effect/noCatchAllToMapError": "error",
50
+ "effect/noUnnecessaryPipeChain": "error",
51
+ "effect/noMultipleEffectProvide": "error",
52
+ "effect/noSchemaUnionOfLiterals": "warn",
53
+ "effect/noSchemaStructWithTag": "warn",
54
+ "effect/noRedundantSchemaTagIdentifier": "warn",
55
+ "effect/noEffectMapFlatten": "warn",
56
+ "effect/noGlobalErrorInFailure": "error",
57
+ "effect/noGlobalErrorInCatch": "error",
58
+ "effect/noPositionalLogError": "error",
59
+
60
+ // Effect-enforcing bans (prevent escaping Effect model)
61
+ "effect/noThrowStatement": "error",
62
+ "effect/noTryCatch": "error",
63
+ "effect/noNewPromise": "error",
64
+ "effect/noNewError": "error",
65
+ "effect/noReturnNullish": "warn",
71
66
 
72
- // Effect-context rules
73
- "effect/noThrowInEffectGen": "error",
74
- "effect/noTryCatchInEffectGen": "warn",
75
- "effect/noConsoleInEffect": "warn",
76
- "effect/noFetchInEffect": "warn",
77
- "effect/noDateInEffect": "warn",
78
- "effect/noRandomInEffect": "warn",
79
- "effect/noTimersInEffect": "warn",
80
- "effect/noJsonInEffect": "warn",
81
- "effect/noProcessEnvInEffect": "warn",
82
- "effect/noPlatformGlobals": "warn",
83
- "effect/noInlineRuntimeProvide": "warn",
67
+ // Effect-context rules (inside Effect.gen/fn)
68
+ "effect/noGlobals": "error",
69
+ "effect/noInlineProvide": "error",
84
70
  } as const
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Functional preset — strict functional style for Effect code.
3
+ * Bans imperative patterns. Layer on top of core or full.
4
+ */
5
+ export const functional = {
6
+ "effect/noIfStatement": "error",
7
+ "effect/noSwitchStatement": "error",
8
+ "effect/noTernary": "error",
9
+ "effect/noReturnInArrow": "warn",
10
+ "effect/noReturnNull": "warn",
11
+ "effect/noEffectSucceedVariable": "error",
12
+ "effect/noEffectSucceedString": "error",
13
+ "effect/noStringSentinelConst": "warn",
14
+ "effect/noMatchVoidBranch": "error",
15
+ "effect/noMatchEffectBranch": "error",
16
+ "effect/noOptionBooleanNormalization": "error",
17
+ "effect/noArrowLadder": "error",
18
+ } as const
@@ -1,3 +1,5 @@
1
1
  export { full } from "./full.js"
2
2
  export { core } from "./core.js"
3
3
  export { effectNative } from "./effect-native.js"
4
+ export { functional } from "./functional.js"
5
+ export { strict } from "./strict.js"
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Strict preset — every rule at error. No warnings, no off.
3
+ * The nuclear option. Use when you want zero tolerance.
4
+ */
5
+ export const strict = {
6
+ // API bans
7
+ "effect/noEffectDo": "error",
8
+ "effect/noEffectNever": "error",
9
+ "effect/noEffectAs": "error",
10
+ "effect/noEffectAsync": "error",
11
+ "effect/noEffectBind": "error",
12
+ "effect/noOptionAs": "error",
13
+ "effect/noRuntimeRunFork": "error",
14
+ "effect/noRunInEffect": "error",
15
+
16
+ // Style / functional
17
+ "effect/noReturnNull": "error",
18
+ "effect/noSwitchStatement": "error",
19
+ "effect/noIfStatement": "error",
20
+ "effect/noTernary": "error",
21
+ "effect/noReturnInArrow": "error",
22
+ "effect/noStringSentinelConst": "error",
23
+ "effect/noArrowLadder": "error",
24
+
25
+ // Global bans (everywhere, not just Effect context)
26
+ "effect/noAsyncFunction": "error",
27
+ "effect/noNodeBuiltinImport": "error",
28
+
29
+ // AST pattern rules
30
+ "effect/noNestedPipe": "error",
31
+ "effect/noNestedEffectGen": "error",
32
+ "effect/noUnnecessaryEffectGen": "error",
33
+ "effect/noEffectSucceedVoid": "error",
34
+ "effect/noEffectMapVoid": "error",
35
+ "effect/noUnnecessaryPipe": "error",
36
+ "effect/noExtendsNativeError": "error",
37
+ "effect/noEffectFnGenerator": "error",
38
+ "effect/noInstanceofSchema": "error",
39
+ "effect/noFlatmapLadder": "error",
40
+ "effect/noNestedEffectCall": "error",
41
+ "effect/noIifeWrapper": "error",
42
+ "effect/noEffectSucceedString": "error",
43
+ "effect/noEffectOrElseLadder": "error",
44
+ "effect/noFromNullableCoalesce": "error",
45
+ "effect/noUnnecessaryArrowBlock": "error",
46
+ "effect/noEffectGenAdapter": "error",
47
+ "effect/noEffectSyncConsole": "error",
48
+ "effect/noEffectTypeAlias": "error",
49
+ "effect/noEffectWrapperAlias": "error",
50
+ "effect/noEffectSucceedVariable": "error",
51
+ "effect/noManualEffectChannels": "error",
52
+ "effect/noMatchVoidBranch": "error",
53
+ "effect/noOptionBooleanNormalization": "error",
54
+ "effect/noEffectSyncWrapper": "error",
55
+ "effect/noMatchEffectBranch": "error",
56
+ "effect/noCatchAllToMapError": "error",
57
+ "effect/noUnnecessaryPipeChain": "error",
58
+ "effect/noMultipleEffectProvide": "error",
59
+ "effect/noSchemaUnionOfLiterals": "error",
60
+ "effect/noSchemaStructWithTag": "error",
61
+ "effect/noRedundantSchemaTagIdentifier": "error",
62
+ "effect/noEffectMapFlatten": "error",
63
+ "effect/noGlobalErrorInFailure": "error",
64
+ "effect/noGlobalErrorInCatch": "error",
65
+ "effect/noPositionalLogError": "error",
66
+
67
+ // Effect-enforcing bans
68
+ "effect/noThrowStatement": "error",
69
+ "effect/noTryCatch": "error",
70
+ "effect/noNewPromise": "error",
71
+ "effect/noNewError": "error",
72
+ "effect/noReturnNullish": "error",
73
+
74
+ // Effect-context rules
75
+ "effect/noGlobals": "error",
76
+ "effect/noInlineProvide": "error",
77
+ } as const
@@ -14,29 +14,17 @@ export { noOptionAs } from "./no-option-as.js"
14
14
  export { noRunInEffect } from "./no-run-in-effect.js"
15
15
  export { noRuntimeRunFork } from "./no-runtime-run-fork.js"
16
16
 
17
- // --- Global bans ---
18
- export { noGlobalConsole } from "./no-global-console.js"
19
- export { noGlobalDate } from "./no-global-date.js"
20
- export { noGlobalFetch } from "./no-global-fetch.js"
21
- export { noGlobalRandom } from "./no-global-random.js"
22
- export { noGlobalTimers } from "./no-global-timers.js"
23
- export { noProcessEnv } from "./no-process-env.js"
24
-
25
17
  // --- Statement bans ---
26
- export { noDynamicImport } from "./no-dynamic-import.js"
27
18
  export { noIfStatement } from "./no-if-statement.js"
28
19
  export { noSwitchStatement } from "./no-switch-statement.js"
29
- export { noThrowStatement } from "./no-throw-statement.js"
30
- export { noTryCatch } from "./no-try-catch.js"
31
-
32
- // --- JSON ---
33
- export { noJsonParse } from "./no-json-parse.js"
34
20
 
35
21
  // --- AST pattern rules ---
36
22
  export { noArrowLadder } from "./no-arrow-ladder.js"
37
23
  export { noAsyncFunction } from "./no-async-function.js"
24
+ export { noCatchAllToMapError } from "./no-catch-all-to-map-error.js"
38
25
  export { noEffectFnGenerator } from "./no-effect-fn-generator.js"
39
26
  export { noEffectGenAdapter } from "./no-effect-gen-adapter.js"
27
+ export { noEffectMapFlatten } from "./no-effect-map-flatten.js"
40
28
  export { noEffectMapVoid } from "./no-effect-map-void.js"
41
29
  export { noEffectOrElseLadder } from "./no-effect-orElse-ladder.js"
42
30
  export { noEffectSucceedString } from "./no-effect-succeed-string.js"
@@ -49,35 +37,36 @@ export { noEffectWrapperAlias } from "./no-effect-wrapper-alias.js"
49
37
  export { noExtendsNativeError } from "./no-extends-native-error.js"
50
38
  export { noFlatmapLadder } from "./no-flatmap-ladder.js"
51
39
  export { noFromNullableCoalesce } from "./no-fromnullable-coalesce.js"
40
+ export { noGlobalErrorInCatch } from "./no-global-error-in-catch.js"
41
+ export { noGlobalErrorInFailure } from "./no-global-error-in-failure.js"
52
42
  export { noIifeWrapper } from "./no-iife-wrapper.js"
53
43
  export { noInstanceofSchema } from "./no-instanceof-schema.js"
54
44
  export { noManualEffectChannels } from "./no-manual-effect-channels.js"
55
45
  export { noMatchEffectBranch } from "./no-match-effect-branch.js"
56
46
  export { noMatchVoidBranch } from "./no-match-void-branch.js"
47
+ export { noMultipleEffectProvide } from "./no-multiple-effect-provide.js"
57
48
  export { noNestedEffectCall } from "./no-nested-effect-call.js"
58
49
  export { noNestedEffectGen } from "./no-nested-effect-gen.js"
59
50
  export { noNestedPipe } from "./no-nested-pipe.js"
60
- export { noNewError } from "./no-new-error.js"
61
- export { noNewPromise } from "./no-new-promise.js"
62
51
  export { noNodeBuiltinImport } from "./no-node-builtin-import.js"
63
52
  export { noOptionBooleanNormalization } from "./no-option-boolean-normalization.js"
53
+ export { noPositionalLogError } from "./no-positional-log-error.js"
54
+ export { noRedundantSchemaTagIdentifier } from "./no-redundant-schema-tag-identifier.js"
64
55
  export { noReturnInArrow } from "./no-return-in-arrow.js"
65
- export { noReturnNull } from "./no-return-null.js"
56
+ export { noSchemaStructWithTag } from "./no-schema-struct-with-tag.js"
57
+ export { noSchemaUnionOfLiterals } from "./no-schema-union-of-literals.js"
66
58
  export { noStringSentinelConst } from "./no-string-sentinel-const.js"
67
59
  export { noTernary } from "./no-ternary.js"
68
60
  export { noUnnecessaryArrowBlock } from "./no-unnecessary-arrow-block.js"
69
61
  export { noUnnecessaryEffectGen } from "./no-unnecessary-effect-gen.js"
62
+ export { noUnnecessaryPipeChain } from "./no-unnecessary-pipe-chain.js"
70
63
  export { noUnnecessaryPipe } from "./no-unnecessary-pipe.js"
71
64
 
72
65
  // --- Effect-context rules ---
73
- export { noConsoleInEffect } from "./no-console-in-effect.js"
74
- export { noDateInEffect } from "./no-date-in-effect.js"
75
- export { noFetchInEffect } from "./no-fetch-in-effect.js"
76
- export { noInlineRuntimeProvide } from "./no-inline-runtime-provide.js"
77
- export { noJsonInEffect } from "./no-json-in-effect.js"
78
- export { noPlatformGlobals } from "./no-platform-globals.js"
79
- export { noProcessEnvInEffect } from "./no-process-env-in-effect.js"
80
- export { noRandomInEffect } from "./no-random-in-effect.js"
81
- export { noThrowInEffectGen } from "./no-throw-in-effect-gen.js"
82
- export { noTimersInEffect } from "./no-timers-in-effect.js"
83
- export { noTryCatchInEffectGen } from "./no-try-catch-in-effect-gen.js"
66
+ export { noGlobals } from "./no-globals.js"
67
+ export { noInlineProvide } from "./no-inline-provide.js"
68
+ export { noNewError } from "./no-new-error.js"
69
+ export { noNewPromise } from "./no-new-promise.js"
70
+ export { noReturnNullish } from "./no-return-nullish.js"
71
+ export { noThrowStatement } from "./no-throw-statement.js"
72
+ export { noTryCatch } from "./no-try-catch.js"
@@ -5,8 +5,7 @@
5
5
  *
6
6
  * Source: biome-effect-linting-rules/no-arrow-ladder
7
7
  */
8
- import { Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
9
- import { RuleContext } from "../vendor/effect-oxlint/index.js"
8
+ import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
10
9
  import * as Effect from "effect/Effect"
11
10
 
12
11
  const isIife = (node: unknown): boolean => {
@@ -8,8 +8,7 @@
8
8
  * Note: This is an effectNative rule — off by default.
9
9
  * Only enable in codebases fully committed to Effect.
10
10
  */
11
- import { Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
12
- import { RuleContext } from "../vendor/effect-oxlint/index.js"
11
+ import { Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
13
12
  import * as Effect from "effect/Effect"
14
13
 
15
14
  export const noAsyncFunction = Rule.define({
@@ -0,0 +1,89 @@
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
+ }),
53
+ create: function* () {
54
+ const ctx = yield* RuleContext
55
+ return {
56
+ CallExpression: (node) => {
57
+ const call = node as ESTree.CallExpression
58
+ const names = Option.getOrUndefined(AST.memberNames(call.callee as ESTree.MemberExpression))
59
+ if (names === undefined) return Effect.void
60
+ const [obj, prop] = names
61
+ if (obj !== "Effect" && obj !== "_") return Effect.void
62
+ if (!catchNames.has(prop)) return Effect.void
63
+
64
+ // The callback is the last argument
65
+ const args = call.arguments
66
+ if (args.length === 0) return Effect.void
67
+ const callback = args[args.length - 1]
68
+ if (callback === undefined) return Effect.void
69
+ if (
70
+ callback.type !== "ArrowFunctionExpression" &&
71
+ callback.type !== "FunctionExpression"
72
+ ) {
73
+ return Effect.void
74
+ }
75
+
76
+ if (bodyIsEffectFail(callback as ESTree.Node)) {
77
+ const replacement = prop === "catchAllCause" ? "mapErrorCause" : "mapError"
78
+ return ctx.report(
79
+ Diagnostic.make({
80
+ node,
81
+ message: `Use Effect.${replacement} instead of Effect.${prop}(e => Effect.fail(...)).`,
82
+ }),
83
+ )
84
+ }
85
+ return Effect.void
86
+ },
87
+ }
88
+ },
89
+ })
@@ -11,8 +11,7 @@
11
11
  * a name span, which is the discouraged pattern from the biome rules.
12
12
  */
13
13
  import type { ESTree } from "@oxlint/plugins"
14
- import { AST, Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
15
- import { RuleContext } from "../vendor/effect-oxlint/index.js"
14
+ import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
16
15
  import * as Effect from "effect/Effect"
17
16
 
18
17
  export const noEffectFnGenerator = Rule.define({
@@ -6,8 +6,7 @@
6
6
  * Source: language-service/effectGenUsesAdapter
7
7
  */
8
8
  import type { ESTree } from "@oxlint/plugins"
9
- import { AST, Diagnostic, Rule } from "../vendor/effect-oxlint/index.js"
10
- import { RuleContext } from "../vendor/effect-oxlint/index.js"
9
+ import { AST, Diagnostic, Rule, RuleContext } from "../vendor/effect-oxlint/index.js"
11
10
  import * as Effect from "effect/Effect"
12
11
 
13
12
  export const noEffectGenAdapter = Rule.define({