oxlint-plugin-effect 0.0.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 (95) hide show
  1. package/.effect-lsp.json +60 -0
  2. package/.oxlintrc.json +33 -0
  3. package/package.json +51 -0
  4. package/scripts/add-rule.ts +87 -0
  5. package/scripts/codegen.ts +108 -0
  6. package/src/index.ts +9 -0
  7. package/src/plugin.ts +16 -0
  8. package/src/presets/core.ts +36 -0
  9. package/src/presets/effect-native.ts +41 -0
  10. package/src/presets/full.ts +84 -0
  11. package/src/presets/index.ts +3 -0
  12. package/src/rules/_effect-context.ts +28 -0
  13. package/src/rules/index.ts +83 -0
  14. package/src/rules/no-arrow-ladder.ts +71 -0
  15. package/src/rules/no-async-function.ts +48 -0
  16. package/src/rules/no-console-in-effect.ts +46 -0
  17. package/src/rules/no-date-in-effect.ts +61 -0
  18. package/src/rules/no-dynamic-import.ts +13 -0
  19. package/src/rules/no-effect-as.ts +14 -0
  20. package/src/rules/no-effect-async.ts +14 -0
  21. package/src/rules/no-effect-bind.ts +13 -0
  22. package/src/rules/no-effect-do.ts +14 -0
  23. package/src/rules/no-effect-fn-generator.ts +59 -0
  24. package/src/rules/no-effect-gen-adapter.ts +51 -0
  25. package/src/rules/no-effect-map-void.ts +81 -0
  26. package/src/rules/no-effect-never.ts +14 -0
  27. package/src/rules/no-effect-orElse-ladder.ts +80 -0
  28. package/src/rules/no-effect-succeed-string.ts +53 -0
  29. package/src/rules/no-effect-succeed-variable.ts +51 -0
  30. package/src/rules/no-effect-succeed-void.ts +64 -0
  31. package/src/rules/no-effect-sync-console.ts +92 -0
  32. package/src/rules/no-effect-sync-wrapper.ts +68 -0
  33. package/src/rules/no-effect-type-alias.ts +72 -0
  34. package/src/rules/no-effect-wrapper-alias.ts +98 -0
  35. package/src/rules/no-extends-native-error.ts +55 -0
  36. package/src/rules/no-fetch-in-effect.ts +47 -0
  37. package/src/rules/no-flatmap-ladder.ts +79 -0
  38. package/src/rules/no-fromnullable-coalesce.ts +63 -0
  39. package/src/rules/no-global-console.ts +17 -0
  40. package/src/rules/no-global-date.ts +20 -0
  41. package/src/rules/no-global-fetch.ts +14 -0
  42. package/src/rules/no-global-random.ts +13 -0
  43. package/src/rules/no-global-timers.ts +17 -0
  44. package/src/rules/no-if-statement.ts +16 -0
  45. package/src/rules/no-iife-wrapper.ts +52 -0
  46. package/src/rules/no-inline-runtime-provide.ts +42 -0
  47. package/src/rules/no-instanceof-schema.ts +43 -0
  48. package/src/rules/no-json-in-effect.ts +45 -0
  49. package/src/rules/no-json-parse.ts +18 -0
  50. package/src/rules/no-manual-effect-channels.ts +59 -0
  51. package/src/rules/no-match-effect-branch.ts +83 -0
  52. package/src/rules/no-match-void-branch.ts +73 -0
  53. package/src/rules/no-nested-effect-call.ts +59 -0
  54. package/src/rules/no-nested-effect-gen.ts +44 -0
  55. package/src/rules/no-nested-pipe.ts +76 -0
  56. package/src/rules/no-new-error.ts +17 -0
  57. package/src/rules/no-new-promise.ts +14 -0
  58. package/src/rules/no-node-builtin-import.ts +70 -0
  59. package/src/rules/no-option-as.ts +13 -0
  60. package/src/rules/no-option-boolean-normalization.ts +89 -0
  61. package/src/rules/no-platform-globals.ts +117 -0
  62. package/src/rules/no-process-env-in-effect.ts +39 -0
  63. package/src/rules/no-process-env.ts +13 -0
  64. package/src/rules/no-random-in-effect.ts +39 -0
  65. package/src/rules/no-return-in-arrow.ts +77 -0
  66. package/src/rules/no-return-null.ts +47 -0
  67. package/src/rules/no-run-in-effect.ts +18 -0
  68. package/src/rules/no-runtime-run-fork.ts +14 -0
  69. package/src/rules/no-string-sentinel-const.ts +50 -0
  70. package/src/rules/no-switch-statement.ts +13 -0
  71. package/src/rules/no-ternary.ts +32 -0
  72. package/src/rules/no-throw-in-effect-gen.ts +42 -0
  73. package/src/rules/no-throw-statement.ts +13 -0
  74. package/src/rules/no-timers-in-effect.ts +47 -0
  75. package/src/rules/no-try-catch-in-effect-gen.ts +42 -0
  76. package/src/rules/no-try-catch.ts +14 -0
  77. package/src/rules/no-unnecessary-arrow-block.ts +52 -0
  78. package/src/rules/no-unnecessary-effect-gen.ts +85 -0
  79. package/src/rules/no-unnecessary-pipe.ts +46 -0
  80. package/src/vendor/effect-oxlint/AST.ts +516 -0
  81. package/src/vendor/effect-oxlint/Comment.ts +86 -0
  82. package/src/vendor/effect-oxlint/Diagnostic.ts +199 -0
  83. package/src/vendor/effect-oxlint/Plugin.ts +71 -0
  84. package/src/vendor/effect-oxlint/Rule.ts +590 -0
  85. package/src/vendor/effect-oxlint/RuleContext.ts +144 -0
  86. package/src/vendor/effect-oxlint/Scope.ts +177 -0
  87. package/src/vendor/effect-oxlint/SourceCode.ts +377 -0
  88. package/src/vendor/effect-oxlint/Testing.ts +1227 -0
  89. package/src/vendor/effect-oxlint/Token.ts +131 -0
  90. package/src/vendor/effect-oxlint/Visitor.ts +287 -0
  91. package/src/vendor/effect-oxlint/index.ts +88 -0
  92. package/tests/ban-rules.test.ts +252 -0
  93. package/tests/context-rules.test.ts +281 -0
  94. package/tests/pattern-rules.test.ts +258 -0
  95. package/tsconfig.json +15 -0
@@ -0,0 +1,258 @@
1
+ import { describe, test, expect } from "bun:test"
2
+ import { Testing } from "../src/vendor/effect-oxlint/index.js"
3
+ import {
4
+ noReturnNull,
5
+ noUnnecessaryPipe,
6
+ noEffectSucceedVoid,
7
+ noEffectMapVoid,
8
+ noEffectFnGenerator,
9
+ noExtendsNativeError,
10
+ noAsyncFunction,
11
+ noIifeWrapper,
12
+ noEffectSucceedString,
13
+ noFromNullableCoalesce,
14
+ noInstanceofSchema,
15
+ noNestedPipe,
16
+ noNestedEffectCall,
17
+ noFlatmapLadder,
18
+ noEffectOrElseLadder,
19
+ } from "../src/rules/index.js"
20
+
21
+ describe("noReturnNull", () => {
22
+ test("reports return null", () => {
23
+ const node = {
24
+ type: "ReturnStatement",
25
+ argument: { type: "Literal", value: null },
26
+ } as never
27
+ const result = Testing.runRule(noReturnNull, "ReturnStatement", node)
28
+ expect(result.length).toBe(1)
29
+ })
30
+
31
+ test("ignores return 42", () => {
32
+ const node = {
33
+ type: "ReturnStatement",
34
+ argument: { type: "Literal", value: 42 },
35
+ } as never
36
+ const result = Testing.runRule(noReturnNull, "ReturnStatement", node)
37
+ Testing.expectNoDiagnostics(result)
38
+ })
39
+ })
40
+
41
+ describe("noUnnecessaryPipe", () => {
42
+ test("reports pipe(x) with single arg", () => {
43
+ const node = Testing.callExpr("pipe", [Testing.id("myEffect")])
44
+ const result = Testing.runRule(noUnnecessaryPipe, "CallExpression", node)
45
+ expect(result.length).toBe(1)
46
+ })
47
+
48
+ test("ignores pipe(x, f)", () => {
49
+ const node = Testing.callExpr("pipe", [Testing.id("myEffect"), Testing.id("mapFn")])
50
+ const result = Testing.runRule(noUnnecessaryPipe, "CallExpression", node)
51
+ Testing.expectNoDiagnostics(result)
52
+ })
53
+ })
54
+
55
+ describe("noEffectSucceedVoid", () => {
56
+ test("reports Effect.succeed(undefined)", () => {
57
+ const node = Testing.callOfMember("Effect", "succeed", [Testing.id("undefined")])
58
+ const result = Testing.runRule(noEffectSucceedVoid, "CallExpression", node)
59
+ expect(result.length).toBe(1)
60
+ })
61
+
62
+ test("ignores Effect.succeed(42)", () => {
63
+ const node = Testing.callOfMember("Effect", "succeed", [Testing.numLiteral(42)])
64
+ const result = Testing.runRule(noEffectSucceedVoid, "CallExpression", node)
65
+ Testing.expectNoDiagnostics(result)
66
+ })
67
+ })
68
+
69
+ describe("noEffectMapVoid", () => {
70
+ test("reports Effect.map(() => undefined)", () => {
71
+ const fn = Testing.arrowFn(Testing.id("undefined"))
72
+ const node = Testing.callOfMember("Effect", "map", [fn])
73
+ const result = Testing.runRule(noEffectMapVoid, "CallExpression", node)
74
+ expect(result.length).toBe(1)
75
+ })
76
+
77
+ test("reports Effect.map(() => {})", () => {
78
+ const fn = Testing.arrowFn(Testing.blockStmt([]))
79
+ const node = Testing.callOfMember("Effect", "map", [fn])
80
+ const result = Testing.runRule(noEffectMapVoid, "CallExpression", node)
81
+ expect(result.length).toBe(1)
82
+ })
83
+ })
84
+
85
+ describe("noEffectFnGenerator", () => {
86
+ test("reports Effect.fn(function*() {})", () => {
87
+ const gen = {
88
+ type: "FunctionExpression",
89
+ generator: true,
90
+ params: [],
91
+ body: Testing.blockStmt([]),
92
+ }
93
+ const node = Testing.callOfMember("Effect", "fn", [gen])
94
+ const result = Testing.runRule(noEffectFnGenerator, "CallExpression", node)
95
+ expect(result.length).toBe(1)
96
+ })
97
+
98
+ test("ignores Effect.fn('name')", () => {
99
+ const node = Testing.callOfMember("Effect", "fn", [Testing.strLiteral("myFn")])
100
+ const result = Testing.runRule(noEffectFnGenerator, "CallExpression", node)
101
+ Testing.expectNoDiagnostics(result)
102
+ })
103
+ })
104
+
105
+ describe("noExtendsNativeError", () => {
106
+ test("reports class extends Error", () => {
107
+ const node = {
108
+ type: "ClassDeclaration",
109
+ superClass: Testing.id("Error"),
110
+ id: Testing.id("MyError"),
111
+ body: { type: "ClassBody", body: [] },
112
+ } as never
113
+ const result = Testing.runRule(noExtendsNativeError, "ClassDeclaration", node)
114
+ expect(result.length).toBe(1)
115
+ })
116
+
117
+ test("ignores class extends Schema.TaggedErrorClass", () => {
118
+ const node = {
119
+ type: "ClassDeclaration",
120
+ superClass: Testing.memberExpr("Schema", "TaggedErrorClass"),
121
+ id: Testing.id("MyError"),
122
+ body: { type: "ClassBody", body: [] },
123
+ } as never
124
+ const result = Testing.runRule(noExtendsNativeError, "ClassDeclaration", node)
125
+ Testing.expectNoDiagnostics(result)
126
+ })
127
+ })
128
+
129
+ describe("noAsyncFunction", () => {
130
+ test("reports async function", () => {
131
+ const node = {
132
+ type: "FunctionDeclaration",
133
+ async: true,
134
+ id: Testing.id("fetchData"),
135
+ params: [],
136
+ body: Testing.blockStmt([]),
137
+ } as never
138
+ const result = Testing.runRule(noAsyncFunction, "FunctionDeclaration", node)
139
+ expect(result.length).toBe(1)
140
+ })
141
+
142
+ test("ignores non-async function", () => {
143
+ const node = {
144
+ type: "FunctionDeclaration",
145
+ async: false,
146
+ id: Testing.id("fetchData"),
147
+ params: [],
148
+ body: Testing.blockStmt([]),
149
+ } as never
150
+ const result = Testing.runRule(noAsyncFunction, "FunctionDeclaration", node)
151
+ Testing.expectNoDiagnostics(result)
152
+ })
153
+ })
154
+
155
+ describe("noIifeWrapper", () => {
156
+ test("reports (() => expr)()", () => {
157
+ const node = {
158
+ type: "CallExpression",
159
+ callee: Testing.arrowFn(Testing.id("x")),
160
+ arguments: [],
161
+ } as never
162
+ const result = Testing.runRule(noIifeWrapper, "CallExpression", node)
163
+ expect(result.length).toBe(1)
164
+ })
165
+
166
+ test("ignores normal calls", () => {
167
+ const result = Testing.runRule(noIifeWrapper, "CallExpression", Testing.callExpr("myFn"))
168
+ Testing.expectNoDiagnostics(result)
169
+ })
170
+ })
171
+
172
+ describe("noEffectSucceedString", () => {
173
+ test("reports Effect.succeed('done')", () => {
174
+ const node = Testing.callOfMember("Effect", "succeed", [Testing.strLiteral("done")])
175
+ const result = Testing.runRule(noEffectSucceedString, "CallExpression", node)
176
+ expect(result.length).toBe(1)
177
+ })
178
+
179
+ test("ignores Effect.succeed(42)", () => {
180
+ const node = Testing.callOfMember("Effect", "succeed", [Testing.numLiteral(42)])
181
+ const result = Testing.runRule(noEffectSucceedString, "CallExpression", node)
182
+ Testing.expectNoDiagnostics(result)
183
+ })
184
+ })
185
+
186
+ describe("noFromNullableCoalesce", () => {
187
+ test("reports Option.fromNullable(x ?? null)", () => {
188
+ const coalesce = {
189
+ type: "LogicalExpression",
190
+ operator: "??",
191
+ left: Testing.id("x"),
192
+ right: { type: "Literal", value: null },
193
+ }
194
+ const node = Testing.callOfMember("Option", "fromNullable", [coalesce])
195
+ const result = Testing.runRule(noFromNullableCoalesce, "CallExpression", node)
196
+ expect(result.length).toBe(1)
197
+ })
198
+
199
+ test("ignores Option.fromNullable(x)", () => {
200
+ const node = Testing.callOfMember("Option", "fromNullable", [Testing.id("x")])
201
+ const result = Testing.runRule(noFromNullableCoalesce, "CallExpression", node)
202
+ Testing.expectNoDiagnostics(result)
203
+ })
204
+ })
205
+
206
+ describe("noInstanceofSchema", () => {
207
+ test("reports instanceof check", () => {
208
+ const node = {
209
+ type: "BinaryExpression",
210
+ operator: "instanceof",
211
+ left: Testing.id("x"),
212
+ right: Testing.id("MySchema"),
213
+ } as never
214
+ const result = Testing.runRule(noInstanceofSchema, "BinaryExpression", node)
215
+ expect(result.length).toBe(1)
216
+ })
217
+
218
+ test("ignores === check", () => {
219
+ const node = {
220
+ type: "BinaryExpression",
221
+ operator: "===",
222
+ left: Testing.id("x"),
223
+ right: Testing.id("y"),
224
+ } as never
225
+ const result = Testing.runRule(noInstanceofSchema, "BinaryExpression", node)
226
+ Testing.expectNoDiagnostics(result)
227
+ })
228
+ })
229
+
230
+ describe("noNestedPipe", () => {
231
+ test("reports pipe(pipe(x, f), g)", () => {
232
+ const innerPipe = Testing.callExpr("pipe", [Testing.id("x"), Testing.id("f")])
233
+ const outerPipe = Testing.callExpr("pipe", [innerPipe, Testing.id("g")])
234
+ const result = Testing.runRule(noNestedPipe, "CallExpression", outerPipe)
235
+ expect(result.length).toBe(1)
236
+ })
237
+
238
+ test("ignores flat pipe(x, f, g)", () => {
239
+ const node = Testing.callExpr("pipe", [Testing.id("x"), Testing.id("f"), Testing.id("g")])
240
+ const result = Testing.runRule(noNestedPipe, "CallExpression", node)
241
+ Testing.expectNoDiagnostics(result)
242
+ })
243
+ })
244
+
245
+ describe("noNestedEffectCall", () => {
246
+ test("reports Effect.map(Effect.flatMap(...))", () => {
247
+ const inner = Testing.callOfMember("Effect", "flatMap", [Testing.id("x")])
248
+ const outer = Testing.callOfMember("Effect", "map", [inner])
249
+ const result = Testing.runRule(noNestedEffectCall, "CallExpression", outer)
250
+ expect(result.length).toBe(1)
251
+ })
252
+
253
+ test("ignores flat Effect.map(x)", () => {
254
+ const node = Testing.callOfMember("Effect", "map", [Testing.id("x")])
255
+ const result = Testing.runRule(noNestedEffectCall, "CallExpression", node)
256
+ Testing.expectNoDiagnostics(result)
257
+ })
258
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "noUncheckedIndexedAccess": true,
4
+ "noFallthroughCasesInSwitch": true,
5
+ "noImplicitOverride": true,
6
+ "noPropertyAccessFromIndexSignature": true,
7
+ "allowImportingTsExtensions": true,
8
+ "moduleDetection": "force",
9
+ "skipLibCheck": true,
10
+ "types": ["bun"],
11
+ "noEmit": true
12
+ },
13
+ "include": ["src/**/*.ts", "tests/**/*.ts"],
14
+ "exclude": ["node_modules"]
15
+ }