@timmo001/oxlint-rules 0.3.1 → 0.3.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/README.md +2 -1
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/dist/cli.js +733 -35
- package/dist/configs/recommended-effect.js +767 -69
- package/dist/configs/recommended.js +535 -30
- package/dist/upstream/anti-slop.js +535 -30
- package/dist/upstream/effect.js +196 -3
- package/package.json +1 -1
- package/vendor/anti-slop/src/effect/index.ts +8 -0
- package/vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts +52 -0
- package/vendor/anti-slop/src/effect/rules/no-manual-tag-comparison.ts +45 -0
- package/vendor/anti-slop/src/effect/rules/no-manual-tagged-construction.ts +37 -0
- package/vendor/anti-slop/src/effect/rules/prefer-effect-match.ts +54 -0
- package/vendor/anti-slop/src/effect/shared/tagged-values.ts +97 -0
- package/vendor/anti-slop/src/index.ts +2 -0
- package/vendor/anti-slop/src/rules/no-known-value-widening.ts +2 -14
- package/vendor/anti-slop/src/rules/no-module-mocking.ts +3 -14
- package/vendor/anti-slop/src/rules/require-readable-spacing.ts +47 -0
- package/vendor/anti-slop/src/shared/reflect-method.ts +2 -13
- package/vendor/anti-slop/src/shared/scope.ts +15 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/LICENSE +22 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/UPSTREAM.md +28 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-ast.ts +51 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-between-statements.ts +906 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-options.d.ts +87 -0
|
@@ -824,14 +824,7 @@ function functionParameterBindingName(parameter, sourceCode) {
|
|
|
824
824
|
return annotationStart === undefined ? sourceText : sourceText.slice(0, annotationStart - parameter.start).trimEnd();
|
|
825
825
|
}
|
|
826
826
|
|
|
827
|
-
// vendor/anti-slop/src/
|
|
828
|
-
function unwrapExpression(expression) {
|
|
829
|
-
let current = expression;
|
|
830
|
-
while (current.type === "ParenthesizedExpression" || current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSTypeAssertion" || current.type === "TSNonNullExpression") {
|
|
831
|
-
current = current.expression;
|
|
832
|
-
}
|
|
833
|
-
return current;
|
|
834
|
-
}
|
|
827
|
+
// vendor/anti-slop/src/shared/scope.ts
|
|
835
828
|
function resolveVariable(sourceCode, identifier) {
|
|
836
829
|
let scope = sourceCode.getScope(identifier);
|
|
837
830
|
while (scope !== null) {
|
|
@@ -842,6 +835,15 @@ function resolveVariable(sourceCode, identifier) {
|
|
|
842
835
|
}
|
|
843
836
|
return null;
|
|
844
837
|
}
|
|
838
|
+
|
|
839
|
+
// vendor/anti-slop/src/rules/no-known-value-widening.ts
|
|
840
|
+
function unwrapExpression(expression) {
|
|
841
|
+
let current = expression;
|
|
842
|
+
while (current.type === "ParenthesizedExpression" || current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSTypeAssertion" || current.type === "TSNonNullExpression") {
|
|
843
|
+
current = current.expression;
|
|
844
|
+
}
|
|
845
|
+
return current;
|
|
846
|
+
}
|
|
845
847
|
function variableDeclarator(variable) {
|
|
846
848
|
if (variable.defs.length !== 1)
|
|
847
849
|
return null;
|
|
@@ -1109,16 +1111,6 @@ var noKnownValueWideningRule = defineRule5({
|
|
|
1109
1111
|
// vendor/anti-slop/src/rules/no-module-mocking.ts
|
|
1110
1112
|
import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
1111
1113
|
var moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]);
|
|
1112
|
-
function resolveVariable2(sourceCode, identifier) {
|
|
1113
|
-
let scope = sourceCode.getScope(identifier);
|
|
1114
|
-
while (scope !== null) {
|
|
1115
|
-
const variable = scope.set.get(identifier.name);
|
|
1116
|
-
if (variable !== undefined)
|
|
1117
|
-
return variable;
|
|
1118
|
-
scope = scope.upper;
|
|
1119
|
-
}
|
|
1120
|
-
return null;
|
|
1121
|
-
}
|
|
1122
1114
|
function importedName(node) {
|
|
1123
1115
|
if (node.type !== "ImportSpecifier")
|
|
1124
1116
|
return null;
|
|
@@ -1130,7 +1122,7 @@ function isTestFrameworkObject(sourceCode, expression) {
|
|
|
1130
1122
|
if ((expression.name === "vi" || expression.name === "jest") && sourceCode.isGlobalReference(expression)) {
|
|
1131
1123
|
return true;
|
|
1132
1124
|
}
|
|
1133
|
-
const variable =
|
|
1125
|
+
const variable = resolveVariable(sourceCode, expression);
|
|
1134
1126
|
if (variable === null || variable.defs.length === 0) {
|
|
1135
1127
|
return expression.name === "vi" || expression.name === "jest";
|
|
1136
1128
|
}
|
|
@@ -1233,22 +1225,12 @@ var noObjectParametersRule = defineRule7({
|
|
|
1233
1225
|
import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
1234
1226
|
|
|
1235
1227
|
// vendor/anti-slop/src/shared/reflect-method.ts
|
|
1236
|
-
function resolveVariable3(sourceCode, identifier) {
|
|
1237
|
-
let scope = sourceCode.getScope(identifier);
|
|
1238
|
-
while (scope !== null) {
|
|
1239
|
-
const variable = scope.set.get(identifier.name);
|
|
1240
|
-
if (variable !== undefined)
|
|
1241
|
-
return variable;
|
|
1242
|
-
scope = scope.upper;
|
|
1243
|
-
}
|
|
1244
|
-
return null;
|
|
1245
|
-
}
|
|
1246
1228
|
function isGlobalReflect(sourceCode, expression) {
|
|
1247
1229
|
if (expression.type !== "Identifier" || expression.name !== "Reflect")
|
|
1248
1230
|
return false;
|
|
1249
1231
|
if (sourceCode.isGlobalReference(expression))
|
|
1250
1232
|
return true;
|
|
1251
|
-
const variable =
|
|
1233
|
+
const variable = resolveVariable(sourceCode, expression);
|
|
1252
1234
|
return variable === null || variable.defs.length === 0;
|
|
1253
1235
|
}
|
|
1254
1236
|
function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
@@ -1913,6 +1895,528 @@ var noWidenThenAssertRule = defineRule16({
|
|
|
1913
1895
|
}
|
|
1914
1896
|
});
|
|
1915
1897
|
|
|
1898
|
+
// vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-ast.ts
|
|
1899
|
+
var LINEBREAKS = new Set([`\r
|
|
1900
|
+
`, "\r", `
|
|
1901
|
+
`, "\u2028", "\u2029"]);
|
|
1902
|
+
var isClosingBraceToken = (token) => token.type === "Punctuator" && token.value === "}";
|
|
1903
|
+
var isSemicolonToken = (token) => token.type === "Punctuator" && token.value === ";";
|
|
1904
|
+
var isNotSemicolonToken = (token) => !isSemicolonToken(token);
|
|
1905
|
+
var isTokenOnSameLine = (left, right) => left.loc.end.line === right.loc.start.line;
|
|
1906
|
+
var isFunction = (node) => node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
1907
|
+
var isSingleLine = (node) => node.loc.start.line === node.loc.end.line;
|
|
1908
|
+
var skipChainExpression = (node) => node.type === "ChainExpression" ? node.expression : node;
|
|
1909
|
+
var isTopLevelExpressionStatement = (node) => node.type === "ExpressionStatement" && (node.parent.type === "Program" || node.parent.type === "BlockStatement" && isFunction(node.parent.parent));
|
|
1910
|
+
function isParenthesized(node, sourceCode) {
|
|
1911
|
+
const before = sourceCode.getTokenBefore(node);
|
|
1912
|
+
const after = sourceCode.getTokenAfter(node);
|
|
1913
|
+
return before?.value === "(" && after?.value === ")";
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-between-statements.ts
|
|
1917
|
+
var CJS_EXPORT = /^(?:module\s*\.\s*)?exports(?:\s*\.|\s*\[|$)/u;
|
|
1918
|
+
var CJS_IMPORT = /^require\(/u;
|
|
1919
|
+
var LT = `[${Array.from(LINEBREAKS).join("")}]`;
|
|
1920
|
+
var PADDING_LINE_SEQUENCE = new RegExp(String.raw`^(\s*?${LT})\s*${LT}(\s*;?)$`, "u");
|
|
1921
|
+
function isSelectorOption(option) {
|
|
1922
|
+
return typeof option === "object" && !Array.isArray(option);
|
|
1923
|
+
}
|
|
1924
|
+
function newKeywordTester(type, keyword) {
|
|
1925
|
+
return {
|
|
1926
|
+
test(node, sourceCode) {
|
|
1927
|
+
const isSameKeyword = sourceCode.getFirstToken(node)?.value === keyword;
|
|
1928
|
+
const isSameType = Array.isArray(type) ? type.includes(node.type) : type === node.type;
|
|
1929
|
+
return isSameKeyword && isSameType;
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
function newNodeTypeTester(type) {
|
|
1934
|
+
return {
|
|
1935
|
+
test: (node) => node.type === type
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
function isIIFEStatement(node) {
|
|
1939
|
+
if (node.type === "ExpressionStatement") {
|
|
1940
|
+
let expression = skipChainExpression(node.expression);
|
|
1941
|
+
if (expression.type === "UnaryExpression")
|
|
1942
|
+
expression = skipChainExpression(expression.argument);
|
|
1943
|
+
if (expression.type === "CallExpression") {
|
|
1944
|
+
let node = expression.callee;
|
|
1945
|
+
while (node.type === "SequenceExpression") {
|
|
1946
|
+
const lastExpression = node.expressions.at(-1);
|
|
1947
|
+
if (lastExpression === undefined)
|
|
1948
|
+
throw new Error("Padding rule invariant: sequence expression is empty");
|
|
1949
|
+
node = lastExpression;
|
|
1950
|
+
}
|
|
1951
|
+
return isFunction(node);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
return false;
|
|
1955
|
+
}
|
|
1956
|
+
function isCJSRequire(node) {
|
|
1957
|
+
if (node.type === "VariableDeclaration") {
|
|
1958
|
+
const declaration = node.declarations[0];
|
|
1959
|
+
if (declaration?.init) {
|
|
1960
|
+
let call = declaration?.init;
|
|
1961
|
+
while (call.type === "MemberExpression")
|
|
1962
|
+
call = call.object;
|
|
1963
|
+
if (call.type === "CallExpression" && call.callee.type === "Identifier") {
|
|
1964
|
+
return call.callee.name === "require";
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
return false;
|
|
1969
|
+
}
|
|
1970
|
+
function isBlockLikeStatement(node, sourceCode) {
|
|
1971
|
+
if (node.type === "DoWhileStatement" && node.body.type === "BlockStatement") {
|
|
1972
|
+
return true;
|
|
1973
|
+
}
|
|
1974
|
+
if (isIIFEStatement(node))
|
|
1975
|
+
return true;
|
|
1976
|
+
const lastToken = sourceCode.getLastToken(node, isNotSemicolonToken);
|
|
1977
|
+
const belongingNode = lastToken && isClosingBraceToken(lastToken) ? sourceCode.getNodeByRangeIndex(lastToken.range[0]) : null;
|
|
1978
|
+
return !!belongingNode && (belongingNode.type === "BlockStatement" || belongingNode.type === "SwitchStatement");
|
|
1979
|
+
}
|
|
1980
|
+
function isDirective(node, sourceCode) {
|
|
1981
|
+
return isTopLevelExpressionStatement(node) && node.expression.type === "Literal" && typeof node.expression.value === "string" && !isParenthesized(node.expression, sourceCode);
|
|
1982
|
+
}
|
|
1983
|
+
function isDirectivePrologue(node, sourceCode) {
|
|
1984
|
+
if (isDirective(node, sourceCode) && node.parent && "body" in node.parent && Array.isArray(node.parent.body)) {
|
|
1985
|
+
for (const sibling of node.parent.body) {
|
|
1986
|
+
if (sibling === node)
|
|
1987
|
+
break;
|
|
1988
|
+
if (!isDirective(sibling, sourceCode))
|
|
1989
|
+
return false;
|
|
1990
|
+
}
|
|
1991
|
+
return true;
|
|
1992
|
+
}
|
|
1993
|
+
return false;
|
|
1994
|
+
}
|
|
1995
|
+
function isCJSExport(node) {
|
|
1996
|
+
if (node.type === "ExpressionStatement") {
|
|
1997
|
+
const expression = node.expression;
|
|
1998
|
+
if (expression.type === "AssignmentExpression") {
|
|
1999
|
+
let left = expression.left;
|
|
2000
|
+
if (left.type === "MemberExpression") {
|
|
2001
|
+
while (left.object.type === "MemberExpression")
|
|
2002
|
+
left = left.object;
|
|
2003
|
+
return left.object.type === "Identifier" && (left.object.name === "exports" || left.object.name === "module" && left.property.type === "Identifier" && left.property.name === "exports");
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
return false;
|
|
2008
|
+
}
|
|
2009
|
+
function isExpression(node, sourceCode) {
|
|
2010
|
+
return node.type === "ExpressionStatement" && !isDirectivePrologue(node, sourceCode);
|
|
2011
|
+
}
|
|
2012
|
+
function getActualLastToken(node, sourceCode) {
|
|
2013
|
+
const semiToken = sourceCode.getLastToken(node);
|
|
2014
|
+
const prevToken = sourceCode.getTokenBefore(semiToken);
|
|
2015
|
+
const nextToken = sourceCode.getTokenAfter(semiToken);
|
|
2016
|
+
const isSemicolonLessStyle = prevToken && nextToken && prevToken.range[0] >= node.range[0] && isSemicolonToken(semiToken) && !isTokenOnSameLine(prevToken, semiToken) && isTokenOnSameLine(semiToken, nextToken);
|
|
2017
|
+
return isSemicolonLessStyle ? prevToken : semiToken;
|
|
2018
|
+
}
|
|
2019
|
+
function replacerToRemovePaddingLines(_, trailingSpaces, indentSpaces) {
|
|
2020
|
+
return trailingSpaces + indentSpaces;
|
|
2021
|
+
}
|
|
2022
|
+
function getReportLoc(node, sourceCode) {
|
|
2023
|
+
if (isSingleLine(node))
|
|
2024
|
+
return node.loc;
|
|
2025
|
+
const line = node.loc.start.line;
|
|
2026
|
+
const sourceLine = sourceCode.lines[line - 1];
|
|
2027
|
+
if (sourceLine === undefined)
|
|
2028
|
+
throw new Error("Padding rule invariant: statement source line is missing");
|
|
2029
|
+
return {
|
|
2030
|
+
start: node.loc.start,
|
|
2031
|
+
end: {
|
|
2032
|
+
line,
|
|
2033
|
+
column: sourceLine.length
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
function verifyForAny() {}
|
|
2038
|
+
function verifyForNever(context, _, nextNode, paddingLines) {
|
|
2039
|
+
if (paddingLines.length === 0)
|
|
2040
|
+
return;
|
|
2041
|
+
context.report({
|
|
2042
|
+
node: nextNode,
|
|
2043
|
+
messageId: "unexpectedBlankLine",
|
|
2044
|
+
loc: getReportLoc(nextNode, context.sourceCode),
|
|
2045
|
+
fix(fixer) {
|
|
2046
|
+
if (paddingLines.length >= 2)
|
|
2047
|
+
return null;
|
|
2048
|
+
const paddingPair = paddingLines[0];
|
|
2049
|
+
if (paddingPair === undefined)
|
|
2050
|
+
throw new Error("Padding rule invariant: reported padding pair is missing");
|
|
2051
|
+
const [prevToken, nextToken] = paddingPair;
|
|
2052
|
+
const start = prevToken.range[1];
|
|
2053
|
+
const end = nextToken.range[0];
|
|
2054
|
+
const text = context.sourceCode.text.slice(start, end).replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines);
|
|
2055
|
+
return fixer.replaceTextRange([start, end], text);
|
|
2056
|
+
}
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
function verifyForAlways(context, prevNode, nextNode, paddingLines) {
|
|
2060
|
+
if (paddingLines.length > 0)
|
|
2061
|
+
return;
|
|
2062
|
+
context.report({
|
|
2063
|
+
node: nextNode,
|
|
2064
|
+
messageId: "expectedBlankLine",
|
|
2065
|
+
loc: getReportLoc(nextNode, context.sourceCode),
|
|
2066
|
+
fix(fixer) {
|
|
2067
|
+
const sourceCode = context.sourceCode;
|
|
2068
|
+
let prevToken = getActualLastToken(prevNode, sourceCode);
|
|
2069
|
+
const nextToken = sourceCode.getFirstTokenBetween(prevToken, nextNode, {
|
|
2070
|
+
includeComments: true,
|
|
2071
|
+
filter(token) {
|
|
2072
|
+
if (isTokenOnSameLine(prevToken, token)) {
|
|
2073
|
+
prevToken = token;
|
|
2074
|
+
return false;
|
|
2075
|
+
}
|
|
2076
|
+
return true;
|
|
2077
|
+
}
|
|
2078
|
+
}) || nextNode;
|
|
2079
|
+
const insertText = isTokenOnSameLine(prevToken, nextToken) ? `
|
|
2080
|
+
|
|
2081
|
+
` : `
|
|
2082
|
+
`;
|
|
2083
|
+
return fixer.insertTextAfter(prevToken, insertText);
|
|
2084
|
+
}
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
var PaddingTypes = {
|
|
2088
|
+
any: { verify: verifyForAny },
|
|
2089
|
+
never: { verify: verifyForNever },
|
|
2090
|
+
always: { verify: verifyForAlways }
|
|
2091
|
+
};
|
|
2092
|
+
var MaybeMultilineStatementType = {
|
|
2093
|
+
"block-like": { test: isBlockLikeStatement },
|
|
2094
|
+
expression: { test: isExpression },
|
|
2095
|
+
return: newKeywordTester("ReturnStatement", "return"),
|
|
2096
|
+
export: newKeywordTester([
|
|
2097
|
+
"ExportAllDeclaration",
|
|
2098
|
+
"ExportDefaultDeclaration",
|
|
2099
|
+
"ExportNamedDeclaration"
|
|
2100
|
+
], "export"),
|
|
2101
|
+
var: newKeywordTester("VariableDeclaration", "var"),
|
|
2102
|
+
let: newKeywordTester("VariableDeclaration", "let"),
|
|
2103
|
+
const: newKeywordTester("VariableDeclaration", "const"),
|
|
2104
|
+
using: {
|
|
2105
|
+
test: (node) => node.type === "VariableDeclaration" && (node.kind === "using" || node.kind === "await using")
|
|
2106
|
+
},
|
|
2107
|
+
type: newKeywordTester("TSTypeAliasDeclaration", "type")
|
|
2108
|
+
};
|
|
2109
|
+
var StatementTypes = {
|
|
2110
|
+
"*": { test: () => true },
|
|
2111
|
+
exports: { test: isCJSExport },
|
|
2112
|
+
require: { test: isCJSRequire },
|
|
2113
|
+
directive: { test: isDirectivePrologue },
|
|
2114
|
+
iife: { test: isIIFEStatement },
|
|
2115
|
+
block: newNodeTypeTester("BlockStatement"),
|
|
2116
|
+
empty: newNodeTypeTester("EmptyStatement"),
|
|
2117
|
+
function: newNodeTypeTester("FunctionDeclaration"),
|
|
2118
|
+
"ts-method": newNodeTypeTester("TSMethodSignature"),
|
|
2119
|
+
break: newKeywordTester("BreakStatement", "break"),
|
|
2120
|
+
case: newKeywordTester("SwitchCase", "case"),
|
|
2121
|
+
class: newKeywordTester("ClassDeclaration", "class"),
|
|
2122
|
+
continue: newKeywordTester("ContinueStatement", "continue"),
|
|
2123
|
+
debugger: newKeywordTester("DebuggerStatement", "debugger"),
|
|
2124
|
+
default: newKeywordTester(["SwitchCase", "ExportDefaultDeclaration"], "default"),
|
|
2125
|
+
do: newKeywordTester("DoWhileStatement", "do"),
|
|
2126
|
+
for: newKeywordTester([
|
|
2127
|
+
"ForStatement",
|
|
2128
|
+
"ForInStatement",
|
|
2129
|
+
"ForOfStatement"
|
|
2130
|
+
], "for"),
|
|
2131
|
+
if: newKeywordTester("IfStatement", "if"),
|
|
2132
|
+
import: newKeywordTester("ImportDeclaration", "import"),
|
|
2133
|
+
switch: newKeywordTester("SwitchStatement", "switch"),
|
|
2134
|
+
throw: newKeywordTester("ThrowStatement", "throw"),
|
|
2135
|
+
try: newKeywordTester("TryStatement", "try"),
|
|
2136
|
+
while: newKeywordTester(["WhileStatement", "DoWhileStatement"], "while"),
|
|
2137
|
+
with: newKeywordTester("WithStatement", "with"),
|
|
2138
|
+
"cjs-export": {
|
|
2139
|
+
test: (node, sourceCode) => node.type === "ExpressionStatement" && node.expression.type === "AssignmentExpression" && CJS_EXPORT.test(sourceCode.getText(node.expression.left))
|
|
2140
|
+
},
|
|
2141
|
+
"cjs-import": {
|
|
2142
|
+
test: (node, sourceCode) => node.type === "VariableDeclaration" && node.declarations.length > 0 && node.declarations[0]?.init != null && CJS_IMPORT.test(sourceCode.getText(node.declarations[0].init))
|
|
2143
|
+
},
|
|
2144
|
+
enum: newKeywordTester("TSEnumDeclaration", "enum"),
|
|
2145
|
+
interface: newKeywordTester("TSInterfaceDeclaration", "interface"),
|
|
2146
|
+
"function-overload": newNodeTypeTester("TSDeclareFunction"),
|
|
2147
|
+
...Object.fromEntries(Object.entries(MaybeMultilineStatementType).flatMap(([key, value]) => [
|
|
2148
|
+
[key, value],
|
|
2149
|
+
[
|
|
2150
|
+
`singleline-${key}`,
|
|
2151
|
+
{
|
|
2152
|
+
...value,
|
|
2153
|
+
test: (node, sourceCode) => value.test(node, sourceCode) && isSingleLine(node)
|
|
2154
|
+
}
|
|
2155
|
+
],
|
|
2156
|
+
[
|
|
2157
|
+
`multiline-${key}`,
|
|
2158
|
+
{
|
|
2159
|
+
...value,
|
|
2160
|
+
test: (node, sourceCode) => value.test(node, sourceCode) && !isSingleLine(node)
|
|
2161
|
+
}
|
|
2162
|
+
]
|
|
2163
|
+
]))
|
|
2164
|
+
};
|
|
2165
|
+
function createPaddingLineRule(options) {
|
|
2166
|
+
return {
|
|
2167
|
+
meta: {
|
|
2168
|
+
type: "layout",
|
|
2169
|
+
docs: {
|
|
2170
|
+
description: "Require or disallow padding lines between statements"
|
|
2171
|
+
},
|
|
2172
|
+
fixable: "whitespace",
|
|
2173
|
+
hasSuggestions: false,
|
|
2174
|
+
schema: {
|
|
2175
|
+
$defs: {
|
|
2176
|
+
paddingType: {
|
|
2177
|
+
type: "string",
|
|
2178
|
+
enum: Object.keys(PaddingTypes)
|
|
2179
|
+
},
|
|
2180
|
+
statementType: {
|
|
2181
|
+
type: "string",
|
|
2182
|
+
enum: Object.keys(StatementTypes)
|
|
2183
|
+
},
|
|
2184
|
+
selectorOption: {
|
|
2185
|
+
type: "object",
|
|
2186
|
+
properties: {
|
|
2187
|
+
selector: {
|
|
2188
|
+
type: "string"
|
|
2189
|
+
},
|
|
2190
|
+
lineMode: {
|
|
2191
|
+
type: "string",
|
|
2192
|
+
enum: ["any", "singleline", "multiline"]
|
|
2193
|
+
}
|
|
2194
|
+
},
|
|
2195
|
+
required: ["selector"],
|
|
2196
|
+
additionalProperties: false
|
|
2197
|
+
},
|
|
2198
|
+
statementMatcher: {
|
|
2199
|
+
anyOf: [
|
|
2200
|
+
{ $ref: "#/$defs/statementType" },
|
|
2201
|
+
{ $ref: "#/$defs/selectorOption" }
|
|
2202
|
+
]
|
|
2203
|
+
},
|
|
2204
|
+
statementOption: {
|
|
2205
|
+
anyOf: [
|
|
2206
|
+
{ $ref: "#/$defs/statementMatcher" },
|
|
2207
|
+
{
|
|
2208
|
+
type: "array",
|
|
2209
|
+
items: { $ref: "#/$defs/statementMatcher" },
|
|
2210
|
+
minItems: 1,
|
|
2211
|
+
uniqueItems: true,
|
|
2212
|
+
additionalItems: false
|
|
2213
|
+
}
|
|
2214
|
+
]
|
|
2215
|
+
}
|
|
2216
|
+
},
|
|
2217
|
+
type: "array",
|
|
2218
|
+
additionalItems: false,
|
|
2219
|
+
items: {
|
|
2220
|
+
type: "object",
|
|
2221
|
+
properties: {
|
|
2222
|
+
blankLine: { $ref: "#/$defs/paddingType" },
|
|
2223
|
+
prev: { $ref: "#/$defs/statementOption" },
|
|
2224
|
+
next: { $ref: "#/$defs/statementOption" }
|
|
2225
|
+
},
|
|
2226
|
+
additionalProperties: false,
|
|
2227
|
+
required: ["blankLine", "prev", "next"]
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
messages: {
|
|
2231
|
+
unexpectedBlankLine: "Unexpected blank line before this statement.",
|
|
2232
|
+
expectedBlankLine: "Expected blank line before this statement."
|
|
2233
|
+
}
|
|
2234
|
+
},
|
|
2235
|
+
create(context) {
|
|
2236
|
+
const sourceCode = context.sourceCode;
|
|
2237
|
+
const selectorMatchedNodes = new Map;
|
|
2238
|
+
const pendingPairs = [];
|
|
2239
|
+
function collectSelectorOption(option) {
|
|
2240
|
+
if (Array.isArray(option)) {
|
|
2241
|
+
for (const item of option)
|
|
2242
|
+
collectSelectorOption(item);
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
if (!isSelectorOption(option))
|
|
2246
|
+
return;
|
|
2247
|
+
selectorMatchedNodes.set(option.selector, new Set);
|
|
2248
|
+
}
|
|
2249
|
+
for (const configure of options) {
|
|
2250
|
+
collectSelectorOption(configure.prev);
|
|
2251
|
+
collectSelectorOption(configure.next);
|
|
2252
|
+
}
|
|
2253
|
+
let scopeInfo = null;
|
|
2254
|
+
function enterScope() {
|
|
2255
|
+
scopeInfo = {
|
|
2256
|
+
upper: scopeInfo,
|
|
2257
|
+
prevNode: null
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
function exitScope() {
|
|
2261
|
+
if (scopeInfo)
|
|
2262
|
+
scopeInfo = scopeInfo.upper;
|
|
2263
|
+
}
|
|
2264
|
+
function match(node, type) {
|
|
2265
|
+
let innerStatementNode = node;
|
|
2266
|
+
while (innerStatementNode.type === "LabeledStatement")
|
|
2267
|
+
innerStatementNode = innerStatementNode.body;
|
|
2268
|
+
if (Array.isArray(type))
|
|
2269
|
+
return type.some(match.bind(null, innerStatementNode));
|
|
2270
|
+
if (isSelectorOption(type)) {
|
|
2271
|
+
const matchedNodes = selectorMatchedNodes.get(type.selector);
|
|
2272
|
+
if (!matchedNodes?.has(innerStatementNode))
|
|
2273
|
+
return false;
|
|
2274
|
+
const lineMode = type.lineMode;
|
|
2275
|
+
if (lineMode === "singleline")
|
|
2276
|
+
return isSingleLine(innerStatementNode);
|
|
2277
|
+
else if (lineMode === "multiline")
|
|
2278
|
+
return !isSingleLine(innerStatementNode);
|
|
2279
|
+
return true;
|
|
2280
|
+
} else {
|
|
2281
|
+
const statementType = StatementTypes[type];
|
|
2282
|
+
if (statementType === undefined)
|
|
2283
|
+
throw new Error(`Padding rule invariant: unsupported statement type ${type}`);
|
|
2284
|
+
return statementType.test(innerStatementNode, sourceCode);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
function getPaddingType(prevNode, nextNode) {
|
|
2288
|
+
for (let i = options.length - 1;i >= 0; --i) {
|
|
2289
|
+
const configure = options[i];
|
|
2290
|
+
if (configure === undefined)
|
|
2291
|
+
throw new Error("Padding rule invariant: configuration entry is missing");
|
|
2292
|
+
if (match(prevNode, configure.prev) && match(nextNode, configure.next)) {
|
|
2293
|
+
return PaddingTypes[configure.blankLine];
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
return PaddingTypes.any;
|
|
2297
|
+
}
|
|
2298
|
+
function getPaddingLineSequences(prevNode, nextNode) {
|
|
2299
|
+
const pairs = [];
|
|
2300
|
+
let prevToken = getActualLastToken(prevNode, sourceCode);
|
|
2301
|
+
if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
|
|
2302
|
+
do {
|
|
2303
|
+
const token = sourceCode.getTokenAfter(prevToken, {
|
|
2304
|
+
includeComments: true
|
|
2305
|
+
});
|
|
2306
|
+
if (token.loc.start.line - prevToken.loc.end.line >= 2)
|
|
2307
|
+
pairs.push([prevToken, token]);
|
|
2308
|
+
prevToken = token;
|
|
2309
|
+
} while (prevToken.range[0] < nextNode.range[0]);
|
|
2310
|
+
}
|
|
2311
|
+
return pairs;
|
|
2312
|
+
}
|
|
2313
|
+
function verify(node) {
|
|
2314
|
+
if (!node.parent || ![
|
|
2315
|
+
"BlockStatement",
|
|
2316
|
+
"Program",
|
|
2317
|
+
"StaticBlock",
|
|
2318
|
+
"SwitchCase",
|
|
2319
|
+
"SwitchStatement",
|
|
2320
|
+
"TSInterfaceBody",
|
|
2321
|
+
"TSModuleBlock",
|
|
2322
|
+
"TSTypeLiteral"
|
|
2323
|
+
].includes(node.parent.type)) {
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
const prevNode = scopeInfo.prevNode;
|
|
2327
|
+
if (prevNode)
|
|
2328
|
+
pendingPairs.push({ prevNode, nextNode: node });
|
|
2329
|
+
scopeInfo.prevNode = node;
|
|
2330
|
+
}
|
|
2331
|
+
function verifyPendingPairs() {
|
|
2332
|
+
for (const { prevNode, nextNode } of pendingPairs) {
|
|
2333
|
+
const type = getPaddingType(prevNode, nextNode);
|
|
2334
|
+
const paddingLines = getPaddingLineSequences(prevNode, nextNode);
|
|
2335
|
+
type.verify(context, prevNode, nextNode, paddingLines);
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
function verifyThenEnterScope(node) {
|
|
2339
|
+
verify(node);
|
|
2340
|
+
enterScope();
|
|
2341
|
+
}
|
|
2342
|
+
const selectorMatchListeners = Object.fromEntries(Array.from(selectorMatchedNodes.keys(), (selector) => [
|
|
2343
|
+
selector,
|
|
2344
|
+
(node) => {
|
|
2345
|
+
selectorMatchedNodes.get(selector)?.add(node);
|
|
2346
|
+
}
|
|
2347
|
+
]));
|
|
2348
|
+
return {
|
|
2349
|
+
Program: enterScope,
|
|
2350
|
+
"Program:exit": () => {
|
|
2351
|
+
verifyPendingPairs();
|
|
2352
|
+
exitScope();
|
|
2353
|
+
},
|
|
2354
|
+
BlockStatement: enterScope,
|
|
2355
|
+
"BlockStatement:exit": exitScope,
|
|
2356
|
+
SwitchStatement: enterScope,
|
|
2357
|
+
"SwitchStatement:exit": exitScope,
|
|
2358
|
+
SwitchCase: verifyThenEnterScope,
|
|
2359
|
+
"SwitchCase:exit": exitScope,
|
|
2360
|
+
StaticBlock: enterScope,
|
|
2361
|
+
"StaticBlock:exit": exitScope,
|
|
2362
|
+
TSInterfaceBody: enterScope,
|
|
2363
|
+
"TSInterfaceBody:exit": exitScope,
|
|
2364
|
+
TSModuleBlock: enterScope,
|
|
2365
|
+
"TSModuleBlock:exit": exitScope,
|
|
2366
|
+
TSTypeLiteral: enterScope,
|
|
2367
|
+
"TSTypeLiteral:exit": exitScope,
|
|
2368
|
+
TSDeclareFunction: verifyThenEnterScope,
|
|
2369
|
+
"TSDeclareFunction:exit": exitScope,
|
|
2370
|
+
TSMethodSignature: verifyThenEnterScope,
|
|
2371
|
+
"TSMethodSignature:exit": exitScope,
|
|
2372
|
+
":statement": verify,
|
|
2373
|
+
...selectorMatchListeners
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
// vendor/anti-slop/src/rules/require-readable-spacing.ts
|
|
2380
|
+
var paddingRule = createPaddingLineRule([
|
|
2381
|
+
{ blankLine: "always", prev: "import", next: "*" },
|
|
2382
|
+
{ blankLine: "always", prev: "*", next: { selector: "Program > :not(ImportDeclaration)" } },
|
|
2383
|
+
{ blankLine: "always", prev: { selector: "Program > :not(ImportDeclaration)" }, next: "*" },
|
|
2384
|
+
{ blankLine: "always", prev: "*", next: ["function", "class", "interface", "type"] },
|
|
2385
|
+
{ blankLine: "always", prev: ["function", "class", "interface", "type"], next: "*" },
|
|
2386
|
+
{
|
|
2387
|
+
blankLine: "always",
|
|
2388
|
+
prev: "*",
|
|
2389
|
+
next: ["multiline-const", "multiline-let", "multiline-var", "multiline-using"]
|
|
2390
|
+
},
|
|
2391
|
+
{
|
|
2392
|
+
blankLine: "always",
|
|
2393
|
+
prev: ["multiline-const", "multiline-let", "multiline-var", "multiline-using"],
|
|
2394
|
+
next: "*"
|
|
2395
|
+
},
|
|
2396
|
+
{ blankLine: "always", prev: "*", next: ["return", "if", "switch", "try", "for", "while", "do"] },
|
|
2397
|
+
{ blankLine: "always", prev: "block-like", next: "*" },
|
|
2398
|
+
{ blankLine: "any", prev: "import", next: "import" },
|
|
2399
|
+
{
|
|
2400
|
+
blankLine: "any",
|
|
2401
|
+
prev: {
|
|
2402
|
+
selector: ':matches(TSDeclareFunction, ExportNamedDeclaration[declaration.type="TSDeclareFunction"])'
|
|
2403
|
+
},
|
|
2404
|
+
next: {
|
|
2405
|
+
selector: ':matches(TSDeclareFunction, FunctionDeclaration, ExportNamedDeclaration[declaration.type="TSDeclareFunction"], ExportNamedDeclaration[declaration.type="FunctionDeclaration"])'
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
]);
|
|
2409
|
+
var requireReadableSpacingRule = {
|
|
2410
|
+
...paddingRule,
|
|
2411
|
+
meta: {
|
|
2412
|
+
...paddingRule.meta,
|
|
2413
|
+
docs: {
|
|
2414
|
+
description: "Require readable spacing between declarations and logical statement groups."
|
|
2415
|
+
},
|
|
2416
|
+
schema: []
|
|
2417
|
+
}
|
|
2418
|
+
};
|
|
2419
|
+
|
|
1916
2420
|
// vendor/anti-slop/src/rules/require-safety-comment-for-type-assertion.ts
|
|
1917
2421
|
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
1918
2422
|
var DEFAULT_SAFETY_MARKERS = ["SAFETY"];
|
|
@@ -2026,6 +2530,7 @@ var antiSlopPlugin = eslintCompatPlugin({
|
|
|
2026
2530
|
"no-unknown-returns": noUnknownReturnsRule,
|
|
2027
2531
|
"no-unknown-type-aliases": noUnknownTypeAliasesRule,
|
|
2028
2532
|
"no-widen-then-assert": noWidenThenAssertRule,
|
|
2533
|
+
"require-readable-spacing": requireReadableSpacingRule,
|
|
2029
2534
|
"require-safety-comment-for-type-assertion": requireSafetyCommentForTypeAssertionRule
|
|
2030
2535
|
}
|
|
2031
2536
|
});
|