@deslop/coding-standards 0.1.761 → 0.1.804
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 +73 -0
- package/dist/{MutableRef-DT4DAKeI.mjs → MutableRef-NhSl8G9M.mjs} +145 -4
- package/dist/install.js +2 -2
- package/dist/oxlint.d.ts +9 -1
- package/dist/oxlint.js +305 -148
- package/package.json +1 -1
- package/skills/design/SKILL.md +73 -61
- package/skills/engineering/SKILL.md +31 -17
- package/skills/testing/SKILL.md +6 -4
package/dist/oxlint.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $ as fromOption, $n as isNullish$1, A as getSomes, Bn as optimize, C as findFirst, Ct as some, D as flatten, E as flatMap$1, Fn as symbol, G as sort, Gn as hasProperty, H as prepend, Hn as string, I as join, J as get$2, K as take, Kn as isBoolean, L as last, Ln as combine, M as isArrayEmpty, N as isArrayNonEmpty, Nn as byReferenceUnsafe, Pn as equals, Rn as hash, S as filterMap, St as orElse, Tn as NodeInspectSymbol, V as of, W as some$1, Wn as symbol$1, X as remove, Xn as isNotNull, Z as values, Zn as isNotNullish, _ as dropRight, _t as isSome, a as includes, ar as isString, at as all, b as every, bt as match$1, c as startsWith, ct as filter, d as TaggedError, dt as flatten$1, er as isNumber, ft as fromNullishOr, g as dedupe, h as contains$1, i as Order, ir as isReadonlyObject, j as head, k as get$1, lt as firstSomeOf, m as appendAll, mr as dual, mt as getOrElse, n as make$2, o as match, ot as contains, p as append, pt as fromUndefinedOr, q as fromEntries, r as update, s as split, st as exists, t as get$3, ut as flatMap, v as empty, vr as pipe, w as findFirstIndex, wt as zipWith, x as filter$1, xr as pipeArguments, xt as none, y as ensure, yt as map, z as map$1, zn as number } from "./MutableRef-NhSl8G9M.mjs";
|
|
2
2
|
//#region ../../node_modules/.pnpm/effect@4.0.0/node_modules/effect/dist/internal/graph.js
|
|
3
3
|
/** @internal */
|
|
4
4
|
const TypeId = "~effect/Graph";
|
|
@@ -612,7 +612,7 @@ Object.freeze({
|
|
|
612
612
|
}
|
|
613
613
|
});
|
|
614
614
|
//#endregion
|
|
615
|
-
//#region ../../node_modules/.pnpm/oxlint@1.85.0_oxlint-tsgolint@7.0.2003_vite-plus@1.0.0_@opentelemetry+api@1.9.1_@types+
|
|
615
|
+
//#region ../../node_modules/.pnpm/oxlint@1.85.0_oxlint-tsgolint@7.0.2003_vite-plus@1.0.0_@opentelemetry+api@1.9.1_@types+_bd1fc584f29238a6938d999624a6e509/node_modules/oxlint/dist/index.js
|
|
616
616
|
/**
|
|
617
617
|
* Define an Oxlint configuration with type inference.
|
|
618
618
|
*
|
|
@@ -668,16 +668,11 @@ function importedMember(input) {
|
|
|
668
668
|
source: "effect"
|
|
669
669
|
}) && (input.propertyName === void 0 || contains(memberName(input.node), input.propertyName));
|
|
670
670
|
}
|
|
671
|
-
function
|
|
672
|
-
|
|
673
|
-
return builder.type === "MemberExpression" && importedMember({
|
|
674
|
-
context: input.context,
|
|
675
|
-
importedName: "Effect",
|
|
676
|
-
node: builder
|
|
677
|
-
}) ? memberName(builder) : none();
|
|
671
|
+
function matches(regExp) {
|
|
672
|
+
return (text) => isSome(pipe(text, match(regExp)));
|
|
678
673
|
}
|
|
679
674
|
function isSchemaOperationName(name) {
|
|
680
|
-
return /^(?:(?:decode|encode)(?:Unknown)?(?:Effect|Exit|Option|Promise|Result|Sync)|asserts|is)$/u
|
|
675
|
+
return matches(/^(?:(?:decode|encode)(?:Unknown)?(?:Effect|Exit|Option|Promise|Result|Sync)|asserts|is)$/u)(name);
|
|
681
676
|
}
|
|
682
677
|
function isSchemaOperationCall(input) {
|
|
683
678
|
if (input.node.callee.type !== "MemberExpression" || !importedMember({
|
|
@@ -795,7 +790,7 @@ function suspendSeeds(input) {
|
|
|
795
790
|
return pipe(suspendedTypeName({
|
|
796
791
|
context: input.context,
|
|
797
792
|
node: input.node
|
|
798
|
-
}), match({
|
|
793
|
+
}), match$1({
|
|
799
794
|
onNone: () => seeds,
|
|
800
795
|
onSome: (name) => prepend(seeds, name)
|
|
801
796
|
}));
|
|
@@ -866,7 +861,7 @@ function testedValue(node) {
|
|
|
866
861
|
function isSingletonArray(input) {
|
|
867
862
|
if (input.node.type !== "ArrayExpression" || input.node.elements.length !== 1) return false;
|
|
868
863
|
const element = input.node.elements[0];
|
|
869
|
-
if (isNullish(element) || element.type === "SpreadElement") return false;
|
|
864
|
+
if (isNullish$1(element) || element.type === "SpreadElement") return false;
|
|
870
865
|
return input.context.sourceCode.getText(element) === input.context.sourceCode.getText(input.value);
|
|
871
866
|
}
|
|
872
867
|
function restatesArrayEnsure(input) {
|
|
@@ -892,33 +887,10 @@ const noArrayWrapTernary = defineRule({
|
|
|
892
887
|
});
|
|
893
888
|
//#endregion
|
|
894
889
|
//#region src/rules/no-constant-function.ts
|
|
895
|
-
function returnsConstant(node) {
|
|
896
|
-
const returned = returnedExpression(node);
|
|
897
|
-
return isNotNullish(returned) && (returned.type === "Literal" || returned.type === "Identifier" || returned.type === "MemberExpression" || returned.type === "TemplateLiteral" && isArrayEmpty(returned.expressions));
|
|
898
|
-
}
|
|
899
|
-
function functionScope(input) {
|
|
900
|
-
if (input.scope.block === input.node) return some(input.scope);
|
|
901
|
-
return findFirst(input.scope.childScopes, (child) => child.block === input.node);
|
|
902
|
-
}
|
|
903
|
-
function scopeReferences(scope) {
|
|
904
|
-
return appendAll(scope.references, flatMap$1(scope.childScopes, scopeReferences));
|
|
905
|
-
}
|
|
906
|
-
function isImportedVariable(variable) {
|
|
907
|
-
return isArrayNonEmpty(variable.defs) && every(variable.defs, (definition) => definition.type === "ImportBinding");
|
|
908
|
-
}
|
|
909
|
-
function resolvesToImport(reference) {
|
|
910
|
-
return pipe(variableFromScope({
|
|
911
|
-
name: reference.identifier.name,
|
|
912
|
-
scope: reference.from
|
|
913
|
-
}), exists(isImportedVariable));
|
|
914
|
-
}
|
|
915
890
|
function isConstantFunction(input) {
|
|
916
|
-
if (input.node.async || input.node.generator || isNotNullish(input.node.typeParameters)) return false;
|
|
917
|
-
|
|
918
|
-
return
|
|
919
|
-
node: input.node,
|
|
920
|
-
scope: input.context.sourceCode.getScope(input.node)
|
|
921
|
-
}), exists((scope) => every(scopeReferences(scope), resolvesToImport))) && pipe(bindingName(input.node), flatMap((name) => variableFromScope({
|
|
891
|
+
if (input.node.async || input.node.generator || isArrayNonEmpty(input.node.params) || isNotNullish(input.node.typeParameters)) return false;
|
|
892
|
+
const returned = returnedExpression(input.node);
|
|
893
|
+
return isNotNullish(returned) && (returned.type === "Literal" && !hasProperty(returned, "regex") || returned.type === "TemplateLiteral" && isArrayEmpty(returned.expressions)) && pipe(bindingName(input.node), flatMap((name) => variableFromScope({
|
|
922
894
|
name,
|
|
923
895
|
scope: input.context.sourceCode.getScope(input.node)
|
|
924
896
|
})), exists((variable) => every(filter$1(variable.references, (reference) => reference.isRead()), (reference) => reference.identifier.parent.type === "CallExpression" && reference.identifier.parent.callee === reference.identifier)));
|
|
@@ -928,20 +900,15 @@ function isConstBound(node) {
|
|
|
928
900
|
}
|
|
929
901
|
const noConstantFunction = defineRule({
|
|
930
902
|
create: (context) => {
|
|
931
|
-
const spans = make$2(empty());
|
|
932
|
-
function mark(node) {
|
|
933
|
-
update(spans, append(node));
|
|
934
|
-
}
|
|
935
903
|
function report(node) {
|
|
936
904
|
if (isConstantFunction({
|
|
937
905
|
context,
|
|
938
|
-
node
|
|
939
|
-
spans: get$3(spans)
|
|
906
|
+
node
|
|
940
907
|
}) && !singleUseThunk({
|
|
941
908
|
context,
|
|
942
909
|
node
|
|
943
910
|
})) context.report({
|
|
944
|
-
message: "
|
|
911
|
+
message: "Inline this argument-free literal return at its call sites.",
|
|
945
912
|
node
|
|
946
913
|
});
|
|
947
914
|
}
|
|
@@ -952,31 +919,32 @@ const noConstantFunction = defineRule({
|
|
|
952
919
|
"FunctionDeclaration:exit": report,
|
|
953
920
|
"FunctionExpression:exit": (node) => {
|
|
954
921
|
if (isConstBound(node)) report(node);
|
|
955
|
-
}
|
|
956
|
-
JSXElement: mark,
|
|
957
|
-
JSXFragment: mark,
|
|
958
|
-
ThisExpression: mark
|
|
922
|
+
}
|
|
959
923
|
};
|
|
960
924
|
},
|
|
961
925
|
meta: { type: "problem" }
|
|
962
926
|
});
|
|
963
927
|
//#endregion
|
|
964
928
|
//#region src/rules/no-deep-pipe.ts
|
|
965
|
-
function isPipeCall(node) {
|
|
966
|
-
return node.type === "CallExpression" && node.callee.type === "Identifier" &&
|
|
929
|
+
function isPipeCall(context, node) {
|
|
930
|
+
return node.type === "CallExpression" && node.callee.type === "Identifier" && isImportBinding({
|
|
931
|
+
context,
|
|
932
|
+
importedName: "pipe",
|
|
933
|
+
node: node.callee,
|
|
934
|
+
source: "effect"
|
|
935
|
+
});
|
|
967
936
|
}
|
|
968
|
-
function enclosingPipes(node) {
|
|
937
|
+
function enclosingPipes(context, node) {
|
|
969
938
|
if (node.type === "Program" || contains$1([
|
|
970
939
|
"ArrowFunctionExpression",
|
|
971
940
|
"FunctionDeclaration",
|
|
972
941
|
"FunctionExpression"
|
|
973
942
|
], node.type)) return 0;
|
|
974
|
-
|
|
975
|
-
return enclosingPipes(node.parent) + (nested ? 1 : 0);
|
|
943
|
+
return enclosingPipes(context, node.parent) + (isPipeCall(context, node.parent) && some$1(node.parent.arguments, (argument) => argument === node) ? 1 : 0);
|
|
976
944
|
}
|
|
977
945
|
const noDeepPipe = defineRule({
|
|
978
946
|
create: (context) => ({ CallExpression: (node) => {
|
|
979
|
-
if (isPipeCall(node) && enclosingPipes(node) >= 3) context.report({
|
|
947
|
+
if (isPipeCall(context, node) && enclosingPipes(context, node) >= 3) context.report({
|
|
980
948
|
message: "Flatten this pipeline; pipe calls nest at most three deep.",
|
|
981
949
|
node
|
|
982
950
|
});
|
|
@@ -985,23 +953,59 @@ const noDeepPipe = defineRule({
|
|
|
985
953
|
});
|
|
986
954
|
//#endregion
|
|
987
955
|
//#region src/rules/no-destructured-parameter.ts
|
|
988
|
-
function
|
|
989
|
-
|
|
990
|
-
if (
|
|
956
|
+
function namedTuple(input) {
|
|
957
|
+
if (contains$1(input.seen, input.node)) return false;
|
|
958
|
+
if (input.node.type === "TSTupleType") return isArrayNonEmpty(input.node.elementTypes) && every(input.node.elementTypes, (element) => element.type === "TSNamedTupleMember");
|
|
959
|
+
if (input.node.type === "TSParenthesizedType" || input.node.type === "TSTypeOperator" && input.node.operator === "readonly") return namedTuple({
|
|
960
|
+
...input,
|
|
961
|
+
node: input.node.typeAnnotation,
|
|
962
|
+
seen: append(input.seen, input.node)
|
|
963
|
+
});
|
|
964
|
+
if (input.node.type !== "TSTypeReference" || input.node.typeName.type !== "Identifier") return false;
|
|
965
|
+
return pipe(variableFromScope({
|
|
966
|
+
name: input.node.typeName.name,
|
|
967
|
+
scope: input.context.sourceCode.getScope(input.node)
|
|
968
|
+
}), exists((variable) => some$1(variable.defs, (definition) => definition.node.type === "TSTypeAliasDeclaration" && namedTuple({
|
|
969
|
+
context: input.context,
|
|
970
|
+
node: definition.node.typeAnnotation,
|
|
971
|
+
seen: append(input.seen, input.node)
|
|
972
|
+
}))));
|
|
973
|
+
}
|
|
974
|
+
function component(node) {
|
|
975
|
+
const name = (node.type === "ArrowFunctionExpression" ? void 0 : node.id) ?? (node.parent.type === "VariableDeclarator" && node.parent.id.type === "Identifier" ? node.parent.id : void 0);
|
|
976
|
+
if (name === void 0 || !matches(/^[A-Z]/u)(name.name) || node.params.length !== 1 || node.body === null) return false;
|
|
977
|
+
if (node.body.type === "JSXElement" || node.body.type === "JSXFragment") return true;
|
|
978
|
+
return node.body.type === "BlockStatement" && some$1(node.body.body, (statement) => statement.type === "ReturnStatement" && (statement.argument?.type === "JSXElement" || statement.argument?.type === "JSXFragment"));
|
|
979
|
+
}
|
|
980
|
+
function isPattern(input) {
|
|
981
|
+
const target = input.node.type === "AssignmentPattern" ? input.node.left : input.node;
|
|
982
|
+
if (target.type === "ArrayPattern") return !exists(fromNullishOr(target.typeAnnotation), (annotation) => namedTuple({
|
|
983
|
+
context: input.context,
|
|
984
|
+
node: annotation.typeAnnotation,
|
|
985
|
+
seen: []
|
|
986
|
+
}));
|
|
991
987
|
if (target.type !== "ObjectPattern") return false;
|
|
992
988
|
const named = filter$1(target.properties, (property) => property.type === "Property");
|
|
993
|
-
return !(named.length === 1 && named[0]?.key.type === "Identifier" && named[0].key.name === "ref" && some$1(target.properties, (property) => property.type === "RestElement"));
|
|
989
|
+
return !(input.component && named.length === 1 && named[0]?.key.type === "Identifier" && named[0].key.name === "ref" && some$1(target.properties, (property) => property.type === "RestElement"));
|
|
994
990
|
}
|
|
995
991
|
const noDestructuredParameter = defineRule({
|
|
996
992
|
create: (context) => {
|
|
997
993
|
function reportParameters(node) {
|
|
998
|
-
for (const parameter of filter$1(node.params,
|
|
994
|
+
for (const parameter of filter$1(node.params, (candidate) => isPattern({
|
|
995
|
+
component: component(node),
|
|
996
|
+
context,
|
|
997
|
+
node: candidate
|
|
998
|
+
}))) context.report({
|
|
999
999
|
message: "Take the value whole and read its fields instead of destructuring it.",
|
|
1000
1000
|
node: parameter
|
|
1001
1001
|
});
|
|
1002
1002
|
}
|
|
1003
1003
|
function reportLoopVariable(node) {
|
|
1004
|
-
if (node.left.type === "VariableDeclaration" && some$1(node.left.declarations, (declarator) => isPattern(
|
|
1004
|
+
if (node.left.type === "VariableDeclaration" && some$1(node.left.declarations, (declarator) => isPattern({
|
|
1005
|
+
component: false,
|
|
1006
|
+
context,
|
|
1007
|
+
node: declarator.id
|
|
1008
|
+
}))) context.report({
|
|
1005
1009
|
message: "Take the value whole and read its fields instead of destructuring it.",
|
|
1006
1010
|
node: node.left
|
|
1007
1011
|
});
|
|
@@ -1098,7 +1102,7 @@ function receiverName(node) {
|
|
|
1098
1102
|
return node.type === "MemberExpression" ? memberName(node) : none();
|
|
1099
1103
|
}
|
|
1100
1104
|
function isErrorMessage(node) {
|
|
1101
|
-
return node?.type === "MemberExpression" && contains(memberName(node), "message") && exists(receiverName(node.object), (
|
|
1105
|
+
return node?.type === "MemberExpression" && contains(memberName(node), "message") && exists(receiverName(node.object), matches(/^(?:e|err|error|failure|cause|exception)$|Error$/iu));
|
|
1102
1106
|
}
|
|
1103
1107
|
function expectsMessage(node) {
|
|
1104
1108
|
const subject = node.object.type === "MemberExpression" && contains(memberName(node.object), "not") ? node.object.object : node.object;
|
|
@@ -1125,50 +1129,26 @@ const noErrorMessageAssertion = defineRule({
|
|
|
1125
1129
|
meta: { type: "problem" }
|
|
1126
1130
|
});
|
|
1127
1131
|
//#endregion
|
|
1128
|
-
//#region src/rules/no-fail-in-generator.ts
|
|
1129
|
-
function insideEffectGenerator(input) {
|
|
1130
|
-
if (input.node.type === "Program") return false;
|
|
1131
|
-
if ((input.node.type === "ArrowFunctionExpression" || input.node.type === "FunctionDeclaration" || input.node.type === "FunctionExpression") && !input.node.generator) return false;
|
|
1132
|
-
if (input.node.type === "FunctionExpression" && input.node.generator && input.node.parent.type === "CallExpression" && exists(effectBuilderName({
|
|
1133
|
-
context: input.context,
|
|
1134
|
-
node: input.node.parent.callee
|
|
1135
|
-
}), (name) => contains$1([
|
|
1136
|
-
"fn",
|
|
1137
|
-
"fnUntraced",
|
|
1138
|
-
"gen"
|
|
1139
|
-
], name))) return true;
|
|
1140
|
-
return insideEffectGenerator({
|
|
1141
|
-
context: input.context,
|
|
1142
|
-
node: input.node.parent
|
|
1143
|
-
});
|
|
1144
|
-
}
|
|
1145
|
-
const noFailInGenerator = defineRule({
|
|
1146
|
-
create: (context) => ({ CallExpression: (node) => {
|
|
1147
|
-
if (node.callee.type === "MemberExpression" && importedMember({
|
|
1148
|
-
context,
|
|
1149
|
-
importedName: "Effect",
|
|
1150
|
-
node: node.callee,
|
|
1151
|
-
propertyName: "fail"
|
|
1152
|
-
}) && node.parent.type === "YieldExpression" && node.parent.delegate && node.arguments[0]?.type !== "NewExpression" && insideEffectGenerator({
|
|
1153
|
-
context,
|
|
1154
|
-
node
|
|
1155
|
-
})) context.report({
|
|
1156
|
-
message: "Yield the error instead: return yield* E.make(...).",
|
|
1157
|
-
node
|
|
1158
|
-
});
|
|
1159
|
-
} }),
|
|
1160
|
-
meta: { type: "problem" }
|
|
1161
|
-
});
|
|
1162
|
-
//#endregion
|
|
1163
1132
|
//#region src/rules/no-fake-ref-state.ts
|
|
1164
1133
|
function propertyName(node) {
|
|
1165
1134
|
if (!node.computed && node.key.type === "Identifier") return some(node.key.name);
|
|
1166
1135
|
if (node.key.type === "Literal" && isString(node.key.value)) return some(node.key.value);
|
|
1167
1136
|
return none();
|
|
1168
1137
|
}
|
|
1138
|
+
function hasUnusedSetter(input) {
|
|
1139
|
+
const declaration = input.node.parent;
|
|
1140
|
+
if (declaration.type !== "VariableDeclarator" || declaration.id.type !== "ArrayPattern") return false;
|
|
1141
|
+
const setter = declaration.id.elements[1];
|
|
1142
|
+
if (isNullish$1(setter)) return true;
|
|
1143
|
+
if (setter.type !== "Identifier") return false;
|
|
1144
|
+
return pipe(variableFromScope({
|
|
1145
|
+
name: setter.name,
|
|
1146
|
+
scope: input.context.sourceCode.getScope(setter)
|
|
1147
|
+
}), exists((variable) => !some$1(variable.references, (reference) => reference.isRead())));
|
|
1148
|
+
}
|
|
1169
1149
|
function isFakeRefState(input) {
|
|
1170
|
-
if (!isReactUseState(input) || input.node.arguments[0]?.type !== "ArrowFunctionExpression" || input.node.arguments[0].body.type !== "ObjectExpression") return false;
|
|
1171
|
-
return some$1(input.node.arguments[0].body.properties, (property) => property.type === "Property" && contains(propertyName(property), "current"));
|
|
1150
|
+
if (!isReactUseState(input) || input.node.arguments[0]?.type !== "ArrowFunctionExpression" || input.node.arguments[0].body.type !== "ObjectExpression" || input.node.arguments[0].body.properties.length !== 1 || !hasUnusedSetter(input)) return false;
|
|
1151
|
+
return some$1(input.node.arguments[0].body.properties, (property) => property.type === "Property" && contains(propertyName(property), "current") && property.value.type === "Literal" && property.value.value === null);
|
|
1172
1152
|
}
|
|
1173
1153
|
const noFakeRefState = defineRule({
|
|
1174
1154
|
create: (context) => ({ CallExpression: (node) => {
|
|
@@ -1232,10 +1212,10 @@ function check(input) {
|
|
|
1232
1212
|
subject: input.node.right
|
|
1233
1213
|
})]), map(of));
|
|
1234
1214
|
}
|
|
1235
|
-
function report(input) {
|
|
1215
|
+
function report$1(input) {
|
|
1236
1216
|
const predicate = input.node.returnType?.typeAnnotation;
|
|
1237
1217
|
const returned = returnedExpression(input.node);
|
|
1238
|
-
if (predicate?.type !== "TSTypePredicate" || predicate.asserts || predicate.parameterName.type !== "Identifier" || isNullish(returned)) return;
|
|
1218
|
+
if (predicate?.type !== "TSTypePredicate" || predicate.asserts || predicate.parameterName.type !== "Identifier" || isNullish$1(returned)) return;
|
|
1239
1219
|
const name = pipe(check({
|
|
1240
1220
|
name: predicate.parameterName.name,
|
|
1241
1221
|
node: returned
|
|
@@ -1272,19 +1252,19 @@ function report(input) {
|
|
|
1272
1252
|
const noHandWrittenGuard = defineRule({
|
|
1273
1253
|
create: (context) => ({
|
|
1274
1254
|
ArrowFunctionExpression: (node) => {
|
|
1275
|
-
report({
|
|
1255
|
+
report$1({
|
|
1276
1256
|
context,
|
|
1277
1257
|
node
|
|
1278
1258
|
});
|
|
1279
1259
|
},
|
|
1280
1260
|
FunctionDeclaration: (node) => {
|
|
1281
|
-
report({
|
|
1261
|
+
report$1({
|
|
1282
1262
|
context,
|
|
1283
1263
|
node
|
|
1284
1264
|
});
|
|
1285
1265
|
},
|
|
1286
1266
|
FunctionExpression: (node) => {
|
|
1287
|
-
report({
|
|
1267
|
+
report$1({
|
|
1288
1268
|
context,
|
|
1289
1269
|
node
|
|
1290
1270
|
});
|
|
@@ -1387,6 +1367,13 @@ const nativeMethods = [
|
|
|
1387
1367
|
"values",
|
|
1388
1368
|
"with"
|
|
1389
1369
|
];
|
|
1370
|
+
function freshRegExpFlags(input) {
|
|
1371
|
+
if (input.node.type === "Literal" && hasProperty(input.node, "regex")) return some(pipe(input.context.sourceCode.getText(input.node), split("/"), last));
|
|
1372
|
+
if (input.node.type !== "NewExpression" && input.node.type !== "CallExpression" || input.node.callee.type !== "Identifier" || input.node.callee.name !== "RegExp") return none();
|
|
1373
|
+
const flags = input.node.arguments[1];
|
|
1374
|
+
if (flags === void 0) return some(some(""));
|
|
1375
|
+
return some(flags.type === "Literal" && isString(flags.value) ? some(flags.value) : none());
|
|
1376
|
+
}
|
|
1390
1377
|
const noNativeMethodCall = defineRule({
|
|
1391
1378
|
create: (context) => ({ CallExpression: (node) => {
|
|
1392
1379
|
if (node.callee.type !== "MemberExpression" || node.callee.object.type === "Identifier" && (node.callee.object.name === "path" || isImportBinding({
|
|
@@ -1395,6 +1382,17 @@ const noNativeMethodCall = defineRule({
|
|
|
1395
1382
|
source: /^(?:effect(?:\/|$)|@effect\/)/u
|
|
1396
1383
|
}))) return;
|
|
1397
1384
|
const receiver = node.callee.object;
|
|
1385
|
+
const regExpFlags = freshRegExpFlags({
|
|
1386
|
+
context,
|
|
1387
|
+
node: receiver
|
|
1388
|
+
});
|
|
1389
|
+
if (isSome(regExpFlags) && exists(memberName(node.callee), (name) => name === "test" || name === "exec" && exists(flatten$1(regExpFlags), (flags) => !pipe(flags, includes("g"))))) {
|
|
1390
|
+
context.report({
|
|
1391
|
+
message: "Match with String.match, which returns an Option, instead of a native RegExp method.",
|
|
1392
|
+
node: node.callee
|
|
1393
|
+
});
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1398
1396
|
pipe(memberName(node.callee), filter((name) => contains$1(nativeMethods, name)), filter((name) => !contains$1([
|
|
1399
1397
|
"entries",
|
|
1400
1398
|
"keys",
|
|
@@ -1409,6 +1407,50 @@ const noNativeMethodCall = defineRule({
|
|
|
1409
1407
|
meta: { type: "problem" }
|
|
1410
1408
|
});
|
|
1411
1409
|
//#endregion
|
|
1410
|
+
//#region src/rules/no-nullish-ternary.ts
|
|
1411
|
+
const nullishPredicates = [
|
|
1412
|
+
"isNotNull",
|
|
1413
|
+
"isNotNullish",
|
|
1414
|
+
"isNotUndefined",
|
|
1415
|
+
"isNull",
|
|
1416
|
+
"isNullish",
|
|
1417
|
+
"isUndefined"
|
|
1418
|
+
];
|
|
1419
|
+
function isNullish(input) {
|
|
1420
|
+
if (input.node.type === "Literal") return input.node.value === null;
|
|
1421
|
+
return input.node.type === "Identifier" && input.node.name === "undefined";
|
|
1422
|
+
}
|
|
1423
|
+
function testsNullish(input) {
|
|
1424
|
+
if (input.node.type === "UnaryExpression" && input.node.operator === "!") return testsNullish({
|
|
1425
|
+
context: input.context,
|
|
1426
|
+
node: input.node.argument
|
|
1427
|
+
});
|
|
1428
|
+
if (input.node.type === "BinaryExpression" && (input.node.operator === "===" || input.node.operator === "!==")) return isNullish({
|
|
1429
|
+
context: input.context,
|
|
1430
|
+
node: input.node.left
|
|
1431
|
+
}) || isNullish({
|
|
1432
|
+
context: input.context,
|
|
1433
|
+
node: input.node.right
|
|
1434
|
+
});
|
|
1435
|
+
return input.node.type === "CallExpression" && input.node.callee.type === "MemberExpression" && importedMember({
|
|
1436
|
+
context: input.context,
|
|
1437
|
+
importedName: "Predicate",
|
|
1438
|
+
node: input.node.callee
|
|
1439
|
+
}) && exists(memberName(input.node.callee), (name) => contains$1(nullishPredicates, name));
|
|
1440
|
+
}
|
|
1441
|
+
const noNullishTernary = defineRule({
|
|
1442
|
+
create: (context) => ({ ConditionalExpression: (node) => {
|
|
1443
|
+
if (testsNullish({
|
|
1444
|
+
context,
|
|
1445
|
+
node: node.test
|
|
1446
|
+
})) context.report({
|
|
1447
|
+
message: "Use ?? for a default, or Option for a value that may be absent, instead of a nullish ternary.",
|
|
1448
|
+
node
|
|
1449
|
+
});
|
|
1450
|
+
} }),
|
|
1451
|
+
meta: { type: "problem" }
|
|
1452
|
+
});
|
|
1453
|
+
//#endregion
|
|
1412
1454
|
//#region src/rules/no-option-value-access.ts
|
|
1413
1455
|
function checks(input) {
|
|
1414
1456
|
if (input.test.type === "LogicalExpression" && input.test.operator === input.operator) return checks({
|
|
@@ -1435,8 +1477,7 @@ function exits(node) {
|
|
|
1435
1477
|
function earlyExit(input) {
|
|
1436
1478
|
const parent = input.node.parent;
|
|
1437
1479
|
if (parent?.type !== "BlockStatement" && parent?.type !== "Program") return false;
|
|
1438
|
-
|
|
1439
|
-
return some$1(take(parent.body, getOrElse(index, () => 0)), (statement) => statement.type === "IfStatement" && exits(statement.consequent) && checks({
|
|
1480
|
+
return some$1(take(parent.body, getOrElse(findFirstIndex(parent.body, (statement) => statement === input.node), () => 0)), (statement) => statement.type === "IfStatement" && exits(statement.consequent) && checks({
|
|
1440
1481
|
...input,
|
|
1441
1482
|
name: "isNone",
|
|
1442
1483
|
operator: "||",
|
|
@@ -1492,18 +1533,43 @@ function insideCycleType(input) {
|
|
|
1492
1533
|
node: input.node.parent
|
|
1493
1534
|
});
|
|
1494
1535
|
}
|
|
1495
|
-
function
|
|
1496
|
-
if (
|
|
1497
|
-
|
|
1498
|
-
|
|
1536
|
+
function typeDeclarations(input) {
|
|
1537
|
+
if (input.name.type === "Identifier") return pipe(variableFromScope({
|
|
1538
|
+
name: input.name.name,
|
|
1539
|
+
scope: input.context.sourceCode.getScope(input.name)
|
|
1540
|
+
}), flatMap((variable) => variable.scope.block.type === "ClassDeclaration" && some$1(variable.defs, (definition) => definition.node === variable.scope.block) ? variableFromScope({
|
|
1541
|
+
name: variable.name,
|
|
1542
|
+
scope: variable.scope.upper
|
|
1543
|
+
}) : some(variable)), map((variable) => map$1(variable.defs, (definition) => definition.node)), getOrElse(() => empty()));
|
|
1544
|
+
if (input.name.type !== "TSQualifiedName") return [];
|
|
1545
|
+
const name = input.name;
|
|
1546
|
+
return pipe(typeDeclarations({
|
|
1547
|
+
context: input.context,
|
|
1548
|
+
name: name.left
|
|
1549
|
+
}), flatMap$1((declaration) => {
|
|
1550
|
+
if (declaration.type !== "TSModuleDeclaration" || declaration.body === null) return [];
|
|
1551
|
+
return pipe(declaration.body.body, map$1(statementDeclaration), filter$1((node) => node !== null));
|
|
1552
|
+
}), filter$1((declaration) => (declaration.type === "TSTypeAliasDeclaration" || declaration.type === "TSModuleDeclaration") && declaration.id.type === "Identifier" && declaration.id.name === name.right.name));
|
|
1499
1553
|
}
|
|
1500
1554
|
function shapeLiterals(input) {
|
|
1501
1555
|
if (input.type.type === "TSTypeLiteral") return [input.type];
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1556
|
+
if (input.type.type === "TSUnionType" || input.type.type === "TSIntersectionType") return flatMap$1(input.type.types, (type) => shapeLiterals({
|
|
1557
|
+
...input,
|
|
1558
|
+
type
|
|
1559
|
+
}));
|
|
1560
|
+
if (input.type.type === "TSParenthesizedType") return shapeLiterals({
|
|
1561
|
+
...input,
|
|
1562
|
+
type: input.type.typeAnnotation
|
|
1563
|
+
});
|
|
1564
|
+
if (input.type.type !== "TSTypeReference") return [];
|
|
1565
|
+
return pipe(typeDeclarations({
|
|
1566
|
+
context: input.context,
|
|
1567
|
+
name: input.type.typeName
|
|
1568
|
+
}), filter$1((declaration) => declaration.type === "TSTypeAliasDeclaration"), filter$1((alias) => !contains$1(input.seen, alias)), flatMap$1((alias) => shapeLiterals({
|
|
1569
|
+
...input,
|
|
1570
|
+
seen: append(input.seen, alias),
|
|
1505
1571
|
type: alias.typeAnnotation
|
|
1506
|
-
})))
|
|
1572
|
+
})));
|
|
1507
1573
|
}
|
|
1508
1574
|
const noReadonlyTypeSyntax = defineRule({
|
|
1509
1575
|
create: (context) => {
|
|
@@ -1512,7 +1578,6 @@ const noReadonlyTypeSyntax = defineRule({
|
|
|
1512
1578
|
program: context.sourceCode.ast
|
|
1513
1579
|
});
|
|
1514
1580
|
const shapes = make$2(empty());
|
|
1515
|
-
const aliases = make$2(empty());
|
|
1516
1581
|
const properties = make$2(empty());
|
|
1517
1582
|
const methods = make$2(empty());
|
|
1518
1583
|
function exempt(node) {
|
|
@@ -1532,7 +1597,7 @@ const noReadonlyTypeSyntax = defineRule({
|
|
|
1532
1597
|
},
|
|
1533
1598
|
"Program:exit": () => {
|
|
1534
1599
|
const literals = pipe(get$3(shapes), flatMap$1((shape) => shapeLiterals({
|
|
1535
|
-
|
|
1600
|
+
context,
|
|
1536
1601
|
seen: [],
|
|
1537
1602
|
type: shape
|
|
1538
1603
|
})));
|
|
@@ -1572,9 +1637,6 @@ const noReadonlyTypeSyntax = defineRule({
|
|
|
1572
1637
|
TSPropertySignature: (node) => {
|
|
1573
1638
|
update(properties, append(node));
|
|
1574
1639
|
},
|
|
1575
|
-
TSTypeAliasDeclaration: (node) => {
|
|
1576
|
-
update(aliases, append(node));
|
|
1577
|
-
},
|
|
1578
1640
|
TSTypeOperator: (node) => {
|
|
1579
1641
|
if (node.operator === "readonly" && !exempt(node)) context.report({
|
|
1580
1642
|
message: "Use a mutable type shape.",
|
|
@@ -1597,7 +1659,7 @@ function isExported(node) {
|
|
|
1597
1659
|
if (node.parent.type === "ExportNamedDeclaration" || node.parent.type === "ExportDefaultDeclaration") return true;
|
|
1598
1660
|
return node.parent.type === "VariableDeclarator" && node.parent.parent.type === "VariableDeclaration" && node.parent.parent.parent.type === "ExportNamedDeclaration";
|
|
1599
1661
|
}
|
|
1600
|
-
function inferredIdentically
|
|
1662
|
+
function inferredIdentically(input) {
|
|
1601
1663
|
const text = input.context.sourceCode.getText;
|
|
1602
1664
|
const body = input.node.body;
|
|
1603
1665
|
if (body === null) return false;
|
|
@@ -1619,11 +1681,11 @@ const noRedundantReturnType = defineRule({
|
|
|
1619
1681
|
function exit(node) {
|
|
1620
1682
|
const frame = last(get$3(frames));
|
|
1621
1683
|
update(frames, dropRight(1));
|
|
1622
|
-
if (node.async || node.generator || isNullish(node.returnType)) return;
|
|
1623
|
-
if (inferredIdentically
|
|
1684
|
+
if (node.async || node.generator || isNullish$1(node.returnType)) return;
|
|
1685
|
+
if (inferredIdentically({
|
|
1624
1686
|
context,
|
|
1625
1687
|
node,
|
|
1626
|
-
returns: match(frame, {
|
|
1688
|
+
returns: match$1(frame, {
|
|
1627
1689
|
onNone: () => empty(),
|
|
1628
1690
|
onSome: (top) => top.returns
|
|
1629
1691
|
}),
|
|
@@ -1641,7 +1703,7 @@ const noRedundantReturnType = defineRule({
|
|
|
1641
1703
|
FunctionExpression: enter,
|
|
1642
1704
|
"FunctionExpression:exit": exit,
|
|
1643
1705
|
ReturnStatement: (node) => {
|
|
1644
|
-
update(frames, (stack) => pipe(last(stack), match({
|
|
1706
|
+
update(frames, (stack) => pipe(last(stack), match$1({
|
|
1645
1707
|
onNone: () => stack,
|
|
1646
1708
|
onSome: (top) => append(dropRight(stack, 1), { returns: append(top.returns, node) })
|
|
1647
1709
|
})));
|
|
@@ -1710,18 +1772,10 @@ const noRedundantUseRefNullType = defineRule({
|
|
|
1710
1772
|
});
|
|
1711
1773
|
//#endregion
|
|
1712
1774
|
//#region src/rules/no-redundant-variable-annotation.ts
|
|
1713
|
-
function isStringLiteral(node) {
|
|
1714
|
-
return node.type === "Literal" && isString(node.value);
|
|
1715
|
-
}
|
|
1716
|
-
function inferredIdentically(input) {
|
|
1717
|
-
const text = input.context.sourceCode.getText;
|
|
1718
|
-
if (input.init.type === "TSAsExpression") return text(input.init.typeAnnotation) === text(input.type);
|
|
1719
|
-
return input.init.type === "ConditionalExpression" && input.type.type === "TSStringKeyword" && isStringLiteral(input.init.consequent) && isStringLiteral(input.init.alternate);
|
|
1720
|
-
}
|
|
1721
1775
|
const noRedundantVariableAnnotation = defineRule({
|
|
1722
1776
|
create: (context) => ({ VariableDeclarator: (node) => {
|
|
1723
1777
|
const annotation = node.id.typeAnnotation;
|
|
1724
|
-
if (node.init === null || isNullish(annotation)) return;
|
|
1778
|
+
if (node.init === null || isNullish$1(annotation)) return;
|
|
1725
1779
|
if (node.init.type === "ArrayExpression" && isArrayEmpty(node.init.elements)) {
|
|
1726
1780
|
context.report({
|
|
1727
1781
|
message: "Write Array.empty<T>() instead of annotating an empty array.",
|
|
@@ -1729,11 +1783,7 @@ const noRedundantVariableAnnotation = defineRule({
|
|
|
1729
1783
|
});
|
|
1730
1784
|
return;
|
|
1731
1785
|
}
|
|
1732
|
-
if (
|
|
1733
|
-
context,
|
|
1734
|
-
init: node.init,
|
|
1735
|
-
type: annotation.typeAnnotation
|
|
1736
|
-
})) context.report({
|
|
1786
|
+
if (node.init.type === "TSAsExpression" && context.sourceCode.getText(node.init.typeAnnotation) === context.sourceCode.getText(annotation.typeAnnotation)) context.report({
|
|
1737
1787
|
message: "Drop this annotation; inference gives the same type.",
|
|
1738
1788
|
node: annotation
|
|
1739
1789
|
});
|
|
@@ -1792,7 +1842,10 @@ function shippedSchema(input) {
|
|
|
1792
1842
|
node: input.filter.callee
|
|
1793
1843
|
});
|
|
1794
1844
|
const [value, ...rest] = input.filter.arguments;
|
|
1795
|
-
return pipe(shipped, findFirst((entry) => contains(base, entry.base) && contains(check, entry.check) && isArrayEmpty(rest) && (entry.only
|
|
1845
|
+
return pipe(shipped, findFirst((entry) => contains(base, entry.base) && contains(check, entry.check) && isArrayEmpty(rest) && match$1(fromUndefinedOr(entry.only), {
|
|
1846
|
+
onNone: () => value === void 0,
|
|
1847
|
+
onSome: (only) => value?.type === "Literal" && value.value === only
|
|
1848
|
+
})), map((entry) => entry.schema));
|
|
1796
1849
|
}
|
|
1797
1850
|
function pipedBase(node) {
|
|
1798
1851
|
const parent = node.parent;
|
|
@@ -1846,6 +1899,104 @@ const noRenamedImport = defineRule({
|
|
|
1846
1899
|
meta: { type: "problem" }
|
|
1847
1900
|
});
|
|
1848
1901
|
//#endregion
|
|
1902
|
+
//#region src/rules/no-single-use-value.ts
|
|
1903
|
+
const repeating = [
|
|
1904
|
+
"ArrowFunctionExpression",
|
|
1905
|
+
"DoWhileStatement",
|
|
1906
|
+
"ForInStatement",
|
|
1907
|
+
"ForOfStatement",
|
|
1908
|
+
"ForStatement",
|
|
1909
|
+
"FunctionDeclaration",
|
|
1910
|
+
"FunctionExpression",
|
|
1911
|
+
"WhileStatement"
|
|
1912
|
+
];
|
|
1913
|
+
function runsOnce(input) {
|
|
1914
|
+
const node = input.node;
|
|
1915
|
+
const child = input.child;
|
|
1916
|
+
if ((node.type === "ForOfStatement" || node.type === "ForInStatement") && node.right === child || node.type === "IfStatement" && node.test === child || node.type === "ConditionalExpression" && node.test === child || node.type === "LogicalExpression" && node.left === child) return climb({
|
|
1917
|
+
...input,
|
|
1918
|
+
node
|
|
1919
|
+
});
|
|
1920
|
+
if (contains$1(repeating, node.type) || node.type === "IfStatement" || node.type === "ConditionalExpression" || node.type === "LogicalExpression" || node.type === "ChainExpression" || node.type === "SwitchStatement" || node.type === "TryStatement") return false;
|
|
1921
|
+
return climb({
|
|
1922
|
+
...input,
|
|
1923
|
+
node
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
function climb(input) {
|
|
1927
|
+
if (input.node === input.statement) return true;
|
|
1928
|
+
if (isNullish$1(input.node.parent)) return false;
|
|
1929
|
+
return runsOnce({
|
|
1930
|
+
child: input.node,
|
|
1931
|
+
node: input.node.parent,
|
|
1932
|
+
statement: input.statement
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
function insideConditional(input) {
|
|
1936
|
+
if (input.node === input.statement) return false;
|
|
1937
|
+
if (input.node.type === "ConditionalExpression") return true;
|
|
1938
|
+
return isNotNullish(input.node.parent) && insideConditional({
|
|
1939
|
+
...input,
|
|
1940
|
+
node: input.node.parent
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
function candidate(node) {
|
|
1944
|
+
const declaration = node.parent;
|
|
1945
|
+
const init = node.init;
|
|
1946
|
+
return declaration.type === "VariableDeclaration" && declaration.kind === "const" && declaration.declarations.length === 1 && declaration.parent.type === "BlockStatement" && node.id.type === "Identifier" && node.id.typeAnnotation === null && init !== null && !contains$1(["ArrowFunctionExpression", "FunctionExpression"], init.type) && !(init.type === "Literal" && !hasProperty(init, "regex")) && !(init.type === "TemplateLiteral" && isArrayEmpty(init.expressions));
|
|
1947
|
+
}
|
|
1948
|
+
function report(input) {
|
|
1949
|
+
const declaration = input.node.parent;
|
|
1950
|
+
const init = input.node.init;
|
|
1951
|
+
if (declaration.type !== "VariableDeclaration" || declaration.parent.type !== "BlockStatement" || input.node.id.type !== "Identifier" || init === null || pipe(input.context.sourceCode.getText(init), includes("\n"))) return;
|
|
1952
|
+
const statements = declaration.parent.body;
|
|
1953
|
+
const name = input.node.id.name;
|
|
1954
|
+
pipe(findFirstIndex(statements, (statement) => statement === declaration), flatMap((index) => get$1(statements, index + 1)), flatMap((next) => pipe(variableFromScope({
|
|
1955
|
+
name,
|
|
1956
|
+
scope: input.context.sourceCode.getScope(input.node)
|
|
1957
|
+
}), map((variable) => filter$1(variable.references, (reference) => reference.isRead())), filter((reads) => reads.length === 1), flatMap(head), map((reference) => reference.identifier), filter((read) => read.range[0] >= next.range[0] && read.range[1] <= next.range[1] && climb({
|
|
1958
|
+
node: read,
|
|
1959
|
+
statement: next
|
|
1960
|
+
}) && !(init.type === "ConditionalExpression" && insideConditional({
|
|
1961
|
+
node: read,
|
|
1962
|
+
statement: next
|
|
1963
|
+
})) && !some$1(input.effects, (effect) => effect.range[0] >= next.range[0] && effect.range[1] <= read.range[0])))), map(() => {
|
|
1964
|
+
input.context.report({
|
|
1965
|
+
message: "Inline this value into the next statement, its only use.",
|
|
1966
|
+
node: input.node
|
|
1967
|
+
});
|
|
1968
|
+
}));
|
|
1969
|
+
}
|
|
1970
|
+
const noSingleUseValue = defineRule({
|
|
1971
|
+
create: (context) => {
|
|
1972
|
+
const effects = make$2(empty());
|
|
1973
|
+
const candidates = make$2(empty());
|
|
1974
|
+
function effect(node) {
|
|
1975
|
+
update(effects, append(node));
|
|
1976
|
+
}
|
|
1977
|
+
return {
|
|
1978
|
+
AssignmentExpression: effect,
|
|
1979
|
+
AwaitExpression: effect,
|
|
1980
|
+
CallExpression: effect,
|
|
1981
|
+
NewExpression: effect,
|
|
1982
|
+
"Program:exit": () => {
|
|
1983
|
+
for (const node of get$3(candidates)) report({
|
|
1984
|
+
context,
|
|
1985
|
+
effects: get$3(effects),
|
|
1986
|
+
node
|
|
1987
|
+
});
|
|
1988
|
+
},
|
|
1989
|
+
TaggedTemplateExpression: effect,
|
|
1990
|
+
UpdateExpression: effect,
|
|
1991
|
+
VariableDeclarator: (node) => {
|
|
1992
|
+
if (candidate(node)) update(candidates, append(node));
|
|
1993
|
+
},
|
|
1994
|
+
YieldExpression: effect
|
|
1995
|
+
};
|
|
1996
|
+
},
|
|
1997
|
+
meta: { type: "problem" }
|
|
1998
|
+
});
|
|
1999
|
+
//#endregion
|
|
1849
2000
|
//#region src/rules/no-stored-schema-operation.ts
|
|
1850
2001
|
function storedSchemaOperation(node) {
|
|
1851
2002
|
return node.parent.type === "VariableDeclarator" && node.parent.init === node || node.parent.type === "Property" && node.parent.value === node || node.parent.type === "PropertyDefinition" && node.parent.value === node || node.parent.type === "ArrayExpression" || node.parent.type === "AssignmentExpression" && node.parent.right === node;
|
|
@@ -1890,7 +2041,7 @@ function forwardedCall(input) {
|
|
|
1890
2041
|
function exactForwardingFunction(node) {
|
|
1891
2042
|
const names = pipe(node.params, map$1(parameterName), getSomes);
|
|
1892
2043
|
const returned = returnedExpression(node);
|
|
1893
|
-
if (isArrayEmpty(names) || names.length !== node.params.length || isNullish(returned)) return false;
|
|
2044
|
+
if (isArrayEmpty(names) || names.length !== node.params.length || isNullish$1(returned)) return false;
|
|
1894
2045
|
if (returned.type === "Identifier") return names.length === 1 && returned.name === names[0];
|
|
1895
2046
|
return (returned.type === "CallExpression" || returned.type === "NewExpression") && returned.callee.type === "Identifier" && forwardedCall({
|
|
1896
2047
|
names,
|
|
@@ -1915,8 +2066,7 @@ function unexportedBindingName(node) {
|
|
|
1915
2066
|
}
|
|
1916
2067
|
function singleCallerWrapper(input) {
|
|
1917
2068
|
const names = pipe(input.node.params, map$1(parameterName), getSomes);
|
|
1918
|
-
|
|
1919
|
-
if (input.node.async || input.node.generator || input.node.returnType?.typeAnnotation.type === "TSTypePredicate" || isArrayEmpty(names) || names.length !== input.node.params.length || returned?.type !== "CallExpression") return false;
|
|
2069
|
+
if (input.node.async || input.node.generator || input.node.returnType?.typeAnnotation.type === "TSTypePredicate" || isArrayEmpty(names) || names.length !== input.node.params.length || returnedExpression(input.node)?.type !== "CallExpression") return false;
|
|
1920
2070
|
return pipe(unexportedBindingName(input.node), flatMap((name) => variableFromScope({
|
|
1921
2071
|
name,
|
|
1922
2072
|
scope: input.context.sourceCode.getScope(input.node)
|
|
@@ -2072,11 +2222,11 @@ const noUndestructuredUseState = defineRule({
|
|
|
2072
2222
|
//#region src/rules/no-unexplained-disable.ts
|
|
2073
2223
|
const noUnexplainedDisable = defineRule({
|
|
2074
2224
|
create: (context) => ({ Program: () => {
|
|
2075
|
-
for (const comment of context.sourceCode.getAllComments()) if (/^\s*(?:eslint|oxlint)-disable\S*\s(?:(?!\s--\s).)*\bsort-keys\b/u
|
|
2225
|
+
for (const comment of context.sourceCode.getAllComments()) if (matches(/^\s*(?:eslint|oxlint)-disable\S*\s(?:(?!\s--\s).)*\bsort-keys\b/u)(comment.value)) context.report({
|
|
2076
2226
|
message: "Sort the keys, starting a new sorted group after a blank line; never disable sort-keys.",
|
|
2077
2227
|
node: comment
|
|
2078
2228
|
});
|
|
2079
|
-
else if (/^\s*(?:eslint-disable|oxlint-disable|@effect-diagnostics)/u
|
|
2229
|
+
else if (matches(/^\s*(?:eslint-disable|oxlint-disable|@effect-diagnostics)/u)(comment.value) && !matches(/\s--\s*\S/u)(comment.value)) context.report({
|
|
2080
2230
|
message: "Give this disable a `-- reason`.",
|
|
2081
2231
|
node: comment
|
|
2082
2232
|
});
|
|
@@ -2153,7 +2303,7 @@ function schemaDefinitionMember(node) {
|
|
|
2153
2303
|
return none();
|
|
2154
2304
|
}
|
|
2155
2305
|
function isSchemaDefinitionName(name) {
|
|
2156
|
-
return !isSchemaOperationName(name) &&
|
|
2306
|
+
return !isSchemaOperationName(name) && !matches(/^(?:is|to)[A-Z]/u)(name) && !matches(/^makeFilter(?:Group)?$/u)(name);
|
|
2157
2307
|
}
|
|
2158
2308
|
function isSchemaDefinition(input) {
|
|
2159
2309
|
if (input.node.type === "CallExpression" && input.node.callee.type === "Identifier" && isImportBinding({
|
|
@@ -2192,7 +2342,7 @@ function namedTypeAlias(input) {
|
|
|
2192
2342
|
return pipe(input.typeStatement, flatMap(typeAlias), filter((declaration) => declaration.id.name === input.name));
|
|
2193
2343
|
}
|
|
2194
2344
|
function reportSchemaVariable(input) {
|
|
2195
|
-
if (input.variable.id.type !== "Identifier" ||
|
|
2345
|
+
if (input.variable.id.type !== "Identifier" || !matches(/^[A-Z]/u)(input.variable.id.name)) return;
|
|
2196
2346
|
if (input.variable.init === null || !isSchemaDefinition({
|
|
2197
2347
|
context: input.context,
|
|
2198
2348
|
node: input.variable.init
|
|
@@ -2361,12 +2511,12 @@ const oxlint = defineConfig({
|
|
|
2361
2511
|
"@deslop/coding-standards/no-double-nullish-check": "error",
|
|
2362
2512
|
"@deslop/coding-standards/no-effect-property-arrow": "error",
|
|
2363
2513
|
"@deslop/coding-standards/no-error-message-assertion": "error",
|
|
2364
|
-
"@deslop/coding-standards/no-fail-in-generator": "error",
|
|
2365
2514
|
"@deslop/coding-standards/no-fake-ref-state": "error",
|
|
2366
2515
|
"@deslop/coding-standards/no-hand-written-guard": "error",
|
|
2367
2516
|
"@deslop/coding-standards/no-let": "error",
|
|
2368
2517
|
"@deslop/coding-standards/no-native-emptiness-check": "error",
|
|
2369
2518
|
"@deslop/coding-standards/no-native-method-call": "error",
|
|
2519
|
+
"@deslop/coding-standards/no-nullish-ternary": "error",
|
|
2370
2520
|
"@deslop/coding-standards/no-option-value-access": "error",
|
|
2371
2521
|
"@deslop/coding-standards/no-readonly-type-syntax": "error",
|
|
2372
2522
|
"@deslop/coding-standards/no-redundant-return-type": "error",
|
|
@@ -2375,6 +2525,7 @@ const oxlint = defineConfig({
|
|
|
2375
2525
|
"@deslop/coding-standards/no-redundant-variable-annotation": "error",
|
|
2376
2526
|
"@deslop/coding-standards/no-reinvented-schema": "error",
|
|
2377
2527
|
"@deslop/coding-standards/no-renamed-import": "error",
|
|
2528
|
+
"@deslop/coding-standards/no-single-use-value": "error",
|
|
2378
2529
|
"@deslop/coding-standards/no-stored-schema-operation": "error",
|
|
2379
2530
|
"@deslop/coding-standards/no-switch-statement": "error",
|
|
2380
2531
|
"@deslop/coding-standards/no-trivial-indirection": "error",
|
|
@@ -2638,6 +2789,7 @@ const oxlint = defineConfig({
|
|
|
2638
2789
|
"max-depth": ["error", 3],
|
|
2639
2790
|
"max-nested-callbacks": ["error", 6],
|
|
2640
2791
|
"no-cond-assign": "error",
|
|
2792
|
+
"no-constant-binary-expression": "error",
|
|
2641
2793
|
"no-continue": "error",
|
|
2642
2794
|
"no-control-regex": "error",
|
|
2643
2795
|
"no-debugger": "error",
|
|
@@ -2651,6 +2803,7 @@ const oxlint = defineConfig({
|
|
|
2651
2803
|
"no-invalid-regexp": "error",
|
|
2652
2804
|
"no-iterator": "error",
|
|
2653
2805
|
"no-lonely-if": "error",
|
|
2806
|
+
"no-loss-of-precision": "error",
|
|
2654
2807
|
"no-misleading-character-class": "error",
|
|
2655
2808
|
"no-multi-assign": "error",
|
|
2656
2809
|
"no-negated-condition": "error",
|
|
@@ -2888,6 +3041,7 @@ const oxlint = defineConfig({
|
|
|
2888
3041
|
"no-unneeded-ternary": "error",
|
|
2889
3042
|
"no-unreachable-loop": "error",
|
|
2890
3043
|
"no-unsafe-finally": "error",
|
|
3044
|
+
"no-unsafe-optional-chaining": ["error", { disallowArithmeticOperators: true }],
|
|
2891
3045
|
"no-unused-expressions": "error",
|
|
2892
3046
|
"no-useless-assignment": "error",
|
|
2893
3047
|
"no-useless-backreference": "error",
|
|
@@ -2899,6 +3053,7 @@ const oxlint = defineConfig({
|
|
|
2899
3053
|
"no-useless-escape": "error",
|
|
2900
3054
|
"no-useless-rename": "error",
|
|
2901
3055
|
"no-useless-return": "error",
|
|
3056
|
+
"no-var": "error",
|
|
2902
3057
|
"no-void": "error",
|
|
2903
3058
|
"object-shorthand": "error",
|
|
2904
3059
|
"oxc/branches-sharing-code": "error",
|
|
@@ -2910,6 +3065,7 @@ const oxlint = defineConfig({
|
|
|
2910
3065
|
"prefer-template": "error",
|
|
2911
3066
|
"require-unicode-regexp": "error",
|
|
2912
3067
|
"react-doctor/no-call-component-as-function": "error",
|
|
3068
|
+
"react-doctor/no-controlled-input-value-without-state-update": "error",
|
|
2913
3069
|
"react-doctor/no-create-context-in-render": "error",
|
|
2914
3070
|
"react-doctor/no-default-props": "error",
|
|
2915
3071
|
"react-doctor/no-inline-exhaustive-style": "error",
|
|
@@ -3048,12 +3204,12 @@ var oxlint_default = definePlugin({
|
|
|
3048
3204
|
"no-double-nullish-check": noDoubleNullishCheck,
|
|
3049
3205
|
"no-effect-property-arrow": noEffectPropertyArrow,
|
|
3050
3206
|
"no-error-message-assertion": noErrorMessageAssertion,
|
|
3051
|
-
"no-fail-in-generator": noFailInGenerator,
|
|
3052
3207
|
"no-fake-ref-state": noFakeRefState,
|
|
3053
3208
|
"no-hand-written-guard": noHandWrittenGuard,
|
|
3054
3209
|
"no-let": noLet,
|
|
3055
3210
|
"no-native-emptiness-check": noNativeEmptinessCheck,
|
|
3056
3211
|
"no-native-method-call": noNativeMethodCall,
|
|
3212
|
+
"no-nullish-ternary": noNullishTernary,
|
|
3057
3213
|
"no-option-value-access": noOptionValueAccess,
|
|
3058
3214
|
"no-readonly-type-syntax": noReadonlyTypeSyntax,
|
|
3059
3215
|
"no-redundant-return-type": noRedundantReturnType,
|
|
@@ -3062,6 +3218,7 @@ var oxlint_default = definePlugin({
|
|
|
3062
3218
|
"no-redundant-variable-annotation": noRedundantVariableAnnotation,
|
|
3063
3219
|
"no-reinvented-schema": noReinventedSchema,
|
|
3064
3220
|
"no-renamed-import": noRenamedImport,
|
|
3221
|
+
"no-single-use-value": noSingleUseValue,
|
|
3065
3222
|
"no-stored-schema-operation": noStoredSchemaOperation,
|
|
3066
3223
|
"no-switch-statement": noSwitchStatement,
|
|
3067
3224
|
"no-trivial-indirection": noTrivialIndirection,
|