@timmo001/oxlint-rules 0.2.0 → 0.3.0
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 +2 -2
- package/dist/cli.js +211 -211
- package/dist/configs/{effect.js → recommended-effect.js} +211 -211
- package/package.json +3 -3
- package/skills/add-oxlint-rule/SKILL.md +4 -1
- package/skills/install-timmo-oxlint-rules/SKILL.md +3 -2
- package/skills/release-oxlint-rules/SKILL.md +38 -0
package/dist/cli.js
CHANGED
|
@@ -1,170 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/effect/index.ts
|
|
4
|
-
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
5
|
-
|
|
6
|
-
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
7
|
-
import { defineRule } from "@oxlint/plugins";
|
|
8
|
-
function resolveVariable(sourceCode, identifier) {
|
|
9
|
-
let scope = sourceCode.getScope(identifier);
|
|
10
|
-
while (scope) {
|
|
11
|
-
const variable = scope.set.get(identifier.name);
|
|
12
|
-
if (variable)
|
|
13
|
-
return variable;
|
|
14
|
-
scope = scope.upper;
|
|
15
|
-
}
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
function nearestEnclosingFunction(node) {
|
|
19
|
-
let current = node.parent;
|
|
20
|
-
while (current) {
|
|
21
|
-
if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression") {
|
|
22
|
-
return current;
|
|
23
|
-
}
|
|
24
|
-
current = current.parent;
|
|
25
|
-
}
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
function staticMemberName(node) {
|
|
29
|
-
if (node.type !== "MemberExpression" || node.computed)
|
|
30
|
-
return null;
|
|
31
|
-
return node.property.type === "Identifier" ? node.property.name : null;
|
|
32
|
-
}
|
|
33
|
-
function isEffectImport(sourceCode, identifier, namespace) {
|
|
34
|
-
const variable = resolveVariable(sourceCode, identifier);
|
|
35
|
-
return variable?.defs.some((definition) => {
|
|
36
|
-
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== "effect") {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
if (namespace)
|
|
40
|
-
return definition.node.type === "ImportNamespaceSpecifier";
|
|
41
|
-
if (definition.node.type !== "ImportSpecifier")
|
|
42
|
-
return false;
|
|
43
|
-
const imported = definition.node.imported;
|
|
44
|
-
return (imported.type === "Identifier" ? imported.name : imported.value) === "Effect";
|
|
45
|
-
}) ?? false;
|
|
46
|
-
}
|
|
47
|
-
function isEffectMethod(sourceCode, node, method) {
|
|
48
|
-
if (staticMemberName(node) !== method || node.type !== "MemberExpression") {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
const object = node.object;
|
|
52
|
-
if (object.type === "Identifier") {
|
|
53
|
-
return isEffectImport(sourceCode, object, false);
|
|
54
|
-
}
|
|
55
|
-
if (staticMemberName(object) !== "Effect" || object.type !== "MemberExpression" || object.object.type !== "Identifier") {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
return isEffectImport(sourceCode, object.object, true);
|
|
59
|
-
}
|
|
60
|
-
function isDirectArgument(owner, call) {
|
|
61
|
-
return call.arguments.some((argument) => argument === owner);
|
|
62
|
-
}
|
|
63
|
-
function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
64
|
-
const parent = owner.parent;
|
|
65
|
-
if (parent.type !== "CallExpression" || !isDirectArgument(owner, parent)) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
if (isEffectMethod(sourceCode, parent.callee, "gen"))
|
|
69
|
-
return true;
|
|
70
|
-
const factoryCall = parent.callee;
|
|
71
|
-
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
72
|
-
}
|
|
73
|
-
var noTryCatchInEffectGeneratorsRule = defineRule({
|
|
74
|
-
meta: {
|
|
75
|
-
type: "problem",
|
|
76
|
-
docs: {
|
|
77
|
-
description: "Disallow synchronous try/catch owned by recognised Effect generator callbacks."
|
|
78
|
-
},
|
|
79
|
-
messages: {
|
|
80
|
-
useEffectErrorChannel: "Keep expected failures in the Effect error channel. Use Effect.try for synchronous throwing work, Effect.tryPromise for asynchronous throwing work, Effect-returning schema APIs for decoding, and Effect recovery combinators for recovery."
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
create(context) {
|
|
84
|
-
return {
|
|
85
|
-
TryStatement(node) {
|
|
86
|
-
if (!node.handler)
|
|
87
|
-
return;
|
|
88
|
-
const owner = nearestEnclosingFunction(node);
|
|
89
|
-
if (!owner?.generator || !isRecognisedEffectGenerator(context.sourceCode, owner)) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
context.report({ node, messageId: "useEffectErrorChannel" });
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// src/effect/index.ts
|
|
99
|
-
var timmoEffectPlugin = eslintCompatPlugin({
|
|
100
|
-
meta: { name: "timmo-effect" },
|
|
101
|
-
rules: {
|
|
102
|
-
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
var effect_default = timmoEffectPlugin;
|
|
106
|
-
|
|
107
|
-
// vendor/anti-slop/src/effect/index.ts
|
|
108
|
-
import { eslintCompatPlugin as eslintCompatPlugin2 } from "@oxlint/plugins";
|
|
109
|
-
|
|
110
|
-
// vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
|
|
111
|
-
import { defineRule as defineRule2 } from "@oxlint/plugins";
|
|
112
|
-
var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
|
|
113
|
-
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
|
|
114
|
-
function isProjectLocalImport(source) {
|
|
115
|
-
return source.startsWith("./") || source.startsWith("../");
|
|
116
|
-
}
|
|
117
|
-
function getImportedName(specifier) {
|
|
118
|
-
if (specifier.imported.type === "Identifier")
|
|
119
|
-
return specifier.imported.name;
|
|
120
|
-
return specifier.imported.value;
|
|
121
|
-
}
|
|
122
|
-
var noServiceConstructorImportsRule = defineRule2({
|
|
123
|
-
meta: {
|
|
124
|
-
type: "problem",
|
|
125
|
-
docs: {
|
|
126
|
-
description: "Disallow project-local make<CapabilityName> imports outside test and spec files."
|
|
127
|
-
},
|
|
128
|
-
messages: {
|
|
129
|
-
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.'
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
create(context) {
|
|
133
|
-
const isTestFile = TEST_FILE.test(context.filename.replaceAll("\\", "/"));
|
|
134
|
-
return {
|
|
135
|
-
ImportDeclaration(node) {
|
|
136
|
-
if (isTestFile || !isProjectLocalImport(node.source.value))
|
|
137
|
-
return;
|
|
138
|
-
for (const specifier of node.specifiers) {
|
|
139
|
-
if (specifier.type !== "ImportSpecifier")
|
|
140
|
-
continue;
|
|
141
|
-
const importedName = getImportedName(specifier);
|
|
142
|
-
if (!SERVICE_CONSTRUCTOR_NAME.test(importedName))
|
|
143
|
-
continue;
|
|
144
|
-
context.report({
|
|
145
|
-
node: specifier,
|
|
146
|
-
messageId: "serviceConstructorImport",
|
|
147
|
-
data: { name: importedName }
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// vendor/anti-slop/src/effect/index.ts
|
|
156
|
-
var antiSlopEffectPlugin = eslintCompatPlugin2({
|
|
157
|
-
meta: { name: "anti-slop-effect" },
|
|
158
|
-
rules: {
|
|
159
|
-
"no-service-constructor-imports": noServiceConstructorImportsRule
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
var effect_default2 = antiSlopEffectPlugin;
|
|
163
3
|
// vendor/anti-slop/src/index.ts
|
|
164
|
-
import { eslintCompatPlugin
|
|
4
|
+
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
165
5
|
|
|
166
6
|
// vendor/anti-slop/src/rules/no-chained-type-assertions.ts
|
|
167
|
-
import { defineRule
|
|
7
|
+
import { defineRule } from "@oxlint/plugins";
|
|
168
8
|
function isTypeAssertionExpression(node) {
|
|
169
9
|
return node.type === "TSAsExpression" || node.type === "TSTypeAssertion";
|
|
170
10
|
}
|
|
@@ -199,7 +39,7 @@ function isForbiddenAssertionChain(node) {
|
|
|
199
39
|
}
|
|
200
40
|
return assertionCount > 1 && hasNonConstAssertion;
|
|
201
41
|
}
|
|
202
|
-
var noChainedTypeAssertionsRule =
|
|
42
|
+
var noChainedTypeAssertionsRule = defineRule({
|
|
203
43
|
meta: {
|
|
204
44
|
type: "problem",
|
|
205
45
|
docs: {
|
|
@@ -223,7 +63,7 @@ var noChainedTypeAssertionsRule = defineRule3({
|
|
|
223
63
|
});
|
|
224
64
|
|
|
225
65
|
// vendor/anti-slop/src/rules/no-conditional-empty-object-spread.ts
|
|
226
|
-
import { defineRule as
|
|
66
|
+
import { defineRule as defineRule2 } from "@oxlint/plugins";
|
|
227
67
|
function unwrapParentheses(node) {
|
|
228
68
|
let current = node;
|
|
229
69
|
while (current.type === "ParenthesizedExpression") {
|
|
@@ -238,7 +78,7 @@ function isConditionalEmptyObjectSpread(node) {
|
|
|
238
78
|
const conditional = unwrapParentheses(node);
|
|
239
79
|
return conditional.type === "ConditionalExpression" && (isEmptyObjectExpression(conditional.consequent) || isEmptyObjectExpression(conditional.alternate));
|
|
240
80
|
}
|
|
241
|
-
var noConditionalEmptyObjectSpreadRule =
|
|
81
|
+
var noConditionalEmptyObjectSpreadRule = defineRule2({
|
|
242
82
|
meta: {
|
|
243
83
|
type: "suggestion",
|
|
244
84
|
docs: {
|
|
@@ -262,7 +102,7 @@ var noConditionalEmptyObjectSpreadRule = defineRule4({
|
|
|
262
102
|
});
|
|
263
103
|
|
|
264
104
|
// vendor/anti-slop/src/rules/no-known-value-widening.ts
|
|
265
|
-
import { defineRule as
|
|
105
|
+
import { defineRule as defineRule3 } from "@oxlint/plugins";
|
|
266
106
|
|
|
267
107
|
// vendor/anti-slop/src/shared/lexical-type-parameters.ts
|
|
268
108
|
function isNode(value) {
|
|
@@ -799,7 +639,7 @@ function unwrapExpression(expression) {
|
|
|
799
639
|
}
|
|
800
640
|
return current;
|
|
801
641
|
}
|
|
802
|
-
function
|
|
642
|
+
function resolveVariable(sourceCode, identifier) {
|
|
803
643
|
let scope = sourceCode.getScope(identifier);
|
|
804
644
|
while (scope !== null) {
|
|
805
645
|
const variable = scope.set.get(identifier.name);
|
|
@@ -824,7 +664,7 @@ function hasKnownEvidence(sourceCode, expression, visitedVariables = new Set) {
|
|
|
824
664
|
const unwrapped = unwrapExpression(expression);
|
|
825
665
|
if (unwrapped.type !== "Identifier")
|
|
826
666
|
return false;
|
|
827
|
-
const variable =
|
|
667
|
+
const variable = resolveVariable(sourceCode, unwrapped);
|
|
828
668
|
if (variable === null || visitedVariables.has(variable))
|
|
829
669
|
return false;
|
|
830
670
|
const declarator = variableDeclarator(variable);
|
|
@@ -843,7 +683,7 @@ function localFunctionForCall(sourceCode, callee) {
|
|
|
843
683
|
return unwrapped;
|
|
844
684
|
if (unwrapped.type !== "Identifier")
|
|
845
685
|
return null;
|
|
846
|
-
const variable =
|
|
686
|
+
const variable = resolveVariable(sourceCode, unwrapped);
|
|
847
687
|
if (variable === null || variable.defs.length !== 1)
|
|
848
688
|
return null;
|
|
849
689
|
const [definition] = variable.defs;
|
|
@@ -896,7 +736,7 @@ function hasKnownCallArgumentEvidence(sourceCode, expression, environment, visit
|
|
|
896
736
|
}
|
|
897
737
|
if (expression.type !== "Identifier")
|
|
898
738
|
return isKnownEvidenceExpression(expression);
|
|
899
|
-
const variable =
|
|
739
|
+
const variable = resolveVariable(sourceCode, expression);
|
|
900
740
|
if (variable === null || visitedVariables.has(variable))
|
|
901
741
|
return false;
|
|
902
742
|
const annotation = variableTypeAnnotation(sourceCode, variable);
|
|
@@ -961,7 +801,7 @@ function isDictionaryAccumulatorTarget(destination) {
|
|
|
961
801
|
function hasParentAssertion(node) {
|
|
962
802
|
return node.parent?.type === "TSAsExpression" || node.parent?.type === "TSTypeAssertion";
|
|
963
803
|
}
|
|
964
|
-
var noKnownValueWideningRule =
|
|
804
|
+
var noKnownValueWideningRule = defineRule3({
|
|
965
805
|
meta: {
|
|
966
806
|
type: "problem",
|
|
967
807
|
docs: {
|
|
@@ -1010,7 +850,7 @@ var noKnownValueWideningRule = defineRule5({
|
|
|
1010
850
|
AssignmentExpression(node) {
|
|
1011
851
|
if (node.operator !== "=" || node.left.type !== "Identifier")
|
|
1012
852
|
return;
|
|
1013
|
-
const variable =
|
|
853
|
+
const variable = resolveVariable(context.sourceCode, node.left);
|
|
1014
854
|
if (variable === null)
|
|
1015
855
|
return;
|
|
1016
856
|
const declarator = variableDeclarator(variable);
|
|
@@ -1074,9 +914,9 @@ var noKnownValueWideningRule = defineRule5({
|
|
|
1074
914
|
});
|
|
1075
915
|
|
|
1076
916
|
// vendor/anti-slop/src/rules/no-module-mocking.ts
|
|
1077
|
-
import { defineRule as
|
|
917
|
+
import { defineRule as defineRule4 } from "@oxlint/plugins";
|
|
1078
918
|
var moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]);
|
|
1079
|
-
function
|
|
919
|
+
function resolveVariable2(sourceCode, identifier) {
|
|
1080
920
|
let scope = sourceCode.getScope(identifier);
|
|
1081
921
|
while (scope !== null) {
|
|
1082
922
|
const variable = scope.set.get(identifier.name);
|
|
@@ -1097,7 +937,7 @@ function isTestFrameworkObject(sourceCode, expression) {
|
|
|
1097
937
|
if ((expression.name === "vi" || expression.name === "jest") && sourceCode.isGlobalReference(expression)) {
|
|
1098
938
|
return true;
|
|
1099
939
|
}
|
|
1100
|
-
const variable =
|
|
940
|
+
const variable = resolveVariable2(sourceCode, expression);
|
|
1101
941
|
if (variable === null || variable.defs.length === 0) {
|
|
1102
942
|
return expression.name === "vi" || expression.name === "jest";
|
|
1103
943
|
}
|
|
@@ -1119,7 +959,7 @@ function moduleMockCall(sourceCode, callee) {
|
|
|
1119
959
|
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;
|
|
1120
960
|
return method !== null && moduleMockMethods.has(method);
|
|
1121
961
|
}
|
|
1122
|
-
var noModuleMockingRule =
|
|
962
|
+
var noModuleMockingRule = defineRule4({
|
|
1123
963
|
meta: {
|
|
1124
964
|
type: "problem",
|
|
1125
965
|
docs: {
|
|
@@ -1143,8 +983,8 @@ var noModuleMockingRule = defineRule6({
|
|
|
1143
983
|
});
|
|
1144
984
|
|
|
1145
985
|
// vendor/anti-slop/src/rules/no-object-parameters.ts
|
|
1146
|
-
import { defineRule as
|
|
1147
|
-
var noObjectParametersRule =
|
|
986
|
+
import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
987
|
+
var noObjectParametersRule = defineRule5({
|
|
1148
988
|
meta: {
|
|
1149
989
|
type: "problem",
|
|
1150
990
|
docs: {
|
|
@@ -1197,10 +1037,10 @@ var noObjectParametersRule = defineRule7({
|
|
|
1197
1037
|
});
|
|
1198
1038
|
|
|
1199
1039
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1200
|
-
import { defineRule as
|
|
1040
|
+
import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
1201
1041
|
|
|
1202
1042
|
// vendor/anti-slop/src/shared/reflect-method.ts
|
|
1203
|
-
function
|
|
1043
|
+
function resolveVariable3(sourceCode, identifier) {
|
|
1204
1044
|
let scope = sourceCode.getScope(identifier);
|
|
1205
1045
|
while (scope !== null) {
|
|
1206
1046
|
const variable = scope.set.get(identifier.name);
|
|
@@ -1215,7 +1055,7 @@ function isGlobalReflect(sourceCode, expression) {
|
|
|
1215
1055
|
return false;
|
|
1216
1056
|
if (sourceCode.isGlobalReference(expression))
|
|
1217
1057
|
return true;
|
|
1218
|
-
const variable =
|
|
1058
|
+
const variable = resolveVariable3(sourceCode, expression);
|
|
1219
1059
|
return variable === null || variable.defs.length === 0;
|
|
1220
1060
|
}
|
|
1221
1061
|
function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
@@ -1228,7 +1068,7 @@ function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
|
1228
1068
|
}
|
|
1229
1069
|
|
|
1230
1070
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1231
|
-
var noReflectApplyRule =
|
|
1071
|
+
var noReflectApplyRule = defineRule6({
|
|
1232
1072
|
meta: {
|
|
1233
1073
|
type: "problem",
|
|
1234
1074
|
docs: {
|
|
@@ -1252,8 +1092,8 @@ var noReflectApplyRule = defineRule8({
|
|
|
1252
1092
|
});
|
|
1253
1093
|
|
|
1254
1094
|
// vendor/anti-slop/src/rules/no-reflect-get.ts
|
|
1255
|
-
import { defineRule as
|
|
1256
|
-
var noReflectGetRule =
|
|
1095
|
+
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
1096
|
+
var noReflectGetRule = defineRule7({
|
|
1257
1097
|
meta: {
|
|
1258
1098
|
type: "problem",
|
|
1259
1099
|
docs: {
|
|
@@ -1277,7 +1117,7 @@ var noReflectGetRule = defineRule9({
|
|
|
1277
1117
|
});
|
|
1278
1118
|
|
|
1279
1119
|
// vendor/anti-slop/src/rules/no-runtime-typeof.ts
|
|
1280
|
-
import { defineRule as
|
|
1120
|
+
import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
1281
1121
|
function isRuntimeFunction(node) {
|
|
1282
1122
|
return node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression";
|
|
1283
1123
|
}
|
|
@@ -1300,7 +1140,7 @@ function isExistenceProbe(node) {
|
|
|
1300
1140
|
const other = parent.left === node ? parent.right : parent.left;
|
|
1301
1141
|
return other.type === "Literal" && other.value === "undefined";
|
|
1302
1142
|
}
|
|
1303
|
-
var noRuntimeTypeofRule =
|
|
1143
|
+
var noRuntimeTypeofRule = defineRule8({
|
|
1304
1144
|
meta: {
|
|
1305
1145
|
type: "problem",
|
|
1306
1146
|
docs: {
|
|
@@ -1334,7 +1174,7 @@ var noRuntimeTypeofRule = defineRule10({
|
|
|
1334
1174
|
});
|
|
1335
1175
|
|
|
1336
1176
|
// vendor/anti-slop/src/rules/no-shape-in-symbol-names.ts
|
|
1337
|
-
import { defineRule as
|
|
1177
|
+
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
1338
1178
|
var FORBIDDEN_SYMBOL_NAME = "shape";
|
|
1339
1179
|
function containsForbiddenSymbolName(name) {
|
|
1340
1180
|
return name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME);
|
|
@@ -1345,7 +1185,7 @@ function isBorrowedMemberName(node) {
|
|
|
1345
1185
|
return false;
|
|
1346
1186
|
return parent.property === node && parent.computed === false;
|
|
1347
1187
|
}
|
|
1348
|
-
var noForbiddenTermInSymbolNamesRule =
|
|
1188
|
+
var noForbiddenTermInSymbolNamesRule = defineRule9({
|
|
1349
1189
|
meta: {
|
|
1350
1190
|
type: "problem",
|
|
1351
1191
|
docs: {
|
|
@@ -1374,12 +1214,12 @@ var noForbiddenTermInSymbolNamesRule = defineRule11({
|
|
|
1374
1214
|
});
|
|
1375
1215
|
|
|
1376
1216
|
// vendor/anti-slop/src/rules/no-unknown-parameters.ts
|
|
1377
|
-
import { defineRule as
|
|
1217
|
+
import { defineRule as defineRule10 } from "@oxlint/plugins";
|
|
1378
1218
|
function isTypePredicateSubject(owner, parameterName) {
|
|
1379
1219
|
const predicate = owner.returnType?.typeAnnotation;
|
|
1380
1220
|
return predicate?.type === "TSTypePredicate" && predicate.parameterName.type === "Identifier" && predicate.parameterName.name === parameterName;
|
|
1381
1221
|
}
|
|
1382
|
-
var noUnknownParametersRule =
|
|
1222
|
+
var noUnknownParametersRule = defineRule10({
|
|
1383
1223
|
meta: {
|
|
1384
1224
|
type: "problem",
|
|
1385
1225
|
docs: {
|
|
@@ -1423,8 +1263,8 @@ var noUnknownParametersRule = defineRule12({
|
|
|
1423
1263
|
});
|
|
1424
1264
|
|
|
1425
1265
|
// vendor/anti-slop/src/rules/no-unknown-returns.ts
|
|
1426
|
-
import { defineRule as
|
|
1427
|
-
var noUnknownReturnsRule =
|
|
1266
|
+
import { defineRule as defineRule11 } from "@oxlint/plugins";
|
|
1267
|
+
var noUnknownReturnsRule = defineRule11({
|
|
1428
1268
|
meta: {
|
|
1429
1269
|
type: "problem",
|
|
1430
1270
|
docs: {
|
|
@@ -1477,8 +1317,8 @@ var noUnknownReturnsRule = defineRule13({
|
|
|
1477
1317
|
});
|
|
1478
1318
|
|
|
1479
1319
|
// vendor/anti-slop/src/rules/no-unknown-type-aliases.ts
|
|
1480
|
-
import { defineRule as
|
|
1481
|
-
var noUnknownTypeAliasesRule =
|
|
1320
|
+
import { defineRule as defineRule12 } from "@oxlint/plugins";
|
|
1321
|
+
var noUnknownTypeAliasesRule = defineRule12({
|
|
1482
1322
|
meta: {
|
|
1483
1323
|
type: "problem",
|
|
1484
1324
|
docs: {
|
|
@@ -1516,7 +1356,7 @@ var noUnknownTypeAliasesRule = defineRule14({
|
|
|
1516
1356
|
});
|
|
1517
1357
|
|
|
1518
1358
|
// vendor/anti-slop/src/rules/no-unsafe-dictionary-type.ts
|
|
1519
|
-
import { defineRule as
|
|
1359
|
+
import { defineRule as defineRule13 } from "@oxlint/plugins";
|
|
1520
1360
|
var typeNodeKinds = new Set([
|
|
1521
1361
|
"JSDocNonNullableType",
|
|
1522
1362
|
"JSDocNullableType",
|
|
@@ -1603,7 +1443,7 @@ function shouldReportType(node, environment) {
|
|
|
1603
1443
|
}
|
|
1604
1444
|
return true;
|
|
1605
1445
|
}
|
|
1606
|
-
var noUnsafeDictionaryTypeRule =
|
|
1446
|
+
var noUnsafeDictionaryTypeRule = defineRule13({
|
|
1607
1447
|
meta: {
|
|
1608
1448
|
type: "problem",
|
|
1609
1449
|
docs: {
|
|
@@ -1645,7 +1485,7 @@ var noUnsafeDictionaryTypeRule = defineRule15({
|
|
|
1645
1485
|
});
|
|
1646
1486
|
|
|
1647
1487
|
// vendor/anti-slop/src/rules/no-widen-then-assert.ts
|
|
1648
|
-
import { defineRule as
|
|
1488
|
+
import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
1649
1489
|
var functionBoundaryTypes = new Set([
|
|
1650
1490
|
"ArrowFunctionExpression",
|
|
1651
1491
|
"FunctionDeclaration",
|
|
@@ -1841,7 +1681,7 @@ function assertionIsNarrower(sourceText, broadKind, evidence, assertedType) {
|
|
|
1841
1681
|
return isDefinitelyObjectType(assertedType);
|
|
1842
1682
|
return isDefinitelyNarrowerRecordType(assertedType);
|
|
1843
1683
|
}
|
|
1844
|
-
var noWidenThenAssertRule =
|
|
1684
|
+
var noWidenThenAssertRule = defineRule14({
|
|
1845
1685
|
meta: {
|
|
1846
1686
|
type: "problem",
|
|
1847
1687
|
docs: {
|
|
@@ -1881,7 +1721,7 @@ var noWidenThenAssertRule = defineRule16({
|
|
|
1881
1721
|
});
|
|
1882
1722
|
|
|
1883
1723
|
// vendor/anti-slop/src/rules/require-safety-comment-for-type-assertion.ts
|
|
1884
|
-
import { defineRule as
|
|
1724
|
+
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
1885
1725
|
var DEFAULT_SAFETY_MARKERS = ["SAFETY"];
|
|
1886
1726
|
var commentOwnerKinds = new Set([
|
|
1887
1727
|
"ExpressionStatement",
|
|
@@ -1924,7 +1764,7 @@ function hasSafetyComment(sourceCode, node, pattern) {
|
|
|
1924
1764
|
current = current.parent;
|
|
1925
1765
|
}
|
|
1926
1766
|
}
|
|
1927
|
-
var requireSafetyCommentForTypeAssertionRule =
|
|
1767
|
+
var requireSafetyCommentForTypeAssertionRule = defineRule15({
|
|
1928
1768
|
meta: {
|
|
1929
1769
|
type: "problem",
|
|
1930
1770
|
docs: {
|
|
@@ -1974,7 +1814,7 @@ var requireSafetyCommentForTypeAssertionRule = defineRule17({
|
|
|
1974
1814
|
});
|
|
1975
1815
|
|
|
1976
1816
|
// vendor/anti-slop/src/index.ts
|
|
1977
|
-
var antiSlopPlugin =
|
|
1817
|
+
var antiSlopPlugin = eslintCompatPlugin({
|
|
1978
1818
|
meta: { name: "anti-slop" },
|
|
1979
1819
|
rules: {
|
|
1980
1820
|
"no-chained-type-assertions": noChainedTypeAssertionsRule,
|
|
@@ -1996,11 +1836,11 @@ var antiSlopPlugin = eslintCompatPlugin3({
|
|
|
1996
1836
|
});
|
|
1997
1837
|
var src_default = antiSlopPlugin;
|
|
1998
1838
|
// src/generic/index.ts
|
|
1999
|
-
import { eslintCompatPlugin as
|
|
1839
|
+
import { eslintCompatPlugin as eslintCompatPlugin2 } from "@oxlint/plugins";
|
|
2000
1840
|
|
|
2001
1841
|
// src/generic/rules/prefer-event-parameter-type.ts
|
|
2002
|
-
import { defineRule as
|
|
2003
|
-
function
|
|
1842
|
+
import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
1843
|
+
function nearestEnclosingFunction(node) {
|
|
2004
1844
|
let current = node.parent;
|
|
2005
1845
|
while (current) {
|
|
2006
1846
|
if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression") {
|
|
@@ -2017,7 +1857,7 @@ function assertedEventParameter(node) {
|
|
|
2017
1857
|
}
|
|
2018
1858
|
const parameterName = expression.object.name;
|
|
2019
1859
|
const property = expression.property.name;
|
|
2020
|
-
const owner =
|
|
1860
|
+
const owner = nearestEnclosingFunction(node);
|
|
2021
1861
|
if (!owner?.params.some((parameter) => parameter.type === "Identifier" && parameter.name === parameterName)) {
|
|
2022
1862
|
return null;
|
|
2023
1863
|
}
|
|
@@ -2026,7 +1866,7 @@ function assertedEventParameter(node) {
|
|
|
2026
1866
|
property
|
|
2027
1867
|
};
|
|
2028
1868
|
}
|
|
2029
|
-
var preferEventParameterTypeRule =
|
|
1869
|
+
var preferEventParameterTypeRule = defineRule16({
|
|
2030
1870
|
meta: {
|
|
2031
1871
|
type: "suggestion",
|
|
2032
1872
|
docs: {
|
|
@@ -2055,7 +1895,7 @@ var preferEventParameterTypeRule = defineRule18({
|
|
|
2055
1895
|
});
|
|
2056
1896
|
|
|
2057
1897
|
// src/generic/index.ts
|
|
2058
|
-
var timmoPlugin =
|
|
1898
|
+
var timmoPlugin = eslintCompatPlugin2({
|
|
2059
1899
|
meta: { name: "timmo" },
|
|
2060
1900
|
rules: {
|
|
2061
1901
|
"prefer-event-parameter-type": preferEventParameterTypeRule
|
|
@@ -2089,8 +1929,168 @@ var recommended = defineConfig({
|
|
|
2089
1929
|
});
|
|
2090
1930
|
var recommended_default = recommended;
|
|
2091
1931
|
|
|
2092
|
-
// src/
|
|
2093
|
-
|
|
1932
|
+
// src/effect/index.ts
|
|
1933
|
+
import { eslintCompatPlugin as eslintCompatPlugin3 } from "@oxlint/plugins";
|
|
1934
|
+
|
|
1935
|
+
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
1936
|
+
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
1937
|
+
function resolveVariable4(sourceCode, identifier) {
|
|
1938
|
+
let scope = sourceCode.getScope(identifier);
|
|
1939
|
+
while (scope) {
|
|
1940
|
+
const variable = scope.set.get(identifier.name);
|
|
1941
|
+
if (variable)
|
|
1942
|
+
return variable;
|
|
1943
|
+
scope = scope.upper;
|
|
1944
|
+
}
|
|
1945
|
+
return null;
|
|
1946
|
+
}
|
|
1947
|
+
function nearestEnclosingFunction2(node) {
|
|
1948
|
+
let current = node.parent;
|
|
1949
|
+
while (current) {
|
|
1950
|
+
if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression") {
|
|
1951
|
+
return current;
|
|
1952
|
+
}
|
|
1953
|
+
current = current.parent;
|
|
1954
|
+
}
|
|
1955
|
+
return null;
|
|
1956
|
+
}
|
|
1957
|
+
function staticMemberName(node) {
|
|
1958
|
+
if (node.type !== "MemberExpression" || node.computed)
|
|
1959
|
+
return null;
|
|
1960
|
+
return node.property.type === "Identifier" ? node.property.name : null;
|
|
1961
|
+
}
|
|
1962
|
+
function isEffectImport(sourceCode, identifier, namespace) {
|
|
1963
|
+
const variable = resolveVariable4(sourceCode, identifier);
|
|
1964
|
+
return variable?.defs.some((definition) => {
|
|
1965
|
+
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== "effect") {
|
|
1966
|
+
return false;
|
|
1967
|
+
}
|
|
1968
|
+
if (namespace)
|
|
1969
|
+
return definition.node.type === "ImportNamespaceSpecifier";
|
|
1970
|
+
if (definition.node.type !== "ImportSpecifier")
|
|
1971
|
+
return false;
|
|
1972
|
+
const imported = definition.node.imported;
|
|
1973
|
+
return (imported.type === "Identifier" ? imported.name : imported.value) === "Effect";
|
|
1974
|
+
}) ?? false;
|
|
1975
|
+
}
|
|
1976
|
+
function isEffectMethod(sourceCode, node, method) {
|
|
1977
|
+
if (staticMemberName(node) !== method || node.type !== "MemberExpression") {
|
|
1978
|
+
return false;
|
|
1979
|
+
}
|
|
1980
|
+
const object = node.object;
|
|
1981
|
+
if (object.type === "Identifier") {
|
|
1982
|
+
return isEffectImport(sourceCode, object, false);
|
|
1983
|
+
}
|
|
1984
|
+
if (staticMemberName(object) !== "Effect" || object.type !== "MemberExpression" || object.object.type !== "Identifier") {
|
|
1985
|
+
return false;
|
|
1986
|
+
}
|
|
1987
|
+
return isEffectImport(sourceCode, object.object, true);
|
|
1988
|
+
}
|
|
1989
|
+
function isDirectArgument(owner, call) {
|
|
1990
|
+
return call.arguments.some((argument) => argument === owner);
|
|
1991
|
+
}
|
|
1992
|
+
function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
1993
|
+
const parent = owner.parent;
|
|
1994
|
+
if (parent.type !== "CallExpression" || !isDirectArgument(owner, parent)) {
|
|
1995
|
+
return false;
|
|
1996
|
+
}
|
|
1997
|
+
if (isEffectMethod(sourceCode, parent.callee, "gen"))
|
|
1998
|
+
return true;
|
|
1999
|
+
const factoryCall = parent.callee;
|
|
2000
|
+
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
2001
|
+
}
|
|
2002
|
+
var noTryCatchInEffectGeneratorsRule = defineRule17({
|
|
2003
|
+
meta: {
|
|
2004
|
+
type: "problem",
|
|
2005
|
+
docs: {
|
|
2006
|
+
description: "Disallow synchronous try/catch owned by recognised Effect generator callbacks."
|
|
2007
|
+
},
|
|
2008
|
+
messages: {
|
|
2009
|
+
useEffectErrorChannel: "Keep expected failures in the Effect error channel. Use Effect.try for synchronous throwing work, Effect.tryPromise for asynchronous throwing work, Effect-returning schema APIs for decoding, and Effect recovery combinators for recovery."
|
|
2010
|
+
}
|
|
2011
|
+
},
|
|
2012
|
+
create(context) {
|
|
2013
|
+
return {
|
|
2014
|
+
TryStatement(node) {
|
|
2015
|
+
if (!node.handler)
|
|
2016
|
+
return;
|
|
2017
|
+
const owner = nearestEnclosingFunction2(node);
|
|
2018
|
+
if (!owner?.generator || !isRecognisedEffectGenerator(context.sourceCode, owner)) {
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
context.report({ node, messageId: "useEffectErrorChannel" });
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
});
|
|
2026
|
+
|
|
2027
|
+
// src/effect/index.ts
|
|
2028
|
+
var timmoEffectPlugin = eslintCompatPlugin3({
|
|
2029
|
+
meta: { name: "timmo-effect" },
|
|
2030
|
+
rules: {
|
|
2031
|
+
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule
|
|
2032
|
+
}
|
|
2033
|
+
});
|
|
2034
|
+
var effect_default = timmoEffectPlugin;
|
|
2035
|
+
|
|
2036
|
+
// vendor/anti-slop/src/effect/index.ts
|
|
2037
|
+
import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
|
|
2038
|
+
|
|
2039
|
+
// vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
|
|
2040
|
+
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
2041
|
+
var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
|
|
2042
|
+
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
|
|
2043
|
+
function isProjectLocalImport(source) {
|
|
2044
|
+
return source.startsWith("./") || source.startsWith("../");
|
|
2045
|
+
}
|
|
2046
|
+
function getImportedName(specifier) {
|
|
2047
|
+
if (specifier.imported.type === "Identifier")
|
|
2048
|
+
return specifier.imported.name;
|
|
2049
|
+
return specifier.imported.value;
|
|
2050
|
+
}
|
|
2051
|
+
var noServiceConstructorImportsRule = defineRule18({
|
|
2052
|
+
meta: {
|
|
2053
|
+
type: "problem",
|
|
2054
|
+
docs: {
|
|
2055
|
+
description: "Disallow project-local make<CapabilityName> imports outside test and spec files."
|
|
2056
|
+
},
|
|
2057
|
+
messages: {
|
|
2058
|
+
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.'
|
|
2059
|
+
}
|
|
2060
|
+
},
|
|
2061
|
+
create(context) {
|
|
2062
|
+
const isTestFile = TEST_FILE.test(context.filename.replaceAll("\\", "/"));
|
|
2063
|
+
return {
|
|
2064
|
+
ImportDeclaration(node) {
|
|
2065
|
+
if (isTestFile || !isProjectLocalImport(node.source.value))
|
|
2066
|
+
return;
|
|
2067
|
+
for (const specifier of node.specifiers) {
|
|
2068
|
+
if (specifier.type !== "ImportSpecifier")
|
|
2069
|
+
continue;
|
|
2070
|
+
const importedName2 = getImportedName(specifier);
|
|
2071
|
+
if (!SERVICE_CONSTRUCTOR_NAME.test(importedName2))
|
|
2072
|
+
continue;
|
|
2073
|
+
context.report({
|
|
2074
|
+
node: specifier,
|
|
2075
|
+
messageId: "serviceConstructorImport",
|
|
2076
|
+
data: { name: importedName2 }
|
|
2077
|
+
});
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
|
|
2084
|
+
// vendor/anti-slop/src/effect/index.ts
|
|
2085
|
+
var antiSlopEffectPlugin = eslintCompatPlugin4({
|
|
2086
|
+
meta: { name: "anti-slop-effect" },
|
|
2087
|
+
rules: {
|
|
2088
|
+
"no-service-constructor-imports": noServiceConstructorImportsRule
|
|
2089
|
+
}
|
|
2090
|
+
});
|
|
2091
|
+
var effect_default2 = antiSlopEffectPlugin;
|
|
2092
|
+
// src/configs/recommended-effect.ts
|
|
2093
|
+
var recommendedEffect = defineConfig({
|
|
2094
2094
|
extends: [recommended_default],
|
|
2095
2095
|
jsPlugins: [
|
|
2096
2096
|
{
|
|
@@ -2104,7 +2104,7 @@ var effect = defineConfig({
|
|
|
2104
2104
|
...enablePluginRules("timmo-effect", effect_default)
|
|
2105
2105
|
}
|
|
2106
2106
|
});
|
|
2107
|
-
var
|
|
2107
|
+
var recommended_effect_default = recommendedEffect;
|
|
2108
2108
|
|
|
2109
2109
|
// src/cli.ts
|
|
2110
2110
|
import { resolve as resolve2 } from "node:path";
|
|
@@ -2189,7 +2189,7 @@ if (command === "--help" || command === "-h") {
|
|
|
2189
2189
|
console.log(` timmo: ${entries.timmo}`);
|
|
2190
2190
|
console.log(` timmo-effect: ${entries.timmoEffect}`);
|
|
2191
2191
|
printRuleSettings("General rule settings:", recommended_default.rules ?? {});
|
|
2192
|
-
printRuleSettings("Effect rule settings (opt-in):",
|
|
2192
|
+
printRuleSettings("Effect rule settings (opt-in):", recommended_effect_default.rules ?? {});
|
|
2193
2193
|
} catch (error) {
|
|
2194
2194
|
console.error(error instanceof Error ? error.message : String(error));
|
|
2195
2195
|
process.exitCode = 1;
|