@fedify/lint 2.2.14-dev.2082 → 2.2.15-dev.2196
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/deno.json +1 -1
- package/dist/index.cjs +83 -7
- package/dist/index.js +83 -7
- package/package.json +2 -2
package/deno.json
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@ let _typescript_eslint_parser = require("@typescript-eslint/parser");
|
|
|
29
29
|
_typescript_eslint_parser = __toESM(_typescript_eslint_parser);
|
|
30
30
|
//#region deno.json
|
|
31
31
|
var name = "@fedify/lint";
|
|
32
|
-
var version = "2.2.
|
|
32
|
+
var version = "2.2.15-dev.2196+10201be2";
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/lib/const.ts
|
|
35
35
|
/**
|
|
@@ -830,6 +830,37 @@ function createBindingIndex() {
|
|
|
830
830
|
}
|
|
831
831
|
};
|
|
832
832
|
}
|
|
833
|
+
const position = (node) => node.range?.[0] ?? node.start ?? -1;
|
|
834
|
+
const endPosition = (node) => node.range?.[1] ?? node.end ?? -1;
|
|
835
|
+
const enclosingFunction = (node) => {
|
|
836
|
+
for (let parent = getParent(node); parent != null; parent = getParent(parent)) if (isFunctionLike(parent)) return parent;
|
|
837
|
+
return null;
|
|
838
|
+
};
|
|
839
|
+
const isInside = (node, ancestor) => {
|
|
840
|
+
for (let current = node; current != null; current = getParent(current)) if (current === ancestor) return true;
|
|
841
|
+
return false;
|
|
842
|
+
};
|
|
843
|
+
const isDirectStatement = (node, fn) => {
|
|
844
|
+
let current = node;
|
|
845
|
+
while (getParent(current) !== fn.body) {
|
|
846
|
+
const parent = getParent(current);
|
|
847
|
+
if (parent == null || ![
|
|
848
|
+
"AwaitExpression",
|
|
849
|
+
"ExpressionStatement",
|
|
850
|
+
"ReturnStatement",
|
|
851
|
+
"VariableDeclarator",
|
|
852
|
+
"VariableDeclaration",
|
|
853
|
+
"BlockStatement"
|
|
854
|
+
].includes(parent.type)) return false;
|
|
855
|
+
current = parent;
|
|
856
|
+
}
|
|
857
|
+
return [
|
|
858
|
+
"ExpressionStatement",
|
|
859
|
+
"ReturnStatement",
|
|
860
|
+
"VariableDeclaration",
|
|
861
|
+
"BlockStatement"
|
|
862
|
+
].includes(current.type);
|
|
863
|
+
};
|
|
833
864
|
const resolveBindingValue = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
|
|
834
865
|
if (expr.type !== "Identifier") return expr;
|
|
835
866
|
const binding = bindings.lookup(expr, expr.name);
|
|
@@ -858,12 +889,45 @@ function unwrapArgument(node) {
|
|
|
858
889
|
while (node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression") node = node.expression;
|
|
859
890
|
return node;
|
|
860
891
|
}
|
|
861
|
-
function
|
|
892
|
+
function ignoredLocalSetupFunctions(listener, bindings, calls, assignments) {
|
|
893
|
+
const ignored = [];
|
|
894
|
+
const directCalls = calls.filter((call) => enclosingFunction(call) === listener && isDirectStatement(call, listener));
|
|
895
|
+
for (const assignment of assignments) {
|
|
896
|
+
if (assignment.type !== "AssignmentExpression" || assignment.operator !== "=" || assignment.left.type !== "MemberExpression" || !isFunction(assignment.right)) continue;
|
|
897
|
+
const setup = enclosingFunction(assignment);
|
|
898
|
+
if (setup == null || setup === listener || !isInside(setup, listener)) continue;
|
|
899
|
+
const setupParent = getParent(setup);
|
|
900
|
+
const namedLocalSetup = enclosingFunction(setup) === listener && (setup.type === "FunctionDeclaration" || setupParent?.type === "VariableDeclarator" && setupParent.init === setup && setupParent.id.type === "Identifier");
|
|
901
|
+
const passedToCall = calls.some((call) => call.arguments.some((argument) => argument.type !== "SpreadElement" && resolveListenerReference(argument, bindings) === setup));
|
|
902
|
+
if (!namedLocalSetup || passedToCall) continue;
|
|
903
|
+
const installed = assignment.right;
|
|
904
|
+
if (!isDirectStatement(assignment, setup) || assignment.left.object.type !== "Identifier") {
|
|
905
|
+
ignored.push(installed);
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
const property = getMemberPropertyName(assignment.left);
|
|
909
|
+
if (property == null) continue;
|
|
910
|
+
const setupCalls = directCalls.filter((call) => resolveListenerReference(call.callee, bindings) === setup);
|
|
911
|
+
if (setupCalls.length === 0) {
|
|
912
|
+
const called = calls.some((call) => resolveListenerReference(call.callee, bindings) === setup);
|
|
913
|
+
ignored.push(called ? assignment.right : setup);
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
const objectBinding = bindings.lookup(assignment.left.object, assignment.left.object.name);
|
|
917
|
+
const deliveryCalls = directCalls.filter((call) => {
|
|
918
|
+
const callee = call.callee;
|
|
919
|
+
return callee.type === "MemberExpression" && callee.object.type === "Identifier" && getMemberPropertyName(callee) === property && bindings.lookup(callee.object, callee.object.name) === objectBinding;
|
|
920
|
+
});
|
|
921
|
+
if (!(objectBinding != null && setupCalls.some((setupCall) => deliveryCalls.some((deliveryCall) => position(setupCall) >= 0 && position(setupCall) < position(deliveryCall))))) ignored.push(installed);
|
|
922
|
+
}
|
|
923
|
+
return ignored;
|
|
924
|
+
}
|
|
925
|
+
function functionCallsDelivery(sourceCode, listener, bindings, calls, assignments, contextIndex = 0, visited = /* @__PURE__ */ new Map()) {
|
|
862
926
|
let indices = visited.get(listener);
|
|
863
927
|
if (indices?.has(contextIndex)) return false;
|
|
864
928
|
if (indices == null) visited.set(listener, indices = /* @__PURE__ */ new Set());
|
|
865
929
|
indices.add(contextIndex);
|
|
866
|
-
if (listenerCallsDeliveryMethod(sourceCode, listener, contextIndex)) return true;
|
|
930
|
+
if (listenerCallsDeliveryMethod(sourceCode, listener, contextIndex, ignoredLocalSetupFunctions(listener, bindings, calls, assignments))) return true;
|
|
867
931
|
const param = unwrapContextParam(listener.params[contextIndex]);
|
|
868
932
|
if (param?.type !== "Identifier") return false;
|
|
869
933
|
const contextBinding = bindings.lookup(listener, param.name);
|
|
@@ -883,13 +947,21 @@ function functionCallsDelivery(sourceCode, listener, bindings, calls, contextInd
|
|
|
883
947
|
if (argument.type === "SpreadElement") break;
|
|
884
948
|
const arg = unwrapArgument(argument);
|
|
885
949
|
if (arg.type !== "Identifier" || arg.name !== param.name || bindings.lookup(arg, arg.name) !== contextBinding || helper.params[index]?.type === "RestElement") continue;
|
|
886
|
-
if (functionCallsDelivery(sourceCode, helper, bindings, calls, index, visited)) return true;
|
|
950
|
+
if (functionCallsDelivery(sourceCode, helper, bindings, calls, assignments, index, visited)) return true;
|
|
887
951
|
}
|
|
888
952
|
}
|
|
889
953
|
return false;
|
|
890
954
|
}
|
|
891
|
-
const listenerCallsDeliveryMethod = (sourceCode, listener, contextIndex = 0) => {
|
|
892
|
-
|
|
955
|
+
const listenerCallsDeliveryMethod = (sourceCode, listener, contextIndex = 0, ignored = []) => {
|
|
956
|
+
let text = sourceCode.getText(listener);
|
|
957
|
+
const start = position(listener);
|
|
958
|
+
for (const fn of ignored) {
|
|
959
|
+
const from = position(fn) - start;
|
|
960
|
+
const to = endPosition(fn) - start;
|
|
961
|
+
if (from < 0 || to > text.length || to < from) continue;
|
|
962
|
+
text = text.slice(0, from) + " ".repeat(to - from) + text.slice(to);
|
|
963
|
+
}
|
|
964
|
+
const code = stripCommentsAndStrings(text);
|
|
893
965
|
const aliases = /* @__PURE__ */ new Set();
|
|
894
966
|
const contextParam = unwrapContextParam(listener.params[contextIndex]);
|
|
895
967
|
const contextName = contextParam?.type === "Identifier" ? contextParam.name : null;
|
|
@@ -922,6 +994,7 @@ function createRule(buildReport) {
|
|
|
922
994
|
const federationTracker = trackFederationVariables();
|
|
923
995
|
const bindings = createBindingIndex();
|
|
924
996
|
const pendingCalls = [];
|
|
997
|
+
const pendingAssignments = [];
|
|
925
998
|
const sourceCode = context.sourceCode;
|
|
926
999
|
const inspectCall = (node) => {
|
|
927
1000
|
if (!hasMemberExpressionCallee(node) || !hasIdentifierProperty(node) || !hasMethodName("on")(node) || node.arguments.length < 2) return;
|
|
@@ -929,7 +1002,7 @@ function createRule(buildReport) {
|
|
|
929
1002
|
const listener = node.arguments[1];
|
|
930
1003
|
const resolvedListener = isNode(listener) && isFunction(listener) ? listener : isNode(listener) ? resolveListenerReference(listener, bindings) : null;
|
|
931
1004
|
if (resolvedListener == null) return;
|
|
932
|
-
if (functionCallsDelivery(sourceCode, resolvedListener, bindings, pendingCalls)) return;
|
|
1005
|
+
if (functionCallsDelivery(sourceCode, resolvedListener, bindings, pendingCalls, pendingAssignments)) return;
|
|
933
1006
|
context.report({
|
|
934
1007
|
node: resolvedListener,
|
|
935
1008
|
...buildReport
|
|
@@ -957,6 +1030,9 @@ function createRule(buildReport) {
|
|
|
957
1030
|
CallExpression(node) {
|
|
958
1031
|
pendingCalls.push(node);
|
|
959
1032
|
},
|
|
1033
|
+
AssignmentExpression(node) {
|
|
1034
|
+
pendingAssignments.push(node);
|
|
1035
|
+
},
|
|
960
1036
|
"Program:exit"() {
|
|
961
1037
|
for (const node of pendingCalls) inspectCall(node);
|
|
962
1038
|
}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { always, every, fromEntries, head, isEmpty, isObject, keys, map, negate,
|
|
|
2
2
|
import parser from "@typescript-eslint/parser";
|
|
3
3
|
//#region deno.json
|
|
4
4
|
var name = "@fedify/lint";
|
|
5
|
-
var version = "2.2.
|
|
5
|
+
var version = "2.2.15-dev.2196+10201be2";
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/lib/const.ts
|
|
8
8
|
/**
|
|
@@ -803,6 +803,37 @@ function createBindingIndex() {
|
|
|
803
803
|
}
|
|
804
804
|
};
|
|
805
805
|
}
|
|
806
|
+
const position = (node) => node.range?.[0] ?? node.start ?? -1;
|
|
807
|
+
const endPosition = (node) => node.range?.[1] ?? node.end ?? -1;
|
|
808
|
+
const enclosingFunction = (node) => {
|
|
809
|
+
for (let parent = getParent(node); parent != null; parent = getParent(parent)) if (isFunctionLike(parent)) return parent;
|
|
810
|
+
return null;
|
|
811
|
+
};
|
|
812
|
+
const isInside = (node, ancestor) => {
|
|
813
|
+
for (let current = node; current != null; current = getParent(current)) if (current === ancestor) return true;
|
|
814
|
+
return false;
|
|
815
|
+
};
|
|
816
|
+
const isDirectStatement = (node, fn) => {
|
|
817
|
+
let current = node;
|
|
818
|
+
while (getParent(current) !== fn.body) {
|
|
819
|
+
const parent = getParent(current);
|
|
820
|
+
if (parent == null || ![
|
|
821
|
+
"AwaitExpression",
|
|
822
|
+
"ExpressionStatement",
|
|
823
|
+
"ReturnStatement",
|
|
824
|
+
"VariableDeclarator",
|
|
825
|
+
"VariableDeclaration",
|
|
826
|
+
"BlockStatement"
|
|
827
|
+
].includes(parent.type)) return false;
|
|
828
|
+
current = parent;
|
|
829
|
+
}
|
|
830
|
+
return [
|
|
831
|
+
"ExpressionStatement",
|
|
832
|
+
"ReturnStatement",
|
|
833
|
+
"VariableDeclaration",
|
|
834
|
+
"BlockStatement"
|
|
835
|
+
].includes(current.type);
|
|
836
|
+
};
|
|
806
837
|
const resolveBindingValue = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
|
|
807
838
|
if (expr.type !== "Identifier") return expr;
|
|
808
839
|
const binding = bindings.lookup(expr, expr.name);
|
|
@@ -831,12 +862,45 @@ function unwrapArgument(node) {
|
|
|
831
862
|
while (node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression") node = node.expression;
|
|
832
863
|
return node;
|
|
833
864
|
}
|
|
834
|
-
function
|
|
865
|
+
function ignoredLocalSetupFunctions(listener, bindings, calls, assignments) {
|
|
866
|
+
const ignored = [];
|
|
867
|
+
const directCalls = calls.filter((call) => enclosingFunction(call) === listener && isDirectStatement(call, listener));
|
|
868
|
+
for (const assignment of assignments) {
|
|
869
|
+
if (assignment.type !== "AssignmentExpression" || assignment.operator !== "=" || assignment.left.type !== "MemberExpression" || !isFunction(assignment.right)) continue;
|
|
870
|
+
const setup = enclosingFunction(assignment);
|
|
871
|
+
if (setup == null || setup === listener || !isInside(setup, listener)) continue;
|
|
872
|
+
const setupParent = getParent(setup);
|
|
873
|
+
const namedLocalSetup = enclosingFunction(setup) === listener && (setup.type === "FunctionDeclaration" || setupParent?.type === "VariableDeclarator" && setupParent.init === setup && setupParent.id.type === "Identifier");
|
|
874
|
+
const passedToCall = calls.some((call) => call.arguments.some((argument) => argument.type !== "SpreadElement" && resolveListenerReference(argument, bindings) === setup));
|
|
875
|
+
if (!namedLocalSetup || passedToCall) continue;
|
|
876
|
+
const installed = assignment.right;
|
|
877
|
+
if (!isDirectStatement(assignment, setup) || assignment.left.object.type !== "Identifier") {
|
|
878
|
+
ignored.push(installed);
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
const property = getMemberPropertyName(assignment.left);
|
|
882
|
+
if (property == null) continue;
|
|
883
|
+
const setupCalls = directCalls.filter((call) => resolveListenerReference(call.callee, bindings) === setup);
|
|
884
|
+
if (setupCalls.length === 0) {
|
|
885
|
+
const called = calls.some((call) => resolveListenerReference(call.callee, bindings) === setup);
|
|
886
|
+
ignored.push(called ? assignment.right : setup);
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
const objectBinding = bindings.lookup(assignment.left.object, assignment.left.object.name);
|
|
890
|
+
const deliveryCalls = directCalls.filter((call) => {
|
|
891
|
+
const callee = call.callee;
|
|
892
|
+
return callee.type === "MemberExpression" && callee.object.type === "Identifier" && getMemberPropertyName(callee) === property && bindings.lookup(callee.object, callee.object.name) === objectBinding;
|
|
893
|
+
});
|
|
894
|
+
if (!(objectBinding != null && setupCalls.some((setupCall) => deliveryCalls.some((deliveryCall) => position(setupCall) >= 0 && position(setupCall) < position(deliveryCall))))) ignored.push(installed);
|
|
895
|
+
}
|
|
896
|
+
return ignored;
|
|
897
|
+
}
|
|
898
|
+
function functionCallsDelivery(sourceCode, listener, bindings, calls, assignments, contextIndex = 0, visited = /* @__PURE__ */ new Map()) {
|
|
835
899
|
let indices = visited.get(listener);
|
|
836
900
|
if (indices?.has(contextIndex)) return false;
|
|
837
901
|
if (indices == null) visited.set(listener, indices = /* @__PURE__ */ new Set());
|
|
838
902
|
indices.add(contextIndex);
|
|
839
|
-
if (listenerCallsDeliveryMethod(sourceCode, listener, contextIndex)) return true;
|
|
903
|
+
if (listenerCallsDeliveryMethod(sourceCode, listener, contextIndex, ignoredLocalSetupFunctions(listener, bindings, calls, assignments))) return true;
|
|
840
904
|
const param = unwrapContextParam(listener.params[contextIndex]);
|
|
841
905
|
if (param?.type !== "Identifier") return false;
|
|
842
906
|
const contextBinding = bindings.lookup(listener, param.name);
|
|
@@ -856,13 +920,21 @@ function functionCallsDelivery(sourceCode, listener, bindings, calls, contextInd
|
|
|
856
920
|
if (argument.type === "SpreadElement") break;
|
|
857
921
|
const arg = unwrapArgument(argument);
|
|
858
922
|
if (arg.type !== "Identifier" || arg.name !== param.name || bindings.lookup(arg, arg.name) !== contextBinding || helper.params[index]?.type === "RestElement") continue;
|
|
859
|
-
if (functionCallsDelivery(sourceCode, helper, bindings, calls, index, visited)) return true;
|
|
923
|
+
if (functionCallsDelivery(sourceCode, helper, bindings, calls, assignments, index, visited)) return true;
|
|
860
924
|
}
|
|
861
925
|
}
|
|
862
926
|
return false;
|
|
863
927
|
}
|
|
864
|
-
const listenerCallsDeliveryMethod = (sourceCode, listener, contextIndex = 0) => {
|
|
865
|
-
|
|
928
|
+
const listenerCallsDeliveryMethod = (sourceCode, listener, contextIndex = 0, ignored = []) => {
|
|
929
|
+
let text = sourceCode.getText(listener);
|
|
930
|
+
const start = position(listener);
|
|
931
|
+
for (const fn of ignored) {
|
|
932
|
+
const from = position(fn) - start;
|
|
933
|
+
const to = endPosition(fn) - start;
|
|
934
|
+
if (from < 0 || to > text.length || to < from) continue;
|
|
935
|
+
text = text.slice(0, from) + " ".repeat(to - from) + text.slice(to);
|
|
936
|
+
}
|
|
937
|
+
const code = stripCommentsAndStrings(text);
|
|
866
938
|
const aliases = /* @__PURE__ */ new Set();
|
|
867
939
|
const contextParam = unwrapContextParam(listener.params[contextIndex]);
|
|
868
940
|
const contextName = contextParam?.type === "Identifier" ? contextParam.name : null;
|
|
@@ -895,6 +967,7 @@ function createRule(buildReport) {
|
|
|
895
967
|
const federationTracker = trackFederationVariables();
|
|
896
968
|
const bindings = createBindingIndex();
|
|
897
969
|
const pendingCalls = [];
|
|
970
|
+
const pendingAssignments = [];
|
|
898
971
|
const sourceCode = context.sourceCode;
|
|
899
972
|
const inspectCall = (node) => {
|
|
900
973
|
if (!hasMemberExpressionCallee(node) || !hasIdentifierProperty(node) || !hasMethodName("on")(node) || node.arguments.length < 2) return;
|
|
@@ -902,7 +975,7 @@ function createRule(buildReport) {
|
|
|
902
975
|
const listener = node.arguments[1];
|
|
903
976
|
const resolvedListener = isNode(listener) && isFunction(listener) ? listener : isNode(listener) ? resolveListenerReference(listener, bindings) : null;
|
|
904
977
|
if (resolvedListener == null) return;
|
|
905
|
-
if (functionCallsDelivery(sourceCode, resolvedListener, bindings, pendingCalls)) return;
|
|
978
|
+
if (functionCallsDelivery(sourceCode, resolvedListener, bindings, pendingCalls, pendingAssignments)) return;
|
|
906
979
|
context.report({
|
|
907
980
|
node: resolvedListener,
|
|
908
981
|
...buildReport
|
|
@@ -930,6 +1003,9 @@ function createRule(buildReport) {
|
|
|
930
1003
|
CallExpression(node) {
|
|
931
1004
|
pendingCalls.push(node);
|
|
932
1005
|
},
|
|
1006
|
+
AssignmentExpression(node) {
|
|
1007
|
+
pendingAssignments.push(node);
|
|
1008
|
+
},
|
|
933
1009
|
"Program:exit"() {
|
|
934
1010
|
for (const node of pendingCalls) inspectCall(node);
|
|
935
1011
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/lint",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.15-dev.2196+10201be2",
|
|
4
4
|
"description": "Fedify linting rules and plugins",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Fedify",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
],
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"eslint": ">=9.0.0",
|
|
50
|
-
"@fedify/fedify": "^2.2.
|
|
50
|
+
"@fedify/fedify": "^2.2.15-dev.2196+10201be2"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"eslint": {
|