eslint-plugin-flawless 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs
CHANGED
package/dist/oxlint.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import * as core from "@eslint-react/core";
|
|
|
14
14
|
import { getStaticTOMLValue } from "toml-eslint-parser";
|
|
15
15
|
//#region package.json
|
|
16
16
|
var name = "eslint-plugin-flawless";
|
|
17
|
-
var version = "1.4.
|
|
17
|
+
var version = "1.4.2";
|
|
18
18
|
var repository = {
|
|
19
19
|
"url": "git+https://github.com/christopher-buss/eslint-plugin-flawless.git",
|
|
20
20
|
"type": "git"
|
|
@@ -3030,6 +3030,11 @@ const DEFAULTS$1 = {
|
|
|
3030
3030
|
};
|
|
3031
3031
|
/** Callee identifiers that name a vitest test block (`describe` is excluded). */
|
|
3032
3032
|
const TEST_BLOCK_NAMES$1 = /* @__PURE__ */ new Set(["it", "test"]);
|
|
3033
|
+
/**
|
|
3034
|
+
* Root identifiers whose call arguments are assertion conditions. Matched by
|
|
3035
|
+
* name as well as by vitest resolution, so `assert` from `node:assert` counts.
|
|
3036
|
+
*/
|
|
3037
|
+
const ASSERTION_ROOT_NAMES = /* @__PURE__ */ new Set(["assert", "expect"]);
|
|
3033
3038
|
const messages$14 = { [MESSAGE_ID$9]: "Avoid having conditionals in tests." };
|
|
3034
3039
|
const schema$3 = [{
|
|
3035
3040
|
additionalProperties: false,
|
|
@@ -3113,12 +3118,43 @@ function resolveVitestName$1(sourceCode, identifier) {
|
|
|
3113
3118
|
return null;
|
|
3114
3119
|
}
|
|
3115
3120
|
/**
|
|
3116
|
-
*
|
|
3117
|
-
*
|
|
3118
|
-
*
|
|
3119
|
-
*
|
|
3120
|
-
*
|
|
3121
|
-
*
|
|
3121
|
+
* Determines whether a node sits directly in the argument list of an assertion
|
|
3122
|
+
* call (`expect(...)`, `assert(...)`, `assert.ok(...)`, `expect(x).toBe(...)`).
|
|
3123
|
+
* The search walks up to the nearest enclosing call and stops there, so an
|
|
3124
|
+
* argument of some other function nested inside an assertion
|
|
3125
|
+
* (`expect(wrap(a && b))`) does not qualify; it also stops at a function
|
|
3126
|
+
* boundary, since a callback's body runs on the callback's terms rather than as
|
|
3127
|
+
* part of the assertion's condition.
|
|
3128
|
+
*
|
|
3129
|
+
* @param node - The node to locate.
|
|
3130
|
+
* @param sourceCode - Provides the scope used to resolve the callee.
|
|
3131
|
+
* @returns `true` when the node is an argument of an assertion call.
|
|
3132
|
+
*/
|
|
3133
|
+
function isInAssertionArgument(node, sourceCode) {
|
|
3134
|
+
let current = node;
|
|
3135
|
+
for (;;) {
|
|
3136
|
+
const { parent } = current;
|
|
3137
|
+
if (parent === void 0) return false;
|
|
3138
|
+
if (parent.type === AST_NODE_TYPES.ArrowFunctionExpression || parent.type === AST_NODE_TYPES.FunctionDeclaration || parent.type === AST_NODE_TYPES.FunctionExpression) return false;
|
|
3139
|
+
if (parent.type === AST_NODE_TYPES.CallExpression) {
|
|
3140
|
+
if (current === parent.callee) return false;
|
|
3141
|
+
const root = getRootIdentifier$1(parent.callee);
|
|
3142
|
+
if (root === null) return false;
|
|
3143
|
+
return ASSERTION_ROOT_NAMES.has(root.name) || ASSERTION_ROOT_NAMES.has(resolveVitestName$1(sourceCode, root) ?? "");
|
|
3144
|
+
}
|
|
3145
|
+
current = parent;
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
/**
|
|
3149
|
+
* Collects the `?.` tokens along an optional chain's primary spine and the parts
|
|
3150
|
+
* that convert each into a non-null assertion. The `!` is anchored to the token
|
|
3151
|
+
* preceding `?.` rather than written in place of it, because TypeScript forbids
|
|
3152
|
+
* a line break before `!` — a chain wrapped as `a\n?.b` has to become `a!\n.b`,
|
|
3153
|
+
* not `a\n!.b`. What replaces `?.` is therefore only the connector: `.` for a
|
|
3154
|
+
* plain member (`a?.b` -> `a!.b`), nothing for a computed member or optional
|
|
3155
|
+
* call (`a?.[x]` -> `a![x]`, `fn?.()` -> `fn!()`). Only the object/callee spine
|
|
3156
|
+
* is walked — optional chains inside computed keys or call arguments are their
|
|
3157
|
+
* own `ChainExpression` nodes and are visited (and fixed) separately.
|
|
3122
3158
|
*
|
|
3123
3159
|
* @param chain - The chain expression to convert.
|
|
3124
3160
|
* @param sourceCode - Provides token lookups.
|
|
@@ -3131,8 +3167,10 @@ function collectOptionalTokenFixes(chain, sourceCode) {
|
|
|
3131
3167
|
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
3132
3168
|
if (node.optional) {
|
|
3133
3169
|
const token = sourceCode.getTokenAfter(node.object, { filter: (candidate) => candidate.value === "?." });
|
|
3134
|
-
|
|
3135
|
-
|
|
3170
|
+
const anchor = token === null ? null : sourceCode.getTokenBefore(token);
|
|
3171
|
+
if (token !== null && anchor !== null) fixes.push({
|
|
3172
|
+
anchor,
|
|
3173
|
+
text: node.computed ? "" : ".",
|
|
3136
3174
|
token
|
|
3137
3175
|
});
|
|
3138
3176
|
}
|
|
@@ -3142,8 +3180,10 @@ function collectOptionalTokenFixes(chain, sourceCode) {
|
|
|
3142
3180
|
if (node.type === AST_NODE_TYPES.CallExpression) {
|
|
3143
3181
|
if (node.optional) {
|
|
3144
3182
|
const token = sourceCode.getTokenAfter(node.callee, { filter: (candidate) => candidate.value === "?." });
|
|
3145
|
-
|
|
3146
|
-
|
|
3183
|
+
const anchor = token === null ? null : sourceCode.getTokenBefore(token);
|
|
3184
|
+
if (token !== null && anchor !== null) fixes.push({
|
|
3185
|
+
anchor,
|
|
3186
|
+
text: "",
|
|
3147
3187
|
token
|
|
3148
3188
|
});
|
|
3149
3189
|
}
|
|
@@ -3210,8 +3250,8 @@ function createOnce$10(context) {
|
|
|
3210
3250
|
if (!inTestCase || config.allowOptionalChaining) return;
|
|
3211
3251
|
context.report({
|
|
3212
3252
|
fix: (fixer) => {
|
|
3213
|
-
return collectOptionalTokenFixes(node, sourceCode).
|
|
3214
|
-
return fixer.replaceText(optionalFix.token, optionalFix.text);
|
|
3253
|
+
return collectOptionalTokenFixes(node, sourceCode).flatMap((optionalFix) => {
|
|
3254
|
+
return [fixer.insertTextAfter(optionalFix.anchor, "!"), fixer.replaceText(optionalFix.token, optionalFix.text)];
|
|
3215
3255
|
});
|
|
3216
3256
|
},
|
|
3217
3257
|
messageId: MESSAGE_ID$9,
|
|
@@ -3220,7 +3260,10 @@ function createOnce$10(context) {
|
|
|
3220
3260
|
},
|
|
3221
3261
|
"ConditionalExpression": maybeReportConditional,
|
|
3222
3262
|
"IfStatement": maybeReportConditional,
|
|
3223
|
-
"LogicalExpression":
|
|
3263
|
+
"LogicalExpression": function(node) {
|
|
3264
|
+
if (node.operator === "&&" && isInAssertionArgument(node, sourceCode)) return;
|
|
3265
|
+
maybeReportConditional(node);
|
|
3266
|
+
},
|
|
3224
3267
|
"SwitchStatement": maybeReportConditional
|
|
3225
3268
|
};
|
|
3226
3269
|
}
|