@timmo001/oxlint-rules 0.5.0 → 0.6.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/README.md +21 -2
- package/dist/cli.js +79 -14
- package/dist/configs/recommended-effect.js +126 -60
- package/dist/effect/index.js +70 -4
- package/package.json +10 -9
- package/skills/install-timmo-oxlint-rules/SKILL.md +18 -5
- package/src/effect/index.ts +2 -0
- package/src/effect/rules/no-raw-gh.ts +133 -0
package/README.md
CHANGED
|
@@ -69,6 +69,19 @@ the package configs to merge into the target Oxlint config. Effect settings
|
|
|
69
69
|
remain opt-in. It excludes tests and repository metadata, and refuses to
|
|
70
70
|
replace an existing destination unless `--force` is passed.
|
|
71
71
|
|
|
72
|
+
## Skills
|
|
73
|
+
|
|
74
|
+
[`install-timmo-oxlint-rules`](skills/install-timmo-oxlint-rules/SKILL.md)
|
|
75
|
+
guides agents through installing or copying these rules:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npx skills add timmo001/oxlint-rules --skill install-timmo-oxlint-rules
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
[`add-oxlint-rule`](skills/add-oxlint-rule/SKILL.md) and
|
|
82
|
+
[`release-oxlint-rules`](skills/release-oxlint-rules/SKILL.md) are for
|
|
83
|
+
maintaining this package.
|
|
84
|
+
|
|
72
85
|
## Rules
|
|
73
86
|
|
|
74
87
|
### `anti-slop` and `anti-slop-effect`
|
|
@@ -122,6 +135,13 @@ they only run when the consumer enables `typeAware`.
|
|
|
122
135
|
|
|
123
136
|
### `timmo-effect`
|
|
124
137
|
|
|
138
|
+
- `no-raw-gh`: reports the raw `execute`, `json` and `stream` methods called on
|
|
139
|
+
a `yield* Gh` binding from `@timmo001/effect-gh`, `Api.raw` from that package,
|
|
140
|
+
and calls that launch gh: `"gh"` followed by its arguments, such as
|
|
141
|
+
`executor.run("gh", ...)`, or an argument array starting with `"gh"`, such
|
|
142
|
+
as `Bun.spawn(["gh", ...])`. Use the
|
|
143
|
+
package's typed operations, and add one to effect-gh when a command has none.
|
|
144
|
+
effect-gh's own relative imports are not reported.
|
|
125
145
|
- `no-try-catch-in-effect-generators`: diagnoses synchronous `try/catch` owned
|
|
126
146
|
by generators passed directly to `Effect.gen` or the curried `Effect.fn`
|
|
127
147
|
form. It leaves ordinary async polling, nested callback boundaries,
|
|
@@ -139,8 +159,7 @@ Initialise the upstream source and run the package checks:
|
|
|
139
159
|
|
|
140
160
|
```sh
|
|
141
161
|
git submodule update --init --recursive
|
|
142
|
-
mise run check
|
|
143
|
-
mise run build
|
|
162
|
+
mise run check ::: build
|
|
144
163
|
mise run test:package
|
|
145
164
|
npm pack --dry-run
|
|
146
165
|
bunx jsr@0.14.3 publish --dry-run --allow-dirty
|
package/dist/cli.js
CHANGED
|
@@ -2985,8 +2985,72 @@ var recommended_default = recommended;
|
|
|
2985
2985
|
// src/effect/index.ts
|
|
2986
2986
|
import { eslintCompatPlugin as eslintCompatPlugin3 } from "@oxlint/plugins";
|
|
2987
2987
|
|
|
2988
|
-
// src/effect/rules/no-
|
|
2988
|
+
// src/effect/rules/no-raw-gh.ts
|
|
2989
2989
|
import { defineRule as defineRule24 } from "@oxlint/plugins";
|
|
2990
|
+
var PACKAGE = "@timmo001/effect-gh";
|
|
2991
|
+
var rawMethods = new Set(["execute", "json", "stream"]);
|
|
2992
|
+
function isEffectGhImport(sourceCode, identifier, name) {
|
|
2993
|
+
return resolveVariable(sourceCode, identifier)?.defs.some((definition) => {
|
|
2994
|
+
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== PACKAGE || definition.node.type !== "ImportSpecifier") {
|
|
2995
|
+
return false;
|
|
2996
|
+
}
|
|
2997
|
+
const imported = definition.node.imported;
|
|
2998
|
+
return (imported.type === "Identifier" ? imported.name : imported.value) === name;
|
|
2999
|
+
}) ?? false;
|
|
3000
|
+
}
|
|
3001
|
+
function isYieldGh(sourceCode, node) {
|
|
3002
|
+
return node?.type === "YieldExpression" && node.delegate && node.argument?.type === "Identifier" && isEffectGhImport(sourceCode, node.argument, "Gh");
|
|
3003
|
+
}
|
|
3004
|
+
function isGhBinding(sourceCode, identifier) {
|
|
3005
|
+
return resolveVariable(sourceCode, identifier)?.defs.some((definition) => definition.type === "Variable" && definition.node.type === "VariableDeclarator" && isYieldGh(sourceCode, definition.node.init)) ?? false;
|
|
3006
|
+
}
|
|
3007
|
+
function launchesGh(args) {
|
|
3008
|
+
const [command, argv] = args;
|
|
3009
|
+
if (command?.type === "Literal")
|
|
3010
|
+
return command.value === "gh" && argv !== undefined;
|
|
3011
|
+
if (command?.type !== "ArrayExpression")
|
|
3012
|
+
return false;
|
|
3013
|
+
const first = command.elements[0];
|
|
3014
|
+
return first?.type === "Literal" && first.value === "gh";
|
|
3015
|
+
}
|
|
3016
|
+
var noRawGhRule = defineRule24({
|
|
3017
|
+
meta: {
|
|
3018
|
+
type: "problem",
|
|
3019
|
+
docs: {
|
|
3020
|
+
description: "Use @timmo001/effect-gh typed operations instead of the raw Gh methods, Api.raw, or spawning gh directly."
|
|
3021
|
+
},
|
|
3022
|
+
messages: {
|
|
3023
|
+
rawGh: "Use a typed effect-gh operation instead of `Gh.{{method}}` with raw argv. Add one to effect-gh if the command has none.",
|
|
3024
|
+
rawApi: "Use `Api.json`, `Api.pages`, `Api.empty`, `Api.text` or `Api.headers` instead of `Api.raw`, so the response is typed.",
|
|
3025
|
+
spawnGh: "Run gh through a typed @timmo001/effect-gh operation instead of spawning it directly."
|
|
3026
|
+
}
|
|
3027
|
+
},
|
|
3028
|
+
create(context) {
|
|
3029
|
+
return {
|
|
3030
|
+
CallExpression(node) {
|
|
3031
|
+
const callee = node.callee;
|
|
3032
|
+
const method = staticMemberName(callee);
|
|
3033
|
+
if (callee.type === "MemberExpression" && method !== null) {
|
|
3034
|
+
const object = callee.object;
|
|
3035
|
+
if (rawMethods.has(method) && (isYieldGh(context.sourceCode, object) || object.type === "Identifier" && isGhBinding(context.sourceCode, object))) {
|
|
3036
|
+
context.report({ node, messageId: "rawGh", data: { method } });
|
|
3037
|
+
return;
|
|
3038
|
+
}
|
|
3039
|
+
if (method === "raw" && object.type === "Identifier" && isEffectGhImport(context.sourceCode, object, "Api")) {
|
|
3040
|
+
context.report({ node, messageId: "rawApi" });
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
if (launchesGh(node.arguments))
|
|
3045
|
+
context.report({ node, messageId: "spawnGh" });
|
|
3046
|
+
}
|
|
3047
|
+
};
|
|
3048
|
+
}
|
|
3049
|
+
});
|
|
3050
|
+
|
|
3051
|
+
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
3052
|
+
import { defineRule as defineRule25 } from "@oxlint/plugins";
|
|
3053
|
+
|
|
2990
3054
|
// src/shared/effect.ts
|
|
2991
3055
|
function isEffectImport(sourceCode, identifier, namespace) {
|
|
2992
3056
|
const variable = resolveVariable(sourceCode, identifier);
|
|
@@ -3033,7 +3097,7 @@ function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
|
3033
3097
|
const factoryCall = parent.callee;
|
|
3034
3098
|
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
3035
3099
|
}
|
|
3036
|
-
var noTryCatchInEffectGeneratorsRule =
|
|
3100
|
+
var noTryCatchInEffectGeneratorsRule = defineRule25({
|
|
3037
3101
|
meta: {
|
|
3038
3102
|
type: "problem",
|
|
3039
3103
|
docs: {
|
|
@@ -3059,7 +3123,7 @@ var noTryCatchInEffectGeneratorsRule = defineRule24({
|
|
|
3059
3123
|
});
|
|
3060
3124
|
|
|
3061
3125
|
// src/effect/rules/prefer-platform-services.ts
|
|
3062
|
-
import { defineRule as
|
|
3126
|
+
import { defineRule as defineRule26 } from "@oxlint/plugins";
|
|
3063
3127
|
var moduleServices = new Map([
|
|
3064
3128
|
["child_process", "childProcess"],
|
|
3065
3129
|
["fs", "fileSystem"],
|
|
@@ -3072,7 +3136,7 @@ var bunServices = new Map([
|
|
|
3072
3136
|
["spawnSync", "childProcess"],
|
|
3073
3137
|
["write", "fileSystem"]
|
|
3074
3138
|
]);
|
|
3075
|
-
var preferPlatformServicesRule =
|
|
3139
|
+
var preferPlatformServicesRule = defineRule26({
|
|
3076
3140
|
meta: {
|
|
3077
3141
|
type: "suggestion",
|
|
3078
3142
|
docs: {
|
|
@@ -3135,6 +3199,7 @@ var preferPlatformServicesRule = defineRule25({
|
|
|
3135
3199
|
var timmoEffectPlugin = eslintCompatPlugin3({
|
|
3136
3200
|
meta: { name: "timmo-effect" },
|
|
3137
3201
|
rules: {
|
|
3202
|
+
"no-raw-gh": noRawGhRule,
|
|
3138
3203
|
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule,
|
|
3139
3204
|
"prefer-platform-services": preferPlatformServicesRule
|
|
3140
3205
|
}
|
|
@@ -3145,7 +3210,7 @@ var effect_default = timmoEffectPlugin;
|
|
|
3145
3210
|
import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
|
|
3146
3211
|
|
|
3147
3212
|
// vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
|
|
3148
|
-
import { defineRule as
|
|
3213
|
+
import { defineRule as defineRule27 } from "@oxlint/plugins";
|
|
3149
3214
|
|
|
3150
3215
|
// vendor/anti-slop/src/effect/shared/tagged-values.ts
|
|
3151
3216
|
var equalityOperators = new Set(["==", "===", "!=", "!=="]);
|
|
@@ -3192,7 +3257,7 @@ var isMatchPatternObject = (node) => {
|
|
|
3192
3257
|
};
|
|
3193
3258
|
|
|
3194
3259
|
// vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
|
|
3195
|
-
var noManualEffectErrorTagRule =
|
|
3260
|
+
var noManualEffectErrorTagRule = defineRule27({
|
|
3196
3261
|
meta: {
|
|
3197
3262
|
type: "problem",
|
|
3198
3263
|
docs: {
|
|
@@ -3229,8 +3294,8 @@ var noManualEffectErrorTagRule = defineRule26({
|
|
|
3229
3294
|
});
|
|
3230
3295
|
|
|
3231
3296
|
// vendor/anti-slop/src/effect/rules/no-manual-tag-comparison.ts
|
|
3232
|
-
import { defineRule as
|
|
3233
|
-
var noManualTagComparisonRule =
|
|
3297
|
+
import { defineRule as defineRule28 } from "@oxlint/plugins";
|
|
3298
|
+
var noManualTagComparisonRule = defineRule28({
|
|
3234
3299
|
meta: {
|
|
3235
3300
|
type: "problem",
|
|
3236
3301
|
docs: {
|
|
@@ -3260,8 +3325,8 @@ var noManualTagComparisonRule = defineRule27({
|
|
|
3260
3325
|
});
|
|
3261
3326
|
|
|
3262
3327
|
// vendor/anti-slop/src/effect/rules/no-manual-tagged-construction.ts
|
|
3263
|
-
import { defineRule as
|
|
3264
|
-
var noManualTaggedConstructionRule =
|
|
3328
|
+
import { defineRule as defineRule29 } from "@oxlint/plugins";
|
|
3329
|
+
var noManualTaggedConstructionRule = defineRule29({
|
|
3265
3330
|
meta: {
|
|
3266
3331
|
type: "problem",
|
|
3267
3332
|
docs: {
|
|
@@ -3286,7 +3351,7 @@ var noManualTaggedConstructionRule = defineRule28({
|
|
|
3286
3351
|
});
|
|
3287
3352
|
|
|
3288
3353
|
// vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
|
|
3289
|
-
import { defineRule as
|
|
3354
|
+
import { defineRule as defineRule30 } from "@oxlint/plugins";
|
|
3290
3355
|
var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
|
|
3291
3356
|
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
|
|
3292
3357
|
function isProjectLocalImport(source) {
|
|
@@ -3297,7 +3362,7 @@ function getImportedName(specifier) {
|
|
|
3297
3362
|
return specifier.imported.name;
|
|
3298
3363
|
return specifier.imported.value;
|
|
3299
3364
|
}
|
|
3300
|
-
var noServiceConstructorImportsRule =
|
|
3365
|
+
var noServiceConstructorImportsRule = defineRule30({
|
|
3301
3366
|
meta: {
|
|
3302
3367
|
type: "problem",
|
|
3303
3368
|
docs: {
|
|
@@ -3331,9 +3396,9 @@ var noServiceConstructorImportsRule = defineRule29({
|
|
|
3331
3396
|
});
|
|
3332
3397
|
|
|
3333
3398
|
// vendor/anti-slop/src/effect/rules/prefer-effect-match.ts
|
|
3334
|
-
import { defineRule as
|
|
3399
|
+
import { defineRule as defineRule31 } from "@oxlint/plugins";
|
|
3335
3400
|
var equalityOperators2 = new Set(["==", "===", "!=", "!=="]);
|
|
3336
|
-
var preferEffectMatchRule =
|
|
3401
|
+
var preferEffectMatchRule = defineRule31({
|
|
3337
3402
|
meta: {
|
|
3338
3403
|
type: "problem",
|
|
3339
3404
|
docs: {
|
|
@@ -6,7 +6,7 @@ function defineConfig(config) {
|
|
|
6
6
|
// src/effect/index.ts
|
|
7
7
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
8
8
|
|
|
9
|
-
// src/effect/rules/no-
|
|
9
|
+
// src/effect/rules/no-raw-gh.ts
|
|
10
10
|
import { defineRule } from "@oxlint/plugins";
|
|
11
11
|
|
|
12
12
|
// src/shared/ast.ts
|
|
@@ -37,6 +37,71 @@ function resolveVariable(sourceCode, identifier) {
|
|
|
37
37
|
}
|
|
38
38
|
return null;
|
|
39
39
|
}
|
|
40
|
+
// src/effect/rules/no-raw-gh.ts
|
|
41
|
+
var PACKAGE = "@timmo001/effect-gh";
|
|
42
|
+
var rawMethods = new Set(["execute", "json", "stream"]);
|
|
43
|
+
function isEffectGhImport(sourceCode, identifier, name) {
|
|
44
|
+
return resolveVariable(sourceCode, identifier)?.defs.some((definition) => {
|
|
45
|
+
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== PACKAGE || definition.node.type !== "ImportSpecifier") {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const imported = definition.node.imported;
|
|
49
|
+
return (imported.type === "Identifier" ? imported.name : imported.value) === name;
|
|
50
|
+
}) ?? false;
|
|
51
|
+
}
|
|
52
|
+
function isYieldGh(sourceCode, node) {
|
|
53
|
+
return node?.type === "YieldExpression" && node.delegate && node.argument?.type === "Identifier" && isEffectGhImport(sourceCode, node.argument, "Gh");
|
|
54
|
+
}
|
|
55
|
+
function isGhBinding(sourceCode, identifier) {
|
|
56
|
+
return resolveVariable(sourceCode, identifier)?.defs.some((definition) => definition.type === "Variable" && definition.node.type === "VariableDeclarator" && isYieldGh(sourceCode, definition.node.init)) ?? false;
|
|
57
|
+
}
|
|
58
|
+
function launchesGh(args) {
|
|
59
|
+
const [command, argv] = args;
|
|
60
|
+
if (command?.type === "Literal")
|
|
61
|
+
return command.value === "gh" && argv !== undefined;
|
|
62
|
+
if (command?.type !== "ArrayExpression")
|
|
63
|
+
return false;
|
|
64
|
+
const first = command.elements[0];
|
|
65
|
+
return first?.type === "Literal" && first.value === "gh";
|
|
66
|
+
}
|
|
67
|
+
var noRawGhRule = defineRule({
|
|
68
|
+
meta: {
|
|
69
|
+
type: "problem",
|
|
70
|
+
docs: {
|
|
71
|
+
description: "Use @timmo001/effect-gh typed operations instead of the raw Gh methods, Api.raw, or spawning gh directly."
|
|
72
|
+
},
|
|
73
|
+
messages: {
|
|
74
|
+
rawGh: "Use a typed effect-gh operation instead of `Gh.{{method}}` with raw argv. Add one to effect-gh if the command has none.",
|
|
75
|
+
rawApi: "Use `Api.json`, `Api.pages`, `Api.empty`, `Api.text` or `Api.headers` instead of `Api.raw`, so the response is typed.",
|
|
76
|
+
spawnGh: "Run gh through a typed @timmo001/effect-gh operation instead of spawning it directly."
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
create(context) {
|
|
80
|
+
return {
|
|
81
|
+
CallExpression(node) {
|
|
82
|
+
const callee = node.callee;
|
|
83
|
+
const method = staticMemberName(callee);
|
|
84
|
+
if (callee.type === "MemberExpression" && method !== null) {
|
|
85
|
+
const object = callee.object;
|
|
86
|
+
if (rawMethods.has(method) && (isYieldGh(context.sourceCode, object) || object.type === "Identifier" && isGhBinding(context.sourceCode, object))) {
|
|
87
|
+
context.report({ node, messageId: "rawGh", data: { method } });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (method === "raw" && object.type === "Identifier" && isEffectGhImport(context.sourceCode, object, "Api")) {
|
|
91
|
+
context.report({ node, messageId: "rawApi" });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (launchesGh(node.arguments))
|
|
96
|
+
context.report({ node, messageId: "spawnGh" });
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
103
|
+
import { defineRule as defineRule2 } from "@oxlint/plugins";
|
|
104
|
+
|
|
40
105
|
// src/shared/effect.ts
|
|
41
106
|
function isEffectImport(sourceCode, identifier, namespace) {
|
|
42
107
|
const variable = resolveVariable(sourceCode, identifier);
|
|
@@ -83,7 +148,7 @@ function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
|
83
148
|
const factoryCall = parent.callee;
|
|
84
149
|
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
85
150
|
}
|
|
86
|
-
var noTryCatchInEffectGeneratorsRule =
|
|
151
|
+
var noTryCatchInEffectGeneratorsRule = defineRule2({
|
|
87
152
|
meta: {
|
|
88
153
|
type: "problem",
|
|
89
154
|
docs: {
|
|
@@ -109,7 +174,7 @@ var noTryCatchInEffectGeneratorsRule = defineRule({
|
|
|
109
174
|
});
|
|
110
175
|
|
|
111
176
|
// src/effect/rules/prefer-platform-services.ts
|
|
112
|
-
import { defineRule as
|
|
177
|
+
import { defineRule as defineRule3 } from "@oxlint/plugins";
|
|
113
178
|
var moduleServices = new Map([
|
|
114
179
|
["child_process", "childProcess"],
|
|
115
180
|
["fs", "fileSystem"],
|
|
@@ -122,7 +187,7 @@ var bunServices = new Map([
|
|
|
122
187
|
["spawnSync", "childProcess"],
|
|
123
188
|
["write", "fileSystem"]
|
|
124
189
|
]);
|
|
125
|
-
var preferPlatformServicesRule =
|
|
190
|
+
var preferPlatformServicesRule = defineRule3({
|
|
126
191
|
meta: {
|
|
127
192
|
type: "suggestion",
|
|
128
193
|
docs: {
|
|
@@ -185,6 +250,7 @@ var preferPlatformServicesRule = defineRule2({
|
|
|
185
250
|
var timmoEffectPlugin = eslintCompatPlugin({
|
|
186
251
|
meta: { name: "timmo-effect" },
|
|
187
252
|
rules: {
|
|
253
|
+
"no-raw-gh": noRawGhRule,
|
|
188
254
|
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule,
|
|
189
255
|
"prefer-platform-services": preferPlatformServicesRule
|
|
190
256
|
}
|
|
@@ -195,7 +261,7 @@ var effect_default = timmoEffectPlugin;
|
|
|
195
261
|
import { eslintCompatPlugin as eslintCompatPlugin2 } from "@oxlint/plugins";
|
|
196
262
|
|
|
197
263
|
// vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
|
|
198
|
-
import { defineRule as
|
|
264
|
+
import { defineRule as defineRule4 } from "@oxlint/plugins";
|
|
199
265
|
|
|
200
266
|
// vendor/anti-slop/src/effect/shared/tagged-values.ts
|
|
201
267
|
var equalityOperators = new Set(["==", "===", "!=", "!=="]);
|
|
@@ -242,7 +308,7 @@ var isMatchPatternObject = (node) => {
|
|
|
242
308
|
};
|
|
243
309
|
|
|
244
310
|
// vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
|
|
245
|
-
var noManualEffectErrorTagRule =
|
|
311
|
+
var noManualEffectErrorTagRule = defineRule4({
|
|
246
312
|
meta: {
|
|
247
313
|
type: "problem",
|
|
248
314
|
docs: {
|
|
@@ -279,8 +345,8 @@ var noManualEffectErrorTagRule = defineRule3({
|
|
|
279
345
|
});
|
|
280
346
|
|
|
281
347
|
// vendor/anti-slop/src/effect/rules/no-manual-tag-comparison.ts
|
|
282
|
-
import { defineRule as
|
|
283
|
-
var noManualTagComparisonRule =
|
|
348
|
+
import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
349
|
+
var noManualTagComparisonRule = defineRule5({
|
|
284
350
|
meta: {
|
|
285
351
|
type: "problem",
|
|
286
352
|
docs: {
|
|
@@ -310,8 +376,8 @@ var noManualTagComparisonRule = defineRule4({
|
|
|
310
376
|
});
|
|
311
377
|
|
|
312
378
|
// vendor/anti-slop/src/effect/rules/no-manual-tagged-construction.ts
|
|
313
|
-
import { defineRule as
|
|
314
|
-
var noManualTaggedConstructionRule =
|
|
379
|
+
import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
380
|
+
var noManualTaggedConstructionRule = defineRule6({
|
|
315
381
|
meta: {
|
|
316
382
|
type: "problem",
|
|
317
383
|
docs: {
|
|
@@ -336,7 +402,7 @@ var noManualTaggedConstructionRule = defineRule5({
|
|
|
336
402
|
});
|
|
337
403
|
|
|
338
404
|
// vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
|
|
339
|
-
import { defineRule as
|
|
405
|
+
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
340
406
|
var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
|
|
341
407
|
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
|
|
342
408
|
function isProjectLocalImport(source) {
|
|
@@ -347,7 +413,7 @@ function getImportedName(specifier) {
|
|
|
347
413
|
return specifier.imported.name;
|
|
348
414
|
return specifier.imported.value;
|
|
349
415
|
}
|
|
350
|
-
var noServiceConstructorImportsRule =
|
|
416
|
+
var noServiceConstructorImportsRule = defineRule7({
|
|
351
417
|
meta: {
|
|
352
418
|
type: "problem",
|
|
353
419
|
docs: {
|
|
@@ -381,9 +447,9 @@ var noServiceConstructorImportsRule = defineRule6({
|
|
|
381
447
|
});
|
|
382
448
|
|
|
383
449
|
// vendor/anti-slop/src/effect/rules/prefer-effect-match.ts
|
|
384
|
-
import { defineRule as
|
|
450
|
+
import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
385
451
|
var equalityOperators2 = new Set(["==", "===", "!=", "!=="]);
|
|
386
|
-
var preferEffectMatchRule =
|
|
452
|
+
var preferEffectMatchRule = defineRule8({
|
|
387
453
|
meta: {
|
|
388
454
|
type: "problem",
|
|
389
455
|
docs: {
|
|
@@ -449,7 +515,7 @@ function enablePluginRules(namespace, plugin) {
|
|
|
449
515
|
import { eslintCompatPlugin as eslintCompatPlugin3 } from "@oxlint/plugins";
|
|
450
516
|
|
|
451
517
|
// vendor/anti-slop/src/rules/no-array-filter-map.ts
|
|
452
|
-
import { defineRule as
|
|
518
|
+
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
453
519
|
|
|
454
520
|
// vendor/anti-slop/src/shared/array-method.ts
|
|
455
521
|
function unwrapArrayExpression(node) {
|
|
@@ -524,7 +590,7 @@ function isKnownArrayExpression(sourceCode, node, visited = new Set) {
|
|
|
524
590
|
}
|
|
525
591
|
|
|
526
592
|
// vendor/anti-slop/src/rules/no-array-filter-map.ts
|
|
527
|
-
var noArrayFilterMapRule =
|
|
593
|
+
var noArrayFilterMapRule = defineRule9({
|
|
528
594
|
meta: {
|
|
529
595
|
type: "suggestion",
|
|
530
596
|
docs: { description: "Disallow adjacent array filter/map passes in favor of lazy iterator helpers or a single transformation." },
|
|
@@ -553,7 +619,7 @@ var noArrayFilterMapRule = defineRule8({
|
|
|
553
619
|
});
|
|
554
620
|
|
|
555
621
|
// vendor/anti-slop/src/rules/no-reduce-accumulator-copy.ts
|
|
556
|
-
import { defineRule as
|
|
622
|
+
import { defineRule as defineRule10 } from "@oxlint/plugins";
|
|
557
623
|
function enclosingReducer(node) {
|
|
558
624
|
let parent = node.parent;
|
|
559
625
|
while (parent !== null) {
|
|
@@ -603,7 +669,7 @@ function isGlobalCopyOwner(sourceCode, node, name) {
|
|
|
603
669
|
const variable = resolveArrayBinding(sourceCode, node);
|
|
604
670
|
return variable === null || variable.defs.length === 0;
|
|
605
671
|
}
|
|
606
|
-
var noReduceAccumulatorCopyRule =
|
|
672
|
+
var noReduceAccumulatorCopyRule = defineRule10({
|
|
607
673
|
meta: {
|
|
608
674
|
type: "problem",
|
|
609
675
|
docs: { description: "Disallow copying growing reducer accumulators with Object.assign, Array.from, or array copy methods." },
|
|
@@ -644,7 +710,7 @@ var noReduceAccumulatorCopyRule = defineRule9({
|
|
|
644
710
|
});
|
|
645
711
|
|
|
646
712
|
// vendor/anti-slop/src/rules/no-chained-type-assertions.ts
|
|
647
|
-
import { defineRule as
|
|
713
|
+
import { defineRule as defineRule11 } from "@oxlint/plugins";
|
|
648
714
|
function isTypeAssertionExpression(node) {
|
|
649
715
|
return node.type === "TSAsExpression" || node.type === "TSTypeAssertion";
|
|
650
716
|
}
|
|
@@ -679,7 +745,7 @@ function isForbiddenAssertionChain(node) {
|
|
|
679
745
|
}
|
|
680
746
|
return assertionCount > 1 && hasNonConstAssertion;
|
|
681
747
|
}
|
|
682
|
-
var noChainedTypeAssertionsRule =
|
|
748
|
+
var noChainedTypeAssertionsRule = defineRule11({
|
|
683
749
|
meta: {
|
|
684
750
|
type: "problem",
|
|
685
751
|
docs: {
|
|
@@ -703,7 +769,7 @@ var noChainedTypeAssertionsRule = defineRule10({
|
|
|
703
769
|
});
|
|
704
770
|
|
|
705
771
|
// vendor/anti-slop/src/rules/no-conditional-empty-object-spread.ts
|
|
706
|
-
import { defineRule as
|
|
772
|
+
import { defineRule as defineRule12 } from "@oxlint/plugins";
|
|
707
773
|
function unwrapParentheses(node) {
|
|
708
774
|
let current = node;
|
|
709
775
|
while (current.type === "ParenthesizedExpression") {
|
|
@@ -718,7 +784,7 @@ function isConditionalEmptyObjectSpread(node) {
|
|
|
718
784
|
const conditional = unwrapParentheses(node);
|
|
719
785
|
return conditional.type === "ConditionalExpression" && (isEmptyObjectExpression(conditional.consequent) || isEmptyObjectExpression(conditional.alternate));
|
|
720
786
|
}
|
|
721
|
-
var noConditionalEmptyObjectSpreadRule =
|
|
787
|
+
var noConditionalEmptyObjectSpreadRule = defineRule12({
|
|
722
788
|
meta: {
|
|
723
789
|
type: "suggestion",
|
|
724
790
|
docs: {
|
|
@@ -742,7 +808,7 @@ var noConditionalEmptyObjectSpreadRule = defineRule11({
|
|
|
742
808
|
});
|
|
743
809
|
|
|
744
810
|
// vendor/anti-slop/src/rules/no-known-value-widening.ts
|
|
745
|
-
import { defineRule as
|
|
811
|
+
import { defineRule as defineRule13 } from "@oxlint/plugins";
|
|
746
812
|
|
|
747
813
|
// vendor/anti-slop/src/shared/lexical-type-parameters.ts
|
|
748
814
|
function isNode(value) {
|
|
@@ -1431,7 +1497,7 @@ function isDictionaryAccumulatorTarget(destination) {
|
|
|
1431
1497
|
function hasParentAssertion(node) {
|
|
1432
1498
|
return node.parent?.type === "TSAsExpression" || node.parent?.type === "TSTypeAssertion";
|
|
1433
1499
|
}
|
|
1434
|
-
var noKnownValueWideningRule =
|
|
1500
|
+
var noKnownValueWideningRule = defineRule13({
|
|
1435
1501
|
meta: {
|
|
1436
1502
|
type: "problem",
|
|
1437
1503
|
docs: {
|
|
@@ -1544,7 +1610,7 @@ var noKnownValueWideningRule = defineRule12({
|
|
|
1544
1610
|
});
|
|
1545
1611
|
|
|
1546
1612
|
// vendor/anti-slop/src/rules/no-module-mocking.ts
|
|
1547
|
-
import { defineRule as
|
|
1613
|
+
import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
1548
1614
|
var moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]);
|
|
1549
1615
|
function importedName(node) {
|
|
1550
1616
|
if (node.type !== "ImportSpecifier")
|
|
@@ -1579,7 +1645,7 @@ function moduleMockCall(sourceCode, callee) {
|
|
|
1579
1645
|
const method = callee.computed ? property.type === "Literal" && (property.value === "doMock" || property.value === "mock" || property.value === "unstable_mockModule") ? property.value : null : property.type === "Identifier" ? property.name : null;
|
|
1580
1646
|
return method !== null && moduleMockMethods.has(method);
|
|
1581
1647
|
}
|
|
1582
|
-
var noModuleMockingRule =
|
|
1648
|
+
var noModuleMockingRule = defineRule14({
|
|
1583
1649
|
meta: {
|
|
1584
1650
|
type: "problem",
|
|
1585
1651
|
docs: {
|
|
@@ -1603,8 +1669,8 @@ var noModuleMockingRule = defineRule13({
|
|
|
1603
1669
|
});
|
|
1604
1670
|
|
|
1605
1671
|
// vendor/anti-slop/src/rules/no-object-parameters.ts
|
|
1606
|
-
import { defineRule as
|
|
1607
|
-
var noObjectParametersRule =
|
|
1672
|
+
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
1673
|
+
var noObjectParametersRule = defineRule15({
|
|
1608
1674
|
meta: {
|
|
1609
1675
|
type: "problem",
|
|
1610
1676
|
docs: {
|
|
@@ -1657,7 +1723,7 @@ var noObjectParametersRule = defineRule14({
|
|
|
1657
1723
|
});
|
|
1658
1724
|
|
|
1659
1725
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1660
|
-
import { defineRule as
|
|
1726
|
+
import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
1661
1727
|
|
|
1662
1728
|
// vendor/anti-slop/src/shared/reflect-method.ts
|
|
1663
1729
|
function isGlobalReflect(sourceCode, expression) {
|
|
@@ -1678,7 +1744,7 @@ function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
|
1678
1744
|
}
|
|
1679
1745
|
|
|
1680
1746
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1681
|
-
var noReflectApplyRule =
|
|
1747
|
+
var noReflectApplyRule = defineRule16({
|
|
1682
1748
|
meta: {
|
|
1683
1749
|
type: "problem",
|
|
1684
1750
|
docs: {
|
|
@@ -1702,8 +1768,8 @@ var noReflectApplyRule = defineRule15({
|
|
|
1702
1768
|
});
|
|
1703
1769
|
|
|
1704
1770
|
// vendor/anti-slop/src/rules/no-reflect-get.ts
|
|
1705
|
-
import { defineRule as
|
|
1706
|
-
var noReflectGetRule =
|
|
1771
|
+
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
1772
|
+
var noReflectGetRule = defineRule17({
|
|
1707
1773
|
meta: {
|
|
1708
1774
|
type: "problem",
|
|
1709
1775
|
docs: {
|
|
@@ -1727,7 +1793,7 @@ var noReflectGetRule = defineRule16({
|
|
|
1727
1793
|
});
|
|
1728
1794
|
|
|
1729
1795
|
// vendor/anti-slop/src/rules/no-runtime-typeof.ts
|
|
1730
|
-
import { defineRule as
|
|
1796
|
+
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
1731
1797
|
function isRuntimeFunction(node) {
|
|
1732
1798
|
return node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression";
|
|
1733
1799
|
}
|
|
@@ -1750,7 +1816,7 @@ function isExistenceProbe(node) {
|
|
|
1750
1816
|
const other = parent.left === node ? parent.right : parent.left;
|
|
1751
1817
|
return other.type === "Literal" && other.value === "undefined";
|
|
1752
1818
|
}
|
|
1753
|
-
var noRuntimeTypeofRule =
|
|
1819
|
+
var noRuntimeTypeofRule = defineRule18({
|
|
1754
1820
|
meta: {
|
|
1755
1821
|
type: "problem",
|
|
1756
1822
|
docs: {
|
|
@@ -1784,7 +1850,7 @@ var noRuntimeTypeofRule = defineRule17({
|
|
|
1784
1850
|
});
|
|
1785
1851
|
|
|
1786
1852
|
// vendor/anti-slop/src/rules/no-shape-in-symbol-names.ts
|
|
1787
|
-
import { defineRule as
|
|
1853
|
+
import { defineRule as defineRule19 } from "@oxlint/plugins";
|
|
1788
1854
|
var FORBIDDEN_SYMBOL_NAME = "shape";
|
|
1789
1855
|
function containsForbiddenSymbolName(name) {
|
|
1790
1856
|
return name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME);
|
|
@@ -1795,7 +1861,7 @@ function isBorrowedMemberName(node) {
|
|
|
1795
1861
|
return false;
|
|
1796
1862
|
return parent.property === node && parent.computed === false;
|
|
1797
1863
|
}
|
|
1798
|
-
var noForbiddenTermInSymbolNamesRule =
|
|
1864
|
+
var noForbiddenTermInSymbolNamesRule = defineRule19({
|
|
1799
1865
|
meta: {
|
|
1800
1866
|
type: "problem",
|
|
1801
1867
|
docs: {
|
|
@@ -1824,12 +1890,12 @@ var noForbiddenTermInSymbolNamesRule = defineRule18({
|
|
|
1824
1890
|
});
|
|
1825
1891
|
|
|
1826
1892
|
// vendor/anti-slop/src/rules/no-unknown-parameters.ts
|
|
1827
|
-
import { defineRule as
|
|
1893
|
+
import { defineRule as defineRule20 } from "@oxlint/plugins";
|
|
1828
1894
|
function isTypePredicateSubject(owner, parameterName) {
|
|
1829
1895
|
const predicate = owner.returnType?.typeAnnotation;
|
|
1830
1896
|
return predicate?.type === "TSTypePredicate" && predicate.parameterName.type === "Identifier" && predicate.parameterName.name === parameterName;
|
|
1831
1897
|
}
|
|
1832
|
-
var noUnknownParametersRule =
|
|
1898
|
+
var noUnknownParametersRule = defineRule20({
|
|
1833
1899
|
meta: {
|
|
1834
1900
|
type: "problem",
|
|
1835
1901
|
docs: {
|
|
@@ -1873,8 +1939,8 @@ var noUnknownParametersRule = defineRule19({
|
|
|
1873
1939
|
});
|
|
1874
1940
|
|
|
1875
1941
|
// vendor/anti-slop/src/rules/no-unknown-returns.ts
|
|
1876
|
-
import { defineRule as
|
|
1877
|
-
var noUnknownReturnsRule =
|
|
1942
|
+
import { defineRule as defineRule21 } from "@oxlint/plugins";
|
|
1943
|
+
var noUnknownReturnsRule = defineRule21({
|
|
1878
1944
|
meta: {
|
|
1879
1945
|
type: "problem",
|
|
1880
1946
|
docs: {
|
|
@@ -1927,8 +1993,8 @@ var noUnknownReturnsRule = defineRule20({
|
|
|
1927
1993
|
});
|
|
1928
1994
|
|
|
1929
1995
|
// vendor/anti-slop/src/rules/no-unknown-type-aliases.ts
|
|
1930
|
-
import { defineRule as
|
|
1931
|
-
var noUnknownTypeAliasesRule =
|
|
1996
|
+
import { defineRule as defineRule22 } from "@oxlint/plugins";
|
|
1997
|
+
var noUnknownTypeAliasesRule = defineRule22({
|
|
1932
1998
|
meta: {
|
|
1933
1999
|
type: "problem",
|
|
1934
2000
|
docs: {
|
|
@@ -1966,7 +2032,7 @@ var noUnknownTypeAliasesRule = defineRule21({
|
|
|
1966
2032
|
});
|
|
1967
2033
|
|
|
1968
2034
|
// vendor/anti-slop/src/rules/no-unsafe-dictionary-type.ts
|
|
1969
|
-
import { defineRule as
|
|
2035
|
+
import { defineRule as defineRule23 } from "@oxlint/plugins";
|
|
1970
2036
|
var typeNodeKinds = new Set([
|
|
1971
2037
|
"JSDocNonNullableType",
|
|
1972
2038
|
"JSDocNullableType",
|
|
@@ -2053,7 +2119,7 @@ function shouldReportType(node, environment) {
|
|
|
2053
2119
|
}
|
|
2054
2120
|
return true;
|
|
2055
2121
|
}
|
|
2056
|
-
var noUnsafeDictionaryTypeRule =
|
|
2122
|
+
var noUnsafeDictionaryTypeRule = defineRule23({
|
|
2057
2123
|
meta: {
|
|
2058
2124
|
type: "problem",
|
|
2059
2125
|
docs: {
|
|
@@ -2095,7 +2161,7 @@ var noUnsafeDictionaryTypeRule = defineRule22({
|
|
|
2095
2161
|
});
|
|
2096
2162
|
|
|
2097
2163
|
// vendor/anti-slop/src/rules/no-widen-then-assert.ts
|
|
2098
|
-
import { defineRule as
|
|
2164
|
+
import { defineRule as defineRule24 } from "@oxlint/plugins";
|
|
2099
2165
|
var functionBoundaryTypes = new Set([
|
|
2100
2166
|
"ArrowFunctionExpression",
|
|
2101
2167
|
"FunctionDeclaration",
|
|
@@ -2291,7 +2357,7 @@ function assertionIsNarrower(sourceText, broadKind, evidence, assertedType) {
|
|
|
2291
2357
|
return isDefinitelyObjectType(assertedType);
|
|
2292
2358
|
return isDefinitelyNarrowerRecordType(assertedType);
|
|
2293
2359
|
}
|
|
2294
|
-
var noWidenThenAssertRule =
|
|
2360
|
+
var noWidenThenAssertRule = defineRule24({
|
|
2295
2361
|
meta: {
|
|
2296
2362
|
type: "problem",
|
|
2297
2363
|
docs: {
|
|
@@ -2853,7 +2919,7 @@ var requireReadableSpacingRule = {
|
|
|
2853
2919
|
};
|
|
2854
2920
|
|
|
2855
2921
|
// vendor/anti-slop/src/rules/require-safety-comment-for-type-assertion.ts
|
|
2856
|
-
import { defineRule as
|
|
2922
|
+
import { defineRule as defineRule25 } from "@oxlint/plugins";
|
|
2857
2923
|
var DEFAULT_SAFETY_MARKERS = ["SAFETY"];
|
|
2858
2924
|
var commentOwnerKinds = new Set([
|
|
2859
2925
|
"ExpressionStatement",
|
|
@@ -2896,7 +2962,7 @@ function hasSafetyComment(sourceCode, node, pattern) {
|
|
|
2896
2962
|
current = current.parent;
|
|
2897
2963
|
}
|
|
2898
2964
|
}
|
|
2899
|
-
var requireSafetyCommentForTypeAssertionRule =
|
|
2965
|
+
var requireSafetyCommentForTypeAssertionRule = defineRule25({
|
|
2900
2966
|
meta: {
|
|
2901
2967
|
type: "problem",
|
|
2902
2968
|
docs: {
|
|
@@ -2974,7 +3040,7 @@ var src_default = antiSlopPlugin;
|
|
|
2974
3040
|
import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
|
|
2975
3041
|
|
|
2976
3042
|
// src/generic/rules/no-explicit-inferable-type-predicate.ts
|
|
2977
|
-
import { defineRule as
|
|
3043
|
+
import { defineRule as defineRule26 } from "@oxlint/plugins";
|
|
2978
3044
|
function isNamed(node, name) {
|
|
2979
3045
|
return node.type === "Identifier" && node.name === name;
|
|
2980
3046
|
}
|
|
@@ -3014,7 +3080,7 @@ function isPublicSignature(owner) {
|
|
|
3014
3080
|
}
|
|
3015
3081
|
return parent.type === "VariableDeclarator" && parent.parent.parent?.type === "ExportNamedDeclaration";
|
|
3016
3082
|
}
|
|
3017
|
-
var noExplicitInferableTypePredicateRule =
|
|
3083
|
+
var noExplicitInferableTypePredicateRule = defineRule26({
|
|
3018
3084
|
meta: {
|
|
3019
3085
|
type: "suggestion",
|
|
3020
3086
|
docs: {
|
|
@@ -3050,7 +3116,7 @@ var noExplicitInferableTypePredicateRule = defineRule25({
|
|
|
3050
3116
|
});
|
|
3051
3117
|
|
|
3052
3118
|
// src/generic/rules/no-unchecked-query-selector-type.ts
|
|
3053
|
-
import { defineRule as
|
|
3119
|
+
import { defineRule as defineRule27 } from "@oxlint/plugins";
|
|
3054
3120
|
|
|
3055
3121
|
// src/shared/json.ts
|
|
3056
3122
|
function jsonObject(value) {
|
|
@@ -3151,7 +3217,7 @@ function isLitRenderRootQuery(node, bases) {
|
|
|
3151
3217
|
|
|
3152
3218
|
// src/generic/rules/no-unchecked-query-selector-type.ts
|
|
3153
3219
|
var queryMethods = new Set(["closest", "querySelector", "querySelectorAll"]);
|
|
3154
|
-
var noUncheckedQuerySelectorTypeRule =
|
|
3220
|
+
var noUncheckedQuerySelectorTypeRule = defineRule27({
|
|
3155
3221
|
meta: {
|
|
3156
3222
|
type: "problem",
|
|
3157
3223
|
docs: {
|
|
@@ -3180,8 +3246,8 @@ var noUncheckedQuerySelectorTypeRule = defineRule26({
|
|
|
3180
3246
|
});
|
|
3181
3247
|
|
|
3182
3248
|
// src/generic/rules/no-untyped-custom-event.ts
|
|
3183
|
-
import { defineRule as
|
|
3184
|
-
var noUntypedCustomEventRule =
|
|
3249
|
+
import { defineRule as defineRule28 } from "@oxlint/plugins";
|
|
3250
|
+
var noUntypedCustomEventRule = defineRule28({
|
|
3185
3251
|
meta: {
|
|
3186
3252
|
type: "problem",
|
|
3187
3253
|
docs: {
|
|
@@ -3204,7 +3270,7 @@ var noUntypedCustomEventRule = defineRule27({
|
|
|
3204
3270
|
});
|
|
3205
3271
|
|
|
3206
3272
|
// src/generic/rules/prefer-event-parameter-type.ts
|
|
3207
|
-
import { defineRule as
|
|
3273
|
+
import { defineRule as defineRule29 } from "@oxlint/plugins";
|
|
3208
3274
|
function staticMemberPath(node) {
|
|
3209
3275
|
const path = [];
|
|
3210
3276
|
let current = node.type === "ChainExpression" ? node.expression : node;
|
|
@@ -3236,7 +3302,7 @@ function assertedEventParameter(node) {
|
|
|
3236
3302
|
property: member.path.join(".")
|
|
3237
3303
|
};
|
|
3238
3304
|
}
|
|
3239
|
-
var preferEventParameterTypeRule =
|
|
3305
|
+
var preferEventParameterTypeRule = defineRule29({
|
|
3240
3306
|
meta: {
|
|
3241
3307
|
type: "suggestion",
|
|
3242
3308
|
docs: {
|
|
@@ -3265,14 +3331,14 @@ var preferEventParameterTypeRule = defineRule28({
|
|
|
3265
3331
|
});
|
|
3266
3332
|
|
|
3267
3333
|
// src/generic/rules/prefer-lit-query-decorators.ts
|
|
3268
|
-
import { defineRule as
|
|
3334
|
+
import { defineRule as defineRule30 } from "@oxlint/plugins";
|
|
3269
3335
|
var messageIds = {
|
|
3270
3336
|
assignedElements: "preferQueryAssignedElements",
|
|
3271
3337
|
assignedNodes: "preferQueryAssignedNodes",
|
|
3272
3338
|
querySelector: "preferQuery",
|
|
3273
3339
|
querySelectorAll: "preferQueryAll"
|
|
3274
3340
|
};
|
|
3275
|
-
var preferLitQueryDecoratorsRule =
|
|
3341
|
+
var preferLitQueryDecoratorsRule = defineRule30({
|
|
3276
3342
|
meta: {
|
|
3277
3343
|
type: "suggestion",
|
|
3278
3344
|
docs: {
|
|
@@ -3325,8 +3391,8 @@ var preferLitQueryDecoratorsRule = defineRule29({
|
|
|
3325
3391
|
});
|
|
3326
3392
|
|
|
3327
3393
|
// src/generic/rules/prefer-types-over-assertions.ts
|
|
3328
|
-
import { defineRule as
|
|
3329
|
-
var preferTypesOverAssertionsRule =
|
|
3394
|
+
import { defineRule as defineRule31 } from "@oxlint/plugins";
|
|
3395
|
+
var preferTypesOverAssertionsRule = defineRule31({
|
|
3330
3396
|
meta: {
|
|
3331
3397
|
type: "problem",
|
|
3332
3398
|
docs: {
|
package/dist/effect/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/effect/index.ts
|
|
2
2
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
3
3
|
|
|
4
|
-
// src/effect/rules/no-
|
|
4
|
+
// src/effect/rules/no-raw-gh.ts
|
|
5
5
|
import { defineRule } from "@oxlint/plugins";
|
|
6
6
|
|
|
7
7
|
// src/shared/ast.ts
|
|
@@ -32,6 +32,71 @@ function resolveVariable(sourceCode, identifier) {
|
|
|
32
32
|
}
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
|
+
// src/effect/rules/no-raw-gh.ts
|
|
36
|
+
var PACKAGE = "@timmo001/effect-gh";
|
|
37
|
+
var rawMethods = new Set(["execute", "json", "stream"]);
|
|
38
|
+
function isEffectGhImport(sourceCode, identifier, name) {
|
|
39
|
+
return resolveVariable(sourceCode, identifier)?.defs.some((definition) => {
|
|
40
|
+
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== PACKAGE || definition.node.type !== "ImportSpecifier") {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const imported = definition.node.imported;
|
|
44
|
+
return (imported.type === "Identifier" ? imported.name : imported.value) === name;
|
|
45
|
+
}) ?? false;
|
|
46
|
+
}
|
|
47
|
+
function isYieldGh(sourceCode, node) {
|
|
48
|
+
return node?.type === "YieldExpression" && node.delegate && node.argument?.type === "Identifier" && isEffectGhImport(sourceCode, node.argument, "Gh");
|
|
49
|
+
}
|
|
50
|
+
function isGhBinding(sourceCode, identifier) {
|
|
51
|
+
return resolveVariable(sourceCode, identifier)?.defs.some((definition) => definition.type === "Variable" && definition.node.type === "VariableDeclarator" && isYieldGh(sourceCode, definition.node.init)) ?? false;
|
|
52
|
+
}
|
|
53
|
+
function launchesGh(args) {
|
|
54
|
+
const [command, argv] = args;
|
|
55
|
+
if (command?.type === "Literal")
|
|
56
|
+
return command.value === "gh" && argv !== undefined;
|
|
57
|
+
if (command?.type !== "ArrayExpression")
|
|
58
|
+
return false;
|
|
59
|
+
const first = command.elements[0];
|
|
60
|
+
return first?.type === "Literal" && first.value === "gh";
|
|
61
|
+
}
|
|
62
|
+
var noRawGhRule = defineRule({
|
|
63
|
+
meta: {
|
|
64
|
+
type: "problem",
|
|
65
|
+
docs: {
|
|
66
|
+
description: "Use @timmo001/effect-gh typed operations instead of the raw Gh methods, Api.raw, or spawning gh directly."
|
|
67
|
+
},
|
|
68
|
+
messages: {
|
|
69
|
+
rawGh: "Use a typed effect-gh operation instead of `Gh.{{method}}` with raw argv. Add one to effect-gh if the command has none.",
|
|
70
|
+
rawApi: "Use `Api.json`, `Api.pages`, `Api.empty`, `Api.text` or `Api.headers` instead of `Api.raw`, so the response is typed.",
|
|
71
|
+
spawnGh: "Run gh through a typed @timmo001/effect-gh operation instead of spawning it directly."
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
create(context) {
|
|
75
|
+
return {
|
|
76
|
+
CallExpression(node) {
|
|
77
|
+
const callee = node.callee;
|
|
78
|
+
const method = staticMemberName(callee);
|
|
79
|
+
if (callee.type === "MemberExpression" && method !== null) {
|
|
80
|
+
const object = callee.object;
|
|
81
|
+
if (rawMethods.has(method) && (isYieldGh(context.sourceCode, object) || object.type === "Identifier" && isGhBinding(context.sourceCode, object))) {
|
|
82
|
+
context.report({ node, messageId: "rawGh", data: { method } });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (method === "raw" && object.type === "Identifier" && isEffectGhImport(context.sourceCode, object, "Api")) {
|
|
86
|
+
context.report({ node, messageId: "rawApi" });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (launchesGh(node.arguments))
|
|
91
|
+
context.report({ node, messageId: "spawnGh" });
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
98
|
+
import { defineRule as defineRule2 } from "@oxlint/plugins";
|
|
99
|
+
|
|
35
100
|
// src/shared/effect.ts
|
|
36
101
|
function isEffectImport(sourceCode, identifier, namespace) {
|
|
37
102
|
const variable = resolveVariable(sourceCode, identifier);
|
|
@@ -78,7 +143,7 @@ function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
|
78
143
|
const factoryCall = parent.callee;
|
|
79
144
|
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
80
145
|
}
|
|
81
|
-
var noTryCatchInEffectGeneratorsRule =
|
|
146
|
+
var noTryCatchInEffectGeneratorsRule = defineRule2({
|
|
82
147
|
meta: {
|
|
83
148
|
type: "problem",
|
|
84
149
|
docs: {
|
|
@@ -104,7 +169,7 @@ var noTryCatchInEffectGeneratorsRule = defineRule({
|
|
|
104
169
|
});
|
|
105
170
|
|
|
106
171
|
// src/effect/rules/prefer-platform-services.ts
|
|
107
|
-
import { defineRule as
|
|
172
|
+
import { defineRule as defineRule3 } from "@oxlint/plugins";
|
|
108
173
|
var moduleServices = new Map([
|
|
109
174
|
["child_process", "childProcess"],
|
|
110
175
|
["fs", "fileSystem"],
|
|
@@ -117,7 +182,7 @@ var bunServices = new Map([
|
|
|
117
182
|
["spawnSync", "childProcess"],
|
|
118
183
|
["write", "fileSystem"]
|
|
119
184
|
]);
|
|
120
|
-
var preferPlatformServicesRule =
|
|
185
|
+
var preferPlatformServicesRule = defineRule3({
|
|
121
186
|
meta: {
|
|
122
187
|
type: "suggestion",
|
|
123
188
|
docs: {
|
|
@@ -180,6 +245,7 @@ var preferPlatformServicesRule = defineRule2({
|
|
|
180
245
|
var timmoEffectPlugin = eslintCompatPlugin({
|
|
181
246
|
meta: { name: "timmo-effect" },
|
|
182
247
|
rules: {
|
|
248
|
+
"no-raw-gh": noRawGhRule,
|
|
183
249
|
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule,
|
|
184
250
|
"prefer-platform-services": preferPlatformServicesRule
|
|
185
251
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timmo001/oxlint-rules",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Shared Oxlint plugins and configs with optional Effect rules.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -38,24 +38,25 @@
|
|
|
38
38
|
],
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "bun run scripts/build.ts",
|
|
41
|
-
"check": "bun run
|
|
41
|
+
"check": "bun run --parallel --no-exit-on-error lint test typecheck format:check skills:validate",
|
|
42
42
|
"format": "prettier --write \"{src,scripts}/**/*.ts\" \"skills/**/*.{md,mjs}\" \"*.ts\" \"*.md\" \"*.json\"",
|
|
43
43
|
"format:check": "prettier --check \"{src,scripts}/**/*.ts\" \"skills/**/*.{md,mjs}\" \"*.ts\" \"*.md\" \"*.json\"",
|
|
44
|
-
"lint": "bun run build &&
|
|
45
|
-
"
|
|
44
|
+
"lint": "bun run build && bun run lint:oxlint",
|
|
45
|
+
"lint:oxlint": "oxlint --disable-nested-config .",
|
|
46
|
+
"skills:validate": "printf '%s\\n' skills/*/ | xargs -P 0 -n 1 skills-ref validate",
|
|
46
47
|
"test": "node --experimental-strip-types scripts/test.ts",
|
|
47
48
|
"test:package": "node --experimental-strip-types scripts/test-package.ts",
|
|
48
49
|
"typecheck": "tsc --noEmit"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
|
-
"@oxlint/plugins": "1.
|
|
52
|
-
"oxlint": "1.
|
|
52
|
+
"@oxlint/plugins": "1.87.0",
|
|
53
|
+
"oxlint": "1.87.0"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@oxlint/plugins": "1.
|
|
56
|
+
"@oxlint/plugins": "1.87.0",
|
|
56
57
|
"@types/bun": "^1.3.14",
|
|
57
|
-
"oxlint": "1.
|
|
58
|
-
"oxlint-tsgolint": "7.0.
|
|
58
|
+
"oxlint": "1.87.0",
|
|
59
|
+
"oxlint-tsgolint": "7.0.2004",
|
|
59
60
|
"prettier": "^3.9.5",
|
|
60
61
|
"skills-ref": "0.1.5",
|
|
61
62
|
"typescript": "^7.0.0"
|
|
@@ -32,10 +32,8 @@ description: >-
|
|
|
32
32
|
instead only when `effect` is a direct dependency or the user explicitly
|
|
33
33
|
requests it.
|
|
34
34
|
4. Keep dependency and config edits visible. Do not delegate them to a script.
|
|
35
|
-
5.
|
|
36
|
-
|
|
37
|
-
Enable `options.typeAware` in the target config and verify type-aware linting
|
|
38
|
-
alongside the shared rules.
|
|
35
|
+
5. Explicitly pin the latest `oxlint-tsgolint` that satisfies Oxlint's peer
|
|
36
|
+
requirement and was validated with the rules release.
|
|
39
37
|
|
|
40
38
|
## Copy rules
|
|
41
39
|
|
|
@@ -51,8 +49,23 @@ description: >-
|
|
|
51
49
|
output as authoritative rather than maintaining plugin or rule inventories
|
|
52
50
|
in this skill.
|
|
53
51
|
|
|
52
|
+
## Strictness
|
|
53
|
+
|
|
54
|
+
1. Start with every strictness option in the target config's `options`:
|
|
55
|
+
`typeAware: true`, `typeCheck: true`, and `maxWarnings: 0`. Keep them in the
|
|
56
|
+
config rather than as lint script flags, and remove any existing
|
|
57
|
+
`--type-aware`, `--type-check`, `--deny-warnings`, or `--max-warnings` flags
|
|
58
|
+
so the config is the single source.
|
|
59
|
+
2. Run the target's lint command. If it passes, keep every option.
|
|
60
|
+
3. If it fails, group the failures by cause and the option that raises them,
|
|
61
|
+
then ask one structured question: fix the failures, or drop the smallest set
|
|
62
|
+
of options that makes lint pass (`typeCheck` first, then `maxWarnings`, then
|
|
63
|
+
`typeAware`). Recommend the reduction that keeps the most strictness, and name
|
|
64
|
+
any shared cause, such as a missing declaration in an upstream package, that
|
|
65
|
+
a follow-up could fix for every consumer.
|
|
66
|
+
|
|
54
67
|
Run the target repository's lint command to verify the configuration loads, plus
|
|
55
68
|
any checks explicitly required by that repository. Run typechecks, tests, or a
|
|
56
69
|
build only when code or dependencies changed in a way those checks cover. Report
|
|
57
70
|
package-manager changes, preserved local configuration, enabled rule groups,
|
|
58
|
-
and checks.
|
|
71
|
+
strictness options kept or dropped, and checks.
|
package/src/effect/index.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
2
2
|
|
|
3
|
+
import { noRawGhRule } from "./rules/no-raw-gh.ts";
|
|
3
4
|
import { noTryCatchInEffectGeneratorsRule } from "./rules/no-try-catch-in-effect-generators.ts";
|
|
4
5
|
import { preferPlatformServicesRule } from "./rules/prefer-platform-services.ts";
|
|
5
6
|
|
|
6
7
|
const timmoEffectPlugin = eslintCompatPlugin({
|
|
7
8
|
meta: { name: "timmo-effect" },
|
|
8
9
|
rules: {
|
|
10
|
+
"no-raw-gh": noRawGhRule,
|
|
9
11
|
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule,
|
|
10
12
|
"prefer-platform-services": preferPlatformServicesRule,
|
|
11
13
|
},
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { defineRule } from "@oxlint/plugins";
|
|
2
|
+
|
|
3
|
+
import { staticMemberName } from "../../shared/ast.ts";
|
|
4
|
+
import { resolveVariable } from "../../shared/scope.ts";
|
|
5
|
+
|
|
6
|
+
import type { ESTree, SourceCode } from "@oxlint/plugins";
|
|
7
|
+
|
|
8
|
+
const PACKAGE = "@timmo001/effect-gh";
|
|
9
|
+
|
|
10
|
+
const rawMethods = new Set(["execute", "json", "stream"]);
|
|
11
|
+
|
|
12
|
+
/** Whether an identifier is bound by a named import of `name` from effect-gh. */
|
|
13
|
+
function isEffectGhImport(
|
|
14
|
+
sourceCode: SourceCode,
|
|
15
|
+
identifier: ESTree.IdentifierReference,
|
|
16
|
+
name: string,
|
|
17
|
+
): boolean {
|
|
18
|
+
return (
|
|
19
|
+
resolveVariable(sourceCode, identifier)?.defs.some((definition) => {
|
|
20
|
+
if (
|
|
21
|
+
definition.type !== "ImportBinding" ||
|
|
22
|
+
definition.parent?.type !== "ImportDeclaration" ||
|
|
23
|
+
definition.parent.source.value !== PACKAGE ||
|
|
24
|
+
definition.node.type !== "ImportSpecifier"
|
|
25
|
+
) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const imported = definition.node.imported;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
(imported.type === "Identifier" ? imported.name : imported.value) ===
|
|
33
|
+
name
|
|
34
|
+
);
|
|
35
|
+
}) ?? false
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Whether an expression is `yield* Gh` with Gh from effect-gh. */
|
|
40
|
+
function isYieldGh(sourceCode: SourceCode, node: ESTree.Node | null): boolean {
|
|
41
|
+
return (
|
|
42
|
+
node?.type === "YieldExpression" &&
|
|
43
|
+
node.delegate &&
|
|
44
|
+
node.argument?.type === "Identifier" &&
|
|
45
|
+
isEffectGhImport(sourceCode, node.argument, "Gh")
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Whether an identifier is a variable initialised with `yield* Gh`. */
|
|
50
|
+
function isGhBinding(
|
|
51
|
+
sourceCode: SourceCode,
|
|
52
|
+
identifier: ESTree.IdentifierReference,
|
|
53
|
+
): boolean {
|
|
54
|
+
return (
|
|
55
|
+
resolveVariable(sourceCode, identifier)?.defs.some(
|
|
56
|
+
(definition) =>
|
|
57
|
+
definition.type === "Variable" &&
|
|
58
|
+
definition.node.type === "VariableDeclarator" &&
|
|
59
|
+
isYieldGh(sourceCode, definition.node.init),
|
|
60
|
+
) ?? false
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Whether call arguments launch gh: `"gh"` followed by its argv, as in
|
|
66
|
+
* `run("gh", args)`, or an argv array starting with `"gh"`.
|
|
67
|
+
*/
|
|
68
|
+
function launchesGh(args: ESTree.CallExpression["arguments"]): boolean {
|
|
69
|
+
const [command, argv] = args;
|
|
70
|
+
|
|
71
|
+
if (command?.type === "Literal")
|
|
72
|
+
return command.value === "gh" && argv !== undefined;
|
|
73
|
+
|
|
74
|
+
if (command?.type !== "ArrayExpression") return false;
|
|
75
|
+
const first = command.elements[0];
|
|
76
|
+
|
|
77
|
+
return first?.type === "Literal" && first.value === "gh";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Route gh through effect-gh's typed operations instead of raw argv or direct spawns. */
|
|
81
|
+
export const noRawGhRule = defineRule({
|
|
82
|
+
meta: {
|
|
83
|
+
type: "problem",
|
|
84
|
+
docs: {
|
|
85
|
+
description:
|
|
86
|
+
"Use @timmo001/effect-gh typed operations instead of the raw Gh methods, Api.raw, or spawning gh directly.",
|
|
87
|
+
},
|
|
88
|
+
messages: {
|
|
89
|
+
rawGh:
|
|
90
|
+
"Use a typed effect-gh operation instead of `Gh.{{method}}` with raw argv. Add one to effect-gh if the command has none.",
|
|
91
|
+
rawApi:
|
|
92
|
+
"Use `Api.json`, `Api.pages`, `Api.empty`, `Api.text` or `Api.headers` instead of `Api.raw`, so the response is typed.",
|
|
93
|
+
spawnGh:
|
|
94
|
+
"Run gh through a typed @timmo001/effect-gh operation instead of spawning it directly.",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
create(context) {
|
|
98
|
+
return {
|
|
99
|
+
CallExpression(node) {
|
|
100
|
+
const callee = node.callee;
|
|
101
|
+
const method = staticMemberName(callee);
|
|
102
|
+
|
|
103
|
+
if (callee.type === "MemberExpression" && method !== null) {
|
|
104
|
+
const object = callee.object;
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
rawMethods.has(method) &&
|
|
108
|
+
(isYieldGh(context.sourceCode, object) ||
|
|
109
|
+
(object.type === "Identifier" &&
|
|
110
|
+
isGhBinding(context.sourceCode, object)))
|
|
111
|
+
) {
|
|
112
|
+
context.report({ node, messageId: "rawGh", data: { method } });
|
|
113
|
+
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
method === "raw" &&
|
|
119
|
+
object.type === "Identifier" &&
|
|
120
|
+
isEffectGhImport(context.sourceCode, object, "Api")
|
|
121
|
+
) {
|
|
122
|
+
context.report({ node, messageId: "rawApi" });
|
|
123
|
+
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (launchesGh(node.arguments))
|
|
129
|
+
context.report({ node, messageId: "spawnGh" });
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
});
|