@2digits/oxlint-plugin 0.0.7 → 0.1.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/NOTICE +32 -0
- package/README.md +103 -0
- package/dist/index.d.mts +78 -50
- package/dist/index.mjs +5 -2
- package/package.json +7 -3
package/NOTICE
CHANGED
|
@@ -10,6 +10,11 @@ Copyright 2025 Moritz Süßer and contributors
|
|
|
10
10
|
https://github.com/mpsuesser/oxlint-plugin-effect
|
|
11
11
|
Licensed under the MIT License.
|
|
12
12
|
|
|
13
|
+
anti-slop
|
|
14
|
+
Copyright (c) 2026 Dillon Mulroy
|
|
15
|
+
https://github.com/dmmulroy/anti-slop
|
|
16
|
+
Licensed under the MIT License. The permission notice below applies to this project too.
|
|
17
|
+
|
|
13
18
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
19
|
of this software and associated documentation files (the "Software"), to deal
|
|
15
20
|
in the Software without restriction, including without limitation the rights
|
|
@@ -30,3 +35,30 @@ SOFTWARE.
|
|
|
30
35
|
|
|
31
36
|
The full Apache License 2.0 text is available at:
|
|
32
37
|
https://www.apache.org/licenses/LICENSE-2.0
|
|
38
|
+
|
|
39
|
+
padding-line-between-statements is adapted from ESLint Stylistic via anti-slop:
|
|
40
|
+
https://github.com/eslint-stylistic/eslint-stylistic
|
|
41
|
+
https://github.com/dmmulroy/anti-slop/tree/main/src/vendor/eslint-stylistic
|
|
42
|
+
|
|
43
|
+
MIT License
|
|
44
|
+
|
|
45
|
+
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
|
46
|
+
Copyright (c) 2023-PRESENT ESLint Stylistic contributors
|
|
47
|
+
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
49
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
50
|
+
in the Software without restriction, including without limitation the rights
|
|
51
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
52
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
53
|
+
furnished to do so, subject to the following conditions:
|
|
54
|
+
|
|
55
|
+
The above copyright notice and this permission notice shall be included in all
|
|
56
|
+
copies or substantial portions of the Software.
|
|
57
|
+
|
|
58
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
59
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
60
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
61
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
62
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
63
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
64
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -36,8 +36,111 @@ The package exports all rules as `rules`, their names as `RuleName`, and the def
|
|
|
36
36
|
See each rule's `meta.docs.url` for its upstream rule, issue, or framework documentation. Copied-code attribution is in
|
|
37
37
|
[`NOTICE`](./NOTICE).
|
|
38
38
|
|
|
39
|
+
## Endpoint header schema keys
|
|
40
|
+
|
|
41
|
+
`no-uppercase-http-api-header` reports each static ASCII-uppercase key in a direct Effect v4 endpoint `headers`
|
|
42
|
+
fields object. Incoming headers are lowercase, and schema decoding looks up keys exactly:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import * as Schema from 'effect/Schema';
|
|
46
|
+
import { HttpApiEndpoint } from 'effect/unstable/httpapi';
|
|
47
|
+
|
|
48
|
+
// Diagnosed: the required header is missing to the decoder even when it arrived.
|
|
49
|
+
HttpApiEndpoint.get('me', '/me', { headers: { 'X-Api-Key': Schema.String } });
|
|
50
|
+
// Valid: the schema matches the lowercase incoming key.
|
|
51
|
+
HttpApiEndpoint.get('me', '/me', { headers: { 'x-api-key': Schema.String } });
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The rule checks options at argument 2 of `get`, `post`, `put`, `patch`, `delete`, `head`, and `options`.
|
|
55
|
+
It resolves lexical import bindings from `effect/unstable/httpapi` and its `HttpApiEndpoint` submodule, including
|
|
56
|
+
named aliases and namespace imports, and ignores shadowed bindings. Referenced schemas, computed keys, spreads,
|
|
57
|
+
duplicate keys, accessors, and ambiguous options objects are outside this initial slice. Curried `make(method)`,
|
|
58
|
+
v3 `setHeaders`, native Request/Response/fetch headers, outgoing setters, and native `Headers.get`/`has` are not checked.
|
|
59
|
+
Only ASCII uppercase letters are diagnosed; the rule does not normalize non-ASCII names.
|
|
60
|
+
|
|
61
|
+
There is **no autofix**: renaming a header schema key changes typed contracts and may collide with a lowercase key.
|
|
62
|
+
Review the schema and its consumers together. Runtime controls use the workspace's Effect version with `@effect/vitest`.
|
|
63
|
+
This is preventive guidance: the historical agency scan found **zero bad sites and seven valid endpoint schemas**,
|
|
64
|
+
not seven defects or a runtime outage.
|
|
65
|
+
|
|
66
|
+
### Tests
|
|
67
|
+
|
|
68
|
+
Use `@effect/vitest` for tests exercising Effect code. Run effects with `it.effect` (or `it.live` when live runtime
|
|
69
|
+
services are required), not manual `Effect.run*` calls. RuleTester and synchronous CLI tests use regular `it`.
|
|
70
|
+
|
|
71
|
+
### Function-valued Config defaults
|
|
72
|
+
|
|
73
|
+
`no-function-config-default` reports inline zero-parameter functions passed to Effect's eager `Config.withDefault` API,
|
|
74
|
+
except when the receiving config is locally proven to hold a function:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import * as Config from 'effect/Config';
|
|
78
|
+
|
|
79
|
+
Config.withDefault(
|
|
80
|
+
Config.succeed(() => 1),
|
|
81
|
+
() => 2,
|
|
82
|
+
);
|
|
83
|
+
const config = Config.succeed(() => {
|
|
84
|
+
return 1;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
config.pipe(Config.withDefault(() => 2));
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The proof follows same-file `const` receiver aliases with no reassignment and recognizes runtime Config imports from
|
|
91
|
+
`effect` and `effect/Config`, including aliases and lexical shadowing. The `succeed` argument must be a function literal;
|
|
92
|
+
a nonfunction object containing a function does not qualify. In `.pipe(...)`, only the first operation can use the proof.
|
|
93
|
+
Imported, mutable, or otherwise composed configs remain unknown and retain the diagnostic. This is syntax proof, not
|
|
94
|
+
general inference of `Config<A>`. Parameterized function defaults remain excluded. There is no autofix: eagerly evaluating
|
|
95
|
+
or unwrapping a thunk could change side effects or an intentional function value.
|
|
96
|
+
|
|
97
|
+
## anti-slop Effect rules
|
|
98
|
+
|
|
99
|
+
Adapted from [`dmmulroy/anti-slop`](https://github.com/dmmulroy/anti-slop/tree/main/src/effect/rules):
|
|
100
|
+
|
|
101
|
+
- `no-manual-effect-error-tag`: prefer tagged handlers for `_tag` comparisons/switches in broad Effect catches.
|
|
102
|
+
- `no-manual-tag-comparison`: prefer Match/Predicate for literal `_tag` comparisons and switches outside those catches.
|
|
103
|
+
- `no-manual-tagged-construction`: prefer existing constructors over literal string `_tag` objects; direct
|
|
104
|
+
`Match.when`/`Match.not` pattern objects are exempt.
|
|
105
|
+
- `no-service-constructor-imports`: reject relative named `make[A-Z]` imports outside `.test`/`.spec` files.
|
|
106
|
+
- `prefer-effect-match`: also reports chained literal ternaries comparing the same source expression, while retaining
|
|
107
|
+
the existing Effect-file switch diagnostic.
|
|
108
|
+
|
|
109
|
+
All are included in `recommendedRules`, without autofixes. Like upstream, these are syntactic policies: they do not
|
|
110
|
+
require Effect imports, infer tagged types, or prove that constructors exist. Catch and pattern exemptions recognize
|
|
111
|
+
the literal `Effect`/`Match` identifiers, not aliases or shadowing. Constructor imports are matched by imported name
|
|
112
|
+
(including aliases), not return type; package/absolute imports are excluded. The switch rules can overlap with the
|
|
113
|
+
existing `prefer-effect-match` diagnostic.
|
|
114
|
+
|
|
39
115
|
## Automatic fixes
|
|
40
116
|
|
|
117
|
+
### Statement spacing (opt-in)
|
|
118
|
+
|
|
119
|
+
`padding-line-between-statements` adapts anti-slop's vendored ESLint Stylistic rule. It is excluded from
|
|
120
|
+
`recommendedRules`: enable it with an explicit policy. Later matching entries override earlier entries.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
export default {
|
|
124
|
+
rules: {
|
|
125
|
+
'2digits/padding-line-between-statements': [
|
|
126
|
+
'error',
|
|
127
|
+
{ blankLine: 'always', prev: '*', next: 'return' },
|
|
128
|
+
{ blankLine: 'always', prev: ['const', 'let'], next: '*' },
|
|
129
|
+
{ blankLine: 'any', prev: ['const', 'let'], next: ['const', 'let'] },
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Options accept `always`, `never`, or `any`, statement names (including TypeScript declarations and
|
|
136
|
+
`singleline-*`/`multiline-*` variants), arrays, or `{ selector: 'ExpressionStatement', lineMode: 'multiline' }` AST selectors.
|
|
137
|
+
Selectors must match statement nodes (for example `ExpressionStatement[expression.type="CallExpression"]`), not their
|
|
138
|
+
nested expressions. See the [upstream statement names](https://eslint.style/rules/padding-line-between-statements).
|
|
139
|
+
Autofixes preserve trailing comments and avoid collapsing multiple blank-line gaps separated by comments.
|
|
140
|
+
The exported `PaddingLineOption` type describes each configuration entry. No options means no diagnostics.
|
|
141
|
+
|
|
142
|
+
### Other fixes
|
|
143
|
+
|
|
41
144
|
Run `vp lint --fix` to apply fixes from `prefer-effect-duration`, `no-empty-effect-callback`,
|
|
42
145
|
`no-effect-alchemy-barrel-imports`, `prefer-effect-alchemy-namespace-imports`,
|
|
43
146
|
`alchemy-no-v1-worker-properties`, and `alchemy-no-deprecated-docker-constraints`.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,60 +1,88 @@
|
|
|
1
1
|
import { Plugin } from "@oxlint/plugins";
|
|
2
|
+
import * as Arr from "effect/Array";
|
|
2
3
|
//#region src/rules/index.d.ts
|
|
3
4
|
export declare const rules: {
|
|
4
|
-
readonly 'alchemy-no-cloudflare-init-finalizer': import("
|
|
5
|
-
readonly 'alchemy-no-deprecated-docker-constraints': import("
|
|
6
|
-
readonly 'alchemy-no-deprecated-resource': import("
|
|
7
|
-
readonly 'alchemy-no-plaintext-github-secret': import("
|
|
8
|
-
readonly 'alchemy-no-removed-config-api': import("
|
|
9
|
-
readonly 'alchemy-no-reserved-eventbridge-default-name': import("
|
|
10
|
-
readonly 'alchemy-no-runtime-config': import("
|
|
11
|
-
readonly 'alchemy-no-v1-import': import("
|
|
12
|
-
readonly 'alchemy-no-v1-worker-properties': import("
|
|
13
|
-
readonly 'avoid-data-tagged-error': import("
|
|
14
|
-
readonly 'ban-error-string': import("
|
|
15
|
-
readonly 'cors-credentials-with-wildcard': import("
|
|
16
|
-
readonly 'dual-numeric-arity-with-optional-parameter': import("
|
|
17
|
-
readonly 'effect-promise-vs-trypromise': import("
|
|
18
|
-
readonly 'no-already-started-promise': import("
|
|
19
|
-
readonly 'no-async-effect-try': import("
|
|
20
|
-
readonly 'no-discarded-run-promise': import("
|
|
21
|
-
readonly 'no-discarded-schema-checks': import("
|
|
22
|
-
readonly 'no-empty-effect-callback': import("
|
|
23
|
-
readonly 'no-empty-schema-struct': import("
|
|
24
|
-
readonly 'no-effect-alchemy-barrel-imports': import("
|
|
25
|
-
readonly 'no-function-config-default': import("
|
|
26
|
-
readonly 'no-hash-as-identity': import("
|
|
27
|
-
readonly 'no-logging-in-catch': import("
|
|
28
|
-
readonly 'no-
|
|
29
|
-
readonly 'no-
|
|
30
|
-
readonly 'no-
|
|
31
|
-
readonly 'no-
|
|
32
|
-
readonly 'no-
|
|
33
|
-
readonly 'no-
|
|
34
|
-
readonly 'no-
|
|
35
|
-
readonly '
|
|
36
|
-
readonly '
|
|
37
|
-
readonly '
|
|
38
|
-
readonly '
|
|
39
|
-
readonly '
|
|
40
|
-
readonly '
|
|
41
|
-
readonly 'prefer-effect-
|
|
42
|
-
readonly 'prefer-effect-
|
|
43
|
-
readonly 'prefer-effect-
|
|
44
|
-
readonly 'prefer-effect-
|
|
45
|
-
readonly 'prefer-effect-
|
|
46
|
-
readonly 'prefer-
|
|
47
|
-
readonly 'prefer-
|
|
48
|
-
readonly 'prefer-
|
|
49
|
-
readonly '
|
|
50
|
-
readonly '
|
|
51
|
-
readonly '
|
|
52
|
-
readonly '
|
|
5
|
+
readonly 'alchemy-no-cloudflare-init-finalizer': import("effect-oxlint").OxlintRule;
|
|
6
|
+
readonly 'alchemy-no-deprecated-docker-constraints': import("effect-oxlint").OxlintRule;
|
|
7
|
+
readonly 'alchemy-no-deprecated-resource': import("effect-oxlint").OxlintRule;
|
|
8
|
+
readonly 'alchemy-no-plaintext-github-secret': import("effect-oxlint").OxlintRule;
|
|
9
|
+
readonly 'alchemy-no-removed-config-api': import("effect-oxlint").OxlintRule;
|
|
10
|
+
readonly 'alchemy-no-reserved-eventbridge-default-name': import("effect-oxlint").OxlintRule;
|
|
11
|
+
readonly 'alchemy-no-runtime-config': import("effect-oxlint").OxlintRule;
|
|
12
|
+
readonly 'alchemy-no-v1-import': import("effect-oxlint").OxlintRule;
|
|
13
|
+
readonly 'alchemy-no-v1-worker-properties': import("effect-oxlint").OxlintRule;
|
|
14
|
+
readonly 'avoid-data-tagged-error': import("effect-oxlint").OxlintRule;
|
|
15
|
+
readonly 'ban-error-string': import("effect-oxlint").OxlintRule;
|
|
16
|
+
readonly 'cors-credentials-with-wildcard': import("effect-oxlint").OxlintRule;
|
|
17
|
+
readonly 'dual-numeric-arity-with-optional-parameter': import("effect-oxlint").OxlintRule;
|
|
18
|
+
readonly 'effect-promise-vs-trypromise': import("effect-oxlint").OxlintRule;
|
|
19
|
+
readonly 'no-already-started-promise': import("effect-oxlint").OxlintRule;
|
|
20
|
+
readonly 'no-async-effect-try': import("effect-oxlint").OxlintRule;
|
|
21
|
+
readonly 'no-discarded-run-promise': import("effect-oxlint").OxlintRule;
|
|
22
|
+
readonly 'no-discarded-schema-checks': import("effect-oxlint").OxlintRule;
|
|
23
|
+
readonly 'no-empty-effect-callback': import("effect-oxlint").OxlintRule;
|
|
24
|
+
readonly 'no-empty-schema-struct': import("effect-oxlint").OxlintRule;
|
|
25
|
+
readonly 'no-effect-alchemy-barrel-imports': import("effect-oxlint").OxlintRule;
|
|
26
|
+
readonly 'no-function-config-default': import("effect-oxlint").OxlintRule;
|
|
27
|
+
readonly 'no-hash-as-identity': import("effect-oxlint").OxlintRule;
|
|
28
|
+
readonly 'no-logging-in-catch': import("effect-oxlint").OxlintRule;
|
|
29
|
+
readonly 'no-manual-effect-error-tag': import("effect-oxlint").OxlintRule;
|
|
30
|
+
readonly 'no-manual-tag-comparison': import("effect-oxlint").OxlintRule;
|
|
31
|
+
readonly 'no-manual-tagged-construction': import("effect-oxlint").OxlintRule;
|
|
32
|
+
readonly 'no-multi-shot-effect-callback': import("effect-oxlint").OxlintRule;
|
|
33
|
+
readonly 'no-non-json-schema-annotation': import("effect-oxlint").OxlintRule;
|
|
34
|
+
readonly 'no-option-of-service': import("effect-oxlint").OxlintRule;
|
|
35
|
+
readonly 'no-overwritten-discriminant': import("effect-oxlint").OxlintRule;
|
|
36
|
+
readonly 'no-service-option-get-or-throw': import("effect-oxlint").OxlintRule;
|
|
37
|
+
readonly 'no-service-constructor-imports': import("effect-oxlint").OxlintRule;
|
|
38
|
+
readonly 'no-throw-in-effect-callback': import("effect-oxlint").OxlintRule;
|
|
39
|
+
readonly 'no-uppercase-http-api-header': import("effect-oxlint").OxlintRule;
|
|
40
|
+
readonly 'no-zero-retry-times': import("effect-oxlint").OxlintRule;
|
|
41
|
+
readonly 'padding-line-between-statements': import("effect-oxlint").CreateRule;
|
|
42
|
+
readonly 'prefer-effect-alchemy-namespace-imports': import("effect-oxlint").OxlintRule;
|
|
43
|
+
readonly 'prefer-effect-array-sort': import("effect-oxlint").OxlintRule;
|
|
44
|
+
readonly 'prefer-effect-datetime': import("effect-oxlint").OxlintRule;
|
|
45
|
+
readonly 'prefer-effect-duration': import("effect-oxlint").OxlintRule;
|
|
46
|
+
readonly 'prefer-effect-encoding': import("effect-oxlint").OxlintRule;
|
|
47
|
+
readonly 'prefer-effect-filesystem': import("effect-oxlint").OxlintRule;
|
|
48
|
+
readonly 'prefer-effect-filter': import("effect-oxlint").OxlintRule;
|
|
49
|
+
readonly 'prefer-effect-headers': import("effect-oxlint").OxlintRule;
|
|
50
|
+
readonly 'prefer-effect-match': import("effect-oxlint").OxlintRule;
|
|
51
|
+
readonly 'prefer-effect-path': import("effect-oxlint").OxlintRule;
|
|
52
|
+
readonly 'prefer-effect-url': import("effect-oxlint").OxlintRule;
|
|
53
|
+
readonly 'prefer-uninterruptible': import("effect-oxlint").OxlintRule;
|
|
54
|
+
readonly 'prefer-with-span': import("effect-oxlint").OxlintRule;
|
|
55
|
+
readonly 'prefer-yield-now': import("effect-oxlint").OxlintRule;
|
|
56
|
+
readonly 'preserve-caught-error': import("effect-oxlint").OxlintRule;
|
|
57
|
+
readonly 'require-schema-class-brand': import("effect-oxlint").OxlintRule;
|
|
58
|
+
readonly 'require-try-promise-abort-signal': import("effect-oxlint").OxlintRule;
|
|
59
|
+
readonly 'throw-in-effect-gen': import("effect-oxlint").OxlintRule;
|
|
53
60
|
};
|
|
54
61
|
//#endregion
|
|
62
|
+
//#region src/rules/padding-line-between-statements.d.ts
|
|
63
|
+
type PaddingType = 'any' | 'never' | 'always';
|
|
64
|
+
type LineMode = 'any' | 'singleline' | 'multiline';
|
|
65
|
+
interface SelectorOption {
|
|
66
|
+
readonly selector: string;
|
|
67
|
+
readonly lineMode?: LineMode;
|
|
68
|
+
}
|
|
69
|
+
type MultilineStatementType = 'block-like' | 'expression' | 'return' | 'export' | 'var' | 'let' | 'const' | 'using' | 'type';
|
|
70
|
+
type BasicStatementType = '*' | 'exports' | 'require' | 'directive' | 'iife' | 'block' | 'empty' | 'function' | 'ts-method' | 'break' | 'case' | 'class' | 'continue' | 'debugger' | 'default' | 'do' | 'for' | 'if' | 'import' | 'switch' | 'throw' | 'try' | 'while' | 'with' | 'cjs-export' | 'cjs-import' | 'enum' | 'interface' | 'function-overload';
|
|
71
|
+
type StatementType = BasicStatementType | MultilineStatementType | `singleline-${MultilineStatementType}` | `multiline-${MultilineStatementType}`;
|
|
72
|
+
type StatementMatcher = StatementType | SelectorOption;
|
|
73
|
+
type StatementOption = StatementMatcher | Arr.NonEmptyReadonlyArray<StatementMatcher>;
|
|
74
|
+
/**
|
|
75
|
+
* A spacing policy; later matching entries override earlier entries.
|
|
76
|
+
*/
|
|
77
|
+
interface PaddingLineOption {
|
|
78
|
+
readonly blankLine: PaddingType;
|
|
79
|
+
readonly prev: StatementOption;
|
|
80
|
+
readonly next: StatementOption;
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
55
83
|
//#region src/index.d.ts
|
|
56
84
|
export type RuleName = keyof typeof rules;
|
|
57
85
|
export declare const recommendedRules: Partial<Record<`2digits/${RuleName}`, 'error'>>;
|
|
58
86
|
declare const plugin: Plugin;
|
|
59
87
|
//#endregion
|
|
60
|
-
export { plugin as default };
|
|
88
|
+
export { type PaddingLineOption, plugin as default };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import{defineRule as e,eslintCompatPlugin as t}from"@oxlint/plugins";const n={bindings:/* @__PURE__ */ new Map,hasEffectImport:!1};function r(e){return e.imported.type===`Identifier`?e.imported.name:typeof e.imported.value==`string`?e.imported.value:void 0}function i(e){if(e===`alchemy`)return[`Alchemy`];if(e===`effect`||e===`@effect/platform`)return[];if(e.startsWith(`effect/`)||e.startsWith(`@effect/platform/`)||e.startsWith(`alchemy/`)){let t=e.split(`/`).at(-1);return t===void 0?void 0:/^\p{Ll}/u.test(t)?[]:[t]}}function a(e){let t=/* @__PURE__ */ new Map,n=!1;for(let a of e.body){if(a.type!==`ImportDeclaration`)continue;let e=a.source.value;(e===`effect`||e.startsWith(`effect/`)||e.startsWith(`@effect/`))&&(n=!0);let o=i(e);if(o!==void 0)for(let e of a.specifiers){if(e.type===`ImportNamespaceSpecifier`||e.type===`ImportDefaultSpecifier`){t.set(e.local.name,o);continue}let n=r(e);n!==void 0&&t.set(e.local.name,[...o,n])}}return{bindings:t,hasEffectImport:n}}function o(t,n){return e({meta:t,createOnce:n})}function s(t,r){return e({meta:t,createOnce(e){let t=n,{before:i,Program:o,...s}=r(e,()=>t);return{before(){t=n,i?.()},Program(e){t=a(e),o?.(e)},...s}}})}function c(e,t,n,r){return{type:e,docs:{description:t,recommended:!0,...r===void 0?{}:{url:r}},schema:[],messages:n}}function l(e){if(!e.computed&&e.property.type===`Identifier`)return e.property.name;if(e.computed&&e.property.type===`Literal`&&typeof e.property.value==`string`)return e.property.value}function u(e){let t=[],n=e;for(;n.type===`ChainExpression`||n.type===`MemberExpression`;){if(n.type===`ChainExpression`){n=n.expression;continue}let e=l(n);if(e===void 0)return;t.unshift(e),n=n.object}return n.type===`Identifier`?[n.name,...t]:void 0}function d(e,t,n){if(e.type!==`Identifier`||e.name!==n)return!1;let r=t.sourceCode.getScope(e);for(;r!==null;){if(r.set.has(n))return!1;r=r.upper}return!0}function f(e,t){let n=u(e),r=n?.[0];if(n===void 0||r===void 0)return;let i=t.bindings.get(r);return i===void 0?void 0:[...i,...n.slice(1)]}function p(e,t,n,r){let i=f(e,t);return i?.length===2&&i[0]===n&&i[1]===r}function m(e,t,n){let r=f(e,t);return r?.length===n.length&&r.every((e,t)=>e===n[t])}function h(e){return e?.type===`ArrowFunctionExpression`||e?.type===`FunctionExpression`}function g(e,t){let n=e.arguments[t];return n===void 0||n.type===`SpreadElement`?void 0:n}function _(e){if(!e.computed&&e.key.type===`Identifier`)return e.key.name;if(e.key.type===`Literal`&&typeof e.key.value==`string`)return e.key.value}function v(e,t){for(let n of e.properties)if(n.type===`Property`&&_(n)===t)return n}function ee(e){return[`ParenthesizedExpression`,`TSAsExpression`,`TSNonNullExpression`,`TSSatisfiesExpression`,`TSTypeAssertion`].includes(e.type)}function y(e){let t=e;for(;ee(t);)t=t.expression;return t}function te(e,t){if(Array.isArray(e)){for(let n of e)t.push(n);return}for(let[n,r]of Object.entries(e))[`loc`,`parent`,`range`].includes(n)||t.push(r)}function b(e,t){let n=[e],r=/* @__PURE__ */ new WeakSet;for(;n.length>0;){let e=n.pop();if(e&&typeof e==`object`&&!r.has(e)){if(r.add(e),typeof e.type==`string`&&t(e)===!0)return!0;te(e,n)}}return!1}function x(e,t){return b(e,e=>e.type===`Identifier`&&e.name===t)}function S(e){let t=e.params[0];return t?.type===`Identifier`?t:void 0}function C(e){let t=S(e);return t===void 0||!e.body||t.name.startsWith(`_`)?!1:x(e.body,t.name)}function w(e){let t=e.parent;for(;t;){if(h(t))return t;t=t.parent}}function T(e){let t=e.parent;if(t.type===`CallExpression`&&t.arguments.includes(e))return t}function E(e,t){return e.type===`Literal`&&e.value===t}function ne(e){let t=e.parent;return t?t.type===`ExpressionStatement`||t.type===`UnaryExpression`&&t.operator===`void`||t.type===`SequenceExpression`&&t.expressions.at(-1)!==e:!1}function D(e){return u(e.callee)?.at(-1)?.endsWith(`Error`)===!0}const re=/* @__PURE__ */ new Set([`alarm`,`fetch`,`queue`,`rpc`,`scheduled`,`tail`,`trace`,`webSocketClose`,`webSocketError`,`webSocketMessage`]);function ie(e,t){return m(e,t,[`Cloudflare`,`Worker`])||m(e,t,[`Cloudflare`,`Workers`,`Worker`])}function O(e,t){let n=e.parent;for(;n;){if(n.type===`CallExpression`&&ie(n.callee,t))return n;n=n.parent}}function k(e,t){let n=w(e),r=n===void 0?void 0:T(n);return r!==void 0&&p(r.callee,t,`Effect`,`gen`)?r:void 0}function ae(e){let t=e.parent;for(;t;){if(h(t))return;if(t.type===`Property`){let e=_(t);if(e!==void 0&&re.has(e))return e}t=t.parent}}const oe=s(c(`problem`,`Disallow finalizers in Cloudflare Worker initialization, where workerd never runs them.`,{finalizer:`A Cloudflare Worker init finalizer never runs because workerd has no isolate teardown hook. Acquire disposable resources inside an event handler.`},`https://alchemy.run/cloudflare/compute/workers`),(e,t)=>({CallExpression(n){let r=t();if(!p(n.callee,r,`Effect`,`addFinalizer`))return;let i=k(n,r);i!==void 0&&O(i,r)?.arguments.includes(i)&&e.report({node:n,messageId:`finalizer`})}}));function A(e,t,n){let r=e.sourceCode.getScope(t);for(;r!==null;){let e=r.set.get(n);if(e!==void 0)return e;r=r.upper}}function j(e,t){let n=u(t)?.[0];return(n===void 0?void 0:A(e,t,n))?.defs.some(e=>{let t=e.node;return e.type===`ImportBinding`&&t.parent?.type===`ImportDeclaration`&&t.parent.importKind!==`type`&&(t.type!==`ImportSpecifier`||t.importKind!==`type`)})===!0}function M(e,t,n,r,i){let a=e.sourceCode.ast;for(let r of a.body)if(r.type===`ImportDeclaration`&&r.source.value===n&&r.importKind!==`type`){for(let n of r.specifiers)if(n.type===`ImportNamespaceSpecifier`&&A(e,t,n.local.name)?.defs.some(e=>e.node===n))return{name:n.local.name,fixes:[]}}let o=new Set(e.sourceCode.scopeManager.scopes.flatMap(e=>[...e.variables.map(e=>e.name),...e.references.map(e=>e.identifier.name)])),s=r,c=2;for(;o.has(s);)s=`${r}${c++}`;let l=`import * as ${s} from '${n}';\n`,u=a.body.find(e=>e.type!==`ExpressionStatement`||e.expression.type!==`Literal`||typeof e.expression.value!=`string`);return{name:s,fixes:[u===void 0?i.insertTextAfter(a,`\n${l}`):i.insertTextBefore(u,l)]}}function N(e,t){let n=/* @__PURE__ */ new Set;return e.properties.every(e=>{if(e.type!==`Property`||e.computed||e.method||e.kind!==`init`)return!1;let r=e.key.type===`Identifier`?e.key.name:e.key.type===`Literal`?String(e.key.value):void 0;return r===void 0||r===t||n.has(r)?!1:(n.add(r),!0)})}const se=s({...c(`problem`,`Disallow the deprecated top-level Docker Service constraints property.`,{constraints:`Docker.Service constraints is deprecated. Move it to placement: { constraints: ... }.`},`https://alchemy.run/providers/docker/service`),fixable:`code`},(e,t)=>({CallExpression(n){if(!p(n.callee,t(),`Docker`,`Service`))return;let r=g(n,1),i=r?.type===`ObjectExpression`?v(r,`constraints`):void 0;i!==void 0&&e.report({node:i,messageId:`constraints`,fix(t){if(j(e,n.callee)&&r?.type===`ObjectExpression`&&N(r,`placement`))return t.replaceText(i,`placement: { ${e.sourceCode.getText(i)} }`)}})}})),ce=/* @__PURE__ */ new Map([[`Cloudflare.Access.Bookmark`,`Cloudflare.Access.Application with type: "bookmark"`],[`AWS.RDSData.ExecuteSql`,`AWS.RDSData.ExecuteStatement`],[`AWS.EKS.Deployment`,`Kubernetes.Deployment from alchemy/Kubernetes`],[`AWS.EKS.HelmChart`,`Kubernetes.HelmChart from alchemy/Kubernetes`],[`AWS.EKS.Job`,`Kubernetes.Job from alchemy/Kubernetes`],[`AWS.EKS.Manifest`,`Kubernetes.Manifest from alchemy/Kubernetes`]]),le=s(c(`problem`,`Disallow deprecated Alchemy resource APIs that have supported replacements.`,{deprecated:`{{api}} is deprecated. Use {{replacement}}.`},`https://alchemy.run/llms-full.txt`),(e,t)=>({CallExpression(n){let r=f(n.callee,t());if(r===void 0)return;let i=r.join(`.`),a=ce.get(i);a!==void 0&&e.report({node:n.callee,messageId:`deprecated`,data:{api:i,replacement:a}})}}));function ue(e,t){let n=y(e);if(n.type===`Literal`&&typeof n.value==`string`||n.type===`TemplateLiteral`)return!0;let r=u(n);return r?.[0]===`process`&&r[1]===`env`||n.type===`CallExpression`&&p(n.callee,t,`Config`,`string`)}const de=s(c(`problem`,`Require singular GitHub Secret values to use Redacted.`,{plaintext:`GitHub.Secret value must be Redacted so it stays out of logs and state. Use Redacted.make(...) or Config.redacted(...).`},`https://alchemy.run/providers/github/secret`),(e,t)=>({CallExpression(n){let r=t();if(!p(n.callee,r,`GitHub`,`Secret`))return;let i=g(n,1),a=i?.type===`ObjectExpression`?v(i,`value`):void 0;a!==void 0&&ue(a.value,r)&&e.report({node:a.value,messageId:`plaintext`})}})),fe=s(c(`problem`,`Disallow removed Alchemy Secret and Variable APIs.`,{removed:`Alchemy.{{api}} was removed. Use effect/Config (Config.redacted for secrets, Config.string for variables).`},`https://alchemy.run/blog/2026-05-29-beta-45`),(e,t)=>({CallExpression(n){let r=f(n.callee,t());r?.[0]===`Alchemy`&&(r[1]===`Secret`||r[1]===`Variable`)&&e.report({node:n.callee,messageId:`removed`,data:{api:r[1]}})}})),pe=s(c(`problem`,`Disallow creating an EventBridge bus with the reserved default name.`,{reserved:`EventBridge reserves the name "default". Omit the bus argument to use the account default, or choose another name.`},`https://alchemy.run/aws/messaging/eventbridge`),(e,t)=>({CallExpression(n){if(!m(n.callee,t(),[`AWS`,`EventBridge`,`EventBus`]))return;let r=g(n,1),i=r?.type===`ObjectExpression`?v(r,`name`):void 0;i!==void 0&&E(i.value,`default`)&&e.report({node:i.value,messageId:`reserved`})}})),me=s(c(`problem`,`Require Effect Config values to be resolved during Alchemy Worker initialization.`,{runtime:`Config resolved inside the {{handler}} handler is invisible to Alchemy deployment. Resolve it in Worker init and close over the value, or put it in env.`},`https://alchemy.run/environments/secrets`),(e,t)=>({YieldExpression(n){let r=t(),i=n.argument;if(i?.type!==`CallExpression`||f(i.callee,r)?.[0]!==`Config`)return;let a=k(n,r),o=a===void 0?void 0:ae(a);a!==void 0&&o!==void 0&&O(a,r)!==void 0&&e.report({node:i,messageId:`runtime`,data:{handler:o}})}})),he=o(c(`problem`,`Disallow Alchemy v1 imports that bypass the Effect-based Stack API.`,{defaultImport:`The default alchemy() API is from v1. Use import * as Alchemy and Alchemy.Stack.`,providerImport:`Use the v2 provider entrypoint {{replacement}} (capitalization is significant).`},`https://alchemy.run/migrating-from-v1`),e=>({ImportDeclaration(t){let n=t.source.value;if(n===`alchemy`){let n=t.specifiers.find(e=>e.type===`ImportDefaultSpecifier`);n!==void 0&&e.report({node:n,messageId:`defaultImport`});return}let r=/^alchemy\/(aws|cloudflare)$/.exec(n)?.[1];if(r===void 0)return;let i=`alchemy/${r===`aws`?`AWS`:`Cloudflare`}`;e.report({node:t.source,messageId:`providerImport`,data:{replacement:i}})}})),ge=s({...c(`problem`,`Disallow Alchemy v1 Cloudflare Worker property names.`,{property:`Cloudflare.Worker {{old}} was replaced in v2. Use {{replacement}}.`},`https://alchemy.run/migrating-from-v1`),fixable:`code`},(e,t)=>({CallExpression(n){if(!ie(n.callee,t()))return;let r=g(n,1);if(r?.type===`ObjectExpression`)for(let[t,i]of[[`entrypoint`,`main`],[`bindings`,`env`]]){let a=v(r,t);a!==void 0&&e.report({node:a,messageId:`property`,data:{old:t,replacement:i},fix(o){if(j(e,n.callee)&&N(r,i))return o.replaceText(a.key,a.shorthand?`${i}: ${t}`:i)}})}}})),_e=s(c(`suggestion`,`Prefer schema-based tagged errors so errors have a serializable contract.`,{taggedError:`Prefer Schema.TaggedErrorClass over Data.TaggedError.`}),(e,t)=>({CallExpression(n){p(n.callee,t(),`Data`,`TaggedError`)&&e.report({node:n.callee,messageId:`taggedError`})}})),ve=/* @__PURE__ */ new Set([`error`,`err`,`e`,`cause`,`exception`,`ex`]);function P(e){return e?.type===`Identifier`&&ve.has(e.name)?e.name:void 0}function F(e){if(e.type!==`CallExpression`||e.arguments.length!==1)return!1;let t=u(e.callee);return t?.at(-1)===`String`&&t.length<=2}const ye=o({...c(`problem`,`Disallow string coercion that discards an error value’s stack, type, and cause chain.`,{errorString:`Do not stringify {{name}}. Preserve the original error as an Error cause instead.`,useCause:`Replace {{pattern}} with {{replacement}} to preserve the original error.`}),hasSuggestions:!0},e=>({NewExpression(t){let n=g(t,0);if(n===void 0||!F(n)||!D(t))return;let r=g(n,0);if(r===void 0)return;let i=e.sourceCode.getText(r),a=`'Error occurred', { cause: ${i} }`;e.report({node:n,messageId:`errorString`,data:{name:i},suggest:[{messageId:`useCause`,data:{pattern:e.sourceCode.getText(n),replacement:a},fix:e=>e.replaceText(n,a)}]})},CallExpression(t){if(F(t)){if(t.parent.type===`NewExpression`&&t.parent.arguments[0]===t&&D(t.parent))return;let n=P(t.arguments[0]);n!==void 0&&e.report({node:t,messageId:`errorString`,data:{name:n}});return}if(t.callee.type!==`MemberExpression`||u(t.callee)?.at(-1)!==`toString`||t.arguments.length>0)return;let n=P(t.callee.object);n!==void 0&&e.report({node:t,messageId:`errorString`,data:{name:n}})},TemplateLiteral(t){let[n,r]=t.quasis,i=P(t.expressions[0]);i!==void 0&&t.quasis.length===2&&n?.value.raw===``&&r?.value.raw===``&&e.report({node:t,messageId:`errorString`,data:{name:i}})}}));function I(e){for(let t of e.arguments)if(t.type===`ObjectExpression`)return t}function L(e,t){let n=e.parent;if(n.type!==`Property`||_(n)!==t)return;let r=n.parent,i=r.parent;return r.type===`ObjectExpression`&&i?.type===`CallExpression`?i:void 0}function R(e,t){let n=T(e);return n===void 0?void 0:f(n.callee,t)}function z(e){let t=y(e);if(t.type===`NewExpression`)return u(t.callee)?.join(`.`)===`Promise`;if(t.type!==`CallExpression`)return!1;let n=u(t.callee);return n?.join(`.`)===`fetch`||n?.[0]===`Promise`&&n[1]!==`withResolvers`||[`catch`,`finally`,`then`].includes(n?.at(-1)??``)||h(t.callee)&&t.callee.async}function B(e){if(e.body){if(e.body.type!==`BlockStatement`)return y(e.body);if(e.body.body.length===1&&e.body.body[0]?.type===`ReturnStatement`&&e.body.body[0].argument)return y(e.body.body[0].argument)}}function be(e){let t=y(e);return E(t,`*`)?!0:t.type===`ArrayExpression`&&(t.elements.length===0||t.elements.some(e=>!e||e.type===`SpreadElement`?!1:E(e,`*`)))}const xe=s(c(`problem`,`Disallow credentialed CORS with wildcard origins because browsers reject that combination.`,{wildcard:`Credentialed CORS cannot use a wildcard origin. Set allowedOrigins to explicit trusted origins or disable credentials.`},`https://github.com/Effect-TS/tsgo/issues/400`),(e,t)=>({CallExpression(n){let r=t();if(!p(n.callee,r,`HttpMiddleware`,`cors`)&&!p(n.callee,r,`HttpRouter`,`cors`)&&!p(n.callee,r,`HttpApiBuilder`,`middlewareCors`))return;let i=I(n);if(i===void 0||!E(v(i,`credentials`)?.value??i,!0))return;let a=v(i,`allowedOrigins`);(a===void 0||be(a.value))&&e.report({node:n,messageId:`wildcard`})}}));function Se(e){return e.type===`AssignmentPattern`||e.type===`RestElement`||e.optional===!0}const Ce=s(c(`problem`,`Disallow numeric dual arity with optional or rest parameters because dispatch becomes ambiguous.`,{unsafeArity:`Function.dual with numeric arity misdispatches an implementation with optional/default/rest parameters. Use predicate dispatch.`},`https://github.com/Effect-TS/tsgo/issues/401`),(e,t)=>({CallExpression(n){let r=g(n,0),i=g(n,1);i!==void 0&&p(n.callee,t(),`Function`,`dual`)&&r?.type===`Literal`&&typeof r.value==`number`&&h(i)&&i.params.some(e=>Se(e))&&e.report({node:r,messageId:`unsafeArity`})}})),we=s(c(`problem`,`Require Effect.tryPromise so Promise rejections enter the typed error channel.`,{tryPromise:`Use Effect.tryPromise instead of Effect.promise so rejections are typed failures.`}),(e,t)=>({CallExpression(n){p(n.callee,t(),`Effect`,`promise`)&&e.report({node:n.callee,messageId:`tryPromise`})}}));function Te(e,t){if(!p(e.callee,t,`Effect`,`promise`)&&!p(e.callee,t,`Effect`,`tryPromise`))return;let n=g(e,0);if(n!==void 0&&h(n))return n;if(n?.type===`ObjectExpression`){let e=v(n,`try`);if(e!==void 0&&h(e.value))return e.value}}const Ee=s(c(`problem`,`Ensure Effect Promise thunks start fresh asynchronous work rather than reusing an already-started Promise.`,{prestarted:`This thunk returns an already-started Promise. Start the asynchronous work inside the thunk so retries and repeats run it again.`},`https://github.com/Effect-TS/tsgo/issues/475`),(e,t)=>{let n=/* @__PURE__ */ new Set;return{before(){n=/* @__PURE__ */ new Set},VariableDeclarator(e){e.id.type===`Identifier`&&e.init&&z(e.init)&&n.add(e.id.name)},CallExpression(r){let i=Te(r,t()),a=i===void 0?void 0:B(i);a?.type===`Identifier`&&n.has(a.name)&&e.report({node:a,messageId:`prestarted`})}}}),De=s(c(`problem`,`Disallow async thunks in Effect.try because rejected Promises bypass its catch mapper.`,{asyncTry:`Effect.try does not await Promises. Use Effect.tryPromise so rejection enters the typed error channel.`},`https://github.com/Effect-TS/tsgo/issues/657`),(e,t)=>({CallExpression(n){if(!p(n.callee,t(),`Effect`,`try`))return;let r=g(n,0),i=r!==void 0&&h(r)?r:void 0;if(i===void 0&&r?.type===`ObjectExpression`){let e=v(r,`try`)?.value;e!==void 0&&h(e)&&(i=e)}let a=i===void 0?void 0:B(i);i!==void 0&&(i.async||a!==void 0&&z(a))&&e.report({node:i,messageId:`asyncTry`})}})),Oe=s(c(`problem`,`Disallow discarded Effect.runPromise results that can become unhandled rejections.`,{discarded:`The Promise returned by Effect.runPromise is discarded. Await/return/handle it, or use Effect.runFork for fire-and-forget work.`},`https://github.com/Effect-TS/tsgo/issues/643`),(e,t)=>({CallExpression(n){let r=t(),i=p(n.callee,r,`Effect`,`runPromise`),a=n.callee.type===`CallExpression`&&p(n.callee.callee,r,`Effect`,`runPromiseWith`);(i||a)&&ne(n)&&e.report({node:n,messageId:`discarded`})}}));function ke(e,t){let n=y(e);if(n.type===`CallExpression`&&n.callee.type===`MemberExpression`&&l(n.callee)===t)return n}const Ae=s(c(`problem`,`Disallow schema mapping that silently drops checks attached to the receiver.`,{discarded:`{{method}} creates a new schema and drops the preceding check. Re-attach the check after mapping or explicitly preserve it.`},`https://github.com/Effect-TS/tsgo/issues/435`),(e,t)=>({CallExpression(n){if(!t().hasEffectImport||n.callee.type!==`MemberExpression`)return;let r=l(n.callee);if(r===void 0||![`mapElements`,`mapFields`,`mapMembers`].includes(r)||ke(n.callee.object,`check`)===void 0)return;let i=n.arguments.find(e=>e.type===`ObjectExpression`),a=i?.type===`ObjectExpression`?v(i,`unsafePreserveChecks`):void 0;a!==void 0&&E(a.value,!0)||e.report({node:n,messageId:`discarded`,data:{method:r}})}})),je={Array:`Arr`,Boolean:`Bool`,Equal:`Eq`,Function:`Fn`,Number:`Num`,Option:`Opt`,Predicate:`P`,Record:`R`,String:`Str`};function V(e){return e===`@effect/vitest`||e.startsWith(`@effect/vitest/`)}function H(e,t){return e.importKind===`type`||t?.importKind===`type`}function U(e){return je[e]??e}function W(e,t){if(e===`effect`||e===`alchemy`||/^@effect\/[^/]+$/u.test(e)&&!V(e))return`${e}/${t}`}function G(e){if(V(e))return;let t=e.startsWith(`effect/`)||e.startsWith(`alchemy/`)||/^@effect\/[^/]+\//u.test(e)?e.split(`/`).at(-1):void 0;return t!==void 0&&/^\p{Lu}/u.test(t)?t:void 0}function Me(e,t,n){if(e.sourceCode.getCommentsInside(t).length>0||t.attributes.length>0)return;let r=[],i=[];for(let n of t.specifiers){if(n.type!==`ImportSpecifier`)return;let a=n.imported.type===`Identifier`?n.imported.name:n.imported.value,o=/^\p{Lu}/u.test(a)&&!H(t,n)?W(t.source.value,a):void 0;o===void 0?r.push(e.sourceCode.getText(n)):i.push(`import * as ${n.local.name} from '${o}';`)}return r.length>0&&i.unshift(`import { ${r.join(`, `)} } from ${e.sourceCode.getText(t.source)};`),[n.replaceText(t,i.join(`
|
|
2
|
-
`))]}function K(e,t,n){let r=G(t.source.value);if(r===void 0||t.attributes.length>0||e.sourceCode.getCommentsInside(t).length>0)return;let i=U(r),a=e.sourceCode.getDeclaredVariables(t),o=a.find(e=>e.name===i);if(e.sourceCode.scopeManager.scopes.some(e=>e.variables.some(e=>e.name===i&&e!==o)||e.references.some(e=>e.identifier.name===i&&e.resolved!==o)))return;let s=[],c=[];for(let r of t.specifiers){if(r.type===`ImportDefaultSpecifier`)return;if(r.type===`ImportSpecifier`&&H(t,r)){if(r.local.name===i)return;c.push(e.sourceCode.getText(r));continue}let o=Ne(r,a,i,n);if(o===void 0)return;s.push(...o)}let l=e.sourceCode.getText(t.source),u=`import * as ${i} from ${l};${c.length===0?``:`\nimport { ${c.join(`, `)} } from ${l};`}`;return[n.replaceText(t,u),...s]}function Ne(e,t,n,r){let i=t.find(t=>t.name===e.local.name);if(i!==void 0){if(e.type===`ImportNamespaceSpecifier`)return q(i,n,!1,r);if(e.imported.type===`Identifier`)return q(i,`${n}.${e.imported.name}`,!0,r)}}function q(e,t,n,r){let i=[],a=/* @__PURE__ */ new Set;for(let o of e.references){let e=o.identifier;if(a.has(e.range[0]))continue;a.add(e.range[0]);let s=e.parent;if(o.isWrite()||s.type===`ExportSpecifier`||s.type.startsWith(`JSX`))return;let c=s.type===`Property`&&s.shorthand?`${e.name}: ${t}`:t;n&&(s.type===`CallExpression`&&s.callee===e||s.type===`TaggedTemplateExpression`&&s.tag===e)&&(c=`(0, ${t})`),i.push(r.replaceText(e,c))}return i}function Pe(e){return e?.imported.type===`Identifier`?e.imported.name:typeof e?.imported.value==`string`?e.imported.value:void 0}const Fe=o({...c(`suggestion`,`Import Effect and Alchemy module namespaces from their submodule entrypoints instead of root barrels.`,{barrelImport:'Import this module as `import * as {{alias}} from "{{source}}"` instead of from the root barrel.'},`https://github.com/Effect-TS/language-service/blob/main/packages/language-service/src/diagnostics/importFromBarrel.ts`),fixable:`code`},e=>({ImportDeclaration(t){for(let n of t.specifiers){if(n.type!==`ImportSpecifier`||H(t,n))continue;let r=Pe(n),i=r===void 0||!/^\p{Lu}/u.test(r)?void 0:W(t.source.value,r);r!==void 0&&i!==void 0&&e.report({node:n,messageId:`barrelImport`,data:{alias:U(r),source:i},fix:n=>Me(e,t,n)})}}})),Ie=s({...c(`suggestion`,`Prefer Effect.never to an empty Effect.callback registration.`,{emptyCallback:`An empty Effect.callback registration is Effect.never. Use the explicit primitive.`},`https://github.com/Effect-TS/tsgo/issues/636`),fixable:`code`},(e,t)=>({CallExpression(n){if(!p(n.callee,t(),`Effect`,`callback`)&&!p(n.callee,t(),`Effect`,`async`))return;let r=g(n,0);r!==void 0&&h(r)&&r.body?.type===`BlockStatement`&&r.body.body.length===0&&e.report({node:n,messageId:`emptyCallback`,fix(t){if(!j(e,n.callee)||n.arguments.length!==1||r.async||r.generator||r.params.some(e=>e.type!==`Identifier`)||e.sourceCode.getCommentsInside(n).length>0)return;let i=M(e,n,`effect/Effect`,`Effect`,t);return[...i.fixes,t.replaceText(n,`${i.name}.never`)]}})}})),Le=s(c(`problem`,`Disallow Schema.Struct({}), which accepts every non-null object-like value.`,{emptyStruct:`Schema.Struct({}) does not validate an exact empty object. Define the intended fields explicitly.`},`https://github.com/Effect-TS/tsgo/issues/403`),(e,t)=>({CallExpression(n){let r=g(n,0);p(n.callee,t(),`Schema`,`Struct`)&&r?.type===`ObjectExpression`&&r.properties.length===0&&e.report({node:n,messageId:`emptyStruct`})}})),Re=s(c(`problem`,`Disallow obsolete lazy callbacks passed to the now-eager Config.withDefault API.`,{functionDefault:`Config.withDefault takes an eager value. This callback becomes the configured value; pass the returned value directly.`},`https://github.com/Effect-TS/tsgo/issues/408`),(e,t)=>({CallExpression(n){if(!p(n.callee,t(),`Config`,`withDefault`))return;let r=g(n,n.arguments.length-1);r!==void 0&&h(r)&&r.params.length===0&&e.report({node:r,messageId:`functionDefault`})}}));function J(e,t){return e.type===`CallExpression`&&p(e.callee,t,`Hash`,`hash`)}const ze=s(c(`problem`,`Disallow using Hash.hash output as collision-free identity.`,{hashIdentity:`Hash.hash is a bucketing hint, not a unique identity. Use HashMap/Equal.equals or a real identifier instead.`},`https://github.com/Effect-TS/tsgo/issues/482`),(e,t)=>{let n=/* @__PURE__ */ new Set;function r(e){return J(e,t())||e.type===`Identifier`&&n.has(e.name)}return{before(){n=/* @__PURE__ */ new Set},VariableDeclarator(e){e.id.type===`Identifier`&&e.init&&J(e.init,t())&&n.add(e.id.name)},CallExpression(t){if(t.callee.type!==`MemberExpression`||![`delete`,`get`,`has`,`set`].includes(u(t.callee)?.at(-1)??``))return;let n=g(t,0);n!==void 0&&r(n)&&e.report({node:n,messageId:`hashIdentity`})},BinaryExpression(t){[`===`,`!==`,`==`,`!=`].includes(t.operator)&&r(t.left)&&r(t.right)&&e.report({node:t,messageId:`hashIdentity`})},MemberExpression(t){t.computed&&r(t.property)&&e.report({node:t.property,messageId:`hashIdentity`})}}}),Be=/* @__PURE__ */ new Set([`catch`,`catchAll`,`catchAllCause`,`catchIf`,`catchSome`,`catchSomeCause`,`catchTag`,`orElse`,`orElseFail`,`orElseSucceed`]),Ve=/* @__PURE__ */ new Set([`log`,`logDebug`,`logError`,`logInfo`,`logTrace`,`logWarning`]);function He(e,t){let n=e.parent;for(;n;){if(h(n)){let e=T(n);if(e?.arguments.at(-1)===n){let n=f(e.callee,t),r=n?.[1];if(r!==void 0&&n?.[0]===`Effect`&&Be.has(r))return{method:r}}}n=n.parent}}const Ue=s(c(`suggestion`,`Keep logging separate from Effect recovery handlers.`,{logging:`Move {{logger}} out of Effect.{{catchMethod}} and use Effect.tapError before recovery.`}),(e,t)=>({CallExpression(n){let r=t(),i=f(n.callee,r),a=i?.[1]!==void 0&&i[0]===`Effect`&&Ve.has(i[1])?i.join(`.`):void 0;if(a===void 0)return;let o=He(n,r);o!==void 0&&e.report({node:n,messageId:`logging`,data:{logger:a,catchMethod:o.method}})}}));function We(e,t){let n=u(e.callee)?.at(-1);if(n===void 0||![`addEventListener`,`on`,`setInterval`].includes(n))return!1;if(n===`addEventListener`){let t=g(e,2);if(t?.type===`ObjectExpression`){let e=v(t,`once`);if(e!==void 0&&E(e.value,!0))return!1}}let r=g(e,n===`setInterval`?0:1);return r!==void 0&&x(r,t)}const Ge=s(c(`problem`,`Disallow attaching Effect.callback resume to repeating event sources.`,{multiShot:`Effect.callback is single-shot, but this source emits repeatedly. Use a once-style subscription or Stream.callback.`},`https://github.com/Effect-TS/tsgo/issues/484`),(e,t)=>({CallExpression(n){if(!p(n.callee,t(),`Effect`,`callback`))return;let r=g(n,0);if(r===void 0||!h(r))return;let i=S(r)?.name,a=r.body;i!==void 0&&a&&b(a,e=>e.type===`CallExpression`&&We(e,i))&&e.report({node:n,messageId:`multiShot`})}}));function Ke(e){return e.type===`Literal`&&typeof e.value==`bigint`||e.type===`Identifier`&&[`NaN`,`Infinity`,`undefined`].includes(e.name)||h(e)||e.type===`CallExpression`&&u(e.callee)?.at(-1)===`Symbol`}function qe(e,t){if(e.type===`ArrayExpression`){for(let n of e.elements)n&&n.type!==`SpreadElement`&&t.push(n);return}if(e.type===`ObjectExpression`)for(let n of e.properties)n.type===`Property`&&t.push(n.value)}function Je(e){let t=[e];for(;t.length>0;){let e=t.pop();if(e===void 0)continue;let n=y(e);if(Ke(n))return n;qe(n,t)}}const Ye=s(c(`problem`,`Disallow schema examples and defaults that cannot be represented in JSON Schema.`,{nonJson:`This schema annotation value is not JSON-serializable and will be omitted from or corrupt generated JSON Schema.`},`https://github.com/Effect-TS/tsgo/issues/440`),(e,t)=>({CallExpression(n){let r=t();if(!r.hasEffectImport)return;let i=f(n.callee,r),a=n.callee.type===`MemberExpression`?l(n.callee):i?.[0]===`Schema`?i[1]:void 0;if(a===void 0||![`annotate`,`annotateEncoded`,`annotateKey`].includes(a))return;let o=I(n);if(o!==void 0&&v(o,`jsonSchema`)===void 0)for(let t of[`default`,`examples`]){let n=v(o,t);if(n===void 0)continue;let r=Je(n.value);r!==void 0&&e.report({node:r,messageId:`nonJson`})}}})),Xe=s(c(`problem`,`Disallow wrapping infallible Effect.service access in Option or Either.`,{mandatory:`Effect.service never fails, so this wrapper is always present and keeps the service requirement. Use Effect.serviceOption.`},`https://github.com/Effect-TS/tsgo/issues/648`),(e,t)=>({CallExpression(n){let r=t(),i=p(n.callee,r,`Effect`,`option`)||p(n.callee,r,`Effect`,`either`),a=g(n,0);if(i&&a?.type===`CallExpression`&&p(a.callee,r,`Effect`,`service`)){e.report({node:n,messageId:`mandatory`});return}if(n.callee.type!==`MemberExpression`||u(n.callee)?.at(-1)!==`pipe`)return;let o=y(n.callee.object),s=g(n,0);s!==void 0&&o.type===`CallExpression`&&p(o.callee,r,`Effect`,`service`)&&(p(s,r,`Effect`,`option`)||p(s,r,`Effect`,`either`))&&e.report({node:n,messageId:`mandatory`})}})),Ze=s(c(`problem`,`Ensure a later object spread cannot overwrite an explicitly assigned _tag.`,{overwritten:`A later spread can overwrite _tag at runtime. Move _tag after all spreads.`},`https://github.com/Effect-TS/tsgo/issues/426`),e=>({ObjectExpression(t){let n=t.properties.findIndex(e=>e.type===`Property`&&_(e)===`_tag`);if(n===-1)return;let r=t.properties.slice(n+1).some(e=>e.type===`SpreadElement`),i=t.properties[n];r&&i?.type===`Property`&&e.report({node:i,messageId:`overwritten`})}})),Qe=s(c(`problem`,`Disallow turning missing Effect services into untyped Option defects.`,{getOrThrow:`Option.getOrThrow after Effect.serviceOption hides a mandatory service until runtime. Use Effect.service so it remains a typed requirement.`},`https://github.com/Effect-TS/tsgo/issues/650`),(e,t)=>({CallExpression(n){let r=t();if(p(n.callee,r,`Option`,`getOrThrow`)||p(n.callee,r,`Option`,`getOrThrowWith`)){let t=g(n,0),i=t?.type===`YieldExpression`?t.argument:t;i?.type===`CallExpression`&&p(i.callee,r,`Effect`,`serviceOption`)&&e.report({node:n,messageId:`getOrThrow`});return}if(n.callee.type!==`MemberExpression`||u(n.callee)?.at(-1)!==`pipe`)return;let i=y(n.callee.object),a=g(n,0);if(i.type!==`CallExpression`||!p(i.callee,r,`Effect`,`serviceOption`)||a?.type!==`CallExpression`||!p(a.callee,r,`Effect`,`map`))return;let o=g(a,0);o!==void 0&&(p(o,r,`Option`,`getOrThrow`)||p(o,r,`Option`,`getOrThrowWith`))&&e.report({node:n,messageId:`getOrThrow`})}})),$e=/* @__PURE__ */ new Set([`andThen`,`map`,`mapError`,`tap`,`tapError`,`tapErrorCause`]),et=s(c(`problem`,`Disallow throw in Effect callbacks that cannot add the thrown value to the typed error channel.`,{callbackThrow:`Throwing in this Effect callback creates an untyped defect. Return Effect.fail(...) or return the mapped error value instead.`},`https://github.com/Effect-TS/tsgo/issues/406`),(e,t)=>({ThrowStatement(n){let r=w(n);if(r===void 0)return;let i=t(),a=R(r,i),o=L(r,`catch`);(a?.[0]===`Effect`&&a[1]!==void 0&&$e.has(a[1])||o!==void 0&&(p(o.callee,i,`Effect`,`try`)||p(o.callee,i,`Effect`,`tryPromise`)))&&e.report({node:n,messageId:`callbackThrow`})}})),tt=s(c(`problem`,`Disallow no-op retry and repeat wrappers with times: 0.`,{zeroTimes:`times: 0 performs no retries or repeats. Remove the wrapper or use a positive count.`},`https://github.com/Effect-TS/tsgo/issues/412`),(e,t)=>({CallExpression(n){let r=t();if(!p(n.callee,r,`Effect`,`retry`)&&!p(n.callee,r,`Effect`,`repeat`))return;let i=I(n);if(i===void 0)return;let a=v(i,`times`);a!==void 0&&E(a.value,0)&&e.report({node:a,messageId:`zeroTimes`})}})),nt=o({...c(`suggestion`,`Use consistently aliased namespace imports for Effect and Alchemy submodule entrypoints.`,{alias:"Import {{source}} as the canonical namespace alias `{{alias}}`.",namespace:'Use `import * as {{alias}} from "{{source}}"` instead of importing values directly.'},`https://github.com/Effect-TS/language-service/blob/main/packages/language-service/src/core/AutoImport.ts`),fixable:`code`},e=>({ImportDeclaration(t){let n=G(t.source.value);if(n===void 0||t.importKind===`type`)return;let r=U(n);for(let n of t.specifiers)if(!(n.type===`ImportSpecifier`&&H(t,n))){if(n.type===`ImportNamespaceSpecifier`){n.local.name!==r&&e.report({node:n.local,messageId:`alias`,data:{alias:r,source:t.source.value},fix:n=>K(e,t,n)});continue}e.report({node:n,messageId:`namespace`,data:{alias:r,source:t.source.value},fix:n=>K(e,t,n)})}}})),rt=s(c(`suggestion`,`Prefer immutable, Order-based Effect Array sorting in Effect projects.`,{effectArraySort:`Use Arr.sort with an Order instead of the mutable native Array.sort method.`},`https://www.effect.website/docs/v4/api/effect/Array#sort`),(e,t)=>({CallExpression(n){let r=t();r.hasEffectImport&&n.callee.type===`MemberExpression`&&l(n.callee)===`sort`&&!p(n.callee,r,`Array`,`sort`)&&e.report({node:n,messageId:`effectArraySort`})}})),it=/* @__PURE__ */ new Set([`toISOString`,`toLocaleDateString`,`toLocaleTimeString`]),at=s(c(`suggestion`,`Prefer Effect DateTime formatting so time-zone behavior is explicit and composable.`,{effectDateTime:`Convert to DateTime and use DateTime.format, DateTime.formatIso, or another explicit formatter.`},`https://www.effect.website/docs/v4/api/effect/DateTime`),(e,t)=>({CallExpression(n){t().hasEffectImport&&n.callee.type===`MemberExpression`&&it.has(l(n.callee)??``)&&e.report({node:n,messageId:`effectDateTime`})}})),ot=/* @__PURE__ */ new Set([`Effect.delay`,`Effect.sleep`,`Effect.timeout`,`Effect.timeoutOption`,`Effect.timeoutOrElse`,`Schedule.fixed`,`Schedule.spaced`,`Schedule.windowed`]),st=s({...c(`suggestion`,`Prefer explicit Effect Duration constructors over ambiguous millisecond literals.`,{effectDuration:`Wrap this number with Duration.millis or use a more descriptive Duration constructor.`},`https://www.effect.website/docs/v4/api/effect/Duration`),fixable:`code`},(e,t)=>({CallExpression(n){let r=f(n.callee,t());if(r===void 0||!ot.has(r.join(`.`)))return;let i=g(n,n.arguments.length-1);i?.type===`Literal`&&typeof i.value==`number`&&e.report({node:i,messageId:`effectDuration`,fix(t){if(!j(e,n.callee))return;let r=M(e,n,`effect/Duration`,`Duration`,t);return[...r.fixes,t.replaceText(i,`${r.name}.millis(${e.sourceCode.getText(i)})`)]}})}})),ct=/* @__PURE__ */ new Set([`base64`,`base64url`,`hex`]);function Y(e){return e!==void 0&&[...ct].some(t=>E(e,t))}const lt=s(c(`suggestion`,`Prefer Effect Encoding for portable Base64, Base64Url, and hexadecimal encoding.`,{effectEncoding:`Use Encoding encode/decode helpers; decoders return Result instead of throwing.`},`https://www.effect.website/docs/v4/api/effect/Encoding`),(e,t)=>({CallExpression(n){if(!t().hasEffectImport)return;if((d(n.callee,e,`atob`)||d(n.callee,e,`btoa`))&&n.arguments.length>0){e.report({node:n,messageId:`effectEncoding`});return}let r=u(n.callee),i=r?.join(`.`)===`Buffer.from`&&Y(g(n,1)),a=r?.at(-1)===`toString`&&Y(g(n,0));(i||a)&&e.report({node:n,messageId:`effectEncoding`})}})),ut=/* @__PURE__ */ new Set([`fs`,`fs/promises`,`node:fs`,`node:fs/promises`]),dt=s(c(`suggestion`,`Prefer the Effect FileSystem service over direct Node.js filesystem imports in Effect projects.`,{effectFileSystem:`Use the FileSystem service from effect/FileSystem instead of {{source}}.`},`https://www.effect.website/docs/v4/api/effect/FileSystem`),(e,t)=>({ImportDeclaration(n){t().hasEffectImport&&ut.has(n.source.value)&&e.report({node:n.source,messageId:`effectFileSystem`,data:{source:n.source.value}})}}));function X(e,t,n){return e.type===`CallExpression`&&p(e.callee,t,`Result`,n)?g(e,0):void 0}function Z(e,t,n){let r=S(t),i=B(t);if(r===void 0||i?.type!==`ConditionalExpression`)return;let a=X(i.consequent,n,`succeed`),o=X(i.alternate,n,`fail`);a?.type===`Identifier`&&a.name===r.name&&o?.type===`Identifier`&&o.name===r.name&&e.report({node:t,messageId:`effectFilter`})}const ft=s(c(`suggestion`,`Prefer Effect Filter constructors for reusable Result-valued predicates.`,{effectFilter:`Use Filter.fromPredicate for this Result-valued predicate so it composes as a Filter.`},`https://www.effect.website/docs/v4/api/effect/Filter`),(e,t)=>({ArrowFunctionExpression(n){Z(e,n,t())},FunctionExpression(n){Z(e,n,t())}})),pt=s(c(`suggestion`,`Prefer immutable Effect Headers values in Effect projects.`,{effectHeaders:`Use Headers.fromInput to construct normalized, immutable Effect headers.`},`https://www.effect.website/docs/v4/api/effect/unstable/http/Headers`),(e,t)=>({NewExpression(n){t().hasEffectImport&&d(n.callee,e,`Headers`)&&e.report({node:n,messageId:`effectHeaders`})}})),mt=s(c(`suggestion`,`Prefer Effect Match for composable and exhaustive branching in Effect projects.`,{effectMatch:`Use Match.type, Match.value, or Match.tags with Match.exhaustive instead of switch.`},`https://www.effect.website/docs/v4/api/effect/Match`),(e,t)=>({SwitchStatement(n){t().hasEffectImport&&e.report({node:n,messageId:`effectMatch`})}})),ht=/* @__PURE__ */ new Set([`node:path`,`path`]),gt=s(c(`suggestion`,`Prefer the Effect Path service over direct Node.js path imports in Effect projects.`,{effectPath:`Use the Path service from effect/Path instead of {{source}}.`},`https://www.effect.website/docs/v4/api/effect/Path`),(e,t)=>({ImportDeclaration(n){t().hasEffectImport&&ht.has(n.source.value)&&e.report({node:n.source,messageId:`effectPath`,data:{source:n.source.value}})}})),_t=s(c(`suggestion`,`Prefer Effect Url helpers for safe URL parsing in Effect projects.`,{effectUrl:`Use Url.fromString or Url.make so invalid URLs are represented as Result failures.`},`https://www.effect.website/docs/v4/api/effect/unstable/http/Url`),(e,t)=>({NewExpression(n){t().hasEffectImport&&d(n.callee,e,`URL`)&&e.report({node:n,messageId:`effectUrl`})},CallExpression(n){let r=u(n.callee);t().hasEffectImport&&r?.[0]===`URL`&&[`canParse`,`parse`].includes(r[1]??``)&&n.callee.type===`MemberExpression`&&d(n.callee.object,e,`URL`)&&e.report({node:n,messageId:`effectUrl`})}})),vt=s(c(`suggestion`,`Prefer the non-mask interruptibility API when the restore callback is unused.`,{unusedRestore:`The mask callback never uses restore, so the mask is equivalent to {{replacement}} and misleadingly suggests a restored region.`},`https://github.com/Effect-TS/tsgo/issues/659`),(e,t)=>({CallExpression(n){let r=t(),i=p(n.callee,r,`Effect`,`uninterruptibleMask`)?`uninterruptible`:p(n.callee,r,`Effect`,`interruptibleMask`)?`interruptible`:void 0,a=g(n,0);i!==void 0&&a!==void 0&&h(a)&&!C(a)&&e.report({node:n,messageId:`unusedRestore`,data:{replacement:`Effect.${i}`}})}})),yt=s(c(`suggestion`,`Prefer Effect.withSpan when the callback does not use the span handle.`,{unusedSpan:`The useSpan callback ignores its span. Use Effect.withSpan so nested spans are parented beneath this span.`},`https://github.com/Effect-TS/tsgo/issues/663`),(e,t)=>({CallExpression(n){if(!p(n.callee,t(),`Effect`,`useSpan`))return;let r=g(n,n.arguments.length-1);r!==void 0&&h(r)&&!C(r)&&e.report({node:n,messageId:`unusedSpan`})}}));function bt(e,t){let n=y(e);if(E(n,0))return!0;if(n.type===`Literal`&&typeof n.value==`string`)return/^0\s*(?:nanos?|micros?|millis?|seconds?|minutes?|hours?|days?|weeks?)$/i.test(n.value);if(p(n,t,`Duration`,`zero`))return!0;if(n.type===`CallExpression`){let e=f(n.callee,t),r=g(n,0);return r!==void 0&&e?.[0]===`Duration`&&E(r,0)}return!1}const xt=s(c(`suggestion`,`Prefer scheduler yielding to a zero-duration Clock sleep.`,{zeroSleep:`Effect.sleep(0) uses Clock and interacts with TestClock. Use Effect.yieldNow for a cooperative scheduler yield.`},`https://github.com/Effect-TS/tsgo/issues/661`),(e,t)=>({CallExpression(n){let r=t(),i=g(n,0);i!==void 0&&p(n.callee,r,`Effect`,`sleep`)&&bt(i,r)&&e.report({node:n,messageId:`zeroSleep`})}})),St=/* @__PURE__ */ new Set([`catch`,`catchAll`,`mapError`]);function Q(e,t){let n=R(e,t),r=L(e,`catch`);if(!(n?.[0]===`Effect`&&n[1]!==void 0&&St.has(n[1])||r!==void 0&&(p(r.callee,t,`Effect`,`try`)||p(r.callee,t,`Effect`,`tryPromise`)))||!e.body)return!1;let i=S(e);return b(e.body,e=>e.type===`NewExpression`&&D(e)&&(i===void 0||!x(e,i.name)))}const Ct=s(c(`suggestion`,`Preserve the underlying cause when wrapping an Effect failure.`,{droppedCause:`This handler constructs a new error but drops the caught failure. Accept it as a parameter and attach it as cause.`},`https://github.com/Effect-TS/tsgo/issues/490`),(e,t)=>({ArrowFunctionExpression(n){Q(n,t())&&e.report({node:n,messageId:`droppedCause`})},FunctionExpression(n){Q(n,t())&&e.report({node:n,messageId:`droppedCause`})}})),wt=s(c(`problem`,`Require Schema.Class declarations to carry a nominal brand.`,{missingBrand:`Schema.Class without a second type parameter is structural. Add a unique brand so plain objects cannot masquerade as instances.`},`https://github.com/Effect-TS/tsgo/issues/468`),(e,t)=>({CallExpression(n){p(n.callee,t(),`Schema`,`Class`)&&(n.typeArguments?.params.length??0)<2&&e.report({node:n,messageId:`missingBrand`})}}));function Tt(e,t){if(!p(e.callee,t,`Effect`,`tryPromise`))return;let n=g(e,0);if(n!==void 0&&h(n))return n;if(n?.type===`ObjectExpression`){let e=v(n,`try`);if(e!==void 0&&h(e.value))return e.value}}const Et=s(c(`suggestion`,`Require Effect.tryPromise thunks to accept and use their AbortSignal for interruption.`,{missingSignal:"Accept the AbortSignal parameter and pass it to the Promise API. Name it `_signal` only when cancellation is unsupported.",unusedSignal:"Pass this AbortSignal to the Promise API, or rename it to `_signal` to explicitly acknowledge that cancellation is unsupported."},`https://www.effect.website/docs/v4/api/effect/Effect#tryPromise`),(e,t)=>({CallExpression(n){let r=Tt(n,t());if(r===void 0)return;let i=S(r);i===void 0?e.report({node:r,messageId:`missingSignal`}):!i.name.startsWith(`_`)&&!C(r)&&e.report({node:i,messageId:`unusedSignal`})}}));function Dt(e,t){let n=e.parent;if(n.type===`CallExpression`&&g(n,0)===e)return p(n.callee,t,`Effect`,`try`)||p(n.callee,t,`Effect`,`tryPromise`);if(n.type!==`Property`||n.key.type!==`Identifier`||n.key.name!==`try`)return!1;let r=n.parent;return r.type===`ObjectExpression`&&r.parent.type===`CallExpression`&&(p(r.parent.callee,t,`Effect`,`try`)||p(r.parent.callee,t,`Effect`,`tryPromise`))}const $={"alchemy-no-cloudflare-init-finalizer":oe,"alchemy-no-deprecated-docker-constraints":se,"alchemy-no-deprecated-resource":le,"alchemy-no-plaintext-github-secret":de,"alchemy-no-removed-config-api":fe,"alchemy-no-reserved-eventbridge-default-name":pe,"alchemy-no-runtime-config":me,"alchemy-no-v1-import":he,"alchemy-no-v1-worker-properties":ge,"avoid-data-tagged-error":_e,"ban-error-string":ye,"cors-credentials-with-wildcard":xe,"dual-numeric-arity-with-optional-parameter":Ce,"effect-promise-vs-trypromise":we,"no-already-started-promise":Ee,"no-async-effect-try":De,"no-discarded-run-promise":Oe,"no-discarded-schema-checks":Ae,"no-empty-effect-callback":Ie,"no-empty-schema-struct":Le,"no-effect-alchemy-barrel-imports":Fe,"no-function-config-default":Re,"no-hash-as-identity":ze,"no-logging-in-catch":Ue,"no-multi-shot-effect-callback":Ge,"no-non-json-schema-annotation":Ye,"no-option-of-service":Xe,"no-overwritten-discriminant":Ze,"no-service-option-get-or-throw":Qe,"no-throw-in-effect-callback":et,"no-zero-retry-times":tt,"prefer-effect-alchemy-namespace-imports":nt,"prefer-effect-array-sort":rt,"prefer-effect-datetime":at,"prefer-effect-duration":st,"prefer-effect-encoding":lt,"prefer-effect-filesystem":dt,"prefer-effect-filter":ft,"prefer-effect-headers":pt,"prefer-effect-match":mt,"prefer-effect-path":gt,"prefer-effect-url":_t,"prefer-uninterruptible":vt,"prefer-with-span":yt,"prefer-yield-now":xt,"preserve-caught-error":Ct,"require-schema-class-brand":wt,"require-try-promise-abort-signal":Et,"throw-in-effect-gen":s(c(`problem`,`Disallow throw in Effect generator APIs because it creates an untyped defect.`,{throwInGen:`Use yield* Effect.fail(...) instead of throw so the failure stays in the typed error channel.`}),(e,t)=>({ThrowStatement(n){let r=t(),i=n.parent;for(;i&&!h(i);)i=i.parent??void 0;if(i===void 0||Dt(i,r))return;let a=T(i),o=a!==void 0&&[`fn`,`fnUntraced`,`gen`].some(e=>p(a.callee,r,`Effect`,e)),s=a?.callee,c=s?.type===`CallExpression`&&[`fn`,`fnUntraced`].some(e=>p(s.callee,r,`Effect`,e));(o||c)&&e.report({node:n,messageId:`throwInGen`})}}))},Ot=/* @__PURE__ */ new Set([`prefer-effect-filesystem`,`prefer-effect-path`]),kt=Object.fromEntries(Object.keys($).filter(e=>!Ot.has(e)).map(e=>[`2digits/${e}`,`error`])),At=t({meta:{name:`@2digits/oxlint-plugin`},rules:$});export{At as default,kt as recommendedRules,$ as rules};
|
|
1
|
+
import{defineRule as e,eslintCompatPlugin as t}from"@oxlint/plugins";import{Rule as n,RuleContext as r,Visitor as i}from"effect-oxlint";import*as a from"effect/Array";import*as o from"effect/Effect";import*as s from"effect/Function";import*as c from"effect/Match";import*as l from"effect/Option";import*as u from"effect/Ref";const d={bindings:/* @__PURE__ */ new Map,hasEffectImport:!1};function f(e){return e.imported.type===`Identifier`?e.imported.name:typeof e.imported.value==`string`?e.imported.value:void 0}function p(e){if(e===`alchemy`)return[`Alchemy`];if(e===`effect`||e===`@effect/platform`)return[];if(e.startsWith(`effect/`)||e.startsWith(`@effect/platform/`)||e.startsWith(`alchemy/`)){let t=e.split(`/`).at(-1);return t===void 0?void 0:/^\p{Ll}/u.test(t)?[]:[t]}}function m(e){let t=/* @__PURE__ */ new Map,n=!1;for(let r of e.body){if(r.type!==`ImportDeclaration`)continue;let e=r.source.value;(e===`effect`||e.startsWith(`effect/`)||e.startsWith(`@effect/`))&&(n=!0);let i=p(e);if(i!==void 0)for(let e of r.specifiers){if(e.type===`ImportNamespaceSpecifier`||e.type===`ImportDefaultSpecifier`){t.set(e.local.name,i);continue}let n=f(e);n!==void 0&&t.set(e.local.name,[...i,n])}}return{bindings:t,hasEffectImport:n}}function h(t,n){return e({meta:t,createOnce:n})}function g(t,n){return e({meta:t,createOnce(e){let t=d,{before:r,Program:i,...a}=n(e,()=>t);return{before(){t=d,r?.()},Program(e){t=m(e),i?.(e)},...a}}})}function _(e,t,n,r){return{type:e,docs:{description:t,recommended:!0,...r===void 0?{}:{url:r}},schema:[],messages:n}}function v(e){if(!e.computed&&e.property.type===`Identifier`)return e.property.name;if(e.computed&&e.property.type===`Literal`&&typeof e.property.value==`string`)return e.property.value}function y(e){let t=[],n=e;for(;n.type===`ChainExpression`||n.type===`MemberExpression`;){if(n.type===`ChainExpression`){n=n.expression;continue}let e=v(n);if(e===void 0)return;t.unshift(e),n=n.object}return n.type===`Identifier`?[n.name,...t]:void 0}function b(e,t,n){if(e.type!==`Identifier`||e.name!==n)return!1;let r=t.sourceCode.getScope(e);for(;r!==null;){if(r.set.has(n))return!1;r=r.upper}return!0}function x(e,t){let n=y(e),r=n?.[0];if(n===void 0||r===void 0)return;let i=t.bindings.get(r);return i===void 0?void 0:[...i,...n.slice(1)]}function S(e,t,n,r){let i=x(e,t);return i?.length===2&&i[0]===n&&i[1]===r}function C(e,t,n){let r=x(e,t);return r?.length===n.length&&r.every((e,t)=>e===n[t])}function w(e){return e?.type===`ArrowFunctionExpression`||e?.type===`FunctionExpression`}function T(e,t){let n=e.arguments[t];return n===void 0||n.type===`SpreadElement`?void 0:n}function E(e){if(!e.computed&&e.key.type===`Identifier`)return e.key.name;if(e.key.type===`Literal`&&typeof e.key.value==`string`)return e.key.value}function D(e,t){for(let n of e.properties)if(n.type===`Property`&&E(n)===t)return n}function ee(e){return[`ParenthesizedExpression`,`TSAsExpression`,`TSNonNullExpression`,`TSSatisfiesExpression`,`TSTypeAssertion`].includes(e.type)}function O(e){let t=e;for(;ee(t);)t=t.expression;return t}function te(e,t){if(Array.isArray(e)){for(let n of e)t.push(n);return}for(let[n,r]of Object.entries(e))[`loc`,`parent`,`range`].includes(n)||t.push(r)}function k(e,t){let n=[e],r=/* @__PURE__ */ new WeakSet;for(;n.length>0;){let e=n.pop();if(e&&typeof e==`object`&&!r.has(e)){if(r.add(e),typeof e.type==`string`&&t(e)===!0)return!0;te(e,n)}}return!1}function A(e,t){return k(e,e=>e.type===`Identifier`&&e.name===t)}function j(e){let t=e.params[0];return t?.type===`Identifier`?t:void 0}function M(e){let t=j(e);return t===void 0||!e.body||t.name.startsWith(`_`)?!1:A(e.body,t.name)}function ne(e){let t=e.parent;for(;t;){if(w(t))return t;t=t.parent}}function N(e){let t=e.parent;if(t.type===`CallExpression`&&t.arguments.includes(e))return t}function P(e,t){return e.type===`Literal`&&e.value===t}function re(e){let t=e.parent;return t?t.type===`ExpressionStatement`||t.type===`UnaryExpression`&&t.operator===`void`||t.type===`SequenceExpression`&&t.expressions.at(-1)!==e:!1}function F(e){return y(e.callee)?.at(-1)?.endsWith(`Error`)===!0}const ie=/* @__PURE__ */ new Set([`alarm`,`fetch`,`queue`,`rpc`,`scheduled`,`tail`,`trace`,`webSocketClose`,`webSocketError`,`webSocketMessage`]);function ae(e,t){return C(e,t,[`Cloudflare`,`Worker`])||C(e,t,[`Cloudflare`,`Workers`,`Worker`])}function oe(e,t){let n=e.parent;for(;n;){if(n.type===`CallExpression`&&ae(n.callee,t))return n;n=n.parent}}function se(e,t){let n=ne(e),r=n===void 0?void 0:N(n);return r!==void 0&&S(r.callee,t,`Effect`,`gen`)?r:void 0}function ce(e){let t=e.parent;for(;t;){if(w(t))return;if(t.type===`Property`){let e=E(t);if(e!==void 0&&ie.has(e))return e}t=t.parent}}const le=g(_(`problem`,`Disallow finalizers in Cloudflare Worker initialization, where workerd never runs them.`,{finalizer:`A Cloudflare Worker init finalizer never runs because workerd has no isolate teardown hook. Acquire disposable resources inside an event handler.`},`https://alchemy.run/cloudflare/compute/workers`),(e,t)=>({CallExpression(n){let r=t();if(!S(n.callee,r,`Effect`,`addFinalizer`))return;let i=se(n,r);i!==void 0&&oe(i,r)?.arguments.includes(i)&&e.report({node:n,messageId:`finalizer`})}}));function ue(e,t,n){let r=e.sourceCode.getScope(t);for(;r!==null;){let e=r.set.get(n);if(e!==void 0)return e;r=r.upper}}function I(e,t){let n=y(t)?.[0];return(n===void 0?void 0:ue(e,t,n))?.defs.some(e=>{let t=e.node;return e.type===`ImportBinding`&&t.parent?.type===`ImportDeclaration`&&t.parent.importKind!==`type`&&(t.type!==`ImportSpecifier`||t.importKind!==`type`)})===!0}function de(e,t,n,r,i){let a=e.sourceCode.ast;for(let r of a.body)if(r.type===`ImportDeclaration`&&r.source.value===n&&r.importKind!==`type`){for(let n of r.specifiers)if(n.type===`ImportNamespaceSpecifier`&&ue(e,t,n.local.name)?.defs.some(e=>e.node===n))return{name:n.local.name,fixes:[]}}let o=new Set(e.sourceCode.scopeManager.scopes.flatMap(e=>[...e.variables.map(e=>e.name),...e.references.map(e=>e.identifier.name)])),s=r,c=2;for(;o.has(s);)s=`${r}${c++}`;let l=`import * as ${s} from '${n}';\n`,u=a.body.find(e=>e.type!==`ExpressionStatement`||e.expression.type!==`Literal`||typeof e.expression.value!=`string`);return{name:s,fixes:[u===void 0?i.insertTextAfter(a,`\n${l}`):i.insertTextBefore(u,l)]}}function fe(e,t){let n=/* @__PURE__ */ new Set;return e.properties.every(e=>{if(e.type!==`Property`||e.computed||e.method||e.kind!==`init`||e.key.type!==`Identifier`&&e.key.type!==`Literal`)return!1;let r=e.key.type===`Identifier`?e.key.name:String(e.key.value);return r===t||n.has(r)?!1:(n.add(r),!0)})}const pe=g({..._(`problem`,`Disallow the deprecated top-level Docker Service constraints property.`,{constraints:`Docker.Service constraints is deprecated. Move it to placement: { constraints: ... }.`},`https://alchemy.run/providers/docker/service`),fixable:`code`},(e,t)=>({CallExpression(n){if(!S(n.callee,t(),`Docker`,`Service`))return;let r=T(n,1),i=r?.type===`ObjectExpression`?D(r,`constraints`):void 0;i!==void 0&&e.report({node:i,messageId:`constraints`,fix(t){if(I(e,n.callee)&&r?.type===`ObjectExpression`&&fe(r,`placement`))return t.replaceText(i,`placement: { ${e.sourceCode.getText(i)} }`)}})}})),me=/* @__PURE__ */ new Map([[`Cloudflare.Access.Bookmark`,`Cloudflare.Access.Application with type: "bookmark"`],[`AWS.RDSData.ExecuteSql`,`AWS.RDSData.ExecuteStatement`],[`AWS.EKS.Deployment`,`Kubernetes.Deployment from alchemy/Kubernetes`],[`AWS.EKS.HelmChart`,`Kubernetes.HelmChart from alchemy/Kubernetes`],[`AWS.EKS.Job`,`Kubernetes.Job from alchemy/Kubernetes`],[`AWS.EKS.Manifest`,`Kubernetes.Manifest from alchemy/Kubernetes`]]),he=g(_(`problem`,`Disallow deprecated Alchemy resource APIs that have supported replacements.`,{deprecated:`{{api}} is deprecated. Use {{replacement}}.`},`https://alchemy.run/llms-full.txt`),(e,t)=>({CallExpression(n){let r=x(n.callee,t());if(r===void 0)return;let i=r.join(`.`),a=me.get(i);a!==void 0&&e.report({node:n.callee,messageId:`deprecated`,data:{api:i,replacement:a}})}}));function ge(e,t){let n=O(e);if(n.type===`Literal`&&typeof n.value==`string`||n.type===`TemplateLiteral`)return!0;let r=y(n);return r?.[0]===`process`&&r[1]===`env`||n.type===`CallExpression`&&S(n.callee,t,`Config`,`string`)}const _e=g(_(`problem`,`Require singular GitHub Secret values to use Redacted.`,{plaintext:`GitHub.Secret value must be Redacted so it stays out of logs and state. Use Redacted.make(...) or Config.redacted(...).`},`https://alchemy.run/providers/github/secret`),(e,t)=>({CallExpression(n){let r=t();if(!S(n.callee,r,`GitHub`,`Secret`))return;let i=T(n,1),a=i?.type===`ObjectExpression`?D(i,`value`):void 0;a!==void 0&&ge(a.value,r)&&e.report({node:a.value,messageId:`plaintext`})}})),ve=g(_(`problem`,`Disallow removed Alchemy Secret and Variable APIs.`,{removed:`Alchemy.{{api}} was removed. Use effect/Config (Config.redacted for secrets, Config.string for variables).`},`https://alchemy.run/blog/2026-05-29-beta-45`),(e,t)=>({CallExpression(n){let r=x(n.callee,t());r?.[0]===`Alchemy`&&(r[1]===`Secret`||r[1]===`Variable`)&&e.report({node:n.callee,messageId:`removed`,data:{api:r[1]}})}})),ye=g(_(`problem`,`Disallow creating an EventBridge bus with the reserved default name.`,{reserved:`EventBridge reserves the name "default". Omit the bus argument to use the account default, or choose another name.`},`https://alchemy.run/aws/messaging/eventbridge`),(e,t)=>({CallExpression(n){if(!C(n.callee,t(),[`AWS`,`EventBridge`,`EventBus`]))return;let r=T(n,1),i=r?.type===`ObjectExpression`?D(r,`name`):void 0;i!==void 0&&P(i.value,`default`)&&e.report({node:i.value,messageId:`reserved`})}})),be=g(_(`problem`,`Require Effect Config values to be resolved during Alchemy Worker initialization.`,{runtime:`Config resolved inside the {{handler}} handler is invisible to Alchemy deployment. Resolve it in Worker init and close over the value, or put it in env.`},`https://alchemy.run/environments/secrets`),(e,t)=>({YieldExpression(n){let r=t(),i=n.argument;if(i?.type!==`CallExpression`||x(i.callee,r)?.[0]!==`Config`)return;let a=se(n,r),o=a===void 0?void 0:ce(a);a!==void 0&&o!==void 0&&oe(a,r)!==void 0&&e.report({node:i,messageId:`runtime`,data:{handler:o}})}})),xe=h(_(`problem`,`Disallow Alchemy v1 imports that bypass the Effect-based Stack API.`,{defaultImport:`The default alchemy() API is from v1. Use import * as Alchemy and Alchemy.Stack.`,providerImport:`Use the v2 provider entrypoint {{replacement}} (capitalization is significant).`},`https://alchemy.run/migrating-from-v1`),e=>({ImportDeclaration(t){let n=t.source.value;if(n===`alchemy`){let n=t.specifiers.find(e=>e.type===`ImportDefaultSpecifier`);n!==void 0&&e.report({node:n,messageId:`defaultImport`});return}let r=/^alchemy\/(aws|cloudflare)$/.exec(n)?.[1];if(r===void 0)return;let i=`alchemy/${r===`aws`?`AWS`:`Cloudflare`}`;e.report({node:t.source,messageId:`providerImport`,data:{replacement:i}})}})),Se=g({..._(`problem`,`Disallow Alchemy v1 Cloudflare Worker property names.`,{property:`Cloudflare.Worker {{old}} was replaced in v2. Use {{replacement}}.`},`https://alchemy.run/migrating-from-v1`),fixable:`code`},(e,t)=>({CallExpression(n){if(!ae(n.callee,t()))return;let r=T(n,1);if(r?.type===`ObjectExpression`)for(let[t,i]of[[`entrypoint`,`main`],[`bindings`,`env`]]){let a=D(r,t);a!==void 0&&e.report({node:a,messageId:`property`,data:{old:t,replacement:i},fix(o){if(I(e,n.callee)&&fe(r,i))return o.replaceText(a.key,a.shorthand?`${i}: ${t}`:i)}})}}})),Ce=g(_(`suggestion`,`Prefer schema-based tagged errors so errors have a serializable contract.`,{taggedError:`Prefer Schema.TaggedErrorClass over Data.TaggedError.`}),(e,t)=>({CallExpression(n){S(n.callee,t(),`Data`,`TaggedError`)&&e.report({node:n.callee,messageId:`taggedError`})}})),we=/* @__PURE__ */ new Set([`error`,`err`,`e`,`cause`,`exception`,`ex`]);function L(e){return e?.type===`Identifier`&&we.has(e.name)?e.name:void 0}function Te(e){if(e.type!==`CallExpression`||e.arguments.length!==1)return!1;let t=y(e.callee);return t?.at(-1)===`String`&&t.length<=2}const Ee=h({..._(`problem`,`Disallow string coercion that discards an error value’s stack, type, and cause chain.`,{errorString:`Do not stringify {{name}}. Preserve the original error as an Error cause instead.`,useCause:`Replace {{pattern}} with {{replacement}} to preserve the original error.`}),hasSuggestions:!0},e=>({NewExpression(t){let n=T(t,0);if(n===void 0||!Te(n)||!F(t))return;let r=T(n,0);if(r===void 0)return;let i=e.sourceCode.getText(r),a=`'Error occurred', { cause: ${i} }`;e.report({node:n,messageId:`errorString`,data:{name:i},suggest:[{messageId:`useCause`,data:{pattern:e.sourceCode.getText(n),replacement:a},fix:e=>e.replaceText(n,a)}]})},CallExpression(t){if(Te(t)){if(t.parent.type===`NewExpression`&&t.parent.arguments[0]===t&&F(t.parent))return;let n=L(t.arguments[0]);n!==void 0&&e.report({node:t,messageId:`errorString`,data:{name:n}});return}if(t.callee.type!==`MemberExpression`||y(t.callee)?.at(-1)!==`toString`||t.arguments.length>0)return;let n=L(t.callee.object);n!==void 0&&e.report({node:t,messageId:`errorString`,data:{name:n}})},TemplateLiteral(t){let[n,r]=t.quasis,i=L(t.expressions[0]);i!==void 0&&t.quasis.length===2&&n?.value.raw===``&&r?.value.raw===``&&e.report({node:t,messageId:`errorString`,data:{name:i}})}}));function R(e){for(let t of e.arguments)if(t.type===`ObjectExpression`)return t}function De(e,t){let n=e.parent;if(n.type!==`Property`||E(n)!==t)return;let r=n.parent,i=r.parent;return r.type===`ObjectExpression`&&i?.type===`CallExpression`?i:void 0}function Oe(e,t){let n=N(e);return n===void 0?void 0:x(n.callee,t)}function ke(e){let t=O(e);if(t.type===`NewExpression`)return y(t.callee)?.join(`.`)===`Promise`;if(t.type!==`CallExpression`)return!1;let n=y(t.callee);return n?.join(`.`)===`fetch`||n?.[0]===`Promise`&&n[1]!==`withResolvers`||[`catch`,`finally`,`then`].includes(n?.at(-1)??``)||w(t.callee)&&t.callee.async}function z(e){if(e.body){if(e.body.type!==`BlockStatement`)return O(e.body);if(e.body.body.length===1&&e.body.body[0]?.type===`ReturnStatement`&&e.body.body[0].argument)return O(e.body.body[0].argument)}}function Ae(e){let t=O(e);return P(t,`*`)?!0:t.type===`ArrayExpression`&&(t.elements.length===0||t.elements.some(e=>!e||e.type===`SpreadElement`?!1:P(e,`*`)))}const je=g(_(`problem`,`Disallow credentialed CORS with wildcard origins because browsers reject that combination.`,{wildcard:`Credentialed CORS cannot use a wildcard origin. Set allowedOrigins to explicit trusted origins or disable credentials.`},`https://github.com/Effect-TS/tsgo/issues/400`),(e,t)=>({CallExpression(n){let r=t();if(!S(n.callee,r,`HttpMiddleware`,`cors`)&&!S(n.callee,r,`HttpRouter`,`cors`)&&!S(n.callee,r,`HttpApiBuilder`,`middlewareCors`))return;let i=R(n);if(i===void 0||!P(D(i,`credentials`)?.value??i,!0))return;let a=D(i,`allowedOrigins`);(a===void 0||Ae(a.value))&&e.report({node:n,messageId:`wildcard`})}}));function Me(e){return e.type===`AssignmentPattern`||e.type===`RestElement`||e.optional===!0}const Ne=g(_(`problem`,`Disallow numeric dual arity with optional or rest parameters because dispatch becomes ambiguous.`,{unsafeArity:`Function.dual with numeric arity misdispatches an implementation with optional/default/rest parameters. Use predicate dispatch.`},`https://github.com/Effect-TS/tsgo/issues/401`),(e,t)=>({CallExpression(n){let r=T(n,0),i=T(n,1);i!==void 0&&S(n.callee,t(),`Function`,`dual`)&&r?.type===`Literal`&&typeof r.value==`number`&&w(i)&&i.params.some(e=>Me(e))&&e.report({node:r,messageId:`unsafeArity`})}})),Pe=g(_(`problem`,`Require Effect.tryPromise so Promise rejections enter the typed error channel.`,{tryPromise:`Use Effect.tryPromise instead of Effect.promise so rejections are typed failures.`}),(e,t)=>({CallExpression(n){S(n.callee,t(),`Effect`,`promise`)&&e.report({node:n.callee,messageId:`tryPromise`})}}));function Fe(e,t){if(!S(e.callee,t,`Effect`,`promise`)&&!S(e.callee,t,`Effect`,`tryPromise`))return;let n=T(e,0);if(n!==void 0&&w(n))return n;if(n?.type===`ObjectExpression`){let e=D(n,`try`);if(e!==void 0&&w(e.value))return e.value}}const Ie=g(_(`problem`,`Ensure Effect Promise thunks start fresh asynchronous work rather than reusing an already-started Promise.`,{prestarted:`This thunk returns an already-started Promise. Start the asynchronous work inside the thunk so retries and repeats run it again.`},`https://github.com/Effect-TS/tsgo/issues/475`),(e,t)=>{let n=/* @__PURE__ */ new Set;return{before(){n=/* @__PURE__ */ new Set},VariableDeclarator(e){e.id.type===`Identifier`&&e.init&&ke(e.init)&&n.add(e.id.name)},CallExpression(r){let i=Fe(r,t()),a=i===void 0?void 0:z(i);a?.type===`Identifier`&&n.has(a.name)&&e.report({node:a,messageId:`prestarted`})}}}),Le=g(_(`problem`,`Disallow async thunks in Effect.try because rejected Promises bypass its catch mapper.`,{asyncTry:`Effect.try does not await Promises. Use Effect.tryPromise so rejection enters the typed error channel.`},`https://github.com/Effect-TS/tsgo/issues/657`),(e,t)=>({CallExpression(n){if(!S(n.callee,t(),`Effect`,`try`))return;let r=T(n,0),i=r!==void 0&&w(r)?r:void 0;if(i===void 0&&r?.type===`ObjectExpression`){let e=D(r,`try`)?.value;e!==void 0&&w(e)&&(i=e)}let a=i===void 0?void 0:z(i);i!==void 0&&(i.async||a!==void 0&&ke(a))&&e.report({node:i,messageId:`asyncTry`})}})),Re=g(_(`problem`,`Disallow discarded Effect.runPromise results that can become unhandled rejections.`,{discarded:`The Promise returned by Effect.runPromise is discarded. Await/return/handle it, or use Effect.runFork for fire-and-forget work.`},`https://github.com/Effect-TS/tsgo/issues/643`),(e,t)=>({CallExpression(n){let r=t(),i=S(n.callee,r,`Effect`,`runPromise`),a=n.callee.type===`CallExpression`&&S(n.callee.callee,r,`Effect`,`runPromiseWith`);(i||a)&&re(n)&&e.report({node:n,messageId:`discarded`})}}));function ze(e,t){let n=O(e);if(n.type===`CallExpression`&&n.callee.type===`MemberExpression`&&v(n.callee)===t)return n}const Be=g(_(`problem`,`Disallow schema mapping that silently drops checks attached to the receiver.`,{discarded:`{{method}} creates a new schema and drops the preceding check. Re-attach the check after mapping or explicitly preserve it.`},`https://github.com/Effect-TS/tsgo/issues/435`),(e,t)=>({CallExpression(n){if(!t().hasEffectImport||n.callee.type!==`MemberExpression`)return;let r=v(n.callee);if(r===void 0||![`mapElements`,`mapFields`,`mapMembers`].includes(r)||ze(n.callee.object,`check`)===void 0)return;let i=n.arguments.find(e=>e.type===`ObjectExpression`),a=i?.type===`ObjectExpression`?D(i,`unsafePreserveChecks`):void 0;a!==void 0&&P(a.value,!0)||e.report({node:n,messageId:`discarded`,data:{method:r}})}})),Ve={Array:`Arr`,Boolean:`Bool`,Equal:`Eq`,Function:`Fn`,Number:`Num`,Option:`Opt`,Predicate:`P`,Record:`R`,String:`Str`};function He(e){return e===`@effect/vitest`||e.startsWith(`@effect/vitest/`)}function B(e,t){return e.importKind===`type`||t?.importKind===`type`}function V(e){return Ve[e]??e}function Ue(e,t){if(e===`effect`||e===`alchemy`||/^@effect\/[^/]+$/u.test(e)&&!He(e))return`${e}/${t}`}function We(e){if(He(e))return;let t=e.startsWith(`effect/`)||e.startsWith(`alchemy/`)||/^@effect\/[^/]+\//u.test(e)?e.split(`/`).at(-1):void 0;return t!==void 0&&/^\p{Lu}/u.test(t)?t:void 0}function Ge(e,t,n){if(e.sourceCode.getCommentsInside(t).length>0||t.attributes.length>0)return;let r=[],i=[];for(let n of t.specifiers){if(n.type!==`ImportSpecifier`)return;let a=n.imported.type===`Identifier`?n.imported.name:n.imported.value,o=/^\p{Lu}/u.test(a)&&!B(t,n)?Ue(t.source.value,a):void 0;o===void 0?r.push(e.sourceCode.getText(n)):i.push(`import * as ${n.local.name} from '${o}';`)}return r.length>0&&i.unshift(`import { ${r.join(`, `)} } from ${e.sourceCode.getText(t.source)};`),[n.replaceText(t,i.join(`
|
|
2
|
+
`))]}function Ke(e,t,n){let r=We(t.source.value);if(r===void 0||t.attributes.length>0||e.sourceCode.getCommentsInside(t).length>0)return;let i=V(r),a=e.sourceCode.getDeclaredVariables(t),o=a.find(e=>e.name===i);if(e.sourceCode.scopeManager.scopes.some(e=>e.variables.some(e=>e.name===i&&e!==o)||e.references.some(e=>e.identifier.name===i&&e.resolved!==o)))return;let s=[],c=[];for(let r of t.specifiers){if(r.type===`ImportDefaultSpecifier`)return;if(r.type===`ImportSpecifier`&&B(t,r)){if(r.local.name===i)return;c.push(e.sourceCode.getText(r));continue}let o=qe(r,a,i,n);if(o===void 0)return;s.push(...o)}let l=e.sourceCode.getText(t.source),u=`import * as ${i} from ${l};${c.length===0?``:`\nimport { ${c.join(`, `)} } from ${l};`}`;return[n.replaceText(t,u),...s]}function qe(e,t,n,r){let i=t.find(t=>t.name===e.local.name);if(i!==void 0){if(e.type===`ImportNamespaceSpecifier`)return Je(i,n,!1,r);if(e.imported.type===`Identifier`)return Je(i,`${n}.${e.imported.name}`,!0,r)}}function Je(e,t,n,r){let i=[],a=/* @__PURE__ */ new Set;for(let o of e.references){let e=o.identifier;if(a.has(e.range[0]))continue;a.add(e.range[0]);let s=e.parent;if(o.isWrite()||s.type===`ExportSpecifier`||s.type.startsWith(`JSX`))return;let c=s.type===`Property`&&s.shorthand?`${e.name}: ${t}`:t;n&&(s.type===`CallExpression`&&s.callee===e||s.type===`TaggedTemplateExpression`&&s.tag===e)&&(c=`(0, ${t})`),i.push(r.replaceText(e,c))}return i}function Ye(e){return e?.imported.type===`Identifier`?e.imported.name:typeof e?.imported.value==`string`?e.imported.value:void 0}const Xe=h({..._(`suggestion`,`Import Effect and Alchemy module namespaces from their submodule entrypoints instead of root barrels.`,{barrelImport:'Import this module as `import * as {{alias}} from "{{source}}"` instead of from the root barrel.'},`https://github.com/Effect-TS/language-service/blob/main/packages/language-service/src/diagnostics/importFromBarrel.ts`),fixable:`code`},e=>({ImportDeclaration(t){for(let n of t.specifiers){if(n.type!==`ImportSpecifier`||B(t,n))continue;let r=Ye(n),i=r===void 0||!/^\p{Lu}/u.test(r)?void 0:Ue(t.source.value,r);r!==void 0&&i!==void 0&&e.report({node:n,messageId:`barrelImport`,data:{alias:V(r),source:i},fix:n=>Ge(e,t,n)})}}})),Ze=g({..._(`suggestion`,`Prefer Effect.never to an empty Effect.callback registration.`,{emptyCallback:`An empty Effect.callback registration is Effect.never. Use the explicit primitive.`},`https://github.com/Effect-TS/tsgo/issues/636`),fixable:`code`},(e,t)=>({CallExpression(n){if(!S(n.callee,t(),`Effect`,`callback`)&&!S(n.callee,t(),`Effect`,`async`))return;let r=T(n,0);r!==void 0&&w(r)&&r.body?.type===`BlockStatement`&&r.body.body.length===0&&e.report({node:n,messageId:`emptyCallback`,fix(t){if(!I(e,n.callee)||n.arguments.length!==1||r.async||r.generator||r.params.some(e=>e.type!==`Identifier`)||e.sourceCode.getCommentsInside(n).length>0)return;let i=de(e,n,`effect/Effect`,`Effect`,t);return[...i.fixes,t.replaceText(n,`${i.name}.never`)]}})}})),Qe=g(_(`problem`,`Disallow Schema.Struct({}), which accepts every non-null object-like value.`,{emptyStruct:`Schema.Struct({}) does not validate an exact empty object. Define the intended fields explicitly.`},`https://github.com/Effect-TS/tsgo/issues/403`),(e,t)=>({CallExpression(n){let r=T(n,0);S(n.callee,t(),`Schema`,`Struct`)&&r?.type===`ObjectExpression`&&r.properties.length===0&&e.report({node:n,messageId:`emptyStruct`})}}));function $e(e,t){let n=O(e),r=/* @__PURE__ */ new Set;for(;n.type===`Identifier`;){let e=t.sourceCode.getScope(n);for(;e!==null&&!e.set.has(n.name);)e=e.upper;let i=e?.set.get(n.name),a=i?.defs.length===1?i.defs[0]:void 0,o=a?.node;if(i===void 0||r.has(i)||o?.type!==`VariableDeclarator`||o.id.type!==`Identifier`||a?.parent?.type!==`VariableDeclaration`||a.parent.kind!==`const`||!o.init||i.references.some(e=>e.isWrite()&&!e.init))return;r.add(i),n=O(o.init)}return n}function et(e){if(e.arguments.length===2)return T(e,0);let t=e.parent;if(e.arguments.length===1&&t.type===`CallExpression`&&t.arguments[0]===e&&t.callee.type===`MemberExpression`&&v(t.callee)===`pipe`)return t.callee.object}const tt=g(_(`problem`,`Disallow obsolete lazy callbacks passed to the now-eager Config.withDefault API.`,{functionDefault:`Config.withDefault takes an eager value. This callback becomes the configured value; pass the returned value directly.`},`https://github.com/Effect-TS/tsgo/issues/408`),(e,t)=>({CallExpression(n){if(!S(n.callee,t(),`Config`,`withDefault`)||!I(e,n.callee))return;let r=T(n,n.arguments.length-1),i=et(n),a=i===void 0?void 0:$e(i,e);a?.type===`CallExpression`&&S(a.callee,t(),`Config`,`succeed`)&&I(e,a.callee)&&w(T(a,0))||r!==void 0&&w(r)&&r.params.length===0&&e.report({node:r,messageId:`functionDefault`})}}));function nt(e,t){return e.type===`CallExpression`&&S(e.callee,t,`Hash`,`hash`)}const rt=g(_(`problem`,`Disallow using Hash.hash output as collision-free identity.`,{hashIdentity:`Hash.hash is a bucketing hint, not a unique identity. Use HashMap/Equal.equals or a real identifier instead.`},`https://github.com/Effect-TS/tsgo/issues/482`),(e,t)=>{let n=/* @__PURE__ */ new Set;function r(e){return nt(e,t())||e.type===`Identifier`&&n.has(e.name)}return{before(){n=/* @__PURE__ */ new Set},VariableDeclarator(e){e.id.type===`Identifier`&&e.init&&nt(e.init,t())&&n.add(e.id.name)},CallExpression(t){if(t.callee.type!==`MemberExpression`||![`delete`,`get`,`has`,`set`].includes(y(t.callee)?.at(-1)??``))return;let n=T(t,0);n!==void 0&&r(n)&&e.report({node:n,messageId:`hashIdentity`})},BinaryExpression(t){[`===`,`!==`,`==`,`!=`].includes(t.operator)&&r(t.left)&&r(t.right)&&e.report({node:t,messageId:`hashIdentity`})},MemberExpression(t){t.computed&&r(t.property)&&e.report({node:t.property,messageId:`hashIdentity`})}}}),it=/* @__PURE__ */ new Set([`catch`,`catchAll`,`catchAllCause`,`catchIf`,`catchSome`,`catchSomeCause`,`catchTag`,`orElse`,`orElseFail`,`orElseSucceed`]),at=/* @__PURE__ */ new Set([`log`,`logDebug`,`logError`,`logInfo`,`logTrace`,`logWarning`]);function ot(e,t){let n=e.parent;for(;n;){if(w(n)){let e=N(n);if(e?.arguments.at(-1)===n){let n=x(e.callee,t),r=n?.[1];if(r!==void 0&&n?.[0]===`Effect`&&it.has(r))return{method:r}}}n=n.parent}}const st=g(_(`suggestion`,`Keep logging separate from Effect recovery handlers.`,{logging:`Move {{logger}} out of Effect.{{catchMethod}} and use Effect.tapError before recovery.`}),(e,t)=>({CallExpression(n){let r=t(),i=x(n.callee,r),a=i?.[1]!==void 0&&i[0]===`Effect`&&at.has(i[1])?i.join(`.`):void 0;if(a===void 0)return;let o=ot(n,r);o!==void 0&&e.report({node:n,messageId:`logging`,data:{logger:a,catchMethod:o.method}})}})),ct=/* @__PURE__ */ new Set([`==`,`===`,`!=`,`!==`]),lt=/* @__PURE__ */ new Set([`catch`,`catchAll`,`catchIf`]);function H(e){return e.type===`Literal`&&typeof e.value==`string`}function U(e){return e.type===`MemberExpression`&&v(e)===`_tag`}function ut(e){if(ct.has(e.operator)){if(U(e.left)&&H(e.right))return e.left;if(U(e.right)&&H(e.left))return e.right}}function W(e){let t=e.parent;for(;t;){if(t.type===`ArrowFunctionExpression`||t.type===`FunctionExpression`){let e=t.parent;return e.type===`CallExpression`&&e.arguments.includes(t)&&e.callee.type===`MemberExpression`&&e.callee.object.type===`Identifier`&&e.callee.object.name===`Effect`&&!e.callee.computed&&e.callee.property.type===`Identifier`&<.has(e.callee.property.name)}t=t.parent}return!1}function dt(e){return e.object.type===`MemberExpression`&&v(e.object)===`reason`}function ft(e){let t=e.parent;return t.type===`CallExpression`&&t.arguments.includes(e)&&t.callee.type===`MemberExpression`&&t.callee.object.type===`Identifier`&&t.callee.object.name===`Match`&&!t.callee.computed&&t.callee.property.type===`Identifier`&&(t.callee.property.name===`when`||t.callee.property.name===`not`)}const pt=h(_(`problem`,"Use Effect tagged error handlers instead of manually branching on `_tag` in a catch handler.",{tag:`Use Effect.catchTag or Effect.catchTags instead of manually discriminating a tagged error in a broad Effect catch handler.`,reason:"Use Effect.catchReason or Effect.catchReasons instead of manually discriminating a tagged `reason` in a broad Effect catch handler."},`https://github.com/dmmulroy/anti-slop/blob/main/src/effect/rules/no-manual-effect-error-tag.ts`),e=>({BinaryExpression(t){let n=ut(t);n!==void 0&&W(t)&&e.report({node:t,messageId:dt(n)?`reason`:`tag`})},SwitchStatement(t){U(t.discriminant)&&W(t)&&e.report({node:t,messageId:dt(t.discriminant)?`reason`:`tag`})}})),mt=h(_(`problem`,"Use Effect Match or Predicate helpers instead of manually branching on `_tag`.",{manualComparison:`Use Match.tag/Match.tags for tagged-value branching, or Predicate.isTagged for a simple reusable predicate.`,manualSwitch:"Use Match.value(value).pipe(Match.tag/Match.tags/Match.tagsExhaustive) or the tagged enum `$match` helper instead of switching on `_tag`."},`https://github.com/dmmulroy/anti-slop/blob/main/src/effect/rules/no-manual-tag-comparison.ts`),e=>({BinaryExpression(t){ut(t)===void 0||W(t)||e.report({node:t,messageId:`manualComparison`})},SwitchStatement(t){U(t.discriminant)&&!W(t)&&e.report({node:t,messageId:`manualSwitch`})}})),ht=h(_(`problem`,"Construct tagged values with their existing Effect constructor instead of writing `_tag` manually.",{manualConstruction:"Use the existing Schema tagged `.make`, tagged class/error constructor, or Data.taggedEnum variant constructor instead of writing a literal `_tag` object."},`https://github.com/dmmulroy/anti-slop/blob/main/src/effect/rules/no-manual-tagged-construction.ts`),e=>({ObjectExpression(t){if(ft(t))return;let n=t.properties.find(e=>e.type===`Property`&&E(e)===`_tag`&&H(e.value));n!==void 0&&e.report({node:n,messageId:`manualConstruction`})}}));function gt(e,t){let n=y(e.callee)?.at(-1);if(n===void 0||![`addEventListener`,`on`,`setInterval`].includes(n))return!1;if(n===`addEventListener`){let t=T(e,2);if(t?.type===`ObjectExpression`){let e=D(t,`once`);if(e!==void 0&&P(e.value,!0))return!1}}let r=T(e,n===`setInterval`?0:1);return r!==void 0&&A(r,t)}const _t=g(_(`problem`,`Disallow attaching Effect.callback resume to repeating event sources.`,{multiShot:`Effect.callback is single-shot, but this source emits repeatedly. Use a once-style subscription or Stream.callback.`},`https://github.com/Effect-TS/tsgo/issues/484`),(e,t)=>({CallExpression(n){if(!S(n.callee,t(),`Effect`,`callback`))return;let r=T(n,0);if(r===void 0||!w(r))return;let i=j(r)?.name,a=r.body;i!==void 0&&a&&k(a,e=>e.type===`CallExpression`&>(e,i))&&e.report({node:n,messageId:`multiShot`})}}));function vt(e){return e.type===`Literal`&&typeof e.value==`bigint`||e.type===`Identifier`&&[`NaN`,`Infinity`,`undefined`].includes(e.name)||w(e)||e.type===`CallExpression`&&y(e.callee)?.at(-1)===`Symbol`}function yt(e,t){if(e.type===`ArrayExpression`){for(let n of e.elements)n&&n.type!==`SpreadElement`&&t.push(n);return}if(e.type===`ObjectExpression`)for(let n of e.properties)n.type===`Property`&&t.push(n.value)}function bt(e){let t=[e];for(;t.length>0;){let e=t.pop();if(e===void 0)continue;let n=O(e);if(vt(n))return n;yt(n,t)}}const xt=g(_(`problem`,`Disallow schema examples and defaults that cannot be represented in JSON Schema.`,{nonJson:`This schema annotation value is not JSON-serializable and will be omitted from or corrupt generated JSON Schema.`},`https://github.com/Effect-TS/tsgo/issues/440`),(e,t)=>({CallExpression(n){let r=t();if(!r.hasEffectImport)return;let i=x(n.callee,r),a=n.callee.type===`MemberExpression`?v(n.callee):i?.[0]===`Schema`?i[1]:void 0;if(a===void 0||![`annotate`,`annotateEncoded`,`annotateKey`].includes(a))return;let o=R(n);if(o!==void 0&&D(o,`jsonSchema`)===void 0)for(let t of[`default`,`examples`]){let n=D(o,t);if(n===void 0)continue;let r=bt(n.value);r!==void 0&&e.report({node:r,messageId:`nonJson`})}}})),St=g(_(`problem`,`Disallow wrapping infallible Effect.service access in Option or Either.`,{mandatory:`Effect.service never fails, so this wrapper is always present and keeps the service requirement. Use Effect.serviceOption.`},`https://github.com/Effect-TS/tsgo/issues/648`),(e,t)=>({CallExpression(n){let r=t(),i=S(n.callee,r,`Effect`,`option`)||S(n.callee,r,`Effect`,`either`),a=T(n,0);if(i&&a?.type===`CallExpression`&&S(a.callee,r,`Effect`,`service`)){e.report({node:n,messageId:`mandatory`});return}if(n.callee.type!==`MemberExpression`||y(n.callee)?.at(-1)!==`pipe`)return;let o=O(n.callee.object),s=T(n,0);s!==void 0&&o.type===`CallExpression`&&S(o.callee,r,`Effect`,`service`)&&(S(s,r,`Effect`,`option`)||S(s,r,`Effect`,`either`))&&e.report({node:n,messageId:`mandatory`})}})),Ct=g(_(`problem`,`Ensure a later object spread cannot overwrite an explicitly assigned _tag.`,{overwritten:`A later spread can overwrite _tag at runtime. Move _tag after all spreads.`},`https://github.com/Effect-TS/tsgo/issues/426`),e=>({ObjectExpression(t){let n=t.properties.findIndex(e=>e.type===`Property`&&E(e)===`_tag`);if(n===-1)return;let r=t.properties.slice(n+1).some(e=>e.type===`SpreadElement`),i=t.properties[n];r&&i?.type===`Property`&&e.report({node:i,messageId:`overwritten`})}})),wt=/^make[A-Z]/u,Tt=/\.(?:test|spec)\.[cm]?[jt]sx?$/u,Et=h(_(`problem`,`Disallow project-local make<CapabilityName> imports outside test and spec files.`,{serviceConstructorImport:`Do not import Effect service constructor "{{name}}" into runtime code. Import the owning Layer, yield the contextual service, and allow its requirements to propagate to the composition root.`},`https://github.com/dmmulroy/anti-slop/blob/main/src/effect/rules/no-service-constructor-imports.ts`),e=>({ImportDeclaration(t){if(!Tt.test(e.filename.replaceAll(`\\`,`/`))&&(t.source.value.startsWith(`./`)||t.source.value.startsWith(`../`)))for(let n of t.specifiers){if(n.type!==`ImportSpecifier`)continue;let t=n.imported.type===`Identifier`?n.imported.name:n.imported.value;wt.test(t)&&e.report({node:n,messageId:`serviceConstructorImport`,data:{name:t}})}}})),Dt=g(_(`problem`,`Disallow turning missing Effect services into untyped Option defects.`,{getOrThrow:`Option.getOrThrow after Effect.serviceOption hides a mandatory service until runtime. Use Effect.service so it remains a typed requirement.`},`https://github.com/Effect-TS/tsgo/issues/650`),(e,t)=>({CallExpression(n){let r=t();if(S(n.callee,r,`Option`,`getOrThrow`)||S(n.callee,r,`Option`,`getOrThrowWith`)){let t=T(n,0),i=t?.type===`YieldExpression`?t.argument:t;i?.type===`CallExpression`&&S(i.callee,r,`Effect`,`serviceOption`)&&e.report({node:n,messageId:`getOrThrow`});return}if(n.callee.type!==`MemberExpression`||y(n.callee)?.at(-1)!==`pipe`)return;let i=O(n.callee.object),a=T(n,0);if(i.type!==`CallExpression`||!S(i.callee,r,`Effect`,`serviceOption`)||a?.type!==`CallExpression`||!S(a.callee,r,`Effect`,`map`))return;let o=T(a,0);o!==void 0&&(S(o,r,`Option`,`getOrThrow`)||S(o,r,`Option`,`getOrThrowWith`))&&e.report({node:n,messageId:`getOrThrow`})}})),Ot=/* @__PURE__ */ new Set([`andThen`,`map`,`mapError`,`tap`,`tapError`,`tapErrorCause`]),kt=g(_(`problem`,`Disallow throw in Effect callbacks that cannot add the thrown value to the typed error channel.`,{callbackThrow:`Throwing in this Effect callback creates an untyped defect. Return Effect.fail(...) or return the mapped error value instead.`},`https://github.com/Effect-TS/tsgo/issues/406`),(e,t)=>({ThrowStatement(n){let r=ne(n);if(r===void 0)return;let i=t(),a=Oe(r,i),o=De(r,`catch`);(a?.[0]===`Effect`&&a[1]!==void 0&&Ot.has(a[1])||o!==void 0&&(S(o.callee,i,`Effect`,`try`)||S(o.callee,i,`Effect`,`tryPromise`)))&&e.report({node:n,messageId:`callbackThrow`})}})),At=/* @__PURE__ */ new Set([`get`,`post`,`put`,`patch`,`delete`,`head`,`options`]);function jt(e,t){let n=e.parent,r=e.node;if(e.type!==`ImportBinding`||n?.type!==`ImportDeclaration`||B(n,r.type===`ImportSpecifier`?r:void 0))return!1;let i=n.source.value;return r.type===`ImportNamespaceSpecifier`?i===`effect/unstable/httpapi/HttpApiEndpoint`&&t.length===2||i===`effect/unstable/httpapi`&&t.length===3&&t[1]===`HttpApiEndpoint`:r.type===`ImportSpecifier`&&r.imported.type===`Identifier`&&r.imported.name===`HttpApiEndpoint`&&i===`effect/unstable/httpapi`&&t.length===2}function Mt(e,t){let n=y(e.callee),r=n?.[0],i=n?.at(-1);if(n===void 0||r===void 0||i===void 0||!At.has(i))return!1;let a=t.sourceCode.getScope(e);for(;a;){let e=a.set.get(r);if(e!==void 0){let t=e.defs.length===1?e.defs[0]:void 0;return t!==void 0&&jt(t,n)}a=a.upper}return!1}function Nt(e){if(e?.type!==`ObjectExpression`)return;let t=/* @__PURE__ */ new Set,n=[];for(let r of e.properties){if(r.type!==`Property`||r.computed||r.method||r.kind!==`init`)return;let e=E(r)??(r.key.type===`Literal`&&typeof r.key.value==`number`?String(r.key.value):void 0);if(e===void 0||t.has(e))return;t.add(e),n.push(r)}return n}const Pt=h(_(`problem`,`Require lowercase static keys in Effect v4 endpoint header field schemas.`,{uppercase:`Header schema key "{{name}}" contains ASCII uppercase letters. Incoming headers use exact lowercase runtime lookup; review the schema and its consumers before renaming this key.`},`https://github.com/Effect-TS/tsgo/issues/413`),e=>({CallExpression(t){if(t.arguments.some(e=>e.type===`SpreadElement`)||!Mt(t,e))return;let n=Nt(Nt(T(t,2))?.find(e=>E(e)===`headers`)?.value);if(n!==void 0)for(let t of n){let n=E(t);n!==void 0&&/[A-Z]/u.test(n)&&e.report({node:t.key,messageId:`uppercase`,data:{name:n}})}}})),Ft=g(_(`problem`,`Disallow no-op retry and repeat wrappers with times: 0.`,{zeroTimes:`times: 0 performs no retries or repeats. Remove the wrapper or use a positive count.`},`https://github.com/Effect-TS/tsgo/issues/412`),(e,t)=>({CallExpression(n){let r=t();if(!S(n.callee,r,`Effect`,`retry`)&&!S(n.callee,r,`Effect`,`repeat`))return;let i=R(n);if(i===void 0)return;let a=D(i,`times`);a!==void 0&&P(a.value,0)&&e.report({node:a,messageId:`zeroTimes`})}})),It=h({..._(`suggestion`,`Use consistently aliased namespace imports for Effect and Alchemy submodule entrypoints.`,{alias:"Import {{source}} as the canonical namespace alias `{{alias}}`.",namespace:'Use `import * as {{alias}} from "{{source}}"` instead of importing values directly.'},`https://github.com/Effect-TS/language-service/blob/main/packages/language-service/src/core/AutoImport.ts`),fixable:`code`},e=>({ImportDeclaration(t){let n=We(t.source.value);if(n===void 0||t.importKind===`type`)return;let r=V(n);for(let n of t.specifiers)if(!(n.type===`ImportSpecifier`&&B(t,n))){if(n.type===`ImportNamespaceSpecifier`){n.local.name!==r&&e.report({node:n.local,messageId:`alias`,data:{alias:r,source:t.source.value},fix:n=>Ke(e,t,n)});continue}e.report({node:n,messageId:`namespace`,data:{alias:r,source:t.source.value},fix:n=>Ke(e,t,n)})}}})),Lt=g(_(`suggestion`,`Prefer immutable, Order-based Effect Array sorting in Effect projects.`,{effectArraySort:`Use Arr.sort with an Order instead of the mutable native Array.sort method.`},`https://www.effect.website/docs/v4/api/effect/Array#sort`),(e,t)=>({CallExpression(n){let r=t();r.hasEffectImport&&n.callee.type===`MemberExpression`&&v(n.callee)===`sort`&&!S(n.callee,r,`Array`,`sort`)&&e.report({node:n,messageId:`effectArraySort`})}})),Rt=/* @__PURE__ */ new Set([`toISOString`,`toLocaleDateString`,`toLocaleTimeString`]),zt=g(_(`suggestion`,`Prefer Effect DateTime formatting so time-zone behavior is explicit and composable.`,{effectDateTime:`Convert to DateTime and use DateTime.format, DateTime.formatIso, or another explicit formatter.`},`https://www.effect.website/docs/v4/api/effect/DateTime`),(e,t)=>({CallExpression(n){t().hasEffectImport&&n.callee.type===`MemberExpression`&&Rt.has(v(n.callee)??``)&&e.report({node:n,messageId:`effectDateTime`})}})),Bt=/* @__PURE__ */ new Set([`Effect.delay`,`Effect.sleep`,`Effect.timeout`,`Effect.timeoutOption`,`Effect.timeoutOrElse`,`Schedule.fixed`,`Schedule.spaced`,`Schedule.windowed`]),Vt=g({..._(`suggestion`,`Prefer explicit Effect Duration constructors over ambiguous millisecond literals.`,{effectDuration:`Wrap this number with Duration.millis or use a more descriptive Duration constructor.`},`https://www.effect.website/docs/v4/api/effect/Duration`),fixable:`code`},(e,t)=>({CallExpression(n){let r=x(n.callee,t());if(r===void 0||!Bt.has(r.join(`.`)))return;let i=T(n,n.arguments.length-1);i?.type===`Literal`&&typeof i.value==`number`&&e.report({node:i,messageId:`effectDuration`,fix(t){if(!I(e,n.callee))return;let r=de(e,n,`effect/Duration`,`Duration`,t);return[...r.fixes,t.replaceText(i,`${r.name}.millis(${e.sourceCode.getText(i)})`)]}})}})),Ht=/* @__PURE__ */ new Set([`base64`,`base64url`,`hex`]);function Ut(e){return e!==void 0&&[...Ht].some(t=>P(e,t))}const Wt=g(_(`suggestion`,`Prefer Effect Encoding for portable Base64, Base64Url, and hexadecimal encoding.`,{effectEncoding:`Use Encoding encode/decode helpers; decoders return Result instead of throwing.`},`https://www.effect.website/docs/v4/api/effect/Encoding`),(e,t)=>({CallExpression(n){if(!t().hasEffectImport)return;if((b(n.callee,e,`atob`)||b(n.callee,e,`btoa`))&&n.arguments.length>0){e.report({node:n,messageId:`effectEncoding`});return}let r=y(n.callee),i=r?.join(`.`)===`Buffer.from`&&Ut(T(n,1)),a=r?.at(-1)===`toString`&&Ut(T(n,0));(i||a)&&e.report({node:n,messageId:`effectEncoding`})}})),Gt=/* @__PURE__ */ new Set([`fs`,`fs/promises`,`node:fs`,`node:fs/promises`]),Kt=g(_(`suggestion`,`Prefer the Effect FileSystem service over direct Node.js filesystem imports in Effect projects.`,{effectFileSystem:`Use the FileSystem service from effect/FileSystem instead of {{source}}.`},`https://www.effect.website/docs/v4/api/effect/FileSystem`),(e,t)=>({ImportDeclaration(n){t().hasEffectImport&&Gt.has(n.source.value)&&e.report({node:n.source,messageId:`effectFileSystem`,data:{source:n.source.value}})}}));function qt(e,t,n){return e.type===`CallExpression`&&S(e.callee,t,`Result`,n)?T(e,0):void 0}function Jt(e,t,n){let r=j(t),i=z(t);if(r===void 0||i?.type!==`ConditionalExpression`)return;let a=qt(i.consequent,n,`succeed`),o=qt(i.alternate,n,`fail`);a?.type===`Identifier`&&a.name===r.name&&o?.type===`Identifier`&&o.name===r.name&&e.report({node:t,messageId:`effectFilter`})}const Yt=g(_(`suggestion`,`Prefer Effect Filter constructors for reusable Result-valued predicates.`,{effectFilter:`Use Filter.fromPredicate for this Result-valued predicate so it composes as a Filter.`},`https://www.effect.website/docs/v4/api/effect/Filter`),(e,t)=>({ArrowFunctionExpression(n){Jt(e,n,t())},FunctionExpression(n){Jt(e,n,t())}})),Xt=g(_(`suggestion`,`Prefer immutable Effect Headers values in Effect projects.`,{effectHeaders:`Use Headers.fromInput to construct normalized, immutable Effect headers.`},`https://www.effect.website/docs/v4/api/effect/unstable/http/Headers`),(e,t)=>({NewExpression(n){t().hasEffectImport&&b(n.callee,e,`Headers`)&&e.report({node:n,messageId:`effectHeaders`})}})),Zt=/* @__PURE__ */ new Set([`==`,`===`,`!=`,`!==`]);function Qt(e){return e.type===`Literal`||e.type===`TemplateLiteral`&&e.expressions.length===0}function $t(e,t){if(e.type===`BinaryExpression`&&Zt.has(e.operator)){if(Qt(e.left))return t.sourceCode.getText(e.right);if(Qt(e.right))return t.sourceCode.getText(e.left)}}const en=g(_(`suggestion`,`Prefer Effect Match for composable and exhaustive branching in Effect projects.`,{effectMatch:`Use Match.type, Match.value, or Match.tags with Match.exhaustive instead of switch.`,preferMatch:`Use Match from Effect instead of a chained literal ternary.`},`https://www.effect.website/docs/v4/api/effect/Match`),(e,t)=>({SwitchStatement(n){t().hasEffectImport&&e.report({node:n,messageId:`effectMatch`})},ConditionalExpression(t){if(t.parent.type===`ConditionalExpression`)return;let n=$t(t.test,e);if(n===void 0)return;let r=t.alternate,i=1;for(;r.type===`ConditionalExpression`;){if($t(r.test,e)!==n)return;i+=1,r=r.alternate}i>1&&e.report({node:t,messageId:`preferMatch`})}})),tn=/* @__PURE__ */ new Set([`node:path`,`path`]),nn=g(_(`suggestion`,`Prefer the Effect Path service over direct Node.js path imports in Effect projects.`,{effectPath:`Use the Path service from effect/Path instead of {{source}}.`},`https://www.effect.website/docs/v4/api/effect/Path`),(e,t)=>({ImportDeclaration(n){t().hasEffectImport&&tn.has(n.source.value)&&e.report({node:n.source,messageId:`effectPath`,data:{source:n.source.value}})}})),rn=g(_(`suggestion`,`Prefer Effect Url helpers for safe URL parsing in Effect projects.`,{effectUrl:`Use Url.fromString or Url.make so invalid URLs are represented as Result failures.`},`https://www.effect.website/docs/v4/api/effect/unstable/http/Url`),(e,t)=>({NewExpression(n){t().hasEffectImport&&b(n.callee,e,`URL`)&&e.report({node:n,messageId:`effectUrl`})},CallExpression(n){let r=y(n.callee);t().hasEffectImport&&r?.[0]===`URL`&&[`canParse`,`parse`].includes(r[1]??``)&&n.callee.type===`MemberExpression`&&b(n.callee.object,e,`URL`)&&e.report({node:n,messageId:`effectUrl`})}})),an=g(_(`suggestion`,`Prefer the non-mask interruptibility API when the restore callback is unused.`,{unusedRestore:`The mask callback never uses restore, so the mask is equivalent to {{replacement}} and misleadingly suggests a restored region.`},`https://github.com/Effect-TS/tsgo/issues/659`),(e,t)=>({CallExpression(n){let r=t(),i=S(n.callee,r,`Effect`,`uninterruptibleMask`)?`uninterruptible`:S(n.callee,r,`Effect`,`interruptibleMask`)?`interruptible`:void 0,a=T(n,0);i!==void 0&&a!==void 0&&w(a)&&!M(a)&&e.report({node:n,messageId:`unusedRestore`,data:{replacement:`Effect.${i}`}})}})),on=g(_(`suggestion`,`Prefer Effect.withSpan when the callback does not use the span handle.`,{unusedSpan:`The useSpan callback ignores its span. Use Effect.withSpan so nested spans are parented beneath this span.`},`https://github.com/Effect-TS/tsgo/issues/663`),(e,t)=>({CallExpression(n){if(!S(n.callee,t(),`Effect`,`useSpan`))return;let r=T(n,n.arguments.length-1);r!==void 0&&w(r)&&!M(r)&&e.report({node:n,messageId:`unusedSpan`})}}));function sn(e,t){let n=O(e);if(P(n,0))return!0;if(n.type===`Literal`&&typeof n.value==`string`)return/^0\s*(?:nanos?|micros?|millis?|seconds?|minutes?|hours?|days?|weeks?)$/i.test(n.value);if(S(n,t,`Duration`,`zero`))return!0;if(n.type===`CallExpression`){let e=x(n.callee,t),r=T(n,0);return r!==void 0&&e?.[0]===`Duration`&&P(r,0)}return!1}const cn=g(_(`suggestion`,`Prefer scheduler yielding to a zero-duration Clock sleep.`,{zeroSleep:`Effect.sleep(0) uses Clock and interacts with TestClock. Use Effect.yieldNow for a cooperative scheduler yield.`},`https://github.com/Effect-TS/tsgo/issues/661`),(e,t)=>({CallExpression(n){let r=t(),i=T(n,0);i!==void 0&&S(n.callee,r,`Effect`,`sleep`)&&sn(i,r)&&e.report({node:n,messageId:`zeroSleep`})}})),ln=/* @__PURE__ */ new Set([`catch`,`catchAll`,`mapError`]);function un(e,t){let n=Oe(e,t),r=De(e,`catch`);if(!(n?.[0]===`Effect`&&n[1]!==void 0&&ln.has(n[1])||r!==void 0&&(S(r.callee,t,`Effect`,`try`)||S(r.callee,t,`Effect`,`tryPromise`)))||!e.body)return!1;let i=j(e);return k(e.body,e=>e.type===`NewExpression`&&F(e)&&(i===void 0||!A(e,i.name)))}const dn=g(_(`suggestion`,`Preserve the underlying cause when wrapping an Effect failure.`,{droppedCause:`This handler constructs a new error but drops the caught failure. Accept it as a parameter and attach it as cause.`},`https://github.com/Effect-TS/tsgo/issues/490`),(e,t)=>({ArrowFunctionExpression(n){un(n,t())&&e.report({node:n,messageId:`droppedCause`})},FunctionExpression(n){un(n,t())&&e.report({node:n,messageId:`droppedCause`})}})),fn=g(_(`problem`,`Require Schema.Class declarations to carry a nominal brand.`,{missingBrand:`Schema.Class without a second type parameter is structural. Add a unique brand so plain objects cannot masquerade as instances.`},`https://github.com/Effect-TS/tsgo/issues/468`),(e,t)=>({CallExpression(n){S(n.callee,t(),`Schema`,`Class`)&&(n.typeArguments?.params.length??0)<2&&e.report({node:n,messageId:`missingBrand`})}}));function pn(e,t){if(!S(e.callee,t,`Effect`,`tryPromise`))return;let n=T(e,0);if(n!==void 0&&w(n))return n;if(n?.type===`ObjectExpression`){let e=D(n,`try`);if(e!==void 0&&w(e.value))return e.value}}const mn=g(_(`suggestion`,`Require Effect.tryPromise thunks to accept and use their AbortSignal for interruption.`,{missingSignal:"Accept the AbortSignal parameter and pass it to the Promise API. Name it `_signal` only when cancellation is unsupported.",unusedSignal:"Pass this AbortSignal to the Promise API, or rename it to `_signal` to explicitly acknowledge that cancellation is unsupported."},`https://www.effect.website/docs/v4/api/effect/Effect#tryPromise`),(e,t)=>({CallExpression(n){let r=pn(n,t());if(r===void 0)return;let i=j(r);i===void 0?e.report({node:r,messageId:`missingSignal`}):!i.name.startsWith(`_`)&&!M(r)&&e.report({node:i,messageId:`unusedSignal`})}}));function hn(e,t){let n=e.parent;if(n.type===`CallExpression`&&T(n,0)===e)return S(n.callee,t,`Effect`,`try`)||S(n.callee,t,`Effect`,`tryPromise`);if(n.type!==`Property`||n.key.type!==`Identifier`||n.key.name!==`try`)return!1;let r=n.parent;return r.type===`ObjectExpression`&&r.parent.type===`CallExpression`&&(S(r.parent.callee,t,`Effect`,`try`)||S(r.parent.callee,t,`Effect`,`tryPromise`))}const gn=g(_(`problem`,`Disallow throw in Effect generator APIs because it creates an untyped defect.`,{throwInGen:`Use yield* Effect.fail(...) instead of throw so the failure stays in the typed error channel.`}),(e,t)=>({ThrowStatement(n){let r=t(),i=n.parent;for(;i&&!w(i);)i=i.parent??void 0;if(i===void 0||hn(i,r))return;let a=N(i),o=a!==void 0&&[`fn`,`fnUntraced`,`gen`].some(e=>S(a.callee,r,`Effect`,e)),s=a?.callee,c=s?.type===`CallExpression`&&[`fn`,`fnUntraced`].some(e=>S(s.callee,r,`Effect`,e));(o||c)&&e.report({node:n,messageId:`throwInGen`})}})),_n=String.raw`(?:\r\n|\r(?!\n)|[\n\u2028\u2029])`,G=String.raw`[^\S\r\n\u2028\u2029]*`,vn=RegExp(`^(${G}${_n})(?:${G}${_n})+(${G};?)$`,`u`),yn=/^(?:module\s*\.\s*)?exports(?:\s*\.|\s*\[|$)/u;function bn(e){return e.type===`Punctuator`&&e.value===`;`}function K(e,t){return e.loc.end.line===t.loc.start.line}function q(e){return e.loc.start.line===e.loc.end.line}function xn(e){return[`FunctionDeclaration`,`FunctionExpression`,`ArrowFunctionExpression`].includes(e.type)}function Sn(e){return e.type===`ChainExpression`?e.expression:e}function J(e,t){return(n,r)=>r.getFirstToken(n)?.value===t&&(a.isArray(e)?e.includes(n.type):e===n.type)}function Y(e){return t=>t.type===e}function X(e,t){return(n,r)=>e(n,r)&&q(n)===(t===`singleline`)}function Cn(e){if(e.type!==`ExpressionStatement`)return!1;let t=Sn(e.expression);if(t.type===`UnaryExpression`&&(t=Sn(t.argument)),t.type!==`CallExpression`)return!1;let n=t.callee;for(;n.type===`SequenceExpression`;){let e=n.expressions.at(-1);if(e===void 0)throw Error(`Padding rule invariant: sequence expression is empty`);n=e}return xn(n)}function wn(e){if(e.type!==`VariableDeclaration`)return!1;let t=e.declarations[0]?.init;if(t==null)return!1;for(;t.type===`MemberExpression`;)t=t.object;return t.type===`CallExpression`&&t.callee.type===`Identifier`&&t.callee.name===`require`}function Tn(e,t){if(e.type===`DoWhileStatement`&&e.body.type===`BlockStatement`||Cn(e))return!0;let n=t.getLastToken(e,e=>!bn(e)),r=n?.type===`Punctuator`&&n.value===`}`?t.getNodeByRangeIndex(n.range[0]):null;return r?.type===`BlockStatement`||r?.type===`SwitchStatement`}function En(e,t){return e.type===`ExpressionStatement`&&(e.parent.type===`Program`||e.parent.type===`BlockStatement`&&xn(e.parent.parent))&&e.expression.type===`Literal`&&typeof e.expression.value==`string`&&(t.getTokenBefore(e.expression)?.value!==`(`||t.getTokenAfter(e.expression)?.value!==`)`)}function Dn(e,t){if(!En(e,t)||!e.parent||!(`body`in e.parent)||!Array.isArray(e.parent.body))return!1;for(let n of e.parent.body){if(n===e)break;if(!En(n,t))return!1}return!0}function On(e){if(e.type!==`ExpressionStatement`||e.expression.type!==`AssignmentExpression`)return!1;let t=e.expression.left;if(t.type!==`MemberExpression`)return!1;for(;t.object.type===`MemberExpression`;)t=t.object;return t.object.type===`Identifier`&&(t.object.name===`exports`||t.object.name===`module`&&t.property.type===`Identifier`&&t.property.name===`exports`)}function kn(e,t){let n=t.getLastToken(e);if(n===null)throw Error(`Padding rule invariant: statement has no token`);let r=t.getTokenBefore(n),i=t.getTokenAfter(n);return r&&i&&r.range[0]>=e.range[0]&&bn(n)&&!K(r,n)&&K(n,i)?r:n}function An(e,t){if(q(e))return e.loc;let n=e.loc.start.line,r=t.lines[n-1];if(r===void 0)throw Error(`Padding rule invariant: statement source line is missing`);return{start:e.loc.start,end:{line:n,column:r.length}}}const Z={"block-like":Tn,expression:(e,t)=>e.type===`ExpressionStatement`&&!Dn(e,t),return:J(`ReturnStatement`,`return`),export:J([`ExportAllDeclaration`,`ExportDefaultDeclaration`,`ExportNamedDeclaration`],`export`),var:J(`VariableDeclaration`,`var`),let:J(`VariableDeclaration`,`let`),const:J(`VariableDeclaration`,`const`),using:e=>e.type===`VariableDeclaration`&&(e.kind===`using`||e.kind===`await using`),type:J(`TSTypeAliasDeclaration`,`type`)},Q={"*":()=>!0,exports:On,require:wn,directive:Dn,iife:Cn,block:Y(`BlockStatement`),empty:Y(`EmptyStatement`),function:Y(`FunctionDeclaration`),"ts-method":Y(`TSMethodSignature`),break:J(`BreakStatement`,`break`),case:J(`SwitchCase`,`case`),class:J(`ClassDeclaration`,`class`),continue:J(`ContinueStatement`,`continue`),debugger:J(`DebuggerStatement`,`debugger`),default:J([`SwitchCase`,`ExportDefaultDeclaration`],`default`),do:J(`DoWhileStatement`,`do`),for:J([`ForStatement`,`ForInStatement`,`ForOfStatement`],`for`),if:J(`IfStatement`,`if`),import:J(`ImportDeclaration`,`import`),switch:J(`SwitchStatement`,`switch`),throw:J(`ThrowStatement`,`throw`),try:J(`TryStatement`,`try`),while:J([`WhileStatement`,`DoWhileStatement`],`while`),with:J(`WithStatement`,`with`),"cjs-export":(e,t)=>e.type===`ExpressionStatement`&&e.expression.type===`AssignmentExpression`&&yn.test(t.getText(e.expression.left)),"cjs-import":(e,t)=>e.type===`VariableDeclaration`&&e.declarations[0]?.init!=null&&t.getText(e.declarations[0].init).startsWith(`require(`),enum:J(`TSEnumDeclaration`,`enum`),interface:J(`TSInterfaceDeclaration`,`interface`),"function-overload":Y(`TSDeclareFunction`),...Z,"singleline-block-like":X(Z[`block-like`],`singleline`),"multiline-block-like":X(Z[`block-like`],`multiline`),"singleline-expression":X(Z.expression,`singleline`),"multiline-expression":X(Z.expression,`multiline`),"singleline-return":X(Z.return,`singleline`),"multiline-return":X(Z.return,`multiline`),"singleline-export":X(Z.export,`singleline`),"multiline-export":X(Z.export,`multiline`),"singleline-var":X(Z.var,`singleline`),"multiline-var":X(Z.var,`multiline`),"singleline-let":X(Z.let,`singleline`),"multiline-let":X(Z.let,`multiline`),"singleline-const":X(Z.const,`singleline`),"multiline-const":X(Z.const,`multiline`),"singleline-using":X(Z.using,`singleline`),"multiline-using":X(Z.using,`multiline`),"singleline-type":X(Z.type,`singleline`),"multiline-type":X(Z.type,`multiline`)};function jn(e){return typeof e==`string`&&Object.hasOwn(Q,e)}function Mn(e){return Array.isArray(e)}function $(e){if(jn(e))return e;if(typeof e==`object`&&e&&`selector`in e&&typeof e.selector==`string`&&Object.keys(e).every(e=>e===`selector`||e===`lineMode`)){if(!(`lineMode`in e))return{selector:e.selector};if(e.lineMode===`any`||e.lineMode===`singleline`||e.lineMode===`multiline`)return{selector:e.selector,lineMode:e.lineMode}}throw Error(`Invalid padding-line-between-statements statement matcher`)}function Nn(e){if(!Array.isArray(e))return $(e);let t=e,n=t[0];if(n===void 0)throw Error(`Padding statement matcher arrays must not be empty`);return[$(n),...t.slice(1).map(e=>$(e))]}function Pn(e){return e.map(e=>{if(typeof e!=`object`||!e||!(`blankLine`in e)||!(`prev`in e)||!(`next`in e)||Object.keys(e).some(e=>![`blankLine`,`prev`,`next`].includes(e))||e.blankLine!==`any`&&e.blankLine!==`never`&&e.blankLine!==`always`)throw Error(`Invalid padding-line-between-statements configuration`);return{blankLine:e.blankLine,prev:Nn(e.prev),next:Nn(e.next)}})}function Fn(e,t,n){let r=[],i=kn(e,n);if(t.loc.start.line-i.loc.end.line>=2)do{let e=n.getTokenAfter(i,{includeComments:!0});if(e===null)throw Error(`Padding rule invariant: next statement token is missing`);e.loc.start.line-i.loc.end.line>=2&&r.push([i,e]),i=e}while(i.range[0]<t.range[0]);return r}function In(e,t,n){return o.gen(function*(){if(n===`any`)return yield*o.void;let i=yield*r,a=i.sourceCode,s=Fn(e,t,a);return n===`never`?s.length===0?yield*o.void:yield*i.report({node:t,messageId:`unexpectedBlankLine`,loc:An(t,a),fix(e){if(s.length>=2)return null;let t=s[0];if(t===void 0)throw Error(`Padding rule invariant: reported padding pair is missing`);let n=t[0].range[1],r=t[1].range[0];return e.replaceTextRange([n,r],a.text.slice(n,r).replace(vn,`$1$2`))}}):s.length>0?yield*o.void:yield*i.report({node:t,messageId:`expectedBlankLine`,loc:An(t,a),fix(n){let r=kn(e,a),i=a.getFirstTokenBetween(r,t,{includeComments:!0,filter(e){return!K(r,e)||(r=e,!1)}})??t;return n.insertTextAfter(r,K(r,i)?`
|
|
3
|
+
|
|
4
|
+
`:`
|
|
5
|
+
`)}})})}function*Ln(e,t){let n=e.sourceCode,r=new Set(t.flatMap(e=>[e.prev,e.next].flat().flatMap(e=>typeof e==`string`?[]:e.selector))),d=yield*u.make(new Map(Array.from(r,e=>[e,/* @__PURE__ */ new Set]))),f=yield*u.make(a.empty()),p=yield*u.make(l.none());function m(){return u.update(p,e=>l.some({upper:e,prevNode:l.none()}))}function h(){return u.update(p,l.flatMap(e=>e.upper))}function g(e,t,r){let i=e;for(;i.type===`LabeledStatement`;)i=i.body;return Mn(t)?t.some(e=>g(i,e,r)):typeof t==`string`?Q[t](i,n):r.get(t.selector)?.has(i)===!0&&(t.lineMode===`singleline`?q(i):t.lineMode!==`multiline`||!q(i))}let _=t.toReversed();function v(e,t,n){for(let r of _)if(g(e,r.prev,n)&&g(t,r.next,n))return r.blankLine;return`any`}let y=c.type().pipe(c.when({parent:c.null},s.constant(o.void)),c.not({parent:{type:c.is(`BlockStatement`,`Program`,`StaticBlock`,`SwitchCase`,`SwitchStatement`,`TSInterfaceBody`,`TSModuleBlock`,`TSTypeLiteral`)}},s.constant(o.void)),c.orElse(e=>o.gen(function*(){let t=yield*u.get(p);if(l.isNone(t))return yield*o.die(/* @__PURE__ */ Error(`Padding rule invariant: statement scope is missing`));if(l.isSome(t.value.prevNode)){let n=t.value.prevNode.value;yield*u.update(f,t=>(t.push({prevNode:n,nextNode:e}),t))}yield*u.set(p,l.some({upper:t.value.upper,prevNode:l.some(e)}))})));function b(e){return o.andThen(y(e),m())}let x={Program:m,"Program:exit":o.fn(`'Program:exit'`)(function*(){let e=yield*u.get(d);yield*u.get(f).pipe(o.flatMap(o.forEach(({prevNode:t,nextNode:n})=>In(t,n,v(t,n,e))))),yield*h()}),BlockStatement:m,"BlockStatement:exit":h,SwitchStatement:m,"SwitchStatement:exit":h,SwitchCase:b,"SwitchCase:exit":h,StaticBlock:m,"StaticBlock:exit":h,TSInterfaceBody:m,"TSInterfaceBody:exit":h,TSModuleBlock:m,"TSModuleBlock:exit":h,TSTypeLiteral:m,"TSTypeLiteral:exit":h,TSDeclareFunction:b,"TSDeclareFunction:exit":h,TSMethodSignature:b,"TSMethodSignature:exit":h,":statement":y};return i.merge(x,...Array.from(r,e=>i.on(e,t=>u.update(d,n=>(n.get(e)?.add(t),n)))))}const Rn={"alchemy-no-cloudflare-init-finalizer":le,"alchemy-no-deprecated-docker-constraints":pe,"alchemy-no-deprecated-resource":he,"alchemy-no-plaintext-github-secret":_e,"alchemy-no-removed-config-api":ve,"alchemy-no-reserved-eventbridge-default-name":ye,"alchemy-no-runtime-config":be,"alchemy-no-v1-import":xe,"alchemy-no-v1-worker-properties":Se,"avoid-data-tagged-error":Ce,"ban-error-string":Ee,"cors-credentials-with-wildcard":je,"dual-numeric-arity-with-optional-parameter":Ne,"effect-promise-vs-trypromise":Pe,"no-already-started-promise":Ie,"no-async-effect-try":Le,"no-discarded-run-promise":Re,"no-discarded-schema-checks":Be,"no-empty-effect-callback":Ze,"no-empty-schema-struct":Qe,"no-effect-alchemy-barrel-imports":Xe,"no-function-config-default":tt,"no-hash-as-identity":rt,"no-logging-in-catch":st,"no-manual-effect-error-tag":pt,"no-manual-tag-comparison":mt,"no-manual-tagged-construction":ht,"no-multi-shot-effect-callback":_t,"no-non-json-schema-annotation":xt,"no-option-of-service":St,"no-overwritten-discriminant":Ct,"no-service-option-get-or-throw":Dt,"no-service-constructor-imports":Et,"no-throw-in-effect-callback":kt,"no-uppercase-http-api-header":Pt,"no-zero-retry-times":Ft,"padding-line-between-statements":n.define({name:`padding-line-between-statements`,meta:{type:`layout`,docs:{description:`Require or disallow padding lines between statements`,url:`https://eslint.style/rules/padding-line-between-statements`,recommended:!0},fixable:`whitespace`,schema:{type:`array`,items:{type:`object`,properties:{blankLine:{enum:[`any`,`never`,`always`]},prev:{$ref:`#/$defs/statementOption`},next:{$ref:`#/$defs/statementOption`}},required:[`blankLine`,`prev`,`next`],additionalProperties:!1},$defs:{statementMatcher:{anyOf:[{type:`string`,enum:Object.keys(Q)},{type:`object`,properties:{selector:{type:`string`},lineMode:{enum:[`any`,`singleline`,`multiline`]}},required:[`selector`],additionalProperties:!1}]},statementOption:{anyOf:[{$ref:`#/$defs/statementMatcher`},{type:`array`,items:{$ref:`#/$defs/statementMatcher`},minItems:1,uniqueItems:!0}]}}},messages:{unexpectedBlankLine:`Unexpected blank line before this statement.`,expectedBlankLine:`Expected blank line before this statement.`}},*create(){let e=yield*r;return yield*Ln(e,Pn(e.options))}}),"prefer-effect-alchemy-namespace-imports":It,"prefer-effect-array-sort":Lt,"prefer-effect-datetime":zt,"prefer-effect-duration":Vt,"prefer-effect-encoding":Wt,"prefer-effect-filesystem":Kt,"prefer-effect-filter":Yt,"prefer-effect-headers":Xt,"prefer-effect-match":en,"prefer-effect-path":nn,"prefer-effect-url":rn,"prefer-uninterruptible":an,"prefer-with-span":on,"prefer-yield-now":cn,"preserve-caught-error":dn,"require-schema-class-brand":fn,"require-try-promise-abort-signal":mn,"throw-in-effect-gen":gn},zn=/* @__PURE__ */ new Set([`prefer-effect-filesystem`,`prefer-effect-path`]),Bn=Object.fromEntries(Object.keys(Rn).filter(e=>!zn.has(e)).map(e=>[`2digits/${e}`,`error`])),Vn=t({meta:{name:`@2digits/oxlint-plugin`},rules:Rn});export{Vn as default,Bn as recommendedRules,Rn as rules};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@2digits/oxlint-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Custom Oxlint rules for 2digits projects.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"2digits",
|
|
@@ -28,12 +28,16 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@oxlint/plugins": "1.
|
|
31
|
+
"@oxlint/plugins": "1.87.0",
|
|
32
|
+
"effect": "4.0.1",
|
|
33
|
+
"effect-oxlint": "0.4.0"
|
|
32
34
|
},
|
|
33
35
|
"devDependencies": {
|
|
34
36
|
"@2digits/tsconfig": "0.9.1",
|
|
35
37
|
"@arethetypeswrong/core": "0.18.5",
|
|
36
|
-
"
|
|
38
|
+
"@effect/vitest": "4.0.1",
|
|
39
|
+
"dedent": "1.7.2",
|
|
40
|
+
"oxlint": "1.87.0",
|
|
37
41
|
"publint": "0.3.25",
|
|
38
42
|
"typescript": "7.0.2",
|
|
39
43
|
"vite-plus": "1.0.0",
|