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 +18 -74
- package/package.json +1 -1
- package/src/index.js +0 -2
- package/src/rules/no-button-navigation.js +38 -65
- package/src/rules/no-type-cast.js +0 -50
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 ||
|
|
1209
|
-
return;
|
|
1210
|
-
if (typeof n !== "object")
|
|
1168
|
+
if (found || !n || typeof n !== "object")
|
|
1211
1169
|
return;
|
|
1212
|
-
if (
|
|
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
|
|
1229
|
-
if (
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
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
|
|
1245
|
-
if (openingElement.name
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
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
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
|
-
*
|
|
15
|
-
*
|
|
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 ||
|
|
24
|
-
|
|
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 === "
|
|
49
|
-
n.
|
|
50
|
-
n.
|
|
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
|
-
|
|
53
|
-
|
|
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
|
-
//
|
|
66
|
-
for (const key
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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
|
|
84
|
-
//
|
|
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
|
-
|
|
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
|
|
101
|
-
|
|
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
|
-
};
|