@eslint-react/jsx 0.5.5

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Eva1ent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,594 @@
1
+ 'use strict';
2
+
3
+ var tools = require('@eslint-react/tools');
4
+ var memo = require('micro-memoize');
5
+ var ast = require('@eslint-react/ast');
6
+ var types = require('@typescript-eslint/types');
7
+
8
+ /**
9
+ * Check if a JSXElement or JSXFragment has children
10
+ * @param node The AST node to check
11
+ * @returns `true` if the node has children
12
+ */ function hasChildren(node) {
13
+ return node.children.length > 0;
14
+ }
15
+
16
+ const RE_JSX_ANNOTATION_REGEX = /@jsx\s+(\S+)/u;
17
+ // Does not check for reserved keywords or unicode characters
18
+ const RE_JS_IDENTIFIER_REGEX = /^[$A-Z_a-z][\w$]*$/u;
19
+ function getFragmentFromContext(context) {
20
+ // eslint-disable-next-line prefer-destructuring
21
+ const settings = context.settings;
22
+ const pragma = settings.react?.fragment ?? "Fragment";
23
+ if (!RE_JS_IDENTIFIER_REGEX.test(pragma)) {
24
+ return tools.E.left(new Error(`Fragment pragma ${pragma} is not a valid identifier`));
25
+ }
26
+ return tools.E.right(pragma);
27
+ }
28
+ const getPragmaFromContext = memo((context)=>{
29
+ // eslint-disable-next-line prefer-destructuring
30
+ const settings = context.settings;
31
+ const sourceCode = context.getSourceCode();
32
+ const pragmaNode = sourceCode.getAllComments().find((node)=>RE_JSX_ANNOTATION_REGEX.test(node.value));
33
+ const pragma = settings.react?.pragma ?? tools.F.pipe(tools.O.fromNullable(pragmaNode), tools.O.map((node)=>RE_JSX_ANNOTATION_REGEX.exec(node.value)), tools.O.flatMap((matches)=>tools.O.fromNullable(matches?.[1]?.split(".")[0])), tools.O.getOrElse(()=>"React"));
34
+ if (!RE_JS_IDENTIFIER_REGEX.test(pragma)) {
35
+ return tools.E.left(new Error(`React pragma ${pragma} is not a valid identifier`));
36
+ }
37
+ return tools.E.right(pragma);
38
+ });
39
+
40
+ const t=Symbol.for("@ts-pattern/matcher"),e=Symbol.for("@ts-pattern/isVariadic"),n="@ts-pattern/anonymous-select-key",r=t=>Boolean(t&&"object"==typeof t),i=e=>e&&!!e[t],s=(n,o,c)=>{if(i(n)){const e=n[t](),{matched:r,selections:i}=e.match(o);return r&&i&&Object.keys(i).forEach(t=>c(t,i[t])),r}if(r(n)){if(!r(o))return !1;if(Array.isArray(n)){if(!Array.isArray(o))return !1;let t=[],r=[],a=[];for(const s of n.keys()){const o=n[s];i(o)&&o[e]?a.push(o):a.length?r.push(o):t.push(o);}if(a.length){if(a.length>1)throw new Error("Pattern error: Using `...P.array(...)` several times in a single pattern is not allowed.");if(o.length<t.length+r.length)return !1;const e=o.slice(0,t.length),n=0===r.length?[]:o.slice(-r.length),i=o.slice(t.length,0===r.length?Infinity:-r.length);return t.every((t,n)=>s(t,e[n],c))&&r.every((t,e)=>s(t,n[e],c))&&(0===a.length||s(a[0],i,c))}return n.length===o.length&&n.every((t,e)=>s(t,o[e],c))}return Object.keys(n).every(e=>{const r=n[e];return (e in o||i(a=r)&&"optional"===a[t]().matcherType)&&s(r,o[e],c);var a;})}return Object.is(o,n)},o=e=>{var n,s,a;return r(e)?i(e)?null!=(n=null==(s=(a=e[t]()).getSelectionKeys)?void 0:s.call(a))?n:[]:Array.isArray(e)?c(e,o):c(Object.values(e),o):[]},c=(t,e)=>t.reduce((t,n)=>t.concat(e(n)),[]);function a(...t){if(1===t.length){const[e]=t;return t=>s(e,t,()=>{})}if(2===t.length){const[e,n]=t;return s(e,n,()=>{})}throw new Error(`isMatching wasn't given the right number of arguments: expected 1 or 2, received ${t.length}.`)}function u(t){return Object.assign(t,{optional:()=>l(t),and:e=>m(t,e),or:e=>y(t,e),select:e=>void 0===e?p(t):p(e,t)})}function h(t){return Object.assign((t=>Object.assign(t,{*[Symbol.iterator](){yield Object.assign(t,{[e]:!0});}}))(t),{optional:()=>h(l(t)),select:e=>h(void 0===e?p(t):p(e,t))})}function l(e){return u({[t]:()=>({match:t=>{let n={};const r=(t,e)=>{n[t]=e;};return void 0===t?(o(e).forEach(t=>r(t,void 0)),{matched:!0,selections:n}):{matched:s(e,t,r),selections:n}},getSelectionKeys:()=>o(e),matcherType:"optional"})})}const f=(t,e)=>{for(const n of t)if(!e(n))return !1;return !0},g=(t,e)=>{for(const[n,r]of t.entries())if(!e(r,n))return !1;return !0};function m(...e){return u({[t]:()=>({match:t=>{let n={};const r=(t,e)=>{n[t]=e;};return {matched:e.every(e=>s(e,t,r)),selections:n}},getSelectionKeys:()=>c(e,o),matcherType:"and"})})}function y(...e){return u({[t]:()=>({match:t=>{let n={};const r=(t,e)=>{n[t]=e;};return c(e,o).forEach(t=>r(t,void 0)),{matched:e.some(e=>s(e,t,r)),selections:n}},getSelectionKeys:()=>c(e,o),matcherType:"or"})})}function d(e){return {[t]:()=>({match:t=>({matched:Boolean(e(t))})})}}function p(...e){const r="string"==typeof e[0]?e[0]:void 0,i=2===e.length?e[1]:"string"==typeof e[0]?void 0:e[0];return u({[t]:()=>({match:t=>{let e={[null!=r?r:n]:t};return {matched:void 0===i||s(i,t,(t,n)=>{e[t]=n;}),selections:e}},getSelectionKeys:()=>[null!=r?r:n].concat(void 0===i?[]:o(i))})})}function v(t){return "number"==typeof t}function b(t){return "string"==typeof t}function w(t){return "bigint"==typeof t}const S=u(d(function(t){return !0})),O=S,j=t=>Object.assign(u(t),{startsWith:e=>{return j(m(t,(n=e,d(t=>b(t)&&t.startsWith(n)))));var n;},endsWith:e=>{return j(m(t,(n=e,d(t=>b(t)&&t.endsWith(n)))));var n;},minLength:e=>j(m(t,(t=>d(e=>b(e)&&e.length>=t))(e))),maxLength:e=>j(m(t,(t=>d(e=>b(e)&&e.length<=t))(e))),includes:e=>{return j(m(t,(n=e,d(t=>b(t)&&t.includes(n)))));var n;},regex:e=>{return j(m(t,(n=e,d(t=>b(t)&&Boolean(t.match(n))))));var n;}}),E=j(d(b)),K=t=>Object.assign(u(t),{between:(e,n)=>K(m(t,((t,e)=>d(n=>v(n)&&t<=n&&e>=n))(e,n))),lt:e=>K(m(t,(t=>d(e=>v(e)&&e<t))(e))),gt:e=>K(m(t,(t=>d(e=>v(e)&&e>t))(e))),lte:e=>K(m(t,(t=>d(e=>v(e)&&e<=t))(e))),gte:e=>K(m(t,(t=>d(e=>v(e)&&e>=t))(e))),int:()=>K(m(t,d(t=>v(t)&&Number.isInteger(t)))),finite:()=>K(m(t,d(t=>v(t)&&Number.isFinite(t)))),positive:()=>K(m(t,d(t=>v(t)&&t>0))),negative:()=>K(m(t,d(t=>v(t)&&t<0)))}),A=K(d(v)),x=t=>Object.assign(u(t),{between:(e,n)=>x(m(t,((t,e)=>d(n=>w(n)&&t<=n&&e>=n))(e,n))),lt:e=>x(m(t,(t=>d(e=>w(e)&&e<t))(e))),gt:e=>x(m(t,(t=>d(e=>w(e)&&e>t))(e))),lte:e=>x(m(t,(t=>d(e=>w(e)&&e<=t))(e))),gte:e=>x(m(t,(t=>d(e=>w(e)&&e>=t))(e))),positive:()=>x(m(t,d(t=>w(t)&&t>0))),negative:()=>x(m(t,d(t=>w(t)&&t<0)))}),P=x(d(w)),T=u(d(function(t){return "boolean"==typeof t})),k=u(d(function(t){return "symbol"==typeof t})),B=u(d(function(t){return null==t}));var _={__proto__:null,matcher:t,optional:l,array:function(...e){return h({[t]:()=>({match:t=>{if(!Array.isArray(t))return {matched:!1};if(0===e.length)return {matched:!0};const n=e[0];let r={};if(0===t.length)return o(n).forEach(t=>{r[t]=[];}),{matched:!0,selections:r};const i=(t,e)=>{r[t]=(r[t]||[]).concat([e]);};return {matched:t.every(t=>s(n,t,i)),selections:r}},getSelectionKeys:()=>0===e.length?[]:o(e[0])})})},set:function(...e){return u({[t]:()=>({match:t=>{if(!(t instanceof Set))return {matched:!1};let n={};if(0===t.size)return {matched:!0,selections:n};if(0===e.length)return {matched:!0};const r=(t,e)=>{n[t]=(n[t]||[]).concat([e]);},i=e[0];return {matched:f(t,t=>s(i,t,r)),selections:n}},getSelectionKeys:()=>0===e.length?[]:o(e[0])})})},map:function(...e){return u({[t]:()=>({match:t=>{if(!(t instanceof Map))return {matched:!1};let n={};if(0===t.size)return {matched:!0,selections:n};const r=(t,e)=>{n[t]=(n[t]||[]).concat([e]);};if(0===e.length)return {matched:!0};var i;if(1===e.length)throw new Error(`\`P.map\` wasn't given enough arguments. Expected (key, value), received ${null==(i=e[0])?void 0:i.toString()}`);const[o,c]=e;return {matched:g(t,(t,e)=>{const n=s(o,e,r),i=s(c,t,r);return n&&i}),selections:n}},getSelectionKeys:()=>0===e.length?[]:[...o(e[0]),...o(e[1])]})})},intersection:m,union:y,not:function(e){return u({[t]:()=>({match:t=>({matched:!s(e,t,()=>{})}),getSelectionKeys:()=>[],matcherType:"not"})})},when:d,select:p,any:S,_:O,string:E,number:A,bigint:P,boolean:T,symbol:k,nullish:B,instanceOf:function(t){return u(d(function(t){return e=>e instanceof t}(t)))},shape:function(t){return u(d(a(t)))}};const W={matched:!1,value:void 0};function N(t){return new $(t,W)}class ${constructor(t,e){this.input=void 0,this.state=void 0,this.input=t,this.state=e;}with(...t){if(this.state.matched)return this;const e=t[t.length-1],r=[t[0]];let i;3===t.length&&"function"==typeof t[1]?(r.push(t[0]),i=t[1]):t.length>2&&r.push(...t.slice(1,t.length-1));let o=!1,c={};const a=(t,e)=>{o=!0,c[t]=e;},u=!r.some(t=>s(t,this.input,a))||i&&!Boolean(i(this.input))?W:{matched:!0,value:e(o?n in c?c[n]:c:this.input,this.input)};return new $(this.input,u)}when(t,e){if(this.state.matched)return this;const n=Boolean(t(this.input));return new $(this.input,n?{matched:!0,value:e(this.input,this.input)}:W)}otherwise(t){return this.state.matched?this.state.value:t(this.input)}exhaustive(){return this.run()}run(){if(this.state.matched)return this.state.value;let t;try{t=JSON.stringify(this.input);}catch(e){t=this.input;}throw new Error(`Pattern matching error: no pattern matches value ${t}`)}returnType(){return this}}
41
+
42
+ function isDestructuredFromPragma(variableName, context) {
43
+ const maybePragma = getPragmaFromContext(context);
44
+ const variables = ast.getVariablesUpToGlobal(context.getScope());
45
+ if (tools.E.isLeft(maybePragma)) {
46
+ return false;
47
+ }
48
+ const pragma = maybePragma.right;
49
+ const maybeLatestDef = tools.F.pipe(ast.findVariableByName(variableName)(variables), tools.O.flatMapNullable((variable)=>variable.defs.at(-1)));
50
+ if (tools.O.isNone(maybeLatestDef)) {
51
+ return false;
52
+ }
53
+ const latestDef = maybeLatestDef.value;
54
+ const { node, parent } = latestDef;
55
+ if (node.type === ast.NodeType.VariableDeclarator && node.init) {
56
+ const { init } = node;
57
+ // check for: `variable = pragma.variable`
58
+ if (a({
59
+ type: "MemberExpression",
60
+ object: {
61
+ type: "Identifier",
62
+ name: pragma
63
+ }
64
+ }, init)) {
65
+ return true;
66
+ }
67
+ // check for: `{ variable } = pragma`
68
+ if (a({
69
+ type: "Identifier",
70
+ name: pragma
71
+ }, init)) {
72
+ return true;
73
+ }
74
+ // check if from a require call: `require("react")`
75
+ const maybeRequireExpression = N(init).with({
76
+ type: ast.NodeType.CallExpression
77
+ }, (exp)=>tools.O.some(exp)).with({
78
+ type: ast.NodeType.MemberExpression,
79
+ object: {
80
+ type: ast.NodeType.CallExpression
81
+ }
82
+ }, ({ object })=>tools.O.some(object)).otherwise(tools.O.none);
83
+ if (tools.O.isNone(maybeRequireExpression)) {
84
+ return false;
85
+ }
86
+ const requireExpression = maybeRequireExpression.value;
87
+ if (requireExpression.callee.type !== ast.NodeType.Identifier) {
88
+ return false;
89
+ }
90
+ const calleeName = requireExpression.callee.name;
91
+ const [firstArg] = requireExpression.arguments;
92
+ if (calleeName !== "require" || firstArg?.type !== ast.NodeType.Literal) {
93
+ return false;
94
+ }
95
+ return firstArg.value === pragma.toLowerCase();
96
+ }
97
+ // latest definition is an import declaration: import { variable } from 'react'
98
+ return a({
99
+ type: "ImportDeclaration",
100
+ source: {
101
+ value: pragma.toLowerCase()
102
+ }
103
+ }, parent);
104
+ }
105
+
106
+ /**
107
+ * Checks if the given node is a call expression to the given function or method of the pragma
108
+ * @param name The name of the function or method to check
109
+ * @returns A predicate that checks if the given node is a call expression to the given function or method
110
+ */ const isCallFromPragma = (name)=>(node, context)=>{
111
+ if (node.type !== ast.NodeType.CallExpression || !("callee" in node)) {
112
+ return false;
113
+ }
114
+ const maybePragma = getPragmaFromContext(context);
115
+ if (tools.E.isLeft(maybePragma)) {
116
+ return false;
117
+ }
118
+ const pragma = maybePragma.right;
119
+ return N(node.callee).with({
120
+ type: ast.NodeType.MemberExpression,
121
+ object: {
122
+ name: pragma
123
+ },
124
+ property: {
125
+ name
126
+ }
127
+ }, tools.F.constTrue).with({
128
+ name
129
+ }, ({ name })=>isDestructuredFromPragma(name, context)).otherwise(tools.F.constFalse);
130
+ };
131
+
132
+ /**
133
+ * Checks if the given node is a call expression to `React.createElement`
134
+ * @param node The AST node to check
135
+ * @param context The rule context
136
+ * @returns `true` if the node is a call expression to `createElement`
137
+ */ const isCreateElementCall = isCallFromPragma("createElement");
138
+ /**
139
+ * Checks if the given node is a call expression to `React.cloneElement`
140
+ * @param node The AST node to check
141
+ * @param context The rule context
142
+ * @returns `true` if the node is a call expression to `cloneElement`
143
+ */ const isCloneElementCall = isCallFromPragma("cloneElement");
144
+
145
+ function isChildrenOfCreateElement(node, context) {
146
+ const maybeCallExpression = node.parent;
147
+ if (!maybeCallExpression || !isCreateElementCall(maybeCallExpression, context)) {
148
+ return false;
149
+ }
150
+ return maybeCallExpression.arguments.slice(2).some((child)=>child === node);
151
+ }
152
+
153
+ /**
154
+ * Determines whether inside createElement's props.
155
+ * @param node The AST node to check
156
+ * @param context The rule context
157
+ * @returns `true` if the node is inside createElement's props
158
+ */ function isInsideCreateElementProps(node, context) {
159
+ const parentCreateElement = ast.traverseUp(node, (n)=>isCreateElementCall(n, context));
160
+ if (parentCreateElement?.type !== ast.NodeType.CallExpression) {
161
+ return false;
162
+ }
163
+ return parentCreateElement.arguments.at(1) === ast.traverseUp(node, ast.is(ast.NodeType.ObjectExpression));
164
+ }
165
+
166
+ function resolveMemberExpressions(object, property) {
167
+ if (object.type === types.AST_NODE_TYPES.JSXMemberExpression) {
168
+ return `${resolveMemberExpressions(object.object, object.property)}.${property.name}`;
169
+ }
170
+ if (object.type === types.AST_NODE_TYPES.JSXNamespacedName) {
171
+ return `${object.namespace.name}:${object.name.name}.${property.name}`;
172
+ }
173
+ return `${object.name}.${property.name}`;
174
+ }
175
+ /**
176
+ * Returns the tag name associated with a JSXOpeningElement.
177
+ * @param node The visited JSXOpeningElement node object.
178
+ * @returns The element's tag name.
179
+ */ function elementType(node) {
180
+ if (node.type === types.AST_NODE_TYPES.JSXOpeningFragment) {
181
+ return "<>";
182
+ }
183
+ const { name } = node;
184
+ if (name.type === types.AST_NODE_TYPES.JSXMemberExpression) {
185
+ const { object, property } = name;
186
+ return resolveMemberExpressions(object, property);
187
+ }
188
+ if (name.type === types.AST_NODE_TYPES.JSXNamespacedName) {
189
+ return `${name.namespace.name}:${name.name.name}`;
190
+ }
191
+ return name.name;
192
+ }
193
+
194
+ const hdlAnimation = [
195
+ "onAnimationStart",
196
+ "onAnimationEnd",
197
+ "onAnimationIteration"
198
+ ];
199
+ const hdlClipboard = [
200
+ "onCopy",
201
+ "onCut",
202
+ "onPaste"
203
+ ];
204
+ const hdlComposition = [
205
+ "onCompositionEnd",
206
+ "onCompositionStart",
207
+ "onCompositionUpdate"
208
+ ];
209
+ const hdlFocus = [
210
+ "onFocus",
211
+ "onBlur"
212
+ ];
213
+ const hdlForm = [
214
+ "onChange",
215
+ "onInput",
216
+ "onSubmit"
217
+ ];
218
+ const hdlImage = [
219
+ "onLoad",
220
+ "onError"
221
+ ];
222
+ const hdlKeyboard = [
223
+ "onKeyDown",
224
+ "onKeyPress",
225
+ "onKeyUp"
226
+ ];
227
+ const hdlMedia = [
228
+ "onAbort",
229
+ "onCanPlay",
230
+ "onCanPlayThrough",
231
+ "onDurationChange",
232
+ "onEmptied",
233
+ "onEncrypted",
234
+ "onEnded",
235
+ "onError",
236
+ "onLoadedData",
237
+ "onLoadedMetadata",
238
+ "onLoadStart",
239
+ "onPause",
240
+ "onPlay",
241
+ "onPlaying",
242
+ "onProgress",
243
+ "onRateChange",
244
+ "onSeeked",
245
+ "onSeeking",
246
+ "onStalled",
247
+ "onSuspend",
248
+ "onTimeUpdate",
249
+ "onVolumeChange",
250
+ "onWaiting"
251
+ ];
252
+ const hdlMouse = [
253
+ "onClick",
254
+ "onContextMenu",
255
+ "onDblClick",
256
+ "onDoubleClick",
257
+ "onDrag",
258
+ "onDragEnd",
259
+ "onDragEnter",
260
+ "onDragExit",
261
+ "onDragLeave",
262
+ "onDragOver",
263
+ "onDragStart",
264
+ "onDrop",
265
+ "onMouseDown",
266
+ "onMouseEnter",
267
+ "onMouseLeave",
268
+ "onMouseMove",
269
+ "onMouseOut",
270
+ "onMouseOver",
271
+ "onMouseUp"
272
+ ];
273
+ const hdlSelection = [
274
+ "onSelect"
275
+ ];
276
+ const hdlTouch = [
277
+ "onTouchCancel",
278
+ "onTouchEnd",
279
+ "onTouchMove",
280
+ "onTouchStart"
281
+ ];
282
+ const hdlTransition = [
283
+ "onTransitionEnd"
284
+ ];
285
+ const hdlScroll = [
286
+ "onScroll"
287
+ ];
288
+ const hdlWheel = [
289
+ "onWheel"
290
+ ];
291
+ [
292
+ ...hdlAnimation,
293
+ ...hdlClipboard,
294
+ ...hdlComposition,
295
+ ...hdlFocus,
296
+ ...hdlForm,
297
+ ...hdlImage,
298
+ ...hdlKeyboard,
299
+ ...hdlMedia,
300
+ ...hdlMouse,
301
+ ...hdlSelection,
302
+ ...hdlTouch,
303
+ ...hdlTransition,
304
+ ...hdlScroll,
305
+ ...hdlWheel
306
+ ];
307
+
308
+ /**
309
+ * Tests if a value is a `string`.
310
+ *
311
+ * @param input - The value to test.
312
+ *
313
+ * @example
314
+ * import { isString } from "effect/Predicate"
315
+ *
316
+ * assert.deepStrictEqual(isString("a"), true)
317
+ *
318
+ * assert.deepStrictEqual(isString(1), false)
319
+ *
320
+ * @category guards
321
+ * @since 2.0.0
322
+ */
323
+ const isString = input => typeof input === "string";
324
+
325
+ const defaultJSXValueCheckOptions = {
326
+ ignoreNull: false,
327
+ strict: false
328
+ };
329
+ /**
330
+ * Check if a node is a JSX value
331
+ * @param node The AST node to check
332
+ * @param context The rule context
333
+ * @param options The `JSXValueCheckOptions` to use
334
+ * @returns boolean
335
+ */ function isJSXValue(node, context, options = defaultJSXValueCheckOptions) {
336
+ if (!node) {
337
+ return false;
338
+ }
339
+ // TODO: implement strict mode
340
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
341
+ const { ignoreNull = false, strict = false } = options;
342
+ return N(node.type).with(ast.NodeType.JSXElement, tools.F.constTrue).with(ast.NodeType.JSXFragment, tools.F.constTrue).with(ast.NodeType.Literal, ()=>{
343
+ if (!("value" in node) || ignoreNull) {
344
+ return false;
345
+ }
346
+ return node.value === null;
347
+ }).with(ast.NodeType.ConditionalExpression, ()=>{
348
+ if (!("consequent" in node)) {
349
+ return false;
350
+ }
351
+ const leftHasJSX = N(node.consequent).with(_.array(), (n)=>n.some((n)=>isJSXValue(n, context, options))).with(_.any, (n)=>isJSXValue(n, context, options)).exhaustive();
352
+ if (leftHasJSX) {
353
+ return true;
354
+ }
355
+ return "alternate" in node && isJSXValue(node.alternate, context, options);
356
+ }).with(ast.NodeType.LogicalExpression, ()=>{
357
+ if (!("left" in node)) {
358
+ return false;
359
+ }
360
+ return isJSXValue(node.left, context, options) || isJSXValue(node.right, context, options);
361
+ }).with(ast.NodeType.SequenceExpression, ()=>{
362
+ if (!("expressions" in node)) {
363
+ return false;
364
+ }
365
+ const exp = node.expressions.at(-1);
366
+ return isJSXValue(exp, context, options);
367
+ }).with(ast.NodeType.CallExpression, ()=>isCreateElementCall(node, context)).with(ast.NodeType.Identifier, ()=>{
368
+ if (!("name" in node)) {
369
+ return false;
370
+ }
371
+ if (ast.isJSXTagNameExpression(node)) {
372
+ return true;
373
+ }
374
+ if (!isString(node.name) && node.name.type !== ast.NodeType.Identifier) {
375
+ return ast.isJSXTagNameExpression(node.name);
376
+ }
377
+ const name = N(node.name).with(_.string, tools.F.identity).with({
378
+ type: ast.NodeType.Identifier
379
+ }, (n)=>n.name).exhaustive();
380
+ const variable = ast.findVariableByNameUpToGlobal(name, context.getScope());
381
+ return tools.F.pipe(variable, tools.O.flatMap(ast.getVariableNthDefNodeInit(0)), tools.O.map(ast.isOneOf([
382
+ ast.NodeType.JSXElement,
383
+ ast.NodeType.JSXFragment
384
+ ])), tools.O.getOrElse(tools.F.constFalse));
385
+ }).otherwise(tools.F.constFalse);
386
+ }
387
+
388
+ /**
389
+ * Check if function is returning JSX
390
+ * @param node The return statement node to check
391
+ * @param context The rule context
392
+ * @param options The JSX value check options
393
+ * @returns boolean
394
+ */ function isFunctionReturningJSXValue(node, context, options) {
395
+ if (node.body.type !== ast.NodeType.BlockStatement) {
396
+ return isJSXValue(node.body, context, options);
397
+ }
398
+ const statements = ast.getNestedReturnStatements(node.body);
399
+ return statements.some((statement)=>isJSXValue(statement.argument, context, options));
400
+ }
401
+
402
+ /**
403
+ * Check if the given prop name is present in the given attributes
404
+ * @param attributes The attributes to search in
405
+ * @param propName The prop name to search for
406
+ * @param context The rule context
407
+ * @returns `true` if the given prop name is present in the given properties
408
+ */ function hasProp(attributes, propName, context) {
409
+ return tools.O.isSome(findPropInAttributes(attributes, context)(propName));
410
+ }
411
+ /**
412
+ * Check if any of the given prop names are present in the given attributes
413
+ * @param attributes The attributes to search in
414
+ * @param propNames The prop names to search for
415
+ * @param context The rule context
416
+ * @returns `true` if any of the given prop names are present in the given attributes
417
+ */ function hasAnyProp(attributes, propNames, context) {
418
+ return propNames.some((propName)=>hasProp(attributes, propName, context));
419
+ }
420
+ /**
421
+ * Check if all of the given prop names are present in the given attributes
422
+ * @param attributes The attributes to search in
423
+ * @param propNames The prop names to search for
424
+ * @param context The rule context
425
+ * @returns `true` if all of the given prop names are present in the given attributes
426
+ */ function hasEveryProp(attributes, propNames, context) {
427
+ return propNames.every((propName)=>hasProp(attributes, propName, context));
428
+ }
429
+ /**
430
+ * Get the name of a JSX attribute
431
+ * @param node The JSX attribute node
432
+ * @returns string
433
+ */ function getPropName(node) {
434
+ return N(node.name).when(ast.is(ast.NodeType.JSXIdentifier), (n)=>n.name).when(ast.is(ast.NodeType.JSXNamespacedName), (n)=>n.name.name).exhaustive();
435
+ }
436
+ /**
437
+ * Get the name of a JSX attribute with namespace
438
+ * @param node The JSX attribute node
439
+ * @returns string
440
+ */ function getPropNameWithNamespace(node) {
441
+ return N(node.name).when(ast.is(ast.NodeType.JSXIdentifier), (n)=>n.name).when(ast.is(ast.NodeType.JSXNamespacedName), (n)=>`${n.namespace.name}:${n.name.name}`).exhaustive();
442
+ }
443
+ /**
444
+ * Traverses up prop node
445
+ * @param node The AST node to start traversing from
446
+ * @param predicate The predicate to check each node
447
+ * @returns prop node if found
448
+ */ function traverseUpProp(node, predicate = tools.F.constTrue) {
449
+ const matcher = (node)=>{
450
+ return node.type === ast.NodeType.JSXAttribute && predicate(node);
451
+ };
452
+ return tools.O.fromNullable(ast.traverseUpGuard(node, matcher));
453
+ }
454
+ /**
455
+ * Checks if the node is inside a prop's value
456
+ * @param node The AST node to check
457
+ * @returns `true` if the node is inside a prop's value
458
+ */ function isInsidePropValue(node) {
459
+ if (ast.isStringLiteral(node)) {
460
+ return node.parent.type === ast.NodeType.JSXAttribute;
461
+ }
462
+ return tools.O.isSome(traverseUpProp(node, (n)=>n.value?.type === ast.NodeType.JSXExpressionContainer));
463
+ }
464
+ /**
465
+ * @param properties The properties to search in
466
+ * @param context The rule context
467
+ * @param seenProps The properties that have already been seen
468
+ * @returns A function that searches for a property in the given properties
469
+ */ function findPropInProperties(properties, context, seenProps = []) {
470
+ /**
471
+ * Search for a property in the given properties
472
+ * @param propName The name of the property to search for
473
+ * @returns The property if found
474
+ */ return (propName)=>{
475
+ return tools.O.fromNullable(properties.find((prop)=>{
476
+ if (prop.type === ast.NodeType.Property) {
477
+ return "name" in prop.key && prop.key.name === propName;
478
+ }
479
+ if (prop.type === ast.NodeType.SpreadElement) {
480
+ if (!("argument" in prop && "name" in prop.argument)) {
481
+ return false;
482
+ }
483
+ const { name } = prop.argument;
484
+ const maybeFirstDefNodeInit = tools.F.pipe(ast.findVariableByNameUpToGlobal(name, context.getScope()), tools.O.flatMap(ast.getVariableNthDefNodeInit(0)));
485
+ if (tools.O.isNone(maybeFirstDefNodeInit)) {
486
+ return false;
487
+ }
488
+ const firstDefNodeInit = maybeFirstDefNodeInit.value;
489
+ if (firstDefNodeInit.type !== ast.NodeType.ObjectExpression) {
490
+ return false;
491
+ }
492
+ if (seenProps.includes(name)) {
493
+ return false;
494
+ }
495
+ return tools.O.isSome(findPropInProperties(firstDefNodeInit.properties, context, [
496
+ ...seenProps,
497
+ name
498
+ ])(propName));
499
+ }
500
+ return false;
501
+ }));
502
+ };
503
+ }
504
+ /**
505
+ * @param attributes The attributes to search in
506
+ * @param context The rule context
507
+ * @returns A function that searches for a property in the given attributes
508
+ */ function findPropInAttributes(attributes, context) {
509
+ /**
510
+ * Search for a property in the given attributes
511
+ * @param propName The name of the property to search for
512
+ * @returns The property if found
513
+ */ return (propName)=>{
514
+ return tools.O.fromNullable(attributes.find((attr)=>{
515
+ return N(attr).when(ast.is(ast.NodeType.JSXAttribute), (attr)=>getPropName(attr) === propName).when(ast.is(ast.NodeType.JSXSpreadAttribute), (attr)=>{
516
+ if (!("argument" in attr && "name" in attr.argument)) {
517
+ return false;
518
+ }
519
+ const { name } = attr.argument;
520
+ const maybeFirstDefNodeInit = tools.F.pipe(ast.findVariableByNameUpToGlobal(name, context.getScope()), tools.O.flatMap(ast.getVariableNthDefNodeInit(0)));
521
+ if (tools.O.isNone(maybeFirstDefNodeInit)) {
522
+ return false;
523
+ }
524
+ if (!("properties" in maybeFirstDefNodeInit.value)) {
525
+ return false;
526
+ }
527
+ return tools.O.isSome(findPropInProperties(maybeFirstDefNodeInit.value.properties, context)(propName));
528
+ }).otherwise(tools.F.constFalse);
529
+ }));
530
+ };
531
+ }
532
+
533
+ /**
534
+ * Check if a node is a Literal or JSXText
535
+ * @param node The AST node to check
536
+ * @returns boolean `true` if the node is a Literal or JSXText
537
+ */ const isLiteral = ast.isOneOf([
538
+ ast.NodeType.Literal,
539
+ ast.NodeType.JSXText
540
+ ]);
541
+ /**
542
+ * Check if a Literal or JSXText node is whitespace
543
+ * @param node The AST node to check
544
+ * @returns boolean `true` if the node is whitespace
545
+ */ function isWhiteSpace(node) {
546
+ return isString(node.value) && node.value.trim() === "";
547
+ }
548
+ /**
549
+ * Check if a Literal or JSXText node is a line break
550
+ * @param node The AST node to check
551
+ * @returns boolean
552
+ */ function isLineBreak(node) {
553
+ return isLiteral(node) && isWhiteSpace(node) && ast.isMultiLine(node);
554
+ }
555
+
556
+ exports.defaultJSXValueCheckOptions = defaultJSXValueCheckOptions;
557
+ exports.elementType = elementType;
558
+ exports.findPropInAttributes = findPropInAttributes;
559
+ exports.findPropInProperties = findPropInProperties;
560
+ exports.getFragmentFromContext = getFragmentFromContext;
561
+ exports.getPragmaFromContext = getPragmaFromContext;
562
+ exports.getPropName = getPropName;
563
+ exports.getPropNameWithNamespace = getPropNameWithNamespace;
564
+ exports.hasAnyProp = hasAnyProp;
565
+ exports.hasChildren = hasChildren;
566
+ exports.hasEveryProp = hasEveryProp;
567
+ exports.hasProp = hasProp;
568
+ exports.hdlAnimation = hdlAnimation;
569
+ exports.hdlClipboard = hdlClipboard;
570
+ exports.hdlComposition = hdlComposition;
571
+ exports.hdlFocus = hdlFocus;
572
+ exports.hdlForm = hdlForm;
573
+ exports.hdlImage = hdlImage;
574
+ exports.hdlKeyboard = hdlKeyboard;
575
+ exports.hdlMedia = hdlMedia;
576
+ exports.hdlMouse = hdlMouse;
577
+ exports.hdlScroll = hdlScroll;
578
+ exports.hdlSelection = hdlSelection;
579
+ exports.hdlTouch = hdlTouch;
580
+ exports.hdlTransition = hdlTransition;
581
+ exports.hdlWheel = hdlWheel;
582
+ exports.isCallFromPragma = isCallFromPragma;
583
+ exports.isChildrenOfCreateElement = isChildrenOfCreateElement;
584
+ exports.isCloneElementCall = isCloneElementCall;
585
+ exports.isCreateElementCall = isCreateElementCall;
586
+ exports.isDestructuredFromPragma = isDestructuredFromPragma;
587
+ exports.isFunctionReturningJSXValue = isFunctionReturningJSXValue;
588
+ exports.isInsideCreateElementProps = isInsideCreateElementProps;
589
+ exports.isInsidePropValue = isInsidePropValue;
590
+ exports.isJSXValue = isJSXValue;
591
+ exports.isLineBreak = isLineBreak;
592
+ exports.isLiteral = isLiteral;
593
+ exports.isWhiteSpace = isWhiteSpace;
594
+ exports.traverseUpProp = traverseUpProp;