@fedify/lint 2.2.13 → 2.2.14

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 CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@fedify/lint",
3
- "version": "2.2.13",
3
+ "version": "2.2.14",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts"
7
7
  },
8
8
  "imports": {
9
+ "@fedify/fixture": "jsr:@fedify/fixture@^2.2.14",
9
10
  "eslint": "npm:eslint@^9.0.0",
10
11
  "estree": "npm:@types/estree@^1.0.8"
11
12
  },
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.13";
32
+ var version = "2.2.14";
33
33
  //#endregion
34
34
  //#region src/lib/const.ts
35
35
  /**
@@ -623,7 +623,7 @@ const DELIVERY_METHOD_NAMES = new Set(["sendActivity", "forwardActivity"]);
623
623
  const getMemberPropertyName = (expr) => {
624
624
  if (expr.type !== "MemberExpression") return null;
625
625
  const property = expr.property;
626
- if (property.type === "Identifier") return property.name;
626
+ if (property.type === "Identifier" && !expr.computed) return property.name;
627
627
  if (property.type === "Literal" && typeof property.value === "string") return property.value;
628
628
  return null;
629
629
  };
@@ -759,35 +759,139 @@ function buildContextExpressionPattern(contextName) {
759
759
  const boundedName = String.raw`(?<![\w$])${name}(?![\w$])`;
760
760
  return String.raw`(?:${boundedName}|\(\s*${boundedName}(?:\s+as\s+[^)]+)?\s*\))`;
761
761
  }
762
- const resolveListenerReference = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
763
- if (isFunction(expr)) return expr;
764
- if (expr.type === "Identifier") {
765
- if (seen.has(expr.name)) return null;
766
- seen.add(expr.name);
767
- const binding = bindings.get(expr.name);
768
- if (binding == null || !isNode(binding)) return null;
769
- if (isFunction(binding) || binding.type === "FunctionDeclaration") return binding;
770
- if (binding.type === "Identifier") return resolveListenerReference(binding, bindings, seen);
771
- return null;
762
+ const getParent = (node) => node.parent ?? null;
763
+ const isFunctionLike = (node) => node.type === "FunctionDeclaration" || isFunction(node);
764
+ function bindPattern(node, bindings) {
765
+ switch (node.type) {
766
+ case "Identifier":
767
+ bindings.set(node.name, { value: null });
768
+ break;
769
+ case "AssignmentPattern":
770
+ bindPattern(node.left, bindings);
771
+ break;
772
+ case "RestElement":
773
+ bindPattern(node.argument, bindings);
774
+ break;
775
+ case "ObjectPattern":
776
+ for (const property of node.properties) bindPattern(property.type === "Property" ? property.value : property, bindings);
777
+ break;
778
+ case "ArrayPattern":
779
+ for (const element of node.elements) if (element != null) bindPattern(element, bindings);
780
+ break;
772
781
  }
773
- if (expr.type === "MemberExpression" && expr.object.type === "Identifier" && !expr.computed) {
774
- const binding = bindings.get(expr.object.name);
775
- if (binding == null || !isNode(binding) || binding.type !== "ObjectExpression") return null;
776
- const propertyName = getMemberPropertyName(expr);
777
- if (propertyName == null) return null;
778
- for (const prop of binding.properties) {
779
- if (!isNode(prop) || prop.type !== "Property") continue;
780
- if ((prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null) !== propertyName || !isNode(prop.value)) continue;
781
- const value = prop.value;
782
- if (isFunction(value) || value.type === "FunctionDeclaration") return value;
782
+ }
783
+ function createBindingIndex() {
784
+ const scopes = /* @__PURE__ */ new Map();
785
+ const scopeBindings = (scope) => {
786
+ let bindings = scopes.get(scope);
787
+ if (bindings == null) {
788
+ bindings = /* @__PURE__ */ new Map();
789
+ scopes.set(scope, bindings);
790
+ if (isFunctionLike(scope)) {
791
+ if (scope.type === "FunctionExpression" && scope.id != null) bindings.set(scope.id.name, { value: scope });
792
+ for (const param of scope.params) bindPattern(param, bindings);
793
+ }
794
+ if (scope.type === "ClassExpression" && scope.id != null) bindings.set(scope.id.name, { value: null });
795
+ if (scope.type === "CatchClause" && scope.param != null) bindPattern(scope.param, bindings);
796
+ }
797
+ return bindings;
798
+ };
799
+ const enclosingScope = (node, functionScope = false) => {
800
+ let scope = getParent(node);
801
+ while (scope.type !== "Program" && scope.type !== "StaticBlock" && scope.type !== "TSModuleBlock" && !isFunctionLike(scope) && (functionScope || ![
802
+ "BlockStatement",
803
+ "ForStatement",
804
+ "ForInStatement",
805
+ "ForOfStatement",
806
+ "SwitchStatement",
807
+ "CatchClause"
808
+ ].includes(scope.type))) scope = getParent(scope);
809
+ return scope;
810
+ };
811
+ const lookup = (node, name) => {
812
+ for (let scope = node; scope != null; scope = getParent(scope)) {
813
+ const binding = scopeBindings(scope).get(name);
814
+ if (binding != null) return binding;
815
+ }
816
+ return null;
817
+ };
818
+ return {
819
+ lookup,
820
+ declare(node, pattern, value, hoisted = false) {
821
+ const bindings = scopeBindings(enclosingScope(node, hoisted));
822
+ if (pattern.type === "Identifier") {
823
+ if (hoisted && value == null && bindings.has(pattern.name)) return;
824
+ if (node.type === "FunctionDeclaration" && bindings.get(pattern.name)?.initializedVariable) return;
825
+ bindings.set(pattern.name, {
826
+ value,
827
+ initializedVariable: node.type === "VariableDeclarator" && value != null
828
+ });
829
+ } else bindPattern(pattern, bindings);
783
830
  }
831
+ };
832
+ }
833
+ const resolveBindingValue = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
834
+ if (expr.type !== "Identifier") return expr;
835
+ const binding = bindings.lookup(expr, expr.name);
836
+ if (binding == null || binding.value == null || seen.has(binding)) return null;
837
+ seen.add(binding);
838
+ return resolveBindingValue(binding.value, bindings, seen);
839
+ };
840
+ const resolveListenerReference = (expr, bindings) => {
841
+ const target = resolveBindingValue(expr, bindings);
842
+ if (target == null) return null;
843
+ if (isFunctionLike(target)) return target;
844
+ if (target.type !== "MemberExpression") return null;
845
+ const object = resolveBindingValue(target.object, bindings);
846
+ if (object?.type !== "ObjectExpression") return null;
847
+ const propertyName = getMemberPropertyName(target);
848
+ if (propertyName == null) return null;
849
+ for (const prop of object.properties) {
850
+ if (prop.type !== "Property") continue;
851
+ if ((prop.key.type === "Identifier" && !prop.computed ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null) !== propertyName) continue;
852
+ const value = resolveBindingValue(prop.value, bindings);
853
+ if (value != null && isFunctionLike(value)) return value;
784
854
  }
785
855
  return null;
786
856
  };
787
- const listenerCallsDeliveryMethod = (sourceCode, listener) => {
857
+ function unwrapArgument(node) {
858
+ while (node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression") node = node.expression;
859
+ return node;
860
+ }
861
+ function functionCallsDelivery(sourceCode, listener, bindings, calls, contextIndex = 0, visited = /* @__PURE__ */ new Map()) {
862
+ let indices = visited.get(listener);
863
+ if (indices?.has(contextIndex)) return false;
864
+ if (indices == null) visited.set(listener, indices = /* @__PURE__ */ new Set());
865
+ indices.add(contextIndex);
866
+ if (listenerCallsDeliveryMethod(sourceCode, listener, contextIndex)) return true;
867
+ const param = unwrapContextParam(listener.params[contextIndex]);
868
+ if (param?.type !== "Identifier") return false;
869
+ const contextBinding = bindings.lookup(listener, param.name);
870
+ for (const call of calls) {
871
+ let child = call;
872
+ let owner = getParent(child);
873
+ while (owner != null && !isFunctionLike(owner)) {
874
+ const field = owner;
875
+ if ((field.type === "PropertyDefinition" || field.type === "AccessorProperty") && !field.static && field.value === child) break;
876
+ child = owner;
877
+ owner = getParent(owner);
878
+ }
879
+ if (owner !== listener) continue;
880
+ const helper = resolveListenerReference(call.callee, bindings);
881
+ if (helper == null || "generator" in helper && helper.generator) continue;
882
+ for (const [index, argument] of call.arguments.entries()) {
883
+ if (argument.type === "SpreadElement") break;
884
+ const arg = unwrapArgument(argument);
885
+ 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;
887
+ }
888
+ }
889
+ return false;
890
+ }
891
+ const listenerCallsDeliveryMethod = (sourceCode, listener, contextIndex = 0) => {
788
892
  const code = stripCommentsAndStrings(sourceCode.getText(listener));
789
893
  const aliases = /* @__PURE__ */ new Set();
790
- const contextParam = unwrapContextParam(listener.params[0]);
894
+ const contextParam = unwrapContextParam(listener.params[contextIndex]);
791
895
  const contextName = contextParam?.type === "Identifier" ? contextParam.name : null;
792
896
  if (contextParam?.type === "ObjectPattern") for (const prop of contextParam.properties) {
793
897
  if (!isNode(prop) || prop.type !== "Property") continue;
@@ -816,7 +920,7 @@ const listenerCallsDeliveryMethod = (sourceCode, listener) => {
816
920
  function createRule(buildReport) {
817
921
  return (context) => {
818
922
  const federationTracker = trackFederationVariables();
819
- const bindings = /* @__PURE__ */ new Map();
923
+ const bindings = createBindingIndex();
820
924
  const pendingCalls = [];
821
925
  const sourceCode = context.sourceCode;
822
926
  const inspectCall = (node) => {
@@ -825,7 +929,7 @@ function createRule(buildReport) {
825
929
  const listener = node.arguments[1];
826
930
  const resolvedListener = isNode(listener) && isFunction(listener) ? listener : isNode(listener) ? resolveListenerReference(listener, bindings) : null;
827
931
  if (resolvedListener == null) return;
828
- if (listenerCallsDeliveryMethod(sourceCode, resolvedListener)) return;
932
+ if (functionCallsDelivery(sourceCode, resolvedListener, bindings, pendingCalls)) return;
829
933
  context.report({
830
934
  node: resolvedListener,
831
935
  ...buildReport
@@ -834,10 +938,21 @@ function createRule(buildReport) {
834
938
  return {
835
939
  VariableDeclarator(node) {
836
940
  federationTracker.VariableDeclarator(node);
837
- if (node.id.type === "Identifier" && node.init != null) bindings.set(node.id.name, node.init);
941
+ const declaration = getParent(node);
942
+ bindings.declare(node, node.id, node.init, declaration?.kind === "var");
838
943
  },
839
944
  FunctionDeclaration(node) {
840
- if (node.id != null) bindings.set(node.id.name, node);
945
+ if (node.id == null) return;
946
+ const parent = getParent(node);
947
+ const owner = parent == null ? null : getParent(parent);
948
+ const inVarBody = parent?.type === "BlockStatement" && owner != null && (owner.type === "StaticBlock" || isFunctionLike(owner) && owner.body === parent);
949
+ bindings.declare(node, node.id, node, inVarBody);
950
+ },
951
+ ImportDeclaration(node) {
952
+ for (const specifier of node.specifiers) bindings.declare(node, specifier.local, null);
953
+ },
954
+ ClassDeclaration(node) {
955
+ if (node.id != null) bindings.declare(node, node.id, null);
841
956
  },
842
957
  CallExpression(node) {
843
958
  pendingCalls.push(node);
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.13";
5
+ var version = "2.2.14";
6
6
  //#endregion
7
7
  //#region src/lib/const.ts
8
8
  /**
@@ -596,7 +596,7 @@ const DELIVERY_METHOD_NAMES = new Set(["sendActivity", "forwardActivity"]);
596
596
  const getMemberPropertyName = (expr) => {
597
597
  if (expr.type !== "MemberExpression") return null;
598
598
  const property = expr.property;
599
- if (property.type === "Identifier") return property.name;
599
+ if (property.type === "Identifier" && !expr.computed) return property.name;
600
600
  if (property.type === "Literal" && typeof property.value === "string") return property.value;
601
601
  return null;
602
602
  };
@@ -732,35 +732,139 @@ function buildContextExpressionPattern(contextName) {
732
732
  const boundedName = String.raw`(?<![\w$])${name}(?![\w$])`;
733
733
  return String.raw`(?:${boundedName}|\(\s*${boundedName}(?:\s+as\s+[^)]+)?\s*\))`;
734
734
  }
735
- const resolveListenerReference = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
736
- if (isFunction(expr)) return expr;
737
- if (expr.type === "Identifier") {
738
- if (seen.has(expr.name)) return null;
739
- seen.add(expr.name);
740
- const binding = bindings.get(expr.name);
741
- if (binding == null || !isNode(binding)) return null;
742
- if (isFunction(binding) || binding.type === "FunctionDeclaration") return binding;
743
- if (binding.type === "Identifier") return resolveListenerReference(binding, bindings, seen);
744
- return null;
735
+ const getParent = (node) => node.parent ?? null;
736
+ const isFunctionLike = (node) => node.type === "FunctionDeclaration" || isFunction(node);
737
+ function bindPattern(node, bindings) {
738
+ switch (node.type) {
739
+ case "Identifier":
740
+ bindings.set(node.name, { value: null });
741
+ break;
742
+ case "AssignmentPattern":
743
+ bindPattern(node.left, bindings);
744
+ break;
745
+ case "RestElement":
746
+ bindPattern(node.argument, bindings);
747
+ break;
748
+ case "ObjectPattern":
749
+ for (const property of node.properties) bindPattern(property.type === "Property" ? property.value : property, bindings);
750
+ break;
751
+ case "ArrayPattern":
752
+ for (const element of node.elements) if (element != null) bindPattern(element, bindings);
753
+ break;
745
754
  }
746
- if (expr.type === "MemberExpression" && expr.object.type === "Identifier" && !expr.computed) {
747
- const binding = bindings.get(expr.object.name);
748
- if (binding == null || !isNode(binding) || binding.type !== "ObjectExpression") return null;
749
- const propertyName = getMemberPropertyName(expr);
750
- if (propertyName == null) return null;
751
- for (const prop of binding.properties) {
752
- if (!isNode(prop) || prop.type !== "Property") continue;
753
- if ((prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null) !== propertyName || !isNode(prop.value)) continue;
754
- const value = prop.value;
755
- if (isFunction(value) || value.type === "FunctionDeclaration") return value;
755
+ }
756
+ function createBindingIndex() {
757
+ const scopes = /* @__PURE__ */ new Map();
758
+ const scopeBindings = (scope) => {
759
+ let bindings = scopes.get(scope);
760
+ if (bindings == null) {
761
+ bindings = /* @__PURE__ */ new Map();
762
+ scopes.set(scope, bindings);
763
+ if (isFunctionLike(scope)) {
764
+ if (scope.type === "FunctionExpression" && scope.id != null) bindings.set(scope.id.name, { value: scope });
765
+ for (const param of scope.params) bindPattern(param, bindings);
766
+ }
767
+ if (scope.type === "ClassExpression" && scope.id != null) bindings.set(scope.id.name, { value: null });
768
+ if (scope.type === "CatchClause" && scope.param != null) bindPattern(scope.param, bindings);
769
+ }
770
+ return bindings;
771
+ };
772
+ const enclosingScope = (node, functionScope = false) => {
773
+ let scope = getParent(node);
774
+ while (scope.type !== "Program" && scope.type !== "StaticBlock" && scope.type !== "TSModuleBlock" && !isFunctionLike(scope) && (functionScope || ![
775
+ "BlockStatement",
776
+ "ForStatement",
777
+ "ForInStatement",
778
+ "ForOfStatement",
779
+ "SwitchStatement",
780
+ "CatchClause"
781
+ ].includes(scope.type))) scope = getParent(scope);
782
+ return scope;
783
+ };
784
+ const lookup = (node, name) => {
785
+ for (let scope = node; scope != null; scope = getParent(scope)) {
786
+ const binding = scopeBindings(scope).get(name);
787
+ if (binding != null) return binding;
788
+ }
789
+ return null;
790
+ };
791
+ return {
792
+ lookup,
793
+ declare(node, pattern, value, hoisted = false) {
794
+ const bindings = scopeBindings(enclosingScope(node, hoisted));
795
+ if (pattern.type === "Identifier") {
796
+ if (hoisted && value == null && bindings.has(pattern.name)) return;
797
+ if (node.type === "FunctionDeclaration" && bindings.get(pattern.name)?.initializedVariable) return;
798
+ bindings.set(pattern.name, {
799
+ value,
800
+ initializedVariable: node.type === "VariableDeclarator" && value != null
801
+ });
802
+ } else bindPattern(pattern, bindings);
756
803
  }
804
+ };
805
+ }
806
+ const resolveBindingValue = (expr, bindings, seen = /* @__PURE__ */ new Set()) => {
807
+ if (expr.type !== "Identifier") return expr;
808
+ const binding = bindings.lookup(expr, expr.name);
809
+ if (binding == null || binding.value == null || seen.has(binding)) return null;
810
+ seen.add(binding);
811
+ return resolveBindingValue(binding.value, bindings, seen);
812
+ };
813
+ const resolveListenerReference = (expr, bindings) => {
814
+ const target = resolveBindingValue(expr, bindings);
815
+ if (target == null) return null;
816
+ if (isFunctionLike(target)) return target;
817
+ if (target.type !== "MemberExpression") return null;
818
+ const object = resolveBindingValue(target.object, bindings);
819
+ if (object?.type !== "ObjectExpression") return null;
820
+ const propertyName = getMemberPropertyName(target);
821
+ if (propertyName == null) return null;
822
+ for (const prop of object.properties) {
823
+ if (prop.type !== "Property") continue;
824
+ if ((prop.key.type === "Identifier" && !prop.computed ? prop.key.name : prop.key.type === "Literal" && typeof prop.key.value === "string" ? prop.key.value : null) !== propertyName) continue;
825
+ const value = resolveBindingValue(prop.value, bindings);
826
+ if (value != null && isFunctionLike(value)) return value;
757
827
  }
758
828
  return null;
759
829
  };
760
- const listenerCallsDeliveryMethod = (sourceCode, listener) => {
830
+ function unwrapArgument(node) {
831
+ while (node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression") node = node.expression;
832
+ return node;
833
+ }
834
+ function functionCallsDelivery(sourceCode, listener, bindings, calls, contextIndex = 0, visited = /* @__PURE__ */ new Map()) {
835
+ let indices = visited.get(listener);
836
+ if (indices?.has(contextIndex)) return false;
837
+ if (indices == null) visited.set(listener, indices = /* @__PURE__ */ new Set());
838
+ indices.add(contextIndex);
839
+ if (listenerCallsDeliveryMethod(sourceCode, listener, contextIndex)) return true;
840
+ const param = unwrapContextParam(listener.params[contextIndex]);
841
+ if (param?.type !== "Identifier") return false;
842
+ const contextBinding = bindings.lookup(listener, param.name);
843
+ for (const call of calls) {
844
+ let child = call;
845
+ let owner = getParent(child);
846
+ while (owner != null && !isFunctionLike(owner)) {
847
+ const field = owner;
848
+ if ((field.type === "PropertyDefinition" || field.type === "AccessorProperty") && !field.static && field.value === child) break;
849
+ child = owner;
850
+ owner = getParent(owner);
851
+ }
852
+ if (owner !== listener) continue;
853
+ const helper = resolveListenerReference(call.callee, bindings);
854
+ if (helper == null || "generator" in helper && helper.generator) continue;
855
+ for (const [index, argument] of call.arguments.entries()) {
856
+ if (argument.type === "SpreadElement") break;
857
+ const arg = unwrapArgument(argument);
858
+ 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;
860
+ }
861
+ }
862
+ return false;
863
+ }
864
+ const listenerCallsDeliveryMethod = (sourceCode, listener, contextIndex = 0) => {
761
865
  const code = stripCommentsAndStrings(sourceCode.getText(listener));
762
866
  const aliases = /* @__PURE__ */ new Set();
763
- const contextParam = unwrapContextParam(listener.params[0]);
867
+ const contextParam = unwrapContextParam(listener.params[contextIndex]);
764
868
  const contextName = contextParam?.type === "Identifier" ? contextParam.name : null;
765
869
  if (contextParam?.type === "ObjectPattern") for (const prop of contextParam.properties) {
766
870
  if (!isNode(prop) || prop.type !== "Property") continue;
@@ -789,7 +893,7 @@ const listenerCallsDeliveryMethod = (sourceCode, listener) => {
789
893
  function createRule(buildReport) {
790
894
  return (context) => {
791
895
  const federationTracker = trackFederationVariables();
792
- const bindings = /* @__PURE__ */ new Map();
896
+ const bindings = createBindingIndex();
793
897
  const pendingCalls = [];
794
898
  const sourceCode = context.sourceCode;
795
899
  const inspectCall = (node) => {
@@ -798,7 +902,7 @@ function createRule(buildReport) {
798
902
  const listener = node.arguments[1];
799
903
  const resolvedListener = isNode(listener) && isFunction(listener) ? listener : isNode(listener) ? resolveListenerReference(listener, bindings) : null;
800
904
  if (resolvedListener == null) return;
801
- if (listenerCallsDeliveryMethod(sourceCode, resolvedListener)) return;
905
+ if (functionCallsDelivery(sourceCode, resolvedListener, bindings, pendingCalls)) return;
802
906
  context.report({
803
907
  node: resolvedListener,
804
908
  ...buildReport
@@ -807,10 +911,21 @@ function createRule(buildReport) {
807
911
  return {
808
912
  VariableDeclarator(node) {
809
913
  federationTracker.VariableDeclarator(node);
810
- if (node.id.type === "Identifier" && node.init != null) bindings.set(node.id.name, node.init);
914
+ const declaration = getParent(node);
915
+ bindings.declare(node, node.id, node.init, declaration?.kind === "var");
811
916
  },
812
917
  FunctionDeclaration(node) {
813
- if (node.id != null) bindings.set(node.id.name, node);
918
+ if (node.id == null) return;
919
+ const parent = getParent(node);
920
+ const owner = parent == null ? null : getParent(parent);
921
+ const inVarBody = parent?.type === "BlockStatement" && owner != null && (owner.type === "StaticBlock" || isFunctionLike(owner) && owner.body === parent);
922
+ bindings.declare(node, node.id, node, inVarBody);
923
+ },
924
+ ImportDeclaration(node) {
925
+ for (const specifier of node.specifiers) bindings.declare(node, specifier.local, null);
926
+ },
927
+ ClassDeclaration(node) {
928
+ if (node.id != null) bindings.declare(node, node.id, null);
814
929
  },
815
930
  CallExpression(node) {
816
931
  pendingCalls.push(node);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/lint",
3
- "version": "2.2.13",
3
+ "version": "2.2.14",
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.13"
50
+ "@fedify/fedify": "^2.2.14"
51
51
  },
52
52
  "peerDependenciesMeta": {
53
53
  "eslint": {
@@ -64,7 +64,8 @@
64
64
  "@types/estree": "^1.0.8",
65
65
  "eslint": "^9.0.0",
66
66
  "tsdown": "^0.21.6",
67
- "typescript": "^6.0.0"
67
+ "typescript": "^6.0.0",
68
+ "@fedify/fixture": "^2.0.0"
68
69
  },
69
70
  "scripts": {
70
71
  "build:self": "tsdown",