eslint-plugin-absolute 0.0.2 → 0.0.3

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/dist/index.js CHANGED
@@ -1203,51 +1203,35 @@ var no_button_navigation_default = {
1203
1203
  create(context) {
1204
1204
  function containsWindowNavigation(node) {
1205
1205
  let found = false;
1206
- const visited = new WeakSet;
1207
1206
  function inspect(n) {
1208
- if (!n || found)
1207
+ if (found || !n || typeof n !== "object")
1209
1208
  return;
1210
- if (typeof n !== "object")
1209
+ if (n.type === "MemberExpression" && n.object.type === "Identifier" && n.object.name === "window" && n.property.type === "Identifier" && (n.property.name === "open" || n.property.name === "location")) {
1210
+ found = true;
1211
1211
  return;
1212
- if (visited.has(n))
1213
- return;
1214
- visited.add(n);
1215
- if (n.type === "MemberExpression") {
1216
- if (n.object && n.object.type === "Identifier" && n.object.name === "window" && n.property && (n.property.type === "Identifier" && (n.property.name === "location" || n.property.name === "open") || n.property.type === "Literal" && (n.property.value === "location" || n.property.value === "open"))) {
1217
- found = true;
1218
- return;
1219
- }
1220
- }
1221
- if (n.type === "CallExpression" && n.callee && n.callee.type === "MemberExpression") {
1222
- const callee = n.callee;
1223
- if (callee.object && callee.object.type === "Identifier" && callee.object.name === "window" && callee.property && callee.property.type === "Identifier" && callee.property.name === "open") {
1224
- found = true;
1225
- return;
1226
- }
1227
1212
  }
1228
- for (const key in n) {
1229
- if (Object.prototype.hasOwnProperty.call(n, key)) {
1230
- const child = n[key];
1231
- if (Array.isArray(child)) {
1232
- child.forEach(inspect);
1233
- } else if (child && typeof child === "object") {
1234
- inspect(child);
1235
- }
1213
+ for (const key of Object.keys(n)) {
1214
+ if (key === "parent")
1215
+ continue;
1216
+ const child = n[key];
1217
+ if (Array.isArray(child)) {
1218
+ child.forEach(inspect);
1219
+ } else {
1220
+ inspect(child);
1236
1221
  }
1237
1222
  }
1238
1223
  }
1239
- inspect(node);
1224
+ inspect(node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression" ? node.body : node);
1240
1225
  return found;
1241
1226
  }
1242
1227
  return {
1243
1228
  JSXElement(node) {
1244
- const openingElement = node.openingElement;
1245
- if (openingElement.name && openingElement.name.type === "JSXIdentifier" && openingElement.name.name === "button") {
1246
- const attributes = openingElement.attributes;
1247
- for (const attr of attributes) {
1248
- if (attr.type === "JSXAttribute" && attr.name && attr.name.name === "onClick" && attr.value && attr.value.type === "JSXExpressionContainer") {
1249
- const expression = attr.value.expression;
1250
- if (containsWindowNavigation(expression)) {
1229
+ const { openingElement } = node;
1230
+ if (openingElement.name.type === "JSXIdentifier" && openingElement.name.name === "button") {
1231
+ for (const attr of openingElement.attributes) {
1232
+ if (attr.type === "JSXAttribute" && attr.name.name === "onClick" && attr.value?.type === "JSXExpressionContainer") {
1233
+ const expr = attr.value.expression;
1234
+ if ((expr.type === "ArrowFunctionExpression" || expr.type === "FunctionExpression") && containsWindowNavigation(expr)) {
1251
1235
  context.report({
1252
1236
  node: attr,
1253
1237
  message: "Use an anchor tag for navigation instead of a button with an onClick handler that uses window navigation methods."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-absolute",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "ESLint plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,94 +11,67 @@ export default {
11
11
  },
12
12
  create(context) {
13
13
  /**
14
- * Recursively inspects an AST node to see if it contains a reference to window.location or window.open.
15
- * Uses a WeakSet to track visited nodes to avoid infinite recursion.
16
- * @param {ASTNode} node - The node to inspect.
17
- * @returns {boolean} True if a window navigation reference is found.
14
+ * Inspects an AST node *only* for MemberExpressions where
15
+ * the object is literally `window` and the property is `open` or `location`.
18
16
  */
19
17
  function containsWindowNavigation(node) {
20
18
  let found = false;
21
- const visited = new WeakSet();
22
19
  function inspect(n) {
23
- if (!n || found) return;
24
- if (typeof n !== "object") return; // Only objects can be added to WeakSet
25
- if (visited.has(n)) return;
26
- visited.add(n);
27
-
28
- // Check for MemberExpressions like window.location or window.open
29
- if (n.type === "MemberExpression") {
30
- if (
31
- n.object &&
32
- n.object.type === "Identifier" &&
33
- n.object.name === "window" &&
34
- n.property &&
35
- ((n.property.type === "Identifier" &&
36
- (n.property.name === "location" ||
37
- n.property.name === "open")) ||
38
- (n.property.type === "Literal" &&
39
- (n.property.value === "location" ||
40
- n.property.value === "open")))
41
- ) {
42
- found = true;
43
- return;
44
- }
45
- }
46
- // Check for CallExpressions like window.open()
20
+ if (found || !n || typeof n !== "object") return;
21
+ // Only match MemberExpressions on the global window identifier
47
22
  if (
48
- n.type === "CallExpression" &&
49
- n.callee &&
50
- n.callee.type === "MemberExpression"
23
+ n.type === "MemberExpression" &&
24
+ n.object.type === "Identifier" &&
25
+ n.object.name === "window" &&
26
+ n.property.type === "Identifier" &&
27
+ (n.property.name === "open" ||
28
+ n.property.name === "location")
51
29
  ) {
52
- const callee = n.callee;
53
- if (
54
- callee.object &&
55
- callee.object.type === "Identifier" &&
56
- callee.object.name === "window" &&
57
- callee.property &&
58
- callee.property.type === "Identifier" &&
59
- callee.property.name === "open"
60
- ) {
61
- found = true;
62
- return;
63
- }
30
+ found = true;
31
+ return;
64
32
  }
65
- // Recursively inspect all child nodes
66
- for (const key in n) {
67
- if (Object.prototype.hasOwnProperty.call(n, key)) {
68
- const child = n[key];
69
- if (Array.isArray(child)) {
70
- child.forEach(inspect);
71
- } else if (child && typeof child === "object") {
72
- inspect(child);
73
- }
33
+ // recurse into children—but skip walking back up via `parent`
34
+ for (const key of Object.keys(n)) {
35
+ if (key === "parent") continue;
36
+ const child = n[key];
37
+ if (Array.isArray(child)) {
38
+ child.forEach(inspect);
39
+ } else {
40
+ inspect(child);
74
41
  }
75
42
  }
76
43
  }
77
- inspect(node);
44
+ // If it's a function, start at its body; otherwise start at the node itself
45
+ inspect(
46
+ node.type === "ArrowFunctionExpression" ||
47
+ node.type === "FunctionExpression"
48
+ ? node.body
49
+ : node
50
+ );
78
51
  return found;
79
52
  }
80
53
 
81
54
  return {
82
55
  JSXElement(node) {
83
- const openingElement = node.openingElement;
84
- // Check if the element is a <button>
56
+ const { openingElement } = node;
57
+ // only care about <button ...>
85
58
  if (
86
- openingElement.name &&
87
59
  openingElement.name.type === "JSXIdentifier" &&
88
60
  openingElement.name.name === "button"
89
61
  ) {
90
- // Look for the onClick attribute
91
- const attributes = openingElement.attributes;
92
- for (const attr of attributes) {
62
+ for (const attr of openingElement.attributes) {
93
63
  if (
94
64
  attr.type === "JSXAttribute" &&
95
- attr.name &&
96
65
  attr.name.name === "onClick" &&
97
- attr.value &&
98
- attr.value.type === "JSXExpressionContainer"
66
+ attr.value?.type === "JSXExpressionContainer"
99
67
  ) {
100
- const expression = attr.value.expression;
101
- if (containsWindowNavigation(expression)) {
68
+ const expr = attr.value.expression;
69
+ // only inspect the inline function, not any Identifier calls
70
+ if (
71
+ (expr.type === "ArrowFunctionExpression" ||
72
+ expr.type === "FunctionExpression") &&
73
+ containsWindowNavigation(expr)
74
+ ) {
102
75
  context.report({
103
76
  node: attr,
104
77
  message: