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
@@ -0,0 +1,309 @@
1
+ import { __exportAll } from "../../_virtual/_rolldown/runtime.js";
2
+ import { calleeName, matchImport, matchMember, narrow } from "./AST.js";
3
+ import { make } from "./Diagnostic.js";
4
+ import { RuleContext, fromOxlintContext } from "./RuleContext.js";
5
+ import { merge, toOxlintVisitor } from "./Visitor.js";
6
+ import * as Arr from "effect/Array";
7
+ import { pipe } from "effect/Function";
8
+ import * as Option from "effect/Option";
9
+ import * as P from "effect/Predicate";
10
+ import * as Effect from "effect/Effect";
11
+ import * as Schema from "effect/Schema";
12
+ //#region src/vendor/effect-oxlint/Rule.ts
13
+ var Rule_exports = /* @__PURE__ */ __exportAll({
14
+ banCallOf: () => banCallOf,
15
+ banImport: () => banImport,
16
+ banMember: () => banMember,
17
+ banMultiple: () => banMultiple,
18
+ banNewExpr: () => banNewExpr,
19
+ banStatement: () => banStatement,
20
+ define: () => define,
21
+ meta: () => meta
22
+ });
23
+ /**
24
+ * Extract the identifier name from a `NewExpression` callee.
25
+ *
26
+ * `AST.calleeName` only accepts `CallExpression`. This mirrors the
27
+ * same logic for `NewExpression.callee`.
28
+ *
29
+ * @internal
30
+ */
31
+ const newExprCalleeName = (callee) => callee.type === "Identifier" && "name" in callee && P.isString(callee.name) ? Option.some(callee.name) : Option.none();
32
+ /**
33
+ * Define an Effect-first oxlint lint rule.
34
+ *
35
+ * The `create` generator runs once per file via `Effect.runSync`.
36
+ * Each visitor handler is also executed via `Effect.runSync` per node.
37
+ * `Ref`-based state created in `create` persists across handler calls
38
+ * via closure.
39
+ *
40
+ * `Effect.runSync` is used here at the runtime boundary — the bridge
41
+ * between oxlint's synchronous plugin API and our Effect world.
42
+ *
43
+ * @since 0.1.0
44
+ */
45
+ const define = (config) => ({
46
+ meta: config.meta,
47
+ create(oxlintContext) {
48
+ const ruleCtx = fromOxlintContext(oxlintContext);
49
+ const run = (effect) => Effect.runSync(Effect.provideService(effect, RuleContext, ruleCtx));
50
+ const decodeOptions = () => {
51
+ const schema = config.options;
52
+ if (schema === void 0) return void 0;
53
+ return Schema.decodeUnknownSync(schema)(oxlintContext.options[0]);
54
+ };
55
+ const options = run(Effect.sync(decodeOptions));
56
+ return toOxlintVisitor(run(Effect.gen(() => config.create(options))), run);
57
+ }
58
+ });
59
+ /**
60
+ * Build `RuleMeta` with sensible defaults.
61
+ *
62
+ * @since 0.1.0
63
+ */
64
+ const meta = (opts) => ({
65
+ type: opts.type,
66
+ ...opts.fixable !== void 0 ? { fixable: opts.fixable } : {},
67
+ ...opts.hasSuggestions !== void 0 ? { hasSuggestions: opts.hasSuggestions } : {},
68
+ ...opts.messages !== void 0 ? { messages: opts.messages } : {},
69
+ docs: {
70
+ description: opts.description,
71
+ effectVersion: opts.effectVersion ?? "both",
72
+ ...opts.docs
73
+ }
74
+ });
75
+ /**
76
+ * Create a rule that bans `obj.prop` member expression access.
77
+ *
78
+ * Replaces the common `memberExprRule` utility pattern.
79
+ *
80
+ * @since 0.1.0
81
+ */
82
+ const banMember = (obj, prop, opts) => define({
83
+ name: `ban-${obj}-${P.isString(prop) ? prop : Arr.join(prop, "-")}`,
84
+ meta: meta({
85
+ type: opts.meta?.type ?? "suggestion",
86
+ description: opts.message,
87
+ effectVersion: opts.meta?.effectVersion
88
+ }),
89
+ create: function* () {
90
+ const ctx = yield* RuleContext;
91
+ return { MemberExpression: (node) => pipe(narrow(node, "MemberExpression"), Option.flatMap(matchMember(obj, prop)), Option.match({
92
+ onNone: () => Effect.void,
93
+ onSome: (matched) => ctx.report(make({
94
+ node: matched,
95
+ message: opts.message
96
+ }))
97
+ })) };
98
+ }
99
+ });
100
+ /**
101
+ * Create a rule that bans imports matching a source string or predicate.
102
+ *
103
+ * Replaces the common `importRule` utility pattern.
104
+ *
105
+ * @since 0.1.0
106
+ */
107
+ const banImport = (source, opts) => define({
108
+ name: "ban-import",
109
+ meta: meta({
110
+ type: opts.meta?.type ?? "suggestion",
111
+ description: opts.message,
112
+ effectVersion: opts.meta?.effectVersion
113
+ }),
114
+ create: function* () {
115
+ const ctx = yield* RuleContext;
116
+ return { ImportDeclaration: (node) => pipe(narrow(node, "ImportDeclaration"), Option.flatMap(matchImport(source)), Option.match({
117
+ onNone: () => Effect.void,
118
+ onSome: (matched) => ctx.report(make({
119
+ node: matched,
120
+ message: opts.message
121
+ }))
122
+ })) };
123
+ }
124
+ });
125
+ /**
126
+ * Create a rule that bans bare identifier call expressions.
127
+ *
128
+ * Matches `CallExpression` nodes whose callee is an identifier in
129
+ * the given list (e.g. `fetch()`, `useState()`, `readFileSync()`).
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * // Ban a single call
134
+ * Rule.banCallOf('fetch', { message: 'Use Effect HTTP client' })
135
+ *
136
+ * // Ban multiple calls
137
+ * Rule.banCallOf(['useState', 'useEffect'], { message: 'Use Effect' })
138
+ * ```
139
+ *
140
+ * @since 0.2.0
141
+ */
142
+ const banCallOf = (name, opts) => {
143
+ const names = P.isString(name) ? [name] : name;
144
+ return define({
145
+ name: `ban-call-${Arr.join(names, "-")}`,
146
+ meta: meta({
147
+ type: opts.meta?.type ?? "suggestion",
148
+ description: opts.message,
149
+ effectVersion: opts.meta?.effectVersion
150
+ }),
151
+ create: function* () {
152
+ const ctx = yield* RuleContext;
153
+ return { CallExpression: (node) => pipe(narrow(node, "CallExpression"), Option.flatMap(calleeName), Option.filter((n) => Arr.contains(names, n)), Option.match({
154
+ onNone: () => Effect.void,
155
+ onSome: () => ctx.report(make({
156
+ node,
157
+ message: opts.message
158
+ }))
159
+ })) };
160
+ }
161
+ });
162
+ };
163
+ /**
164
+ * Create a rule that bans `new` expressions with the given callee name.
165
+ *
166
+ * Matches `NewExpression` nodes whose callee is an identifier in
167
+ * the given list (e.g. `new Date()`, `new Error()`).
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * // Ban a single constructor
172
+ * Rule.banNewExpr('Date', { message: 'Use Clock service' })
173
+ *
174
+ * // Ban multiple constructors
175
+ * Rule.banNewExpr(['Error', 'TypeError'], { message: 'Use tagged errors' })
176
+ * ```
177
+ *
178
+ * @since 0.2.0
179
+ */
180
+ const banNewExpr = (name, opts) => {
181
+ const names = P.isString(name) ? [name] : name;
182
+ return define({
183
+ name: `ban-new-${Arr.join(names, "-")}`,
184
+ meta: meta({
185
+ type: opts.meta?.type ?? "suggestion",
186
+ description: opts.message,
187
+ effectVersion: opts.meta?.effectVersion
188
+ }),
189
+ create: function* () {
190
+ const ctx = yield* RuleContext;
191
+ return { NewExpression: (node) => pipe(narrow(node, "NewExpression"), Option.flatMap((n) => newExprCalleeName(n.callee)), Option.filter((n) => Arr.contains(names, n)), Option.match({
192
+ onNone: () => Effect.void,
193
+ onSome: () => ctx.report(make({
194
+ node,
195
+ message: opts.message
196
+ }))
197
+ })) };
198
+ }
199
+ });
200
+ };
201
+ /**
202
+ * Create a rule that bans a specific statement type.
203
+ *
204
+ * @since 0.1.0
205
+ */
206
+ const banStatement = (nodeType, opts) => define({
207
+ name: `ban-${nodeType}`,
208
+ meta: meta({
209
+ type: opts.meta?.type ?? "suggestion",
210
+ description: opts.message,
211
+ effectVersion: opts.meta?.effectVersion
212
+ }),
213
+ create: function* () {
214
+ const ctx = yield* RuleContext;
215
+ return { [nodeType]: (node) => ctx.report(make({
216
+ node,
217
+ message: opts.message
218
+ })) };
219
+ }
220
+ });
221
+ /**
222
+ * Create a rule that bans multiple patterns, each with its own message.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * Rule.banMultiple({
227
+ * name: "no-global-date",
228
+ * meta: { type: "suggestion" },
229
+ * specs: [
230
+ * { type: "new", name: "Date", message: "Avoid new Date(). Use Clock service." },
231
+ * { type: "member", object: "Date", property: "now", message: "Avoid Date.now(). Use Clock service." },
232
+ * ],
233
+ * })
234
+ * ```
235
+ *
236
+ * @since 0.3.0
237
+ */
238
+ const banMultiple = (config) => {
239
+ const description = config.specs.map((s) => s.message).join(" ");
240
+ return define({
241
+ name: config.name,
242
+ meta: meta({
243
+ type: config.meta?.type ?? "suggestion",
244
+ description,
245
+ effectVersion: config.meta?.effectVersion
246
+ }),
247
+ create: function* () {
248
+ const ctx = yield* RuleContext;
249
+ const visitors = [];
250
+ for (const spec of config.specs) switch (spec.type) {
251
+ case "member": {
252
+ const report = (node) => ctx.report(make({
253
+ node,
254
+ message: spec.message
255
+ }));
256
+ visitors.push({ MemberExpression: (node) => pipe(narrow(node, "MemberExpression"), Option.flatMap(matchMember(spec.object, spec.property)), Option.match({
257
+ onNone: () => Effect.void,
258
+ onSome: (matched) => report(matched)
259
+ })) });
260
+ break;
261
+ }
262
+ case "call": {
263
+ const names = P.isString(spec.name) ? [spec.name] : spec.name;
264
+ const report = (node) => ctx.report(make({
265
+ node,
266
+ message: spec.message
267
+ }));
268
+ visitors.push({ CallExpression: (node) => pipe(narrow(node, "CallExpression"), Option.flatMap(calleeName), Option.filter((n) => Arr.contains(names, n)), Option.match({
269
+ onNone: () => Effect.void,
270
+ onSome: () => report(node)
271
+ })) });
272
+ break;
273
+ }
274
+ case "new": {
275
+ const names = P.isString(spec.name) ? [spec.name] : spec.name;
276
+ const report = (node) => ctx.report(make({
277
+ node,
278
+ message: spec.message
279
+ }));
280
+ visitors.push({ NewExpression: (node) => pipe(narrow(node, "NewExpression"), Option.flatMap((n) => newExprCalleeName(n.callee)), Option.filter((n) => Arr.contains(names, n)), Option.match({
281
+ onNone: () => Effect.void,
282
+ onSome: () => report(node)
283
+ })) });
284
+ break;
285
+ }
286
+ case "import": {
287
+ const report = (node) => ctx.report(make({
288
+ node,
289
+ message: spec.message
290
+ }));
291
+ visitors.push({ ImportDeclaration: (node) => pipe(narrow(node, "ImportDeclaration"), Option.flatMap(matchImport(spec.source)), Option.match({
292
+ onNone: () => Effect.void,
293
+ onSome: (matched) => report(matched)
294
+ })) });
295
+ break;
296
+ }
297
+ case "statement":
298
+ visitors.push({ [spec.nodeType]: (node) => ctx.report(make({
299
+ node,
300
+ message: spec.message
301
+ })) });
302
+ break;
303
+ }
304
+ return merge(...visitors);
305
+ }
306
+ });
307
+ };
308
+ //#endregion
309
+ export { Rule_exports, banCallOf, banImport, banMember, banMultiple, banNewExpr, banStatement, define, meta };
@@ -0,0 +1,77 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Context$1 from "effect/Context";
3
+ import { Context, Diagnostic, ESTree, LanguageOptions, Options, Settings, SourceCode } from "@oxlint/plugins";
4
+
5
+ //#region src/vendor/effect-oxlint/RuleContext.d.ts
6
+ declare const RuleContext_base: Context$1.ServiceClass<RuleContext, "effect-oxlint/RuleContext", {
7
+ /** Report a lint diagnostic for the current file. */readonly report: (diagnostic: Diagnostic) => Effect.Effect<void>; /** Rule ID in `plugin/rule` form. */
8
+ readonly id: string; /** Absolute path of the file being linted. */
9
+ readonly filename: string; /** Current working directory. */
10
+ readonly cwd: string; /** Raw rule options (JSON values). */
11
+ readonly options: Readonly<Options>; /** Source code access (tokens, comments, text, scope, etc.). */
12
+ readonly sourceCode: SourceCode; /** Language / parser options for this file. */
13
+ readonly languageOptions: Readonly<LanguageOptions>; /** Shared settings from the oxlint config. */
14
+ readonly settings: Readonly<Settings>;
15
+ }>;
16
+ /**
17
+ * The lint rule context, provided as an Effect service.
18
+ *
19
+ * Available inside `Rule.define`'s `create` generator and every
20
+ * visitor handler via `yield* RuleContext`.
21
+ *
22
+ * @since 0.1.0
23
+ */
24
+ declare class RuleContext extends RuleContext_base {}
25
+ /**
26
+ * Build a `RuleContext` value from the raw oxlint `Context`.
27
+ *
28
+ * @internal
29
+ */
30
+ declare const fromOxlintContext: (ctx: Context) => RuleContext["Service"];
31
+ /**
32
+ * Effectful access to the rule ID.
33
+ *
34
+ * @since 0.1.0
35
+ */
36
+ declare const id: Effect.Effect<string, never, RuleContext>;
37
+ /**
38
+ * Effectful access to the filename of the file being linted.
39
+ *
40
+ * @since 0.1.0
41
+ */
42
+ declare const filename: Effect.Effect<string, never, RuleContext>;
43
+ /**
44
+ * Effectful access to the working directory.
45
+ *
46
+ * @since 0.1.0
47
+ */
48
+ declare const cwd: Effect.Effect<string, never, RuleContext>;
49
+ /**
50
+ * Effectful access to the SourceCode object.
51
+ *
52
+ * @since 0.1.0
53
+ */
54
+ declare const sourceCode: Effect.Effect<SourceCode, never, RuleContext>;
55
+ /**
56
+ * Effectful access to the raw source text.
57
+ *
58
+ * @since 0.1.0
59
+ */
60
+ declare const text: Effect.Effect<string, never, RuleContext>;
61
+ /**
62
+ * Effectful access to the AST root node.
63
+ *
64
+ * @since 0.1.0
65
+ */
66
+ declare const ast: Effect.Effect<ESTree.Program, never, RuleContext>;
67
+ /**
68
+ * Report a lint diagnostic.
69
+ *
70
+ * Shorthand so handlers can `yield* RuleContext.report(diagnostic)`
71
+ * without first resolving the full service.
72
+ *
73
+ * @since 0.1.0
74
+ */
75
+ declare const report: (diagnostic: Diagnostic) => Effect.Effect<void, never, RuleContext>;
76
+ //#endregion
77
+ export { RuleContext, ast, cwd, filename, fromOxlintContext, id, report, sourceCode, text };
@@ -0,0 +1,74 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Context from "effect/Context";
3
+ //#region src/vendor/effect-oxlint/RuleContext.ts
4
+ /**
5
+ * The lint rule context, provided as an Effect service.
6
+ *
7
+ * Available inside `Rule.define`'s `create` generator and every
8
+ * visitor handler via `yield* RuleContext`.
9
+ *
10
+ * @since 0.1.0
11
+ */
12
+ var RuleContext = class extends Context.Service()("effect-oxlint/RuleContext") {};
13
+ /**
14
+ * Build a `RuleContext` value from the raw oxlint `Context`.
15
+ *
16
+ * @internal
17
+ */
18
+ const fromOxlintContext = (ctx) => RuleContext.of({
19
+ report: (diagnostic) => Effect.sync(() => ctx.report(diagnostic)),
20
+ id: ctx.id,
21
+ filename: ctx.filename,
22
+ cwd: ctx.cwd,
23
+ options: ctx.options,
24
+ sourceCode: ctx.sourceCode,
25
+ languageOptions: ctx.languageOptions,
26
+ settings: ctx.settings
27
+ });
28
+ /**
29
+ * Effectful access to the rule ID.
30
+ *
31
+ * @since 0.1.0
32
+ */
33
+ const id = Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.id));
34
+ /**
35
+ * Effectful access to the filename of the file being linted.
36
+ *
37
+ * @since 0.1.0
38
+ */
39
+ const filename = Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.filename));
40
+ /**
41
+ * Effectful access to the working directory.
42
+ *
43
+ * @since 0.1.0
44
+ */
45
+ const cwd = Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.cwd));
46
+ /**
47
+ * Effectful access to the SourceCode object.
48
+ *
49
+ * @since 0.1.0
50
+ */
51
+ const sourceCode = Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.sourceCode));
52
+ /**
53
+ * Effectful access to the raw source text.
54
+ *
55
+ * @since 0.1.0
56
+ */
57
+ const text = Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.sourceCode.text));
58
+ /**
59
+ * Effectful access to the AST root node.
60
+ *
61
+ * @since 0.1.0
62
+ */
63
+ const ast = Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.sourceCode.ast));
64
+ /**
65
+ * Report a lint diagnostic.
66
+ *
67
+ * Shorthand so handlers can `yield* RuleContext.report(diagnostic)`
68
+ * without first resolving the full service.
69
+ *
70
+ * @since 0.1.0
71
+ */
72
+ const report = (diagnostic) => Effect.service(RuleContext).pipe(Effect.flatMap((ctx) => ctx.report(diagnostic)));
73
+ //#endregion
74
+ export { RuleContext, ast, cwd, filename, fromOxlintContext, id, report, sourceCode, text };
@@ -0,0 +1,100 @@
1
+ import * as Option from "effect/Option";
2
+ import { Reference, Scope, Variable } from "@oxlint/plugins";
3
+
4
+ //#region src/vendor/effect-oxlint/Scope.d.ts
5
+ declare namespace Scope_d_exports {
6
+ export { childScopes, findVariable, findVariableUp, getReadReferences, getReferences, getWriteReferences, isReadOnly, isStrict, isUsed, isWritten, throughReferences, upper, variables };
7
+ }
8
+ /**
9
+ * Find a variable by name in a scope.
10
+ *
11
+ * Searches the scope's `set` (a `Map<string, Variable>`).
12
+ *
13
+ * @since 0.2.0
14
+ */
15
+ declare const findVariable: {
16
+ (name: string): (scope: Scope) => Option.Option<Variable>;
17
+ (scope: Scope, name: string): Option.Option<Variable>;
18
+ };
19
+ /**
20
+ * Find a variable by name, walking up the scope chain.
21
+ *
22
+ * Starts at the given scope and checks each `upper` scope until found
23
+ * or the global scope is exhausted.
24
+ *
25
+ * @since 0.2.0
26
+ */
27
+ declare const findVariableUp: {
28
+ (name: string): (scope: Scope) => Option.Option<Variable>;
29
+ (scope: Scope, name: string): Option.Option<Variable>;
30
+ };
31
+ /**
32
+ * Check whether a variable has any read references.
33
+ *
34
+ * A variable is considered "used" if at least one reference reads it.
35
+ *
36
+ * @since 0.2.0
37
+ */
38
+ declare const isUsed: (variable: Variable) => boolean;
39
+ /**
40
+ * Check whether a variable has any write references.
41
+ *
42
+ * @since 0.2.0
43
+ */
44
+ declare const isWritten: (variable: Variable) => boolean;
45
+ /**
46
+ * Check whether a variable is only read (no writes).
47
+ *
48
+ * @since 0.2.0
49
+ */
50
+ declare const isReadOnly: (variable: Variable) => boolean;
51
+ /**
52
+ * Get all references for a variable.
53
+ *
54
+ * @since 0.2.0
55
+ */
56
+ declare const getReferences: (variable: Variable) => ReadonlyArray<Reference>;
57
+ /**
58
+ * Get the read references for a variable.
59
+ *
60
+ * @since 0.2.0
61
+ */
62
+ declare const getReadReferences: (variable: Variable) => ReadonlyArray<Reference>;
63
+ /**
64
+ * Get the write references for a variable.
65
+ *
66
+ * @since 0.2.0
67
+ */
68
+ declare const getWriteReferences: (variable: Variable) => ReadonlyArray<Reference>;
69
+ /**
70
+ * Get the parent (upper) scope.
71
+ *
72
+ * @since 0.2.0
73
+ */
74
+ declare const upper: (scope: Scope) => Option.Option<Scope>;
75
+ /**
76
+ * Get the child scopes.
77
+ *
78
+ * @since 0.2.0
79
+ */
80
+ declare const childScopes: (scope: Scope) => ReadonlyArray<Scope>;
81
+ /**
82
+ * Get all variables in a scope.
83
+ *
84
+ * @since 0.2.0
85
+ */
86
+ declare const variables: (scope: Scope) => ReadonlyArray<Variable>;
87
+ /**
88
+ * Get "through" references (unresolved in this scope).
89
+ *
90
+ * @since 0.2.0
91
+ */
92
+ declare const throughReferences: (scope: Scope) => ReadonlyArray<Reference>;
93
+ /**
94
+ * Check whether a scope is strict mode.
95
+ *
96
+ * @since 0.2.0
97
+ */
98
+ declare const isStrict: (scope: Scope) => boolean;
99
+ //#endregion
100
+ export { Scope_d_exports, childScopes, findVariable, findVariableUp, getReadReferences, getReferences, getWriteReferences, isReadOnly, isStrict, isUsed, isWritten, throughReferences, upper, variables };
@@ -0,0 +1,110 @@
1
+ import { __exportAll } from "../../_virtual/_rolldown/runtime.js";
2
+ import * as Arr from "effect/Array";
3
+ import { dual, pipe } from "effect/Function";
4
+ import * as Option from "effect/Option";
5
+ //#region src/vendor/effect-oxlint/Scope.ts
6
+ var Scope_exports = /* @__PURE__ */ __exportAll({
7
+ childScopes: () => childScopes,
8
+ findVariable: () => findVariable,
9
+ findVariableUp: () => findVariableUp,
10
+ getReadReferences: () => getReadReferences,
11
+ getReferences: () => getReferences,
12
+ getWriteReferences: () => getWriteReferences,
13
+ isReadOnly: () => isReadOnly,
14
+ isStrict: () => isStrict,
15
+ isUsed: () => isUsed,
16
+ isWritten: () => isWritten,
17
+ throughReferences: () => throughReferences,
18
+ upper: () => upper,
19
+ variables: () => variables
20
+ });
21
+ /**
22
+ * Find a variable by name in a scope.
23
+ *
24
+ * Searches the scope's `set` (a `Map<string, Variable>`).
25
+ *
26
+ * @since 0.2.0
27
+ */
28
+ const findVariable = dual(2, (scope, name) => Option.fromNullishOr(scope.set.get(name)));
29
+ /**
30
+ * Find a variable by name, walking up the scope chain.
31
+ *
32
+ * Starts at the given scope and checks each `upper` scope until found
33
+ * or the global scope is exhausted.
34
+ *
35
+ * @since 0.2.0
36
+ */
37
+ const findVariableUp = dual(2, (scope, name) => {
38
+ const walk = (current) => pipe(Option.fromNullishOr(current.set.get(name)), Option.orElse(() => pipe(Option.fromNullishOr(current.upper), Option.flatMap((parent) => walk(parent)))));
39
+ return walk(scope);
40
+ });
41
+ /**
42
+ * Check whether a variable has any read references.
43
+ *
44
+ * A variable is considered "used" if at least one reference reads it.
45
+ *
46
+ * @since 0.2.0
47
+ */
48
+ const isUsed = (variable) => Arr.some(variable.references, (ref) => ref.isRead());
49
+ /**
50
+ * Check whether a variable has any write references.
51
+ *
52
+ * @since 0.2.0
53
+ */
54
+ const isWritten = (variable) => Arr.some(variable.references, (ref) => ref.isWrite());
55
+ /**
56
+ * Check whether a variable is only read (no writes).
57
+ *
58
+ * @since 0.2.0
59
+ */
60
+ const isReadOnly = (variable) => Arr.some(variable.references, (ref) => ref.isReadOnly());
61
+ /**
62
+ * Get all references for a variable.
63
+ *
64
+ * @since 0.2.0
65
+ */
66
+ const getReferences = (variable) => variable.references;
67
+ /**
68
+ * Get the read references for a variable.
69
+ *
70
+ * @since 0.2.0
71
+ */
72
+ const getReadReferences = (variable) => pipe(variable.references, Arr.filter((ref) => ref.isRead()));
73
+ /**
74
+ * Get the write references for a variable.
75
+ *
76
+ * @since 0.2.0
77
+ */
78
+ const getWriteReferences = (variable) => pipe(variable.references, Arr.filter((ref) => ref.isWrite()));
79
+ /**
80
+ * Get the parent (upper) scope.
81
+ *
82
+ * @since 0.2.0
83
+ */
84
+ const upper = (scope) => Option.fromNullishOr(scope.upper);
85
+ /**
86
+ * Get the child scopes.
87
+ *
88
+ * @since 0.2.0
89
+ */
90
+ const childScopes = (scope) => scope.childScopes;
91
+ /**
92
+ * Get all variables in a scope.
93
+ *
94
+ * @since 0.2.0
95
+ */
96
+ const variables = (scope) => scope.variables;
97
+ /**
98
+ * Get "through" references (unresolved in this scope).
99
+ *
100
+ * @since 0.2.0
101
+ */
102
+ const throughReferences = (scope) => scope.through;
103
+ /**
104
+ * Check whether a scope is strict mode.
105
+ *
106
+ * @since 0.2.0
107
+ */
108
+ const isStrict = (scope) => scope.isStrict;
109
+ //#endregion
110
+ export { Scope_exports, childScopes, findVariable, findVariableUp, getReadReferences, getReferences, getWriteReferences, isReadOnly, isStrict, isUsed, isWritten, throughReferences, upper, variables };