source: imaps-frontend/node_modules/eslint-plugin-react/lib/util/jsx.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/**
2 * @fileoverview Utility functions for JSX
3 */
4
5'use strict';
6
7const elementType = require('jsx-ast-utils/elementType');
8
9const astUtil = require('./ast');
10const isCreateElement = require('./isCreateElement');
11const variableUtil = require('./variable');
12
13// See https://github.com/babel/babel/blob/ce420ba51c68591e057696ef43e028f41c6e04cd/packages/babel-types/src/validators/react/isCompatTag.js
14// for why we only test for the first character
15const COMPAT_TAG_REGEX = /^[a-z]/;
16
17/**
18 * Checks if a node represents a DOM element according to React.
19 * @param {object} node - JSXOpeningElement to check.
20 * @returns {boolean} Whether or not the node corresponds to a DOM element.
21 */
22function isDOMComponent(node) {
23 const name = elementType(node);
24 return COMPAT_TAG_REGEX.test(name);
25}
26
27/**
28 * Test whether a JSXElement is a fragment
29 * @param {JSXElement} node
30 * @param {string} reactPragma
31 * @param {string} fragmentPragma
32 * @returns {boolean}
33 */
34function isFragment(node, reactPragma, fragmentPragma) {
35 const name = node.openingElement.name;
36
37 // <Fragment>
38 if (name.type === 'JSXIdentifier' && name.name === fragmentPragma) {
39 return true;
40 }
41
42 // <React.Fragment>
43 if (
44 name.type === 'JSXMemberExpression'
45 && name.object.type === 'JSXIdentifier'
46 && name.object.name === reactPragma
47 && name.property.type === 'JSXIdentifier'
48 && name.property.name === fragmentPragma
49 ) {
50 return true;
51 }
52
53 return false;
54}
55
56/**
57 * Checks if a node represents a JSX element or fragment.
58 * @param {object} node - node to check.
59 * @returns {boolean} Whether or not the node if a JSX element or fragment.
60 */
61function isJSX(node) {
62 return node && ['JSXElement', 'JSXFragment'].indexOf(node.type) >= 0;
63}
64
65/**
66 * Check if node is like `key={...}` as in `<Foo key={...} />`
67 * @param {ASTNode} node
68 * @returns {boolean}
69 */
70function isJSXAttributeKey(node) {
71 return node.type === 'JSXAttribute'
72 && node.name
73 && node.name.type === 'JSXIdentifier'
74 && node.name.name === 'key';
75}
76
77/**
78 * Check if value has only whitespaces
79 * @param {string} value
80 * @returns {boolean}
81 */
82function isWhiteSpaces(value) {
83 return typeof value === 'string' ? /^\s*$/.test(value) : false;
84}
85
86/**
87 * Check if the node is returning JSX or null
88 *
89 * @param {Context} context The context of `ASTNode`.
90 * @param {ASTNode} ASTnode The AST node being checked
91 * @param {Boolean} [strict] If true, in a ternary condition the node must return JSX in both cases
92 * @param {Boolean} [ignoreNull] If true, null return values will be ignored
93 * @returns {Boolean} True if the node is returning JSX or null, false if not
94 */
95function isReturningJSX(context, ASTnode, strict, ignoreNull) {
96 const isJSXValue = (node) => {
97 if (!node) {
98 return false;
99 }
100 switch (node.type) {
101 case 'ConditionalExpression':
102 if (strict) {
103 return isJSXValue(node.consequent) && isJSXValue(node.alternate);
104 }
105 return isJSXValue(node.consequent) || isJSXValue(node.alternate);
106 case 'LogicalExpression':
107 if (strict) {
108 return isJSXValue(node.left) && isJSXValue(node.right);
109 }
110 return isJSXValue(node.left) || isJSXValue(node.right);
111 case 'SequenceExpression':
112 return isJSXValue(node.expressions[node.expressions.length - 1]);
113 case 'JSXElement':
114 case 'JSXFragment':
115 return true;
116 case 'CallExpression':
117 return isCreateElement(context, node);
118 case 'Literal':
119 if (!ignoreNull && node.value === null) {
120 return true;
121 }
122 return false;
123 case 'Identifier': {
124 const variable = variableUtil.findVariableByName(context, node, node.name);
125 return isJSX(variable);
126 }
127 default:
128 return false;
129 }
130 };
131
132 let found = false;
133 astUtil.traverseReturns(ASTnode, context, (node, breakTraverse) => {
134 if (isJSXValue(node)) {
135 found = true;
136 breakTraverse();
137 }
138 });
139
140 return found;
141}
142
143/**
144 * Check if the node is returning only null values
145 *
146 * @param {ASTNode} ASTnode The AST node being checked
147 * @param {Context} context The context of `ASTNode`.
148 * @returns {Boolean} True if the node is returning only null values
149 */
150function isReturningOnlyNull(ASTnode, context) {
151 let found = false;
152 let foundSomethingElse = false;
153 astUtil.traverseReturns(ASTnode, context, (node) => {
154 // Traverse return statement
155 astUtil.traverse(node, {
156 enter(childNode) {
157 const setFound = () => {
158 found = true;
159 this.skip();
160 };
161 const setFoundSomethingElse = () => {
162 foundSomethingElse = true;
163 this.skip();
164 };
165 switch (childNode.type) {
166 case 'ReturnStatement':
167 break;
168 case 'ConditionalExpression':
169 if (childNode.consequent.value === null && childNode.alternate.value === null) {
170 setFound();
171 }
172 break;
173 case 'Literal':
174 if (childNode.value === null) {
175 setFound();
176 }
177 break;
178 default:
179 setFoundSomethingElse();
180 }
181 },
182 });
183 });
184
185 return found && !foundSomethingElse;
186}
187
188module.exports = {
189 isDOMComponent,
190 isFragment,
191 isJSX,
192 isJSXAttributeKey,
193 isWhiteSpaces,
194 isReturningJSX,
195 isReturningOnlyNull,
196};
Note: See TracBrowser for help on using the repository browser.