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.
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.js +18 -0
- package/dist/presets/core.d.ts +43 -0
- package/dist/presets/core.js +43 -0
- package/dist/presets/effect-native.d.ts +28 -0
- package/dist/presets/effect-native.js +28 -0
- package/dist/presets/full.d.ts +60 -0
- package/dist/presets/full.js +60 -0
- package/dist/presets/functional.d.ts +21 -0
- package/dist/presets/functional.js +21 -0
- package/dist/presets/index.d.ts +13 -0
- package/dist/presets/index.js +18 -0
- package/dist/presets/strict.d.ts +69 -0
- package/dist/presets/strict.js +69 -0
- package/dist/presets/v3.d.ts +15 -0
- package/dist/presets/v3.js +15 -0
- package/dist/rules/_effect-context.d.ts +19 -0
- package/dist/rules/_effect-context.js +22 -0
- package/dist/rules/index.d.ts +66 -0
- package/dist/rules/index.js +124 -0
- package/dist/rules/no-arrow-ladder.d.ts +6 -0
- package/dist/rules/no-arrow-ladder.js +61 -0
- package/dist/rules/no-async-function.d.ts +6 -0
- package/dist/rules/no-async-function.js +46 -0
- package/dist/rules/no-catch-all-to-map-error.d.ts +6 -0
- package/dist/rules/no-catch-all-to-map-error.js +67 -0
- package/dist/rules/no-effect-as.d.ts +6 -0
- package/dist/rules/no-effect-as.js +16 -0
- package/dist/rules/no-effect-async.d.ts +6 -0
- package/dist/rules/no-effect-async.js +16 -0
- package/dist/rules/no-effect-bind.d.ts +6 -0
- package/dist/rules/no-effect-bind.js +16 -0
- package/dist/rules/no-effect-do.d.ts +6 -0
- package/dist/rules/no-effect-do.js +16 -0
- package/dist/rules/no-effect-fn-generator.d.ts +6 -0
- package/dist/rules/no-effect-fn-generator.js +30 -0
- package/dist/rules/no-effect-gen-adapter.d.ts +6 -0
- package/dist/rules/no-effect-gen-adapter.js +30 -0
- package/dist/rules/no-effect-map-flatten.d.ts +6 -0
- package/dist/rules/no-effect-map-flatten.js +53 -0
- package/dist/rules/no-effect-map-void.d.ts +6 -0
- package/dist/rules/no-effect-map-void.js +40 -0
- package/dist/rules/no-effect-never.d.ts +6 -0
- package/dist/rules/no-effect-never.js +16 -0
- package/dist/rules/no-effect-orElse-ladder.d.ts +6 -0
- package/dist/rules/no-effect-orElse-ladder.js +53 -0
- package/dist/rules/no-effect-succeed-string.d.ts +6 -0
- package/dist/rules/no-effect-succeed-string.js +30 -0
- package/dist/rules/no-effect-succeed-variable.d.ts +6 -0
- package/dist/rules/no-effect-succeed-variable.js +30 -0
- package/dist/rules/no-effect-succeed-void.d.ts +6 -0
- package/dist/rules/no-effect-succeed-void.js +33 -0
- package/dist/rules/no-effect-sync-console.d.ts +6 -0
- package/dist/rules/no-effect-sync-console.js +63 -0
- package/dist/rules/no-effect-sync-wrapper.d.ts +6 -0
- package/dist/rules/no-effect-sync-wrapper.js +37 -0
- package/dist/rules/no-effect-type-alias.d.ts +6 -0
- package/dist/rules/no-effect-type-alias.js +52 -0
- package/dist/rules/no-effect-wrapper-alias.d.ts +6 -0
- package/dist/rules/no-effect-wrapper-alias.js +69 -0
- package/dist/rules/no-extends-native-error.d.ts +6 -0
- package/dist/rules/no-extends-native-error.js +41 -0
- package/dist/rules/no-flatmap-ladder.d.ts +6 -0
- package/dist/rules/no-flatmap-ladder.js +48 -0
- package/dist/rules/no-fromnullable-coalesce.d.ts +6 -0
- package/dist/rules/no-fromnullable-coalesce.js +36 -0
- package/dist/rules/no-global-error-in-catch.d.ts +6 -0
- package/dist/rules/no-global-error-in-catch.js +75 -0
- package/dist/rules/no-global-error-in-failure.d.ts +6 -0
- package/dist/rules/no-global-error-in-failure.js +54 -0
- package/dist/rules/no-globals.d.ts +6 -0
- package/dist/rules/no-globals.js +164 -0
- package/dist/rules/no-if-statement.d.ts +6 -0
- package/dist/rules/no-if-statement.js +18 -0
- package/dist/rules/no-iife-wrapper.d.ts +6 -0
- package/dist/rules/no-iife-wrapper.js +37 -0
- package/dist/rules/no-inline-provide.d.ts +6 -0
- package/dist/rules/no-inline-provide.js +31 -0
- package/dist/rules/no-instanceof-schema.d.ts +6 -0
- package/dist/rules/no-instanceof-schema.js +35 -0
- package/dist/rules/no-manual-effect-channels.d.ts +6 -0
- package/dist/rules/no-manual-effect-channels.js +40 -0
- package/dist/rules/no-match-effect-branch.d.ts +6 -0
- package/dist/rules/no-match-effect-branch.js +64 -0
- package/dist/rules/no-match-void-branch.d.ts +6 -0
- package/dist/rules/no-match-void-branch.js +50 -0
- package/dist/rules/no-multiple-effect-provide.d.ts +6 -0
- package/dist/rules/no-multiple-effect-provide.js +45 -0
- package/dist/rules/no-nested-effect-call.d.ts +6 -0
- package/dist/rules/no-nested-effect-call.js +97 -0
- package/dist/rules/no-nested-effect-gen.d.ts +6 -0
- package/dist/rules/no-nested-effect-gen.js +46 -0
- package/dist/rules/no-nested-pipe.d.ts +6 -0
- package/dist/rules/no-nested-pipe.js +38 -0
- package/dist/rules/no-new-error.d.ts +6 -0
- package/dist/rules/no-new-error.js +39 -0
- package/dist/rules/no-new-promise.d.ts +6 -0
- package/dist/rules/no-new-promise.js +38 -0
- package/dist/rules/no-node-builtin-import.d.ts +6 -0
- package/dist/rules/no-node-builtin-import.js +61 -0
- package/dist/rules/no-option-as.d.ts +6 -0
- package/dist/rules/no-option-as.js +16 -0
- package/dist/rules/no-option-boolean-normalization.d.ts +6 -0
- package/dist/rules/no-option-boolean-normalization.js +50 -0
- package/dist/rules/no-positional-log-error.d.ts +6 -0
- package/dist/rules/no-positional-log-error.js +52 -0
- package/dist/rules/no-redundant-schema-tag-identifier.d.ts +6 -0
- package/dist/rules/no-redundant-schema-tag-identifier.js +46 -0
- package/dist/rules/no-return-in-arrow.d.ts +6 -0
- package/dist/rules/no-return-in-arrow.js +41 -0
- package/dist/rules/no-return-nullish.d.ts +6 -0
- package/dist/rules/no-return-nullish.js +47 -0
- package/dist/rules/no-run-in-effect-gen.d.ts +6 -0
- package/dist/rules/no-run-in-effect-gen.js +48 -0
- package/dist/rules/no-runtime-run-fork.d.ts +6 -0
- package/dist/rules/no-runtime-run-fork.js +19 -0
- package/dist/rules/no-schema-struct-with-tag.d.ts +6 -0
- package/dist/rules/no-schema-struct-with-tag.js +48 -0
- package/dist/rules/no-schema-union-of-literals.d.ts +6 -0
- package/dist/rules/no-schema-union-of-literals.js +35 -0
- package/dist/rules/no-string-sentinel-const.d.ts +6 -0
- package/dist/rules/no-string-sentinel-const.js +38 -0
- package/dist/rules/no-switch-statement.d.ts +6 -0
- package/dist/rules/no-switch-statement.js +16 -0
- package/dist/rules/no-ternary.d.ts +6 -0
- package/dist/rules/no-ternary.js +30 -0
- package/dist/rules/no-throw-statement.d.ts +6 -0
- package/dist/rules/no-throw-statement.js +34 -0
- package/dist/rules/no-try-catch.d.ts +6 -0
- package/dist/rules/no-try-catch.js +34 -0
- package/dist/rules/no-unnecessary-arrow-block.d.ts +6 -0
- package/dist/rules/no-unnecessary-arrow-block.js +34 -0
- package/dist/rules/no-unnecessary-effect-gen.d.ts +6 -0
- package/dist/rules/no-unnecessary-effect-gen.js +35 -0
- package/dist/rules/no-unnecessary-pipe-chain.d.ts +6 -0
- package/dist/rules/no-unnecessary-pipe-chain.js +36 -0
- package/dist/rules/no-unnecessary-pipe.d.ts +6 -0
- package/dist/rules/no-unnecessary-pipe.js +29 -0
- package/dist/vendor/effect-oxlint/AST.d.ts +199 -0
- package/dist/vendor/effect-oxlint/AST.js +214 -0
- package/dist/vendor/effect-oxlint/Comment.d.ts +55 -0
- package/dist/vendor/effect-oxlint/Comment.js +67 -0
- package/dist/vendor/effect-oxlint/Diagnostic.d.ts +86 -0
- package/dist/vendor/effect-oxlint/Diagnostic.js +115 -0
- package/dist/vendor/effect-oxlint/Plugin.d.ts +38 -0
- package/dist/vendor/effect-oxlint/Plugin.js +45 -0
- package/dist/vendor/effect-oxlint/Rule.d.ts +218 -0
- package/dist/vendor/effect-oxlint/Rule.js +309 -0
- package/dist/vendor/effect-oxlint/RuleContext.d.ts +77 -0
- package/dist/vendor/effect-oxlint/RuleContext.js +74 -0
- package/dist/vendor/effect-oxlint/Scope.d.ts +100 -0
- package/dist/vendor/effect-oxlint/Scope.js +110 -0
- package/dist/vendor/effect-oxlint/SourceCode.d.ts +180 -0
- package/dist/vendor/effect-oxlint/SourceCode.js +203 -0
- package/dist/vendor/effect-oxlint/Testing.d.ts +510 -0
- package/dist/vendor/effect-oxlint/Testing.js +963 -0
- package/dist/vendor/effect-oxlint/Token.d.ts +98 -0
- package/dist/vendor/effect-oxlint/Token.js +103 -0
- package/dist/vendor/effect-oxlint/Visitor.d.ts +166 -0
- package/dist/vendor/effect-oxlint/Visitor.js +138 -0
- package/dist/vendor/effect-oxlint/index.d.ts +13 -0
- package/dist/vendor/effect-oxlint/index.js +12 -0
- package/package.json +24 -5
- package/.effect-lsp.json +0 -60
- package/.oxlintrc.json +0 -33
- package/CHANGELOG.md +0 -55
- package/scripts/add-rule.ts +0 -87
- package/scripts/codegen.ts +0 -108
- package/src/index.ts +0 -9
- package/src/plugin.ts +0 -16
- package/src/presets/core.ts +0 -47
- package/src/presets/effect-native.ts +0 -34
- package/src/presets/full.ts +0 -70
- package/src/presets/functional.ts +0 -18
- package/src/presets/index.ts +0 -5
- package/src/presets/strict.ts +0 -77
- package/src/rules/_effect-context.ts +0 -28
- package/src/rules/index.ts +0 -72
- package/src/rules/no-arrow-ladder.ts +0 -70
- package/src/rules/no-async-function.ts +0 -47
- package/src/rules/no-catch-all-to-map-error.ts +0 -90
- package/src/rules/no-effect-as.ts +0 -14
- package/src/rules/no-effect-async.ts +0 -14
- package/src/rules/no-effect-bind.ts +0 -13
- package/src/rules/no-effect-do.ts +0 -14
- package/src/rules/no-effect-fn-generator.ts +0 -58
- package/src/rules/no-effect-gen-adapter.ts +0 -51
- package/src/rules/no-effect-map-flatten.ts +0 -82
- package/src/rules/no-effect-map-void.ts +0 -80
- package/src/rules/no-effect-never.ts +0 -14
- package/src/rules/no-effect-orElse-ladder.ts +0 -79
- package/src/rules/no-effect-succeed-string.ts +0 -52
- package/src/rules/no-effect-succeed-variable.ts +0 -50
- package/src/rules/no-effect-succeed-void.ts +0 -63
- package/src/rules/no-effect-sync-console.ts +0 -91
- package/src/rules/no-effect-sync-wrapper.ts +0 -67
- package/src/rules/no-effect-type-alias.ts +0 -71
- package/src/rules/no-effect-wrapper-alias.ts +0 -95
- package/src/rules/no-extends-native-error.ts +0 -54
- package/src/rules/no-flatmap-ladder.ts +0 -77
- package/src/rules/no-fromnullable-coalesce.ts +0 -62
- package/src/rules/no-global-error-in-catch.ts +0 -104
- package/src/rules/no-global-error-in-failure.ts +0 -83
- package/src/rules/no-globals.ts +0 -178
- package/src/rules/no-if-statement.ts +0 -16
- package/src/rules/no-iife-wrapper.ts +0 -51
- package/src/rules/no-inline-provide.ts +0 -41
- package/src/rules/no-instanceof-schema.ts +0 -42
- package/src/rules/no-manual-effect-channels.ts +0 -58
- package/src/rules/no-match-effect-branch.ts +0 -82
- package/src/rules/no-match-void-branch.ts +0 -72
- package/src/rules/no-multiple-effect-provide.ts +0 -75
- package/src/rules/no-nested-effect-call.ts +0 -57
- package/src/rules/no-nested-effect-gen.ts +0 -43
- package/src/rules/no-nested-pipe.ts +0 -73
- package/src/rules/no-new-error.ts +0 -53
- package/src/rules/no-new-promise.ts +0 -50
- package/src/rules/no-node-builtin-import.ts +0 -68
- package/src/rules/no-option-as.ts +0 -13
- package/src/rules/no-option-boolean-normalization.ts +0 -88
- package/src/rules/no-positional-log-error.ts +0 -76
- package/src/rules/no-redundant-schema-tag-identifier.ts +0 -62
- package/src/rules/no-return-in-arrow.ts +0 -76
- package/src/rules/no-return-nullish.ts +0 -80
- package/src/rules/no-run-in-effect-gen.ts +0 -66
- package/src/rules/no-runtime-run-fork.ts +0 -14
- package/src/rules/no-schema-struct-with-tag.ts +0 -64
- package/src/rules/no-schema-union-of-literals.ts +0 -48
- package/src/rules/no-string-sentinel-const.ts +0 -49
- package/src/rules/no-switch-statement.ts +0 -13
- package/src/rules/no-ternary.ts +0 -30
- package/src/rules/no-throw-statement.ts +0 -39
- package/src/rules/no-try-catch.ts +0 -39
- package/src/rules/no-unnecessary-arrow-block.ts +0 -51
- package/src/rules/no-unnecessary-effect-gen.ts +0 -83
- package/src/rules/no-unnecessary-pipe-chain.ts +0 -47
- package/src/rules/no-unnecessary-pipe.ts +0 -45
- package/src/vendor/effect-oxlint/AST.ts +0 -516
- package/src/vendor/effect-oxlint/Comment.ts +0 -86
- package/src/vendor/effect-oxlint/Diagnostic.ts +0 -199
- package/src/vendor/effect-oxlint/Plugin.ts +0 -71
- package/src/vendor/effect-oxlint/Rule.ts +0 -548
- package/src/vendor/effect-oxlint/RuleContext.ts +0 -144
- package/src/vendor/effect-oxlint/Scope.ts +0 -177
- package/src/vendor/effect-oxlint/SourceCode.ts +0 -377
- package/src/vendor/effect-oxlint/Testing.ts +0 -1227
- package/src/vendor/effect-oxlint/Token.ts +0 -131
- package/src/vendor/effect-oxlint/Visitor.ts +0 -287
- package/src/vendor/effect-oxlint/index.ts +0 -88
- package/tests/ban-rules.test.ts +0 -68
- package/tests/context-rules.test.ts +0 -263
- package/tests/pattern-rules.test.ts +0 -247
- package/tsconfig.json +0 -15
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token type predicates and helpers for Effect-first lint rules.
|
|
3
|
-
*
|
|
4
|
-
* Provides convenience checks over oxlint's `Token` type (a discriminated
|
|
5
|
-
* union of `BooleanToken`, `IdentifierToken`, `KeywordToken`, etc.).
|
|
6
|
-
*
|
|
7
|
-
* @since 0.2.0
|
|
8
|
-
*/
|
|
9
|
-
import type { Token } from '@oxlint/plugins';
|
|
10
|
-
import { dual } from 'effect/Function';
|
|
11
|
-
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
// Type predicates
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Check whether a token is a keyword with the given value.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* Token.isKeyword(token, 'const') // true if keyword "const"
|
|
22
|
-
* Token.isKeyword(token, 'return') // true if keyword "return"
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @since 0.2.0
|
|
26
|
-
*/
|
|
27
|
-
export const isKeyword: {
|
|
28
|
-
(keyword: string): (token: Token) => boolean;
|
|
29
|
-
(token: Token, keyword: string): boolean;
|
|
30
|
-
} = dual(
|
|
31
|
-
2,
|
|
32
|
-
(token: Token, keyword: string): boolean =>
|
|
33
|
-
token.type === 'Keyword' && token.value === keyword
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Check whether a token is a punctuator with the given value.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```ts
|
|
41
|
-
* Token.isPunctuator(token, '{') // true if punctuator "{"
|
|
42
|
-
* Token.isPunctuator(token, ';') // true if punctuator ";"
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* @since 0.2.0
|
|
46
|
-
*/
|
|
47
|
-
export const isPunctuator: {
|
|
48
|
-
(value: string): (token: Token) => boolean;
|
|
49
|
-
(token: Token, value: string): boolean;
|
|
50
|
-
} = dual(
|
|
51
|
-
2,
|
|
52
|
-
(token: Token, value: string): boolean =>
|
|
53
|
-
token.type === 'Punctuator' && token.value === value
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Check whether a token is an identifier.
|
|
58
|
-
*
|
|
59
|
-
* @since 0.2.0
|
|
60
|
-
*/
|
|
61
|
-
export const isIdentifier = (token: Token): boolean =>
|
|
62
|
-
token.type === 'Identifier';
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Check whether a token is a string literal.
|
|
66
|
-
*
|
|
67
|
-
* @since 0.2.0
|
|
68
|
-
*/
|
|
69
|
-
export const isString = (token: Token): boolean => token.type === 'String';
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Check whether a token is a numeric literal.
|
|
73
|
-
*
|
|
74
|
-
* @since 0.2.0
|
|
75
|
-
*/
|
|
76
|
-
export const isNumeric = (token: Token): boolean => token.type === 'Numeric';
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Check whether a token is a boolean literal.
|
|
80
|
-
*
|
|
81
|
-
* @since 0.2.0
|
|
82
|
-
*/
|
|
83
|
-
export const isBoolean = (token: Token): boolean => token.type === 'Boolean';
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Check whether a token is a null literal.
|
|
87
|
-
*
|
|
88
|
-
* @since 0.2.0
|
|
89
|
-
*/
|
|
90
|
-
export const isNull = (token: Token): boolean => token.type === 'Null';
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Check whether a token is a template literal part.
|
|
94
|
-
*
|
|
95
|
-
* @since 0.2.0
|
|
96
|
-
*/
|
|
97
|
-
export const isTemplate = (token: Token): boolean => token.type === 'Template';
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Check whether a token is a regular expression literal.
|
|
101
|
-
*
|
|
102
|
-
* @since 0.2.0
|
|
103
|
-
*/
|
|
104
|
-
export const isRegularExpression = (token: Token): boolean =>
|
|
105
|
-
token.type === 'RegularExpression';
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Check whether a token is a private identifier (e.g. `#foo`).
|
|
109
|
-
*
|
|
110
|
-
* @since 0.2.0
|
|
111
|
-
*/
|
|
112
|
-
export const isPrivateIdentifier = (token: Token): boolean =>
|
|
113
|
-
token.type === 'PrivateIdentifier';
|
|
114
|
-
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
// Accessors
|
|
117
|
-
// ---------------------------------------------------------------------------
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Get the string value of a token.
|
|
121
|
-
*
|
|
122
|
-
* @since 0.2.0
|
|
123
|
-
*/
|
|
124
|
-
export const value = (token: Token): string => token.value;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Get the type discriminant of a token.
|
|
128
|
-
*
|
|
129
|
-
* @since 0.2.0
|
|
130
|
-
*/
|
|
131
|
-
export const type = (token: Token): string => token.type;
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composable visitor construction for Effect-first oxlint rules.
|
|
3
|
-
*
|
|
4
|
-
* Visitors are maps from AST node type names to Effect-returning handlers.
|
|
5
|
-
* This module provides combinators to build, merge, and enhance visitors.
|
|
6
|
-
*
|
|
7
|
-
* @since 0.1.0
|
|
8
|
-
*/
|
|
9
|
-
import type { ESTree, Visitor as OxlintVisitor } from '@oxlint/plugins';
|
|
10
|
-
import * as Arr from 'effect/Array';
|
|
11
|
-
import * as Effect from 'effect/Effect';
|
|
12
|
-
import { dual, pipe } from 'effect/Function';
|
|
13
|
-
import * as Option from 'effect/Option';
|
|
14
|
-
import * as R from 'effect/Record';
|
|
15
|
-
import * as Ref from 'effect/Ref';
|
|
16
|
-
|
|
17
|
-
import { RuleContext } from './RuleContext.ts';
|
|
18
|
-
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
// Types
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* An effectful visitor handler.
|
|
25
|
-
*
|
|
26
|
-
* Receives an AST node and returns an `Effect<void>` that may read/write
|
|
27
|
-
* `Ref` state and report diagnostics via `RuleContext`.
|
|
28
|
-
*
|
|
29
|
-
* @since 0.1.0
|
|
30
|
-
*/
|
|
31
|
-
export type EffectHandler<N = ESTree.Node> = {
|
|
32
|
-
bivarianceHack(node: N): Effect.Effect<void, never, RuleContext>;
|
|
33
|
-
}['bivarianceHack'];
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* A map from AST node type names (and `"NodeType:exit"` variants) to
|
|
37
|
-
* effectful handlers.
|
|
38
|
-
*
|
|
39
|
-
* This is the internal representation — handlers accept `ESTree.Node`.
|
|
40
|
-
*
|
|
41
|
-
* @since 0.1.0
|
|
42
|
-
*/
|
|
43
|
-
export type EffectVisitor = {
|
|
44
|
-
readonly [key: string]: EffectHandler;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/** @internal Extract the node parameter type from an oxlint visitor handler. */
|
|
48
|
-
type ExtractNode<H> = H extends
|
|
49
|
-
| ((node: infer N) => unknown)
|
|
50
|
-
| { bivarianceHack(node: infer N): void }
|
|
51
|
-
? N
|
|
52
|
-
: ESTree.Node;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Resolve a visitor key to its narrowed node type.
|
|
56
|
-
*
|
|
57
|
-
* For known keys (e.g. `'CallExpression'`), returns the specific
|
|
58
|
-
* ESTree node type. For unknown keys, falls back to `ESTree.Node`.
|
|
59
|
-
*
|
|
60
|
-
* @since 0.2.0
|
|
61
|
-
*/
|
|
62
|
-
export type VisitorNodeType<K extends string> = K extends keyof OxlintVisitor
|
|
63
|
-
? ExtractNode<Exclude<OxlintVisitor[K], undefined>>
|
|
64
|
-
: ESTree.Node;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Typed visitor map where known oxlint visitor keys provide the
|
|
68
|
-
* correctly narrowed node type to handlers (e.g. `MemberExpression`
|
|
69
|
-
* handlers receive `ESTree.MemberExpression`).
|
|
70
|
-
*
|
|
71
|
-
* Return this from `Rule.define`'s `create` generator. Callers get
|
|
72
|
-
* typed nodes in their handlers without manual narrowing.
|
|
73
|
-
*
|
|
74
|
-
* @since 0.2.0
|
|
75
|
-
*/
|
|
76
|
-
export type TypedEffectVisitor = {
|
|
77
|
-
readonly [K in keyof OxlintVisitor]?: EffectHandler<
|
|
78
|
-
ExtractNode<Exclude<OxlintVisitor[K], undefined>>
|
|
79
|
-
>;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
// Constructors
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Create a single-entry visitor that handles one node type.
|
|
88
|
-
*
|
|
89
|
-
* The handler is a generator function that can `yield*` Effects.
|
|
90
|
-
*
|
|
91
|
-
* @example
|
|
92
|
-
* ```ts
|
|
93
|
-
* Visitor.on('ThrowStatement', function*(node) {
|
|
94
|
-
* const depth = yield* Ref.get(myDepthRef)
|
|
95
|
-
* if (depth > 0) {
|
|
96
|
-
* yield* RuleContext.report({ node, message: '...' })
|
|
97
|
-
* }
|
|
98
|
-
* })
|
|
99
|
-
* ```
|
|
100
|
-
*
|
|
101
|
-
* @since 0.1.0
|
|
102
|
-
*/
|
|
103
|
-
export const on = <K extends string>(
|
|
104
|
-
nodeType: K,
|
|
105
|
-
handler: EffectHandler<VisitorNodeType<K>>
|
|
106
|
-
): EffectVisitor => ({ [nodeType]: handler as EffectHandler });
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Create a single-entry visitor for the exit phase of a node type.
|
|
110
|
-
*
|
|
111
|
-
* @since 0.1.0
|
|
112
|
-
*/
|
|
113
|
-
export const onExit = <K extends string>(
|
|
114
|
-
nodeType: K,
|
|
115
|
-
handler: EffectHandler<VisitorNodeType<K>>
|
|
116
|
-
): EffectVisitor => ({ [`${nodeType}:exit`]: handler as EffectHandler });
|
|
117
|
-
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
// Combinators
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
|
|
122
|
-
/** @internal Empty visitor seed for reduce operations. */
|
|
123
|
-
const emptyVisitor: EffectVisitor = {};
|
|
124
|
-
|
|
125
|
-
/** @internal Combine two handlers for the same node type into one sequential handler. */
|
|
126
|
-
const sequenceHandlers =
|
|
127
|
-
(left: EffectHandler, right: EffectHandler): EffectHandler =>
|
|
128
|
-
(node) =>
|
|
129
|
-
Effect.andThen(left(node), right(node));
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Merge multiple visitors into one.
|
|
133
|
-
*
|
|
134
|
-
* When two visitors handle the same node type, both handlers run
|
|
135
|
-
* sequentially (left to right).
|
|
136
|
-
*
|
|
137
|
-
* @since 0.1.0
|
|
138
|
-
*/
|
|
139
|
-
export const merge = (
|
|
140
|
-
...visitors: ReadonlyArray<EffectVisitor>
|
|
141
|
-
): EffectVisitor =>
|
|
142
|
-
Arr.reduce(visitors, emptyVisitor, (acc, visitor) =>
|
|
143
|
-
R.union(acc, visitor, (left, right) => sequenceHandlers(left, right))
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Create an enter/exit visitor pair that increments a `Ref<number>` on
|
|
148
|
-
* enter and decrements on exit, but only when the predicate matches.
|
|
149
|
-
*
|
|
150
|
-
* This replaces the common `let depth = 0` mutable counter pattern.
|
|
151
|
-
*
|
|
152
|
-
* The predicate receives the narrowed node type for the given key
|
|
153
|
-
* (e.g. `ESTree.CallExpression` for `'CallExpression'`).
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* ```ts
|
|
157
|
-
* const effectGenDepth = yield* Ref.make(0)
|
|
158
|
-
*
|
|
159
|
-
* Visitor.tracked('CallExpression',
|
|
160
|
-
* (node) => AST.isCallOf(node, 'Effect', 'gen'),
|
|
161
|
-
* effectGenDepth
|
|
162
|
-
* )
|
|
163
|
-
* ```
|
|
164
|
-
*
|
|
165
|
-
* @since 0.1.0
|
|
166
|
-
*/
|
|
167
|
-
export const tracked = <K extends string>(
|
|
168
|
-
nodeType: K,
|
|
169
|
-
predicate: (node: VisitorNodeType<K>) => boolean,
|
|
170
|
-
ref: Ref.Ref<number>
|
|
171
|
-
): EffectVisitor => ({
|
|
172
|
-
[nodeType]: (node: ESTree.Node) =>
|
|
173
|
-
predicate(node as VisitorNodeType<K>)
|
|
174
|
-
? Ref.update(ref, (n) => n + 1)
|
|
175
|
-
: Effect.void,
|
|
176
|
-
[`${nodeType}:exit`]: (node: ESTree.Node) =>
|
|
177
|
-
predicate(node as VisitorNodeType<K>)
|
|
178
|
-
? Ref.update(ref, (n) => n - 1)
|
|
179
|
-
: Effect.void
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Conditionally apply a visitor based on a predicate evaluated once
|
|
184
|
-
* at create time.
|
|
185
|
-
*
|
|
186
|
-
* Useful for restricting a visitor to specific files (e.g. skip test files).
|
|
187
|
-
*
|
|
188
|
-
* @example
|
|
189
|
-
* ```ts
|
|
190
|
-
* Visitor.filter(
|
|
191
|
-
* (filename) => !filename.endsWith('.test.ts'),
|
|
192
|
-
* mainVisitor
|
|
193
|
-
* )
|
|
194
|
-
* ```
|
|
195
|
-
*
|
|
196
|
-
* @since 0.2.0
|
|
197
|
-
*/
|
|
198
|
-
export const filter: {
|
|
199
|
-
(
|
|
200
|
-
predicate: (filename: string) => boolean
|
|
201
|
-
): (
|
|
202
|
-
visitor: EffectVisitor
|
|
203
|
-
) => Effect.Effect<EffectVisitor, never, RuleContext>;
|
|
204
|
-
(
|
|
205
|
-
predicate: (filename: string) => boolean,
|
|
206
|
-
visitor: EffectVisitor
|
|
207
|
-
): Effect.Effect<EffectVisitor, never, RuleContext>;
|
|
208
|
-
} = dual(
|
|
209
|
-
2,
|
|
210
|
-
(
|
|
211
|
-
predicate: (filename: string) => boolean,
|
|
212
|
-
visitor: EffectVisitor
|
|
213
|
-
): Effect.Effect<EffectVisitor, never, RuleContext> =>
|
|
214
|
-
Effect.service(RuleContext).pipe(
|
|
215
|
-
Effect.map((ctx) => (predicate(ctx.filename) ? visitor : {}))
|
|
216
|
-
)
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Accumulate values during traversal and analyze them at `Program:exit`.
|
|
221
|
-
*
|
|
222
|
-
* The `extract` function is called for each node of `nodeType`. If it
|
|
223
|
-
* returns `Option.some(value)`, that value is accumulated. At
|
|
224
|
-
* `Program:exit`, the `analyze` generator receives all collected items.
|
|
225
|
-
*
|
|
226
|
-
* @example
|
|
227
|
-
* ```ts
|
|
228
|
-
* Visitor.accumulate(
|
|
229
|
-
* 'ExportNamedDeclaration',
|
|
230
|
-
* (node) => AST.narrow(node, 'ExportNamedDeclaration').pipe(
|
|
231
|
-
* Option.map(n => n.declaration)
|
|
232
|
-
* ),
|
|
233
|
-
* function*(accumulated) {
|
|
234
|
-
* // Analyze all collected declarations at end of file
|
|
235
|
-
* }
|
|
236
|
-
* )
|
|
237
|
-
* ```
|
|
238
|
-
*
|
|
239
|
-
* @since 0.2.0
|
|
240
|
-
*/
|
|
241
|
-
export const accumulate = <A>(
|
|
242
|
-
nodeType: string,
|
|
243
|
-
extract: (node: ESTree.Node) => Option.Option<A>,
|
|
244
|
-
analyze: (
|
|
245
|
-
items: ReadonlyArray<A>
|
|
246
|
-
) => Effect.Effect<void, never, RuleContext>
|
|
247
|
-
): Effect.Effect<EffectVisitor, never, RuleContext> =>
|
|
248
|
-
Effect.gen(function* () {
|
|
249
|
-
const ref = yield* Ref.make<ReadonlyArray<A>>([]);
|
|
250
|
-
return merge(
|
|
251
|
-
on(nodeType, (node) =>
|
|
252
|
-
pipe(
|
|
253
|
-
extract(node),
|
|
254
|
-
Option.match({
|
|
255
|
-
onNone: () => Effect.void,
|
|
256
|
-
onSome: (value) =>
|
|
257
|
-
Ref.update(ref, (items) => [...items, value])
|
|
258
|
-
})
|
|
259
|
-
)
|
|
260
|
-
),
|
|
261
|
-
on('Program:exit', () =>
|
|
262
|
-
Effect.flatMap(Ref.get(ref), (items) => analyze(items))
|
|
263
|
-
)
|
|
264
|
-
);
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
// ---------------------------------------------------------------------------
|
|
268
|
-
// Conversion (internal — used by Rule.define at the runtime boundary)
|
|
269
|
-
// ---------------------------------------------------------------------------
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Convert an `EffectVisitor` to a plain oxlint `Visitor` by wrapping
|
|
273
|
-
* each handler with the provided runner function.
|
|
274
|
-
*
|
|
275
|
-
* This is the runtime boundary where Effects are executed. Called once
|
|
276
|
-
* per file inside `Rule.define`'s `create`.
|
|
277
|
-
*
|
|
278
|
-
* @internal
|
|
279
|
-
*/
|
|
280
|
-
export const toOxlintVisitor = (
|
|
281
|
-
effectVisitor: EffectVisitor,
|
|
282
|
-
runHandler: (effect: Effect.Effect<void, never, RuleContext>) => void
|
|
283
|
-
): OxlintVisitor =>
|
|
284
|
-
R.map(
|
|
285
|
-
effectVisitor,
|
|
286
|
-
(handler) => (node: ESTree.Node) => runHandler(handler(node))
|
|
287
|
-
);
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Effect-first library for writing oxlint custom lint rules.
|
|
3
|
-
*
|
|
4
|
-
* @since 0.1.0
|
|
5
|
-
* @packageDocumentation
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
// Core modules
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
/** AST pattern matching helpers returning `Option` for safe composition. */
|
|
13
|
-
export * as AST from './AST.ts';
|
|
14
|
-
|
|
15
|
-
/** Comment type predicates and helpers. */
|
|
16
|
-
export * as Comment from './Comment.ts';
|
|
17
|
-
|
|
18
|
-
/** Structured diagnostic construction. */
|
|
19
|
-
export * as Diagnostic from './Diagnostic.ts';
|
|
20
|
-
|
|
21
|
-
/** Plugin definition and composition. */
|
|
22
|
-
export * as Plugin from './Plugin.ts';
|
|
23
|
-
|
|
24
|
-
/** Core rule builder — `Rule.define` is the primary entry point. */
|
|
25
|
-
export * as Rule from './Rule.ts';
|
|
26
|
-
|
|
27
|
-
/** Effect service wrapping the oxlint rule context. */
|
|
28
|
-
export { RuleContext } from './RuleContext.ts';
|
|
29
|
-
export {
|
|
30
|
-
ast,
|
|
31
|
-
cwd,
|
|
32
|
-
filename,
|
|
33
|
-
id,
|
|
34
|
-
report,
|
|
35
|
-
sourceCode,
|
|
36
|
-
text
|
|
37
|
-
} from './RuleContext.ts';
|
|
38
|
-
|
|
39
|
-
/** Scope analysis helpers with Option. */
|
|
40
|
-
export * as Scope from './Scope.ts';
|
|
41
|
-
|
|
42
|
-
/** Effect-wrapped SourceCode queries with Option. */
|
|
43
|
-
export * as SourceCode from './SourceCode.ts';
|
|
44
|
-
|
|
45
|
-
/** Testing infrastructure — builders, runners, assertion helpers. */
|
|
46
|
-
export * as Testing from './Testing.ts';
|
|
47
|
-
|
|
48
|
-
/** Token type predicates and helpers. */
|
|
49
|
-
export * as Token from './Token.ts';
|
|
50
|
-
|
|
51
|
-
/** Composable visitor construction. */
|
|
52
|
-
export * as Visitor from './Visitor.ts';
|
|
53
|
-
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
// Type re-exports from @oxlint/plugins
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
|
|
58
|
-
export type {
|
|
59
|
-
Comment as OxlintComment,
|
|
60
|
-
Context,
|
|
61
|
-
CreateOnceRule,
|
|
62
|
-
CreateRule,
|
|
63
|
-
Definition,
|
|
64
|
-
DefinitionType,
|
|
65
|
-
ESTree,
|
|
66
|
-
Fix,
|
|
67
|
-
Fixer,
|
|
68
|
-
FixFn,
|
|
69
|
-
LineColumn,
|
|
70
|
-
Location,
|
|
71
|
-
Plugin as OxlintPlugin,
|
|
72
|
-
Range,
|
|
73
|
-
Ranged,
|
|
74
|
-
Reference,
|
|
75
|
-
Rule as OxlintRule,
|
|
76
|
-
RuleDocs,
|
|
77
|
-
RuleMeta,
|
|
78
|
-
Scope as OxlintScope,
|
|
79
|
-
ScopeManager,
|
|
80
|
-
ScopeType,
|
|
81
|
-
Settings,
|
|
82
|
-
SourceCode as OxlintSourceCode,
|
|
83
|
-
Span,
|
|
84
|
-
Suggestion,
|
|
85
|
-
Token as OxlintToken,
|
|
86
|
-
Variable,
|
|
87
|
-
Visitor as OxlintVisitor
|
|
88
|
-
} from '@oxlint/plugins';
|
package/tests/ban-rules.test.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from "bun:test"
|
|
2
|
-
import { Testing } from "../src/vendor/effect-oxlint/index.js"
|
|
3
|
-
import {
|
|
4
|
-
noEffectDo,
|
|
5
|
-
noEffectNever,
|
|
6
|
-
noEffectAs,
|
|
7
|
-
noEffectAsync,
|
|
8
|
-
noEffectBind,
|
|
9
|
-
noOptionAs,
|
|
10
|
-
noRuntimeRunFork,
|
|
11
|
-
} from "../src/rules/index.js"
|
|
12
|
-
|
|
13
|
-
// --- API ban rules ---
|
|
14
|
-
|
|
15
|
-
describe("noEffectDo", () => {
|
|
16
|
-
test("reports Effect.Do", () => {
|
|
17
|
-
const result = Testing.runRule(noEffectDo, "MemberExpression", Testing.memberExpr("Effect", "Do"))
|
|
18
|
-
Testing.expectDiagnostics(result, [{ message: "Avoid Effect.Do builder notation. Use flat pipe-based flow or Effect.gen." }])
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test("ignores Effect.map", () => {
|
|
22
|
-
const result = Testing.runRule(noEffectDo, "MemberExpression", Testing.memberExpr("Effect", "map"))
|
|
23
|
-
Testing.expectNoDiagnostics(result)
|
|
24
|
-
})
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe("noEffectNever", () => {
|
|
28
|
-
test("reports Effect.never", () => {
|
|
29
|
-
const result = Testing.runRule(noEffectNever, "MemberExpression", Testing.memberExpr("Effect", "never"))
|
|
30
|
-
Testing.expectDiagnostics(result, [{ message: "Avoid Effect.never. Use Stream or explicit acquire/release lifecycles." }])
|
|
31
|
-
})
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
describe("noEffectAs", () => {
|
|
35
|
-
test("reports Effect.as", () => {
|
|
36
|
-
const result = Testing.runRule(noEffectAs, "MemberExpression", Testing.memberExpr("Effect", "as"))
|
|
37
|
-
Testing.expectDiagnostics(result, [{ message: "Avoid Effect.as. Use Effect.map for value mapping or Effect.asVoid." }])
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
describe("noEffectAsync", () => {
|
|
42
|
-
test("reports Effect.async", () => {
|
|
43
|
-
const result = Testing.runRule(noEffectAsync, "MemberExpression", Testing.memberExpr("Effect", "async"))
|
|
44
|
-
expect(result.length).toBe(1)
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
describe("noEffectBind", () => {
|
|
49
|
-
test("reports Effect.bind", () => {
|
|
50
|
-
const result = Testing.runRule(noEffectBind, "MemberExpression", Testing.memberExpr("Effect", "bind"))
|
|
51
|
-
expect(result.length).toBe(1)
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
describe("noOptionAs", () => {
|
|
56
|
-
test("reports Option.as", () => {
|
|
57
|
-
const result = Testing.runRule(noOptionAs, "MemberExpression", Testing.memberExpr("Option", "as"))
|
|
58
|
-
expect(result.length).toBe(1)
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
describe("noRuntimeRunFork", () => {
|
|
63
|
-
test("reports Runtime.runFork", () => {
|
|
64
|
-
const result = Testing.runRule(noRuntimeRunFork, "MemberExpression", Testing.memberExpr("Runtime", "runFork"))
|
|
65
|
-
expect(result.length).toBe(1)
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|