eslint-plugin-no-mistakes 0.61.0 → 0.61.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-no-mistakes",
3
- "version": "0.61.0",
3
+ "version": "0.61.2",
4
4
  "description": "ESLint and Oxlint rules that keep code static enough for no-mistakes analyzers and coding agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+
3
+ const { unwrapExpression } = require("./async-ast");
4
+ const { propertyName, literalString } = require("./module-mock-helpers");
5
+
6
+ const UNSTABLE_BINDING_DEF_TYPES = new Set(["Parameter", "CatchClause", "FunctionName"]);
7
+
8
+ function findVariable(scope, name) {
9
+ while (scope) {
10
+ const variable = scope.variables.find((candidate) => candidate.name === name);
11
+ if (variable) return variable;
12
+ scope = scope.upper;
13
+ }
14
+ return null;
15
+ }
16
+
17
+ function resolveVariable(node, context) {
18
+ return findVariable(context.sourceCode.getScope(node), node.name);
19
+ }
20
+
21
+ function isLocalRequire(id, context) {
22
+ const variable = resolveVariable(id, context);
23
+ return Boolean(variable?.defs.some((def) => def.type && def.type !== "ImplicitGlobalVariable"));
24
+ }
25
+
26
+ function isReassigned(id, context) {
27
+ const variable = resolveVariable(id, context);
28
+ if (!variable) return false;
29
+ const writes = variable.references.filter((reference) => reference.isWrite());
30
+ const initializationSites = new Set(
31
+ writes.filter((reference) => reference.init).map((reference) => reference.identifier),
32
+ );
33
+ const isVar = variable.defs.some(
34
+ (definition) => definition.type === "Variable" && definition.parent?.kind === "var",
35
+ );
36
+ return (
37
+ writes.some((reference) => !reference.init) ||
38
+ (isVar && initializationSites.size > 1) ||
39
+ variable.defs.some((definition) => UNSTABLE_BINDING_DEF_TYPES.has(definition.type))
40
+ );
41
+ }
42
+
43
+ function bindingIdentifier(node) {
44
+ if (node?.type === "Identifier") return node;
45
+ return node?.type === "AssignmentPattern" && node.left.type === "Identifier" ? node.left : null;
46
+ }
47
+
48
+ function staticComputedPropertyName(node) {
49
+ return literalString(unwrapExpression(node));
50
+ }
51
+
52
+ function memberPropertyName(node) {
53
+ if (!node.computed) return propertyName(node.property);
54
+ return staticComputedPropertyName(node.property);
55
+ }
56
+
57
+ function recordObjectPatternBindings(pattern, source, recordDirect) {
58
+ for (const property of pattern.properties) {
59
+ if (property.type !== "Property") continue;
60
+ const name = property.computed
61
+ ? staticComputedPropertyName(property.key)
62
+ : propertyName(property.key);
63
+ if (name) recordDirect(bindingIdentifier(property.value), source, name);
64
+ }
65
+ }
66
+
67
+ function namespaceSourceFromInit(init, context, namespaceBindings) {
68
+ const expression = unwrapExpression(init);
69
+ if (expression?.type !== "Identifier") return null;
70
+ return namespaceBindings.get(resolveVariable(expression, context)) || null;
71
+ }
72
+
73
+ module.exports = {
74
+ isLocalRequire,
75
+ isReassigned,
76
+ memberPropertyName,
77
+ namespaceSourceFromInit,
78
+ recordObjectPatternBindings,
79
+ resolveVariable,
80
+ };
@@ -1,32 +1,22 @@
1
1
  "use strict";
2
2
 
3
3
  const { unwrapExpression } = require("./async-ast");
4
+ const {
5
+ isLocalRequire,
6
+ isReassigned,
7
+ memberPropertyName,
8
+ namespaceSourceFromInit,
9
+ recordObjectPatternBindings,
10
+ resolveVariable,
11
+ } = require("./async-target-bindings");
4
12
  const { compileTargets, matchesAny, targetMatches } = require("./async-patterns");
5
- const { propertyName, literalString } = require("./module-mock-helpers");
6
-
7
- function findVariable(scope, name) {
8
- while (scope) {
9
- const variable = scope.variables.find((candidate) => candidate.name === name);
10
- if (variable) return variable;
11
- scope = scope.upper;
12
- }
13
- return null;
14
- }
15
-
16
- function resolveVariable(node, context) {
17
- return findVariable(context.sourceCode.getScope(node), node.name);
18
- }
13
+ const { literalString } = require("./module-mock-helpers");
19
14
 
20
15
  function importSpecifierName(specifier) {
21
16
  const imported = specifier.imported;
22
17
  return imported.type === "Literal" ? String(imported.value) : imported.name;
23
18
  }
24
19
 
25
- function isLocalRequire(id, context) {
26
- const variable = resolveVariable(id, context);
27
- return Boolean(variable?.defs.some((def) => def.type && def.type !== "ImplicitGlobalVariable"));
28
- }
29
-
30
20
  function requireSource(node, context) {
31
21
  const expression = unwrapExpression(node);
32
22
  const source = literalString(unwrapExpression(expression?.arguments?.[0]));
@@ -42,42 +32,16 @@ function requireSource(node, context) {
42
32
  return source;
43
33
  }
44
34
 
45
- function bindingIdentifier(node) {
46
- if (node?.type === "Identifier") return node;
47
- return node?.type === "AssignmentPattern" && node.left.type === "Identifier" ? node.left : null;
48
- }
49
-
50
- function memberPropertyName(node) {
51
- if (!node.computed) return propertyName(node.property);
52
- return staticComputedPropertyName(node.property);
53
- }
54
-
55
- function staticComputedPropertyName(node) {
56
- return literalString(unwrapExpression(node));
57
- }
58
-
59
35
  function createTargetMatcher(context, optionKey = "targets") {
60
36
  const targets = compileTargets(context.options?.[0] || {}, optionKey);
61
37
  const sourceSpecifierPatterns = targets.flatMap((target) => target.sourceSpecifierPatterns);
62
38
  const directBindings = new Map();
63
39
  const namespaceBindings = new Map();
64
40
 
65
- function isReassigned(id) {
66
- const variable = resolveVariable(id, context);
67
- const writes = variable?.references.filter((reference) => reference.isWrite()) || [];
68
- const initializationSites = new Set(
69
- writes.filter((reference) => reference.init).map((reference) => reference.identifier),
70
- );
71
- const isVar = variable?.defs.some(
72
- (definition) => definition.type === "Variable" && definition.parent?.kind === "var",
73
- );
74
- return writes.some((reference) => !reference.init) || (isVar && initializationSites.size > 1);
75
- }
76
-
77
41
  function recordDirect(id, source, calleeName) {
78
42
  if (
79
43
  id?.type !== "Identifier" ||
80
- isReassigned(id) ||
44
+ isReassigned(id, context) ||
81
45
  !targetMatches(targets, source, calleeName)
82
46
  ) {
83
47
  return;
@@ -89,7 +53,7 @@ function createTargetMatcher(context, optionKey = "targets") {
89
53
  function recordNamespace(id, source) {
90
54
  if (
91
55
  id.type !== "Identifier" ||
92
- isReassigned(id) ||
56
+ isReassigned(id, context) ||
93
57
  !matchesAny(source, sourceSpecifierPatterns)
94
58
  ) {
95
59
  return;
@@ -108,21 +72,20 @@ function createTargetMatcher(context, optionKey = "targets") {
108
72
  return;
109
73
  }
110
74
  if (node.id.type === "ObjectPattern") {
111
- for (const property of node.id.properties) {
112
- if (property.type !== "Property") continue;
113
- const name = property.computed
114
- ? staticComputedPropertyName(property.key)
115
- : propertyName(property.key);
116
- if (name) recordDirect(bindingIdentifier(property.value), source, name);
117
- }
75
+ recordObjectPatternBindings(node.id, source, recordDirect);
118
76
  }
119
77
  return;
120
78
  }
121
79
  const member = unwrapExpression(node.init);
122
- if (member?.type !== "MemberExpression" || node.id.type !== "Identifier") return;
123
- const memberSource = requireSource(member.object, context);
124
- const name = memberPropertyName(member);
125
- if (memberSource && name) recordDirect(node.id, memberSource, name);
80
+ if (member?.type === "MemberExpression" && node.id.type === "Identifier") {
81
+ const memberSource = requireSource(member.object, context);
82
+ const name = memberPropertyName(member);
83
+ if (memberSource && name) recordDirect(node.id, memberSource, name);
84
+ return;
85
+ }
86
+ if (node.id.type !== "ObjectPattern") return;
87
+ const nsSource = namespaceSourceFromInit(node.init, context, namespaceBindings);
88
+ if (nsSource) recordObjectPatternBindings(node.id, nsSource, recordDirect);
126
89
  }
127
90
 
128
91
  function recordImportEquals(node) {
@@ -170,7 +133,9 @@ function createTargetMatcher(context, optionKey = "targets") {
170
133
  walk(node, (child) => {
171
134
  if (child.type === "ImportDeclaration") recordImportDeclaration(child);
172
135
  else if (child.type === "TSImportEqualsDeclaration") recordImportEquals(child);
173
- else if (child.type === "VariableDeclarator") recordRequireDeclarator(child);
136
+ });
137
+ walk(node, (child) => {
138
+ if (child.type === "VariableDeclarator") recordRequireDeclarator(child);
174
139
  });
175
140
  }
176
141