eslint-plugin-absolute 0.0.2 → 0.1.0

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
@@ -149,45 +149,6 @@ var explicit_object_types_default = {
149
149
  }
150
150
  };
151
151
 
152
- // src/rules/no-type-cast.js
153
- var no_type_cast_default = {
154
- meta: {
155
- type: "problem",
156
- docs: {
157
- description: 'Disallow type assertions using "as", angle bracket syntax, or built-in conversion functions.',
158
- recommended: false
159
- },
160
- schema: []
161
- },
162
- create(context) {
163
- function isBuiltInConversion(node) {
164
- return node && node.type === "Identifier" && ["Number", "String", "Boolean"].includes(node.name);
165
- }
166
- return {
167
- TSAsExpression(node) {
168
- context.report({
169
- node,
170
- message: 'Type assertions using "as" syntax are not allowed.'
171
- });
172
- },
173
- TSTypeAssertion(node) {
174
- context.report({
175
- node,
176
- message: "Type assertions using angle bracket syntax are not allowed."
177
- });
178
- },
179
- CallExpression(node) {
180
- if (isBuiltInConversion(node.callee)) {
181
- context.report({
182
- node,
183
- message: `Type assertions using "${node.callee.name}()" syntax are not allowed.`
184
- });
185
- }
186
- }
187
- };
188
- }
189
- };
190
-
191
152
  // src/rules/sort-keys-fixable.js
192
153
  var sort_keys_fixable_default = {
193
154
  meta: {
@@ -1203,51 +1164,35 @@ var no_button_navigation_default = {
1203
1164
  create(context) {
1204
1165
  function containsWindowNavigation(node) {
1205
1166
  let found = false;
1206
- const visited = new WeakSet;
1207
1167
  function inspect(n) {
1208
- if (!n || found)
1209
- return;
1210
- if (typeof n !== "object")
1168
+ if (found || !n || typeof n !== "object")
1211
1169
  return;
1212
- if (visited.has(n))
1170
+ if (n.type === "MemberExpression" && n.object.type === "Identifier" && n.object.name === "window" && n.property.type === "Identifier" && (n.property.name === "open" || n.property.name === "location")) {
1171
+ found = true;
1213
1172
  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
1173
  }
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
- }
1174
+ for (const key of Object.keys(n)) {
1175
+ if (key === "parent")
1176
+ continue;
1177
+ const child = n[key];
1178
+ if (Array.isArray(child)) {
1179
+ child.forEach(inspect);
1180
+ } else {
1181
+ inspect(child);
1236
1182
  }
1237
1183
  }
1238
1184
  }
1239
- inspect(node);
1185
+ inspect(node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression" ? node.body : node);
1240
1186
  return found;
1241
1187
  }
1242
1188
  return {
1243
1189
  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)) {
1190
+ const { openingElement } = node;
1191
+ if (openingElement.name.type === "JSXIdentifier" && openingElement.name.name === "button") {
1192
+ for (const attr of openingElement.attributes) {
1193
+ if (attr.type === "JSXAttribute" && attr.name.name === "onClick" && attr.value?.type === "JSXExpressionContainer") {
1194
+ const expr = attr.value.expression;
1195
+ if ((expr.type === "ArrowFunctionExpression" || expr.type === "FunctionExpression") && containsWindowNavigation(expr)) {
1251
1196
  context.report({
1252
1197
  node: attr,
1253
1198
  message: "Use an anchor tag for navigation instead of a button with an onClick handler that uses window navigation methods."
@@ -1856,7 +1801,6 @@ var src_default = {
1856
1801
  rules: {
1857
1802
  "no-nested-jsx-return": no_nested_jsx_return_default,
1858
1803
  "explicit-object-types": explicit_object_types_default,
1859
- "no-type-cast": no_type_cast_default,
1860
1804
  "sort-keys-fixable": sort_keys_fixable_default,
1861
1805
  "no-transition-cssproperties": no_transition_cssproperties_default,
1862
1806
  "no-explicit-return-type": no_explicit_return_types_default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-absolute",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "ESLint plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import noNestedJsxReturn from "./rules/no-nested-jsx-return.js";
2
2
  import explicitObjectTypes from "./rules/explicit-object-types.js";
3
- import noTypeCast from "./rules/no-type-cast.js";
4
3
  import sortKeysFixable from "./rules/sort-keys-fixable.js";
5
4
  import noTransitionCssproperties from "./rules/no-transition-cssproperties.js";
6
5
  import noExplicitReturnTypes from "./rules/no-explicit-return-types.js";
@@ -24,7 +23,6 @@ export default {
24
23
  rules: {
25
24
  "no-nested-jsx-return": noNestedJsxReturn,
26
25
  "explicit-object-types": explicitObjectTypes,
27
- "no-type-cast": noTypeCast,
28
26
  "sort-keys-fixable": sortKeysFixable,
29
27
  "no-transition-cssproperties": noTransitionCssproperties,
30
28
  "no-explicit-return-type": noExplicitReturnTypes,
@@ -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:
@@ -1,50 +0,0 @@
1
- export default {
2
- meta: {
3
- type: "problem",
4
- docs: {
5
- description:
6
- 'Disallow type assertions using "as", angle bracket syntax, or built-in conversion functions.',
7
- recommended: false
8
- },
9
- schema: []
10
- },
11
- create(context) {
12
- // Helper function to determine if a call expression is a built-in conversion.
13
- function isBuiltInConversion(node) {
14
- return (
15
- node &&
16
- node.type === "Identifier" &&
17
- ["Number", "String", "Boolean"].includes(node.name)
18
- );
19
- }
20
-
21
- return {
22
- // Catch type assertions using "as" syntax.
23
- TSAsExpression(node) {
24
- context.report({
25
- node,
26
- message:
27
- 'Type assertions using "as" syntax are not allowed.'
28
- });
29
- },
30
- // Catch type assertions using angle bracket syntax.
31
- TSTypeAssertion(node) {
32
- context.report({
33
- node,
34
- message:
35
- "Type assertions using angle bracket syntax are not allowed."
36
- });
37
- },
38
- // Catch type conversions using built-in functions like Number(prop)
39
- CallExpression(node) {
40
- // Check if the callee is a built-in conversion function.
41
- if (isBuiltInConversion(node.callee)) {
42
- context.report({
43
- node,
44
- message: `Type assertions using "${node.callee.name}()" syntax are not allowed.`
45
- });
46
- }
47
- }
48
- };
49
- }
50
- };