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,548 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core rule builder for Effect-first oxlint rules.
|
|
3
|
-
*
|
|
4
|
-
* `Rule.define` is the primary entry point. It produces a standard
|
|
5
|
-
* `CreateRule` that oxlint can consume, while letting rule authors
|
|
6
|
-
* write fully effectful create generators and visitor handlers.
|
|
7
|
-
*
|
|
8
|
-
* @since 0.1.0
|
|
9
|
-
*/
|
|
10
|
-
import type { CreateRule, ESTree, RuleDocs, RuleMeta } from '@oxlint/plugins';
|
|
11
|
-
import * as Arr from 'effect/Array';
|
|
12
|
-
import * as Effect from 'effect/Effect';
|
|
13
|
-
import * as Option from 'effect/Option';
|
|
14
|
-
import * as P from 'effect/Predicate';
|
|
15
|
-
import * as Schema from 'effect/Schema';
|
|
16
|
-
|
|
17
|
-
import { pipe } from 'effect/Function';
|
|
18
|
-
|
|
19
|
-
import * as AST from './AST.ts';
|
|
20
|
-
import { make as makeDiagnostic } from './Diagnostic.ts';
|
|
21
|
-
import { fromOxlintContext, RuleContext } from './RuleContext.ts';
|
|
22
|
-
import type { EffectVisitor } from './Visitor.ts';
|
|
23
|
-
import { merge as mergeVisitors, toOxlintVisitor } from './Visitor.ts';
|
|
24
|
-
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
// Internal helpers
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Extract the identifier name from a `NewExpression` callee.
|
|
31
|
-
*
|
|
32
|
-
* `AST.calleeName` only accepts `CallExpression`. This mirrors the
|
|
33
|
-
* same logic for `NewExpression.callee`.
|
|
34
|
-
*
|
|
35
|
-
* @internal
|
|
36
|
-
*/
|
|
37
|
-
const newExprCalleeName = (callee: ESTree.Expression): Option.Option<string> =>
|
|
38
|
-
callee.type === 'Identifier' && 'name' in callee && P.isString(callee.name)
|
|
39
|
-
? Option.some(callee.name)
|
|
40
|
-
: Option.none();
|
|
41
|
-
|
|
42
|
-
// ---------------------------------------------------------------------------
|
|
43
|
-
// Types
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Configuration object for `Rule.define`.
|
|
48
|
-
*
|
|
49
|
-
* @since 0.1.0
|
|
50
|
-
*/
|
|
51
|
-
export interface RuleConfig<Options = undefined> {
|
|
52
|
-
/** Rule name (used for tracing spans). */
|
|
53
|
-
readonly name: string;
|
|
54
|
-
/** Oxlint rule metadata. */
|
|
55
|
-
readonly meta: RuleMeta;
|
|
56
|
-
/**
|
|
57
|
-
* Optional Schema for rule options.
|
|
58
|
-
*
|
|
59
|
-
* When provided, the first element of the raw JSON options array
|
|
60
|
-
* is decoded at `create` time against this schema.
|
|
61
|
-
*/
|
|
62
|
-
readonly options?: Schema.Decoder<Options> | undefined;
|
|
63
|
-
/**
|
|
64
|
-
* The create generator.
|
|
65
|
-
*
|
|
66
|
-
* Receives decoded options and returns an `EffectVisitor`.
|
|
67
|
-
* Runs inside an Effect context where `RuleContext` is available.
|
|
68
|
-
*
|
|
69
|
-
* May `yield* Ref.make(...)` for state, `yield* RuleContext` for
|
|
70
|
-
* context access, and return a visitor built with `Visitor.*` helpers.
|
|
71
|
-
*/
|
|
72
|
-
readonly create: (
|
|
73
|
-
options: Options
|
|
74
|
-
) => Effect.gen.Return<EffectVisitor, never, RuleContext>;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
|
-
// Builder
|
|
79
|
-
// ---------------------------------------------------------------------------
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Define an Effect-first oxlint lint rule.
|
|
83
|
-
*
|
|
84
|
-
* The `create` generator runs once per file via `Effect.runSync`.
|
|
85
|
-
* Each visitor handler is also executed via `Effect.runSync` per node.
|
|
86
|
-
* `Ref`-based state created in `create` persists across handler calls
|
|
87
|
-
* via closure.
|
|
88
|
-
*
|
|
89
|
-
* `Effect.runSync` is used here at the runtime boundary — the bridge
|
|
90
|
-
* between oxlint's synchronous plugin API and our Effect world.
|
|
91
|
-
*
|
|
92
|
-
* @since 0.1.0
|
|
93
|
-
*/
|
|
94
|
-
export const define = <Options = undefined>(
|
|
95
|
-
config: RuleConfig<Options>
|
|
96
|
-
): CreateRule => ({
|
|
97
|
-
meta: config.meta,
|
|
98
|
-
create(oxlintContext) {
|
|
99
|
-
const ruleCtx = fromOxlintContext(oxlintContext);
|
|
100
|
-
|
|
101
|
-
// Runtime boundary: execute effects with RuleContext provided.
|
|
102
|
-
// This is the FFI bridge between oxlint's sync API and Effect.
|
|
103
|
-
const run = <A>(effect: Effect.Effect<A, never, RuleContext>): A =>
|
|
104
|
-
Effect.runSync(Effect.provideService(effect, RuleContext, ruleCtx));
|
|
105
|
-
|
|
106
|
-
// Decode options from the raw JSON array.
|
|
107
|
-
// When no schema is configured, `Options` defaults to `undefined`.
|
|
108
|
-
const decodeOptions = (): Options => {
|
|
109
|
-
const schema = config.options;
|
|
110
|
-
if (schema === undefined) return undefined as Options;
|
|
111
|
-
return Schema.decodeUnknownSync(schema)(oxlintContext.options[0]);
|
|
112
|
-
};
|
|
113
|
-
const options = run(Effect.sync(decodeOptions));
|
|
114
|
-
|
|
115
|
-
// Run the create generator to set up Refs and get the visitor map.
|
|
116
|
-
// TypedEffectVisitor → EffectVisitor: the typed keys provide
|
|
117
|
-
// narrowed nodes to callers, but at runtime all handlers receive
|
|
118
|
-
// the same ESTree.Node values. The variance mismatch is safe
|
|
119
|
-
// because oxlint guarantees the node type matches the key.
|
|
120
|
-
const effectVisitor = run(
|
|
121
|
-
Effect.gen(() => config.create(options))
|
|
122
|
-
) as EffectVisitor;
|
|
123
|
-
|
|
124
|
-
// Wrap each handler: Effect<void> → plain () => void
|
|
125
|
-
return toOxlintVisitor(effectVisitor, run);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
// Metadata helper
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Which Effect version a rule applies to.
|
|
135
|
-
*
|
|
136
|
-
* Stored on `meta.docs.effectVersion` so preset authors can filter rules
|
|
137
|
-
* per project. Default `both`, meaning the rule is version-agnostic.
|
|
138
|
-
*
|
|
139
|
-
* @since 0.2.0
|
|
140
|
-
*/
|
|
141
|
-
export type EffectVersion = 'v3' | 'v4' | 'both';
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Build `RuleMeta` with sensible defaults.
|
|
145
|
-
*
|
|
146
|
-
* @since 0.1.0
|
|
147
|
-
*/
|
|
148
|
-
export const meta = (opts: {
|
|
149
|
-
readonly type: 'problem' | 'suggestion' | 'layout';
|
|
150
|
-
readonly description: string;
|
|
151
|
-
readonly fixable?: 'code' | 'whitespace' | undefined;
|
|
152
|
-
readonly hasSuggestions?: boolean | undefined;
|
|
153
|
-
readonly messages?: Record<string, string> | undefined;
|
|
154
|
-
readonly docs?: RuleDocs | undefined;
|
|
155
|
-
readonly effectVersion?: EffectVersion | undefined;
|
|
156
|
-
}): RuleMeta => ({
|
|
157
|
-
type: opts.type,
|
|
158
|
-
...(opts.fixable !== undefined ? { fixable: opts.fixable } : {}),
|
|
159
|
-
...(opts.hasSuggestions !== undefined
|
|
160
|
-
? { hasSuggestions: opts.hasSuggestions }
|
|
161
|
-
: {}),
|
|
162
|
-
...(opts.messages !== undefined ? { messages: opts.messages } : {}),
|
|
163
|
-
docs: {
|
|
164
|
-
description: opts.description,
|
|
165
|
-
effectVersion: opts.effectVersion ?? 'both',
|
|
166
|
-
...opts.docs
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// ---------------------------------------------------------------------------
|
|
171
|
-
// Convenience rule factories (common patterns)
|
|
172
|
-
// ---------------------------------------------------------------------------
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Create a rule that bans `obj.prop` member expression access.
|
|
176
|
-
*
|
|
177
|
-
* Replaces the common `memberExprRule` utility pattern.
|
|
178
|
-
*
|
|
179
|
-
* @since 0.1.0
|
|
180
|
-
*/
|
|
181
|
-
export const banMember = (
|
|
182
|
-
obj: string,
|
|
183
|
-
prop: string | ReadonlyArray<string>,
|
|
184
|
-
opts: {
|
|
185
|
-
readonly message: string;
|
|
186
|
-
readonly meta?:
|
|
187
|
-
| { readonly type?: 'problem' | 'suggestion'; readonly effectVersion?: EffectVersion }
|
|
188
|
-
| undefined;
|
|
189
|
-
}
|
|
190
|
-
): CreateRule =>
|
|
191
|
-
define({
|
|
192
|
-
name: `ban-${obj}-${P.isString(prop) ? prop : Arr.join(prop, '-')}`,
|
|
193
|
-
meta: meta({
|
|
194
|
-
type: opts.meta?.type ?? 'suggestion',
|
|
195
|
-
description: opts.message,
|
|
196
|
-
effectVersion: opts.meta?.effectVersion
|
|
197
|
-
}),
|
|
198
|
-
create: function* () {
|
|
199
|
-
const ctx = yield* RuleContext;
|
|
200
|
-
return {
|
|
201
|
-
MemberExpression: (node: ESTree.Node) =>
|
|
202
|
-
pipe(
|
|
203
|
-
AST.narrow(node, 'MemberExpression'),
|
|
204
|
-
Option.flatMap(AST.matchMember(obj, prop)),
|
|
205
|
-
Option.match({
|
|
206
|
-
onNone: () => Effect.void,
|
|
207
|
-
onSome: (matched) =>
|
|
208
|
-
ctx.report(
|
|
209
|
-
makeDiagnostic({
|
|
210
|
-
node: matched,
|
|
211
|
-
message: opts.message
|
|
212
|
-
})
|
|
213
|
-
)
|
|
214
|
-
})
|
|
215
|
-
)
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Create a rule that bans imports matching a source string or predicate.
|
|
222
|
-
*
|
|
223
|
-
* Replaces the common `importRule` utility pattern.
|
|
224
|
-
*
|
|
225
|
-
* @since 0.1.0
|
|
226
|
-
*/
|
|
227
|
-
export const banImport = (
|
|
228
|
-
source: string | ((source: string) => boolean),
|
|
229
|
-
opts: {
|
|
230
|
-
readonly message: string;
|
|
231
|
-
readonly meta?:
|
|
232
|
-
| { readonly type?: 'problem' | 'suggestion'; readonly effectVersion?: EffectVersion }
|
|
233
|
-
| undefined;
|
|
234
|
-
}
|
|
235
|
-
): CreateRule =>
|
|
236
|
-
define({
|
|
237
|
-
name: 'ban-import',
|
|
238
|
-
meta: meta({
|
|
239
|
-
type: opts.meta?.type ?? 'suggestion',
|
|
240
|
-
description: opts.message,
|
|
241
|
-
effectVersion: opts.meta?.effectVersion
|
|
242
|
-
}),
|
|
243
|
-
create: function* () {
|
|
244
|
-
const ctx = yield* RuleContext;
|
|
245
|
-
return {
|
|
246
|
-
ImportDeclaration: (node: ESTree.Node) =>
|
|
247
|
-
pipe(
|
|
248
|
-
AST.narrow(node, 'ImportDeclaration'),
|
|
249
|
-
Option.flatMap(AST.matchImport(source)),
|
|
250
|
-
Option.match({
|
|
251
|
-
onNone: () => Effect.void,
|
|
252
|
-
onSome: (matched) =>
|
|
253
|
-
ctx.report(
|
|
254
|
-
makeDiagnostic({
|
|
255
|
-
node: matched,
|
|
256
|
-
message: opts.message
|
|
257
|
-
})
|
|
258
|
-
)
|
|
259
|
-
})
|
|
260
|
-
)
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Create a rule that bans bare identifier call expressions.
|
|
267
|
-
*
|
|
268
|
-
* Matches `CallExpression` nodes whose callee is an identifier in
|
|
269
|
-
* the given list (e.g. `fetch()`, `useState()`, `readFileSync()`).
|
|
270
|
-
*
|
|
271
|
-
* @example
|
|
272
|
-
* ```ts
|
|
273
|
-
* // Ban a single call
|
|
274
|
-
* Rule.banCallOf('fetch', { message: 'Use Effect HTTP client' })
|
|
275
|
-
*
|
|
276
|
-
* // Ban multiple calls
|
|
277
|
-
* Rule.banCallOf(['useState', 'useEffect'], { message: 'Use Effect' })
|
|
278
|
-
* ```
|
|
279
|
-
*
|
|
280
|
-
* @since 0.2.0
|
|
281
|
-
*/
|
|
282
|
-
export const banCallOf = (
|
|
283
|
-
name: string | ReadonlyArray<string>,
|
|
284
|
-
opts: {
|
|
285
|
-
readonly message: string;
|
|
286
|
-
readonly meta?:
|
|
287
|
-
| { readonly type?: 'problem' | 'suggestion'; readonly effectVersion?: EffectVersion }
|
|
288
|
-
| undefined;
|
|
289
|
-
}
|
|
290
|
-
): CreateRule => {
|
|
291
|
-
const names = P.isString(name) ? [name] : name;
|
|
292
|
-
return define({
|
|
293
|
-
name: `ban-call-${Arr.join(names, '-')}`,
|
|
294
|
-
meta: meta({
|
|
295
|
-
type: opts.meta?.type ?? 'suggestion',
|
|
296
|
-
description: opts.message,
|
|
297
|
-
effectVersion: opts.meta?.effectVersion
|
|
298
|
-
}),
|
|
299
|
-
create: function* () {
|
|
300
|
-
const ctx = yield* RuleContext;
|
|
301
|
-
return {
|
|
302
|
-
CallExpression: (node: ESTree.Node) =>
|
|
303
|
-
pipe(
|
|
304
|
-
AST.narrow(node, 'CallExpression'),
|
|
305
|
-
Option.flatMap(AST.calleeName),
|
|
306
|
-
Option.filter((n) => Arr.contains(names, n)),
|
|
307
|
-
Option.match({
|
|
308
|
-
onNone: () => Effect.void,
|
|
309
|
-
onSome: () =>
|
|
310
|
-
ctx.report(
|
|
311
|
-
makeDiagnostic({
|
|
312
|
-
node,
|
|
313
|
-
message: opts.message
|
|
314
|
-
})
|
|
315
|
-
)
|
|
316
|
-
})
|
|
317
|
-
)
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Create a rule that bans `new` expressions with the given callee name.
|
|
325
|
-
*
|
|
326
|
-
* Matches `NewExpression` nodes whose callee is an identifier in
|
|
327
|
-
* the given list (e.g. `new Date()`, `new Error()`).
|
|
328
|
-
*
|
|
329
|
-
* @example
|
|
330
|
-
* ```ts
|
|
331
|
-
* // Ban a single constructor
|
|
332
|
-
* Rule.banNewExpr('Date', { message: 'Use Clock service' })
|
|
333
|
-
*
|
|
334
|
-
* // Ban multiple constructors
|
|
335
|
-
* Rule.banNewExpr(['Error', 'TypeError'], { message: 'Use tagged errors' })
|
|
336
|
-
* ```
|
|
337
|
-
*
|
|
338
|
-
* @since 0.2.0
|
|
339
|
-
*/
|
|
340
|
-
export const banNewExpr = (
|
|
341
|
-
name: string | ReadonlyArray<string>,
|
|
342
|
-
opts: {
|
|
343
|
-
readonly message: string;
|
|
344
|
-
readonly meta?:
|
|
345
|
-
| { readonly type?: 'problem' | 'suggestion'; readonly effectVersion?: EffectVersion }
|
|
346
|
-
| undefined;
|
|
347
|
-
}
|
|
348
|
-
): CreateRule => {
|
|
349
|
-
const names = P.isString(name) ? [name] : name;
|
|
350
|
-
return define({
|
|
351
|
-
name: `ban-new-${Arr.join(names, '-')}`,
|
|
352
|
-
meta: meta({
|
|
353
|
-
type: opts.meta?.type ?? 'suggestion',
|
|
354
|
-
description: opts.message,
|
|
355
|
-
effectVersion: opts.meta?.effectVersion
|
|
356
|
-
}),
|
|
357
|
-
create: function* () {
|
|
358
|
-
const ctx = yield* RuleContext;
|
|
359
|
-
return {
|
|
360
|
-
NewExpression: (node: ESTree.Node) =>
|
|
361
|
-
pipe(
|
|
362
|
-
AST.narrow(node, 'NewExpression'),
|
|
363
|
-
Option.flatMap((n) => newExprCalleeName(n.callee)),
|
|
364
|
-
Option.filter((n) => Arr.contains(names, n)),
|
|
365
|
-
Option.match({
|
|
366
|
-
onNone: () => Effect.void,
|
|
367
|
-
onSome: () =>
|
|
368
|
-
ctx.report(
|
|
369
|
-
makeDiagnostic({
|
|
370
|
-
node,
|
|
371
|
-
message: opts.message
|
|
372
|
-
})
|
|
373
|
-
)
|
|
374
|
-
})
|
|
375
|
-
)
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
});
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Create a rule that bans a specific statement type.
|
|
383
|
-
*
|
|
384
|
-
* @since 0.1.0
|
|
385
|
-
*/
|
|
386
|
-
export const banStatement = (
|
|
387
|
-
nodeType: string,
|
|
388
|
-
opts: {
|
|
389
|
-
readonly message: string;
|
|
390
|
-
readonly meta?:
|
|
391
|
-
| { readonly type?: 'problem' | 'suggestion'; readonly effectVersion?: EffectVersion }
|
|
392
|
-
| undefined;
|
|
393
|
-
}
|
|
394
|
-
): CreateRule =>
|
|
395
|
-
define({
|
|
396
|
-
name: `ban-${nodeType}`,
|
|
397
|
-
meta: meta({
|
|
398
|
-
type: opts.meta?.type ?? 'suggestion',
|
|
399
|
-
description: opts.message,
|
|
400
|
-
effectVersion: opts.meta?.effectVersion
|
|
401
|
-
}),
|
|
402
|
-
create: function* () {
|
|
403
|
-
const ctx = yield* RuleContext;
|
|
404
|
-
return {
|
|
405
|
-
[nodeType]: (node: ESTree.Node) =>
|
|
406
|
-
ctx.report(makeDiagnostic({ node, message: opts.message }))
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
// ---------------------------------------------------------------------------
|
|
412
|
-
// Multi-ban combinator
|
|
413
|
-
// ---------------------------------------------------------------------------
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* A single ban specification. Each spec carries its own message so
|
|
417
|
-
* diagnostics are specific to the exact pattern matched.
|
|
418
|
-
*
|
|
419
|
-
* @since 0.3.0
|
|
420
|
-
*/
|
|
421
|
-
export type BanSpec =
|
|
422
|
-
| { readonly type: 'member'; readonly object: string; readonly property: string | ReadonlyArray<string>; readonly message: string }
|
|
423
|
-
| { readonly type: 'call'; readonly name: string | ReadonlyArray<string>; readonly message: string }
|
|
424
|
-
| { readonly type: 'new'; readonly name: string | ReadonlyArray<string>; readonly message: string }
|
|
425
|
-
| { readonly type: 'import'; readonly source: string | ((source: string) => boolean); readonly message: string }
|
|
426
|
-
| { readonly type: 'statement'; readonly nodeType: string; readonly message: string };
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Create a rule that bans multiple patterns, each with its own message.
|
|
430
|
-
*
|
|
431
|
-
* @example
|
|
432
|
-
* ```ts
|
|
433
|
-
* Rule.banMultiple({
|
|
434
|
-
* name: "no-global-date",
|
|
435
|
-
* meta: { type: "suggestion" },
|
|
436
|
-
* specs: [
|
|
437
|
-
* { type: "new", name: "Date", message: "Avoid new Date(). Use Clock service." },
|
|
438
|
-
* { type: "member", object: "Date", property: "now", message: "Avoid Date.now(). Use Clock service." },
|
|
439
|
-
* ],
|
|
440
|
-
* })
|
|
441
|
-
* ```
|
|
442
|
-
*
|
|
443
|
-
* @since 0.3.0
|
|
444
|
-
*/
|
|
445
|
-
export const banMultiple = (config: {
|
|
446
|
-
readonly name: string;
|
|
447
|
-
readonly meta?:
|
|
448
|
-
| { readonly type?: 'problem' | 'suggestion'; readonly effectVersion?: EffectVersion }
|
|
449
|
-
| undefined;
|
|
450
|
-
readonly specs: ReadonlyArray<BanSpec>;
|
|
451
|
-
}): CreateRule => {
|
|
452
|
-
const description = config.specs.map((s) => s.message).join(' ');
|
|
453
|
-
return define({
|
|
454
|
-
name: config.name,
|
|
455
|
-
meta: meta({
|
|
456
|
-
type: config.meta?.type ?? 'suggestion',
|
|
457
|
-
description,
|
|
458
|
-
effectVersion: config.meta?.effectVersion
|
|
459
|
-
}),
|
|
460
|
-
create: function* () {
|
|
461
|
-
const ctx = yield* RuleContext;
|
|
462
|
-
|
|
463
|
-
const visitors: Array<EffectVisitor> = [];
|
|
464
|
-
|
|
465
|
-
for (const spec of config.specs) {
|
|
466
|
-
switch (spec.type) {
|
|
467
|
-
case 'member': {
|
|
468
|
-
const report = (node: ESTree.Node) =>
|
|
469
|
-
ctx.report(makeDiagnostic({ node, message: spec.message }));
|
|
470
|
-
visitors.push({
|
|
471
|
-
MemberExpression: (node: ESTree.Node) =>
|
|
472
|
-
pipe(
|
|
473
|
-
AST.narrow(node, 'MemberExpression'),
|
|
474
|
-
Option.flatMap(AST.matchMember(spec.object, spec.property)),
|
|
475
|
-
Option.match({
|
|
476
|
-
onNone: () => Effect.void,
|
|
477
|
-
onSome: (matched) => report(matched)
|
|
478
|
-
})
|
|
479
|
-
)
|
|
480
|
-
});
|
|
481
|
-
break;
|
|
482
|
-
}
|
|
483
|
-
case 'call': {
|
|
484
|
-
const names = P.isString(spec.name) ? [spec.name] : spec.name;
|
|
485
|
-
const report = (node: ESTree.Node) =>
|
|
486
|
-
ctx.report(makeDiagnostic({ node, message: spec.message }));
|
|
487
|
-
visitors.push({
|
|
488
|
-
CallExpression: (node: ESTree.Node) =>
|
|
489
|
-
pipe(
|
|
490
|
-
AST.narrow(node, 'CallExpression'),
|
|
491
|
-
Option.flatMap(AST.calleeName),
|
|
492
|
-
Option.filter((n) => Arr.contains(names, n)),
|
|
493
|
-
Option.match({
|
|
494
|
-
onNone: () => Effect.void,
|
|
495
|
-
onSome: () => report(node)
|
|
496
|
-
})
|
|
497
|
-
)
|
|
498
|
-
});
|
|
499
|
-
break;
|
|
500
|
-
}
|
|
501
|
-
case 'new': {
|
|
502
|
-
const names = P.isString(spec.name) ? [spec.name] : spec.name;
|
|
503
|
-
const report = (node: ESTree.Node) =>
|
|
504
|
-
ctx.report(makeDiagnostic({ node, message: spec.message }));
|
|
505
|
-
visitors.push({
|
|
506
|
-
NewExpression: (node: ESTree.Node) =>
|
|
507
|
-
pipe(
|
|
508
|
-
AST.narrow(node, 'NewExpression'),
|
|
509
|
-
Option.flatMap((n) => newExprCalleeName(n.callee)),
|
|
510
|
-
Option.filter((n) => Arr.contains(names, n)),
|
|
511
|
-
Option.match({
|
|
512
|
-
onNone: () => Effect.void,
|
|
513
|
-
onSome: () => report(node)
|
|
514
|
-
})
|
|
515
|
-
)
|
|
516
|
-
});
|
|
517
|
-
break;
|
|
518
|
-
}
|
|
519
|
-
case 'import': {
|
|
520
|
-
const report = (node: ESTree.Node) =>
|
|
521
|
-
ctx.report(makeDiagnostic({ node, message: spec.message }));
|
|
522
|
-
visitors.push({
|
|
523
|
-
ImportDeclaration: (node: ESTree.Node) =>
|
|
524
|
-
pipe(
|
|
525
|
-
AST.narrow(node, 'ImportDeclaration'),
|
|
526
|
-
Option.flatMap(AST.matchImport(spec.source)),
|
|
527
|
-
Option.match({
|
|
528
|
-
onNone: () => Effect.void,
|
|
529
|
-
onSome: (matched) => report(matched)
|
|
530
|
-
})
|
|
531
|
-
)
|
|
532
|
-
});
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
case 'statement': {
|
|
536
|
-
visitors.push({
|
|
537
|
-
[spec.nodeType]: (node: ESTree.Node) =>
|
|
538
|
-
ctx.report(makeDiagnostic({ node, message: spec.message }))
|
|
539
|
-
});
|
|
540
|
-
break;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
return mergeVisitors(...visitors);
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
};
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Effect service wrapping the oxlint rule context.
|
|
3
|
-
*
|
|
4
|
-
* Provides effectful access to the linting context — file info,
|
|
5
|
-
* source code queries, diagnostics reporting, and rule options.
|
|
6
|
-
*
|
|
7
|
-
* @since 0.1.0
|
|
8
|
-
*/
|
|
9
|
-
import type {
|
|
10
|
-
Context as OxlintContext,
|
|
11
|
-
Diagnostic as OxlintDiagnostic,
|
|
12
|
-
ESTree,
|
|
13
|
-
LanguageOptions,
|
|
14
|
-
Options,
|
|
15
|
-
Settings,
|
|
16
|
-
SourceCode
|
|
17
|
-
} from '@oxlint/plugins';
|
|
18
|
-
import * as Context from 'effect/Context';
|
|
19
|
-
import * as Effect from 'effect/Effect';
|
|
20
|
-
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
// Service
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* The lint rule context, provided as an Effect service.
|
|
27
|
-
*
|
|
28
|
-
* Available inside `Rule.define`'s `create` generator and every
|
|
29
|
-
* visitor handler via `yield* RuleContext`.
|
|
30
|
-
*
|
|
31
|
-
* @since 0.1.0
|
|
32
|
-
*/
|
|
33
|
-
export class RuleContext extends Context.Service<
|
|
34
|
-
RuleContext,
|
|
35
|
-
{
|
|
36
|
-
/** Report a lint diagnostic for the current file. */
|
|
37
|
-
readonly report: (diagnostic: OxlintDiagnostic) => Effect.Effect<void>;
|
|
38
|
-
/** Rule ID in `plugin/rule` form. */
|
|
39
|
-
readonly id: string;
|
|
40
|
-
/** Absolute path of the file being linted. */
|
|
41
|
-
readonly filename: string;
|
|
42
|
-
/** Current working directory. */
|
|
43
|
-
readonly cwd: string;
|
|
44
|
-
/** Raw rule options (JSON values). */
|
|
45
|
-
readonly options: Readonly<Options>;
|
|
46
|
-
/** Source code access (tokens, comments, text, scope, etc.). */
|
|
47
|
-
readonly sourceCode: SourceCode;
|
|
48
|
-
/** Language / parser options for this file. */
|
|
49
|
-
readonly languageOptions: Readonly<LanguageOptions>;
|
|
50
|
-
/** Shared settings from the oxlint config. */
|
|
51
|
-
readonly settings: Readonly<Settings>;
|
|
52
|
-
}
|
|
53
|
-
>()('effect-oxlint/RuleContext') {}
|
|
54
|
-
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Constructor from raw oxlint Context
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Build a `RuleContext` value from the raw oxlint `Context`.
|
|
61
|
-
*
|
|
62
|
-
* @internal
|
|
63
|
-
*/
|
|
64
|
-
export const fromOxlintContext = (ctx: OxlintContext): RuleContext['Service'] =>
|
|
65
|
-
RuleContext.of({
|
|
66
|
-
report: (diagnostic) => Effect.sync(() => ctx.report(diagnostic)),
|
|
67
|
-
id: ctx.id,
|
|
68
|
-
filename: ctx.filename,
|
|
69
|
-
cwd: ctx.cwd,
|
|
70
|
-
options: ctx.options,
|
|
71
|
-
sourceCode: ctx.sourceCode,
|
|
72
|
-
languageOptions: ctx.languageOptions,
|
|
73
|
-
settings: ctx.settings
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// ---------------------------------------------------------------------------
|
|
77
|
-
// Convenience accessors (yield*-able inside handlers)
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Effectful access to the rule ID.
|
|
82
|
-
*
|
|
83
|
-
* @since 0.1.0
|
|
84
|
-
*/
|
|
85
|
-
export const id: Effect.Effect<string, never, RuleContext> = Effect.service(
|
|
86
|
-
RuleContext
|
|
87
|
-
).pipe(Effect.map((ctx) => ctx.id));
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Effectful access to the filename of the file being linted.
|
|
91
|
-
*
|
|
92
|
-
* @since 0.1.0
|
|
93
|
-
*/
|
|
94
|
-
export const filename: Effect.Effect<string, never, RuleContext> =
|
|
95
|
-
Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.filename));
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Effectful access to the working directory.
|
|
99
|
-
*
|
|
100
|
-
* @since 0.1.0
|
|
101
|
-
*/
|
|
102
|
-
export const cwd: Effect.Effect<string, never, RuleContext> = Effect.service(
|
|
103
|
-
RuleContext
|
|
104
|
-
).pipe(Effect.map((ctx) => ctx.cwd));
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Effectful access to the SourceCode object.
|
|
108
|
-
*
|
|
109
|
-
* @since 0.1.0
|
|
110
|
-
*/
|
|
111
|
-
export const sourceCode: Effect.Effect<SourceCode, never, RuleContext> =
|
|
112
|
-
Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.sourceCode));
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Effectful access to the raw source text.
|
|
116
|
-
*
|
|
117
|
-
* @since 0.1.0
|
|
118
|
-
*/
|
|
119
|
-
export const text: Effect.Effect<string, never, RuleContext> = Effect.service(
|
|
120
|
-
RuleContext
|
|
121
|
-
).pipe(Effect.map((ctx) => ctx.sourceCode.text));
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Effectful access to the AST root node.
|
|
125
|
-
*
|
|
126
|
-
* @since 0.1.0
|
|
127
|
-
*/
|
|
128
|
-
export const ast: Effect.Effect<ESTree.Program, never, RuleContext> =
|
|
129
|
-
Effect.service(RuleContext).pipe(Effect.map((ctx) => ctx.sourceCode.ast));
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Report a lint diagnostic.
|
|
133
|
-
*
|
|
134
|
-
* Shorthand so handlers can `yield* RuleContext.report(diagnostic)`
|
|
135
|
-
* without first resolving the full service.
|
|
136
|
-
*
|
|
137
|
-
* @since 0.1.0
|
|
138
|
-
*/
|
|
139
|
-
export const report = (
|
|
140
|
-
diagnostic: OxlintDiagnostic
|
|
141
|
-
): Effect.Effect<void, never, RuleContext> =>
|
|
142
|
-
Effect.service(RuleContext).pipe(
|
|
143
|
-
Effect.flatMap((ctx) => ctx.report(diagnostic))
|
|
144
|
-
);
|