eslint-plugin-absolute 0.2.6 → 0.2.8

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.
@@ -1,63 +0,0 @@
1
- import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
-
3
- type Options = [];
4
- type MessageIds = "useLogicalAnd";
5
-
6
- export const noOrNoneComponent: TSESLint.RuleModule<MessageIds, Options> = {
7
- create(context) {
8
- return {
9
- ConditionalExpression(node: TSESTree.ConditionalExpression) {
10
- const { alternate } = node;
11
-
12
- // Check if alternate is explicitly null or undefined
13
- const isNullAlternate =
14
- alternate &&
15
- alternate.type === "Literal" &&
16
- alternate.value === null;
17
-
18
- const isUndefinedAlternate =
19
- alternate &&
20
- alternate.type === "Identifier" &&
21
- alternate.name === "undefined";
22
-
23
- if (!isNullAlternate && !isUndefinedAlternate) {
24
- return;
25
- }
26
-
27
- // Check if the node is within a JSX expression container.
28
- const { parent } = node;
29
- if (!parent || parent.type !== "JSXExpressionContainer") {
30
- return;
31
- }
32
-
33
- const containerParent = parent.parent;
34
- // Only flag if the JSXExpressionContainer is used as a child,
35
- // not as a prop (i.e. not within a JSXAttribute)
36
- if (
37
- containerParent &&
38
- containerParent.type !== "JSXAttribute"
39
- ) {
40
- context.report({
41
- messageId: "useLogicalAnd",
42
- node
43
- });
44
- }
45
- }
46
- };
47
- },
48
- defaultOptions: [],
49
- meta: {
50
- docs: {
51
- description:
52
- "Prefer using logical && operator over ternary with null/undefined for conditional JSX rendering."
53
- },
54
- messages: {
55
- useLogicalAnd:
56
- "Prefer using the logical '&&' operator instead of a ternary with null/undefined for conditional rendering."
57
- },
58
- schema: [],
59
- type: "suggestion"
60
- }
61
- };
62
-
63
- // TODO : Add a fix function to this rule, it needs a deep unconflicting fix becasue of react/jsx-no-leaked-render, it needs to explicitly be === something like that
@@ -1,131 +0,0 @@
1
- /**
2
- * @fileoverview Disallow the "transition" property in objects typed as CSSProperties.
3
- *
4
- * This rule inspects VariableDeclarators where the identifier has a type annotation that
5
- * includes "CSSProperties" (either as a TSTypeReference or by a text check fallback).
6
- * It then checks if the initializer is an object literal containing a property named "transition".
7
- *
8
- * This is intended to help avoid conflicts with react-spring.
9
- */
10
-
11
- import { TSESLint, TSESTree } from "@typescript-eslint/utils";
12
-
13
- type Options = [];
14
- type MessageIds = "forbiddenTransition";
15
-
16
- const getKeyName = (prop: TSESTree.Property) => {
17
- if (prop.key.type === "Identifier") {
18
- return prop.key.name;
19
- }
20
- if (prop.key.type !== "Literal") {
21
- return null;
22
- }
23
- return typeof prop.key.value === "string"
24
- ? prop.key.value
25
- : String(prop.key.value);
26
- };
27
-
28
- const checkPropForTransition = (
29
- context: TSESLint.RuleContext<MessageIds, Options>,
30
- prop: TSESTree.Property
31
- ) => {
32
- if (prop.computed) {
33
- return;
34
- }
35
- const keyName = getKeyName(prop);
36
- if (keyName === "transition") {
37
- context.report({
38
- messageId: "forbiddenTransition",
39
- node: prop
40
- });
41
- }
42
- };
43
-
44
- export const noTransitionCSSProperties: TSESLint.RuleModule<
45
- MessageIds,
46
- Options
47
- > = {
48
- create(context) {
49
- const { sourceCode } = context;
50
-
51
- const isCSSPropertiesType = (typeAnnotation: TSESTree.TypeNode) => {
52
- if (typeAnnotation.type !== "TSTypeReference") {
53
- return false;
54
- }
55
-
56
- const { typeName } = typeAnnotation;
57
-
58
- if (
59
- typeName.type === "Identifier" &&
60
- typeName.name === "CSSProperties"
61
- ) {
62
- return true;
63
- }
64
-
65
- return (
66
- typeName.type === "TSQualifiedName" &&
67
- typeName.right &&
68
- typeName.right.type === "Identifier" &&
69
- typeName.right.name === "CSSProperties"
70
- );
71
- };
72
-
73
- return {
74
- VariableDeclarator(node: TSESTree.VariableDeclarator) {
75
- // Ensure the variable identifier exists, is an Identifier, and has a type annotation.
76
- if (
77
- !node.id ||
78
- node.id.type !== "Identifier" ||
79
- !node.id.typeAnnotation
80
- ) {
81
- return;
82
- }
83
-
84
- const { typeAnnotation } = node.id.typeAnnotation;
85
-
86
- // Check if the type annotation is CSSProperties
87
- let isStyleType = isCSSPropertiesType(typeAnnotation);
88
-
89
- // Fallback: if the AST shape doesn't match, check the raw text of the annotation.
90
- if (!isStyleType) {
91
- const annotationText = sourceCode.getText(
92
- node.id.typeAnnotation
93
- );
94
- isStyleType = annotationText.includes("CSSProperties");
95
- }
96
-
97
- if (!isStyleType) {
98
- return;
99
- }
100
-
101
- // Check that the initializer is an object literal.
102
- const { init } = node;
103
- if (!init || init.type !== "ObjectExpression") {
104
- return;
105
- }
106
-
107
- const properties = init.properties.filter(
108
- (prop): prop is TSESTree.Property =>
109
- prop.type === "Property"
110
- );
111
-
112
- properties.forEach((prop) => {
113
- checkPropForTransition(context, prop);
114
- });
115
- }
116
- };
117
- },
118
- defaultOptions: [],
119
- meta: {
120
- docs: {
121
- description:
122
- "Objects typed as CSSProperties must not include a 'transition' property as it conflicts with react-spring."
123
- },
124
- messages: {
125
- forbiddenTransition:
126
- "Objects typed as CSSProperties must not include a 'transition' property as it conflicts with react-spring."
127
- },
128
- schema: [], // no options,
129
- type: "problem"
130
- }
131
- };
@@ -1,65 +0,0 @@
1
- import { TSESLint, TSESTree, AST_NODE_TYPES } from "@typescript-eslint/utils";
2
-
3
- type Options = [];
4
- type MessageIds = "unnecessaryDivWrapper";
5
-
6
- export const noUnnecessaryDiv: TSESLint.RuleModule<MessageIds, Options> = {
7
- create(context) {
8
- const isDivElement = (node: TSESTree.JSXElement) => {
9
- const nameNode = node.openingElement.name;
10
- return (
11
- nameNode.type === AST_NODE_TYPES.JSXIdentifier &&
12
- nameNode.name === "div"
13
- );
14
- };
15
-
16
- const isMeaningfulChild = (child: TSESTree.JSXChild) => {
17
- if (child.type === AST_NODE_TYPES.JSXText) {
18
- return child.value.trim() !== "";
19
- }
20
- return true;
21
- };
22
-
23
- const getMeaningfulChildren = (node: TSESTree.JSXElement) =>
24
- node.children.filter(isMeaningfulChild);
25
-
26
- return {
27
- JSXElement(node: TSESTree.JSXElement) {
28
- if (!isDivElement(node)) {
29
- return;
30
- }
31
-
32
- const meaningfulChildren = getMeaningfulChildren(node);
33
-
34
- if (meaningfulChildren.length !== 1) {
35
- return;
36
- }
37
-
38
- const [onlyChild] = meaningfulChildren;
39
- if (!onlyChild) {
40
- return;
41
- }
42
-
43
- if (onlyChild.type === AST_NODE_TYPES.JSXElement) {
44
- context.report({
45
- messageId: "unnecessaryDivWrapper",
46
- node
47
- });
48
- }
49
- }
50
- };
51
- },
52
- defaultOptions: [],
53
- meta: {
54
- docs: {
55
- description:
56
- "Flag unnecessary <div> wrappers that enclose a single JSX element. Remove the wrapper if it doesn't add semantic or functional value, or replace it with a semantic element if wrapping is needed."
57
- },
58
- messages: {
59
- unnecessaryDivWrapper:
60
- "Unnecessary <div> wrapper detected. Remove it if not needed, or replace with a semantic element that reflects its purpose."
61
- },
62
- schema: [],
63
- type: "suggestion"
64
- }
65
- };
@@ -1,111 +0,0 @@
1
- /**
2
- * @fileoverview Enforce that the key prop is only used on components
3
- * rendered as part of an array mapping. This rule disallows having a key prop
4
- * on a JSX element when it is not part of a mapping, except when the element is
5
- * returned from a helper render function.
6
- *
7
- * Note: This rule does not auto-fix.
8
- */
9
-
10
- import { TSESLint, TSESTree } from "@typescript-eslint/utils";
11
-
12
- type Options = [];
13
- type MessageIds = "unnecessaryKey";
14
-
15
- const isMapCallExpression = (node: TSESTree.Node) => {
16
- if (
17
- node.type !== "CallExpression" ||
18
- node.callee.type !== "MemberExpression"
19
- ) {
20
- return false;
21
- }
22
-
23
- const { property } = node.callee;
24
- return (
25
- (property.type === "Identifier" && property.name === "map") ||
26
- (property.type === "Literal" && property.value === "map")
27
- );
28
- };
29
-
30
- export const noUnnecessaryKey: TSESLint.RuleModule<MessageIds, Options> = {
31
- create(context) {
32
- // Polyfill for context.getAncestors if it's not available.
33
- const getAncestors = (node: TSESTree.Node) => {
34
- const ancestors: TSESTree.Node[] = [];
35
- let current: TSESTree.Node | null | undefined = node.parent;
36
- while (current) {
37
- ancestors.push(current);
38
- current = current.parent;
39
- }
40
- return ancestors;
41
- };
42
-
43
- /**
44
- * Checks if any of the ancestors is a CallExpression
45
- * representing an array mapping.
46
- */
47
- const isInsideMapCall = (ancestors: TSESTree.Node[]) =>
48
- ancestors.some(isMapCallExpression);
49
-
50
- /**
51
- * Checks whether the JSX element is being returned from a helper render
52
- * function.
53
- */
54
- const isReturnedFromFunction = (ancestors: TSESTree.Node[]) =>
55
- ancestors.some((ancestor) => ancestor.type === "ReturnStatement");
56
-
57
- /**
58
- * Reports a JSX element if it has a key prop and is not rendered as part
59
- * of an inline mapping (and not simply returned from a render helper function).
60
- */
61
- const checkJSXOpeningElement = (node: TSESTree.JSXOpeningElement) => {
62
- // Find a key attribute.
63
- const keyAttribute = node.attributes.find(
64
- (attr) =>
65
- attr.type === "JSXAttribute" &&
66
- attr.name.type === "JSXIdentifier" &&
67
- attr.name.name === "key"
68
- );
69
-
70
- if (!keyAttribute) {
71
- return;
72
- }
73
-
74
- // Retrieve ancestors.
75
- const ancestors = getAncestors(node);
76
-
77
- // If the element is (directly or indirectly) part of a map call, allow it.
78
- if (isInsideMapCall(ancestors)) {
79
- return;
80
- }
81
-
82
- // If the element is simply returned from a helper function, allow it.
83
- if (isReturnedFromFunction(ancestors)) {
84
- return;
85
- }
86
-
87
- // Otherwise, report the key prop as unnecessary.
88
- context.report({
89
- messageId: "unnecessaryKey",
90
- node: keyAttribute
91
- });
92
- };
93
-
94
- return {
95
- JSXOpeningElement: checkJSXOpeningElement
96
- };
97
- },
98
- defaultOptions: [],
99
- meta: {
100
- docs: {
101
- description:
102
- "enforce that the key prop is only used on components rendered as part of a mapping"
103
- },
104
- messages: {
105
- unnecessaryKey:
106
- "The key prop should only be used on elements that are directly rendered as part of an array mapping."
107
- },
108
- schema: [],
109
- type: "problem"
110
- }
111
- };
@@ -1,56 +0,0 @@
1
- import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
-
3
- type Options = [];
4
- type MessageIds = "uselessFunction";
5
-
6
- export const noUselessFunction: TSESLint.RuleModule<MessageIds, Options> = {
7
- create(context) {
8
- const isCallbackFunction = (node: TSESTree.ArrowFunctionExpression) => {
9
- const { parent } = node;
10
- if (!parent || parent.type !== "CallExpression") {
11
- return false;
12
- }
13
-
14
- for (const arg of parent.arguments) {
15
- if (arg === node) {
16
- return true;
17
- }
18
- }
19
-
20
- return false;
21
- };
22
-
23
- return {
24
- ArrowFunctionExpression(node: TSESTree.ArrowFunctionExpression) {
25
- // Check for functions with no parameters and a body that's an ObjectExpression
26
- if (
27
- node.params.length === 0 &&
28
- node.body &&
29
- node.body.type === "ObjectExpression"
30
- ) {
31
- // If the function is used as a callback (like in react-spring), skip reporting.
32
- if (isCallbackFunction(node)) {
33
- return;
34
- }
35
- context.report({
36
- messageId: "uselessFunction",
37
- node
38
- });
39
- }
40
- }
41
- };
42
- },
43
- defaultOptions: [],
44
- meta: {
45
- docs: {
46
- description:
47
- "Disallow functions that have no parameters and just return an object literal; consider exporting the object directly, unless the function is used as a callback (e.g., in react-spring)."
48
- },
49
- messages: {
50
- uselessFunction:
51
- "This function has no parameters and simply returns an object. Consider exporting the object directly instead of wrapping it in a function."
52
- },
53
- schema: [],
54
- type: "suggestion"
55
- }
56
- };
@@ -1,79 +0,0 @@
1
- import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
-
3
- type Options = [];
4
- type MessageIds = "moveToFile";
5
-
6
- export const seperateStyleFiles: TSESLint.RuleModule<MessageIds, Options> = {
7
- create(context) {
8
- // Only run this rule on .tsx or .jsx files.
9
- const { filename } = context;
10
- if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) {
11
- return {};
12
- }
13
-
14
- return {
15
- VariableDeclarator(node: TSESTree.VariableDeclarator) {
16
- // Ensure this is a variable declaration with an Identifier.
17
- if (!node.id || node.id.type !== "Identifier") {
18
- return;
19
- }
20
-
21
- const identifier = node.id;
22
-
23
- // Check if there's a type annotation on the variable.
24
- const idTypeAnnotation = identifier.typeAnnotation;
25
- if (
26
- !idTypeAnnotation ||
27
- idTypeAnnotation.type !== "TSTypeAnnotation"
28
- ) {
29
- return;
30
- }
31
-
32
- const typeNode = idTypeAnnotation.typeAnnotation;
33
- if (!typeNode || typeNode.type !== "TSTypeReference") {
34
- return;
35
- }
36
-
37
- // Handle both Identifier and TSQualifiedName cases.
38
- const typeNameNode = typeNode.typeName;
39
- let typeName: string | null = null;
40
-
41
- // When typeName is a simple Identifier.
42
- if (typeNameNode.type === "Identifier") {
43
- typeName = typeNameNode.name;
44
- }
45
- // When typeName is a TSQualifiedName, e.g., React.CSSProperties.
46
- else if (typeNameNode.type === "TSQualifiedName") {
47
- const { right } = typeNameNode;
48
- typeName = right.name;
49
- }
50
-
51
- // Report if the type name is CSSProperties.
52
- if (typeName === "CSSProperties") {
53
- context.report({
54
- data: {
55
- name: identifier.name,
56
- typeName
57
- },
58
- messageId: "moveToFile",
59
- node
60
- });
61
- }
62
- }
63
- };
64
- },
65
- defaultOptions: [],
66
- meta: {
67
- docs: {
68
- description:
69
- "Warn when a component file (.jsx or .tsx) contains a style object typed as CSSProperties. " +
70
- "Style objects should be moved to their own file under the style folder."
71
- },
72
- messages: {
73
- moveToFile:
74
- 'Style object "{{name}}" is typed as {{typeName}}. Move it to its own file under the style folder.'
75
- },
76
- schema: [],
77
- type: "suggestion"
78
- }
79
- };