@eslint-react/jsx 1.46.0 → 4.0.0-beta.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.d.ts +664 -83
- package/dist/index.js +846 -269
- package/package.json +23 -26
- package/dist/index.d.mts +0 -102
- package/dist/index.mjs +0 -257
package/dist/index.d.ts
CHANGED
|
@@ -1,102 +1,683 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import * as VAR from '@eslint-react/var';
|
|
5
|
-
import { TSESTree as TSESTree$1 } from '@typescript-eslint/types';
|
|
1
|
+
import { TSESTreeJSXAttributeLike, TSESTreeJSXElementLike } from "@eslint-react/ast";
|
|
2
|
+
import { TSESTree } from "@typescript-eslint/types";
|
|
3
|
+
import { RuleContext } from "@eslint-react/shared";
|
|
6
4
|
|
|
5
|
+
//#region src/find-attribute.d.ts
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* Find a JSX attribute (or spread attribute containing the property) by name
|
|
8
|
+
* on a given element.
|
|
9
|
+
*
|
|
10
|
+
* Returns the **last** matching attribute to mirror React's behaviour where
|
|
11
|
+
* later props win, or `undefined` when the attribute is not present.
|
|
12
|
+
*
|
|
13
|
+
* Spread attributes are resolved when possible: if the spread argument is an
|
|
14
|
+
* identifier that resolves to an object expression, the object's properties
|
|
15
|
+
* are searched for a matching key.
|
|
16
|
+
*
|
|
17
|
+
* @param context - The ESLint rule context (needed for variable resolution in
|
|
18
|
+
* spread attributes).
|
|
19
|
+
* @param element - The `JSXElement` node to search.
|
|
20
|
+
* @param name - The attribute name to look for (e.g. `"className"`).
|
|
21
|
+
* @returns The matching `JSXAttribute` or `JSXSpreadAttribute`, or
|
|
22
|
+
* `undefined` when not found.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const attr = findAttribute(context, node, "sandbox");
|
|
27
|
+
* if (attr != null) {
|
|
28
|
+
* // attribute (or spread containing it) exists on the element
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
13
31
|
*/
|
|
14
|
-
declare function
|
|
15
|
-
|
|
32
|
+
declare function findAttribute(context: RuleContext, element: TSESTree.JSXElement, name: string): TSESTreeJSXAttributeLike | undefined;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/find-parent-attribute.d.ts
|
|
35
|
+
/**
|
|
36
|
+
* Walk **up** the AST from `node` to find the nearest ancestor that is a
|
|
37
|
+
* `JSXAttribute` and (optionally) passes a predicate.
|
|
38
|
+
*
|
|
39
|
+
* This is useful when a rule visitor enters a deeply‑nested node (e.g. a
|
|
40
|
+
* `Literal` inside an expression container) and needs to know which JSX
|
|
41
|
+
* attribute it belongs to.
|
|
42
|
+
*
|
|
43
|
+
* @param node - The starting node for the upward search.
|
|
44
|
+
* @param test - Optional predicate to filter candidate `JSXAttribute` nodes.
|
|
45
|
+
* When omitted every `JSXAttribute` ancestor matches.
|
|
46
|
+
* @returns The first matching `JSXAttribute` ancestor, or `null` if none is
|
|
47
|
+
* found before reaching the root.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* // Inside a Literal visitor, find the owning attribute:
|
|
52
|
+
* const attr = findParentAttribute(literalNode);
|
|
53
|
+
* if (attr != null) {
|
|
54
|
+
* console.log(getAttributeName(attr));
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function findParentAttribute(node: TSESTree.Node, test?: (node: TSESTree.JSXAttribute) => boolean): TSESTree.JSXAttribute | null;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/get-attribute-name.d.ts
|
|
16
61
|
/**
|
|
17
|
-
* Get the stringified name of a
|
|
18
|
-
*
|
|
19
|
-
*
|
|
62
|
+
* Get the stringified name of a `JSXAttribute` node.
|
|
63
|
+
*
|
|
64
|
+
* Handles both simple identifiers and namespaced names:
|
|
65
|
+
*
|
|
66
|
+
* - `className` -> `"className"`
|
|
67
|
+
* - `aria-label` -> `"aria-label"`
|
|
68
|
+
* - `xml:space` -> `"xml:space"`
|
|
69
|
+
*
|
|
70
|
+
* @param node - A `JSXAttribute` AST node.
|
|
71
|
+
* @returns The attribute name as a plain string.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { getAttributeName } from "@eslint-react/jsx";
|
|
76
|
+
*
|
|
77
|
+
* // Inside a rule visitor:
|
|
78
|
+
* JSXAttribute(node) {
|
|
79
|
+
* const name = getAttributeName(node); // "className"
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
20
82
|
*/
|
|
21
83
|
declare function getAttributeName(node: TSESTree.JSXAttribute): string;
|
|
22
|
-
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/get-attribute-static-value.d.ts
|
|
23
86
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* @
|
|
87
|
+
* Find an attribute by name on a JSX element and collapse its value to a
|
|
88
|
+
* plain JavaScript value in a single step.
|
|
89
|
+
*
|
|
90
|
+
* This is a convenience composition of {@link findAttribute} ->
|
|
91
|
+
* {@link resolveAttributeValue} -> `toStatic()`, with automatic handling
|
|
92
|
+
* of the `spreadProps` case (extracts the named property from the spread
|
|
93
|
+
* object).
|
|
94
|
+
*
|
|
95
|
+
* Returns `undefined` when the attribute is absent **or** when its value
|
|
96
|
+
* cannot be statically determined.
|
|
97
|
+
*
|
|
98
|
+
* @param context - The ESLint rule context.
|
|
99
|
+
* @param element - The `JSXElement` node to inspect.
|
|
100
|
+
* @param name - The attribute name to look up (e.g. `"className"`).
|
|
101
|
+
* @returns The static value of the attribute, or `undefined`.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* // <iframe sandbox="allow-scripts" />
|
|
106
|
+
* const sandbox = getAttributeStaticValue(context, node, "sandbox");
|
|
107
|
+
* // -> "allow-scripts"
|
|
108
|
+
*
|
|
109
|
+
* // <button type={dynamicVar} />
|
|
110
|
+
* const type = getAttributeStaticValue(context, node, "type");
|
|
111
|
+
* // -> undefined (cannot be resolved statically)
|
|
112
|
+
* ```
|
|
29
113
|
*/
|
|
30
|
-
declare function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
declare function hasAttribute(name: string, attributes: TSESTree$1.JSXOpeningElement["attributes"], initialScope?: Scope): boolean;
|
|
35
|
-
declare function hasAnyAttribute(names: string[], attributes: TSESTree$1.JSXOpeningElement["attributes"], initialScope?: Scope): boolean;
|
|
36
|
-
declare function hasEveryAttribute(names: string[], attributes: TSESTree$1.JSXOpeningElement["attributes"], initialScope?: Scope): boolean;
|
|
37
|
-
|
|
114
|
+
declare function getAttributeStaticValue(context: RuleContext, element: TSESTree.JSXElement, name: string): unknown;
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/jsx-attribute-value.d.ts
|
|
38
117
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
118
|
+
* Discriminated union representing the resolved value of a JSX attribute.
|
|
119
|
+
*
|
|
120
|
+
* Each variant carries the original AST `node` (where applicable) and a
|
|
121
|
+
* `toStatic()` helper that attempts to collapse the value into a plain
|
|
122
|
+
* JavaScript value at analysis time.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const value = resolveAttributeValue(context, attr);
|
|
127
|
+
* switch (value.kind) {
|
|
128
|
+
* case "literal":
|
|
129
|
+
* console.log(value.toStatic()); // string | number | boolean | …
|
|
130
|
+
* break;
|
|
131
|
+
* case "unknown":
|
|
132
|
+
* // dynamic – toStatic() may return `undefined`
|
|
133
|
+
* break;
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
43
136
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
137
|
+
type JsxAttributeValue = JsxAttributeValueBoolean | JsxAttributeValueElement | JsxAttributeValueLiteral | JsxAttributeValueUnknown | JsxAttributeValueMissing | JsxAttributeValueSpreadChild | JsxAttributeValueSpreadProps;
|
|
138
|
+
/** Boolean attribute with no value (e.g. `<input disabled />`) */
|
|
139
|
+
interface JsxAttributeValueBoolean {
|
|
140
|
+
readonly kind: "boolean";
|
|
141
|
+
readonly node: null;
|
|
142
|
+
toStatic(): true;
|
|
143
|
+
}
|
|
144
|
+
/** JSX element used as an attribute value (e.g. `<Slot icon=<Icon /> />`) */
|
|
145
|
+
interface JsxAttributeValueElement {
|
|
146
|
+
readonly kind: "element";
|
|
147
|
+
readonly node: TSESTree.JSXElement;
|
|
148
|
+
toStatic(): null;
|
|
149
|
+
}
|
|
150
|
+
/** Literal value (e.g. `<img alt="photo" />`) */
|
|
151
|
+
interface JsxAttributeValueLiteral {
|
|
152
|
+
readonly kind: "literal";
|
|
153
|
+
readonly node: TSESTree.Literal;
|
|
154
|
+
toStatic(): TSESTree.Literal["value"];
|
|
155
|
+
}
|
|
156
|
+
/** Expression container value (e.g. `<Comp value={expr} />`) */
|
|
157
|
+
interface JsxAttributeValueUnknown {
|
|
158
|
+
readonly kind: "unknown";
|
|
159
|
+
readonly node: TSESTree.JSXExpressionContainer["expression"];
|
|
160
|
+
toStatic(): unknown;
|
|
161
|
+
}
|
|
162
|
+
/** Empty expression container (e.g. `<Comp value={} />`) */
|
|
163
|
+
interface JsxAttributeValueMissing {
|
|
164
|
+
readonly kind: "missing";
|
|
165
|
+
readonly node: TSESTree.JSXEmptyExpression;
|
|
166
|
+
toStatic(): null;
|
|
167
|
+
}
|
|
168
|
+
/** Spread child expression (e.g. `{...items}` as children) */
|
|
169
|
+
interface JsxAttributeValueSpreadChild {
|
|
170
|
+
readonly kind: "spreadChild";
|
|
171
|
+
getChildren(at: number): unknown;
|
|
172
|
+
readonly node: TSESTree.JSXSpreadChild["expression"];
|
|
173
|
+
toStatic(): null;
|
|
174
|
+
}
|
|
175
|
+
/** Spread props (e.g. `<Comp {...props} />`) */
|
|
176
|
+
interface JsxAttributeValueSpreadProps {
|
|
177
|
+
readonly kind: "spreadProps";
|
|
178
|
+
getProperty(name: string): unknown;
|
|
179
|
+
readonly node: TSESTree.JSXSpreadAttribute["argument"];
|
|
180
|
+
toStatic(): null;
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/get-attribute-value.d.ts
|
|
46
184
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
185
|
+
* Find an attribute by name on a JSX element **and** resolve its value in a
|
|
186
|
+
* single call.
|
|
187
|
+
*
|
|
188
|
+
* This is a convenience composition of {@link findAttribute} and
|
|
189
|
+
* {@link resolveAttributeValue} that eliminates the most common two-step
|
|
190
|
+
* pattern in lint rules:
|
|
191
|
+
*
|
|
192
|
+
* ```ts
|
|
193
|
+
* const attr = findAttribute(context, element, name);
|
|
194
|
+
* if (attr == null) return;
|
|
195
|
+
* const value = resolveAttributeValue(context, attr);
|
|
196
|
+
* ```
|
|
197
|
+
*
|
|
198
|
+
* @param context - The ESLint rule context.
|
|
199
|
+
* @param element - The `JSXElement` node to search.
|
|
200
|
+
* @param name - The attribute name to look up (e.g. `"className"`).
|
|
201
|
+
* @returns A {@link JsxAttributeValue} descriptor, or `undefined` when the
|
|
202
|
+
* attribute is not present on the element.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* const value = getAttributeValue(context, node, "sandbox");
|
|
207
|
+
* if (value?.kind === "literal") {
|
|
208
|
+
* console.log(value.toStatic()); // the literal value
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
50
211
|
*/
|
|
51
|
-
declare function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
212
|
+
declare function getAttributeValue(context: RuleContext, element: TSESTree.JSXElement, name: string): JsxAttributeValue | undefined;
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/get-children.d.ts
|
|
215
|
+
/**
|
|
216
|
+
* Get the **meaningful** children of a JSX element or fragment.
|
|
217
|
+
*
|
|
218
|
+
* Filters out "padding spaces" — `JSXText` nodes that consist entirely of
|
|
219
|
+
* whitespace and contain at least one newline. These nodes are artefacts of
|
|
220
|
+
* source formatting that React trims away during rendering and are therefore
|
|
221
|
+
* not considered meaningful content.
|
|
222
|
+
*
|
|
223
|
+
* @param element - A `JSXElement` or `JSXFragment` node.
|
|
224
|
+
* @returns An array of children nodes that contribute to rendered output.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* import { getChildren } from "@eslint-react/jsx";
|
|
229
|
+
*
|
|
230
|
+
* // <div>
|
|
231
|
+
* // <span />
|
|
232
|
+
* // </div>
|
|
233
|
+
* //
|
|
234
|
+
* // Raw children: [JSXText("\n "), JSXElement(<span />), JSXText("\n")]
|
|
235
|
+
* // getChildren: [JSXElement(<span />)]
|
|
236
|
+
*
|
|
237
|
+
* const meaningful = getChildren(node);
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
declare function getChildren(element: TSESTreeJSXElementLike): TSESTree.JSXChild[];
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/get-element-type.d.ts
|
|
243
|
+
/**
|
|
244
|
+
* Get the string representation of a JSX element's type.
|
|
245
|
+
*
|
|
246
|
+
* - `<div>` -> `"div"`
|
|
247
|
+
* - `<Foo.Bar>` -> `"Foo.Bar"`
|
|
248
|
+
* - `<React.Fragment>` -> `"React.Fragment"`
|
|
249
|
+
* - `<></>` -> `""`
|
|
250
|
+
*
|
|
251
|
+
* @param node - A `JSXElement` or `JSXFragment` node.
|
|
252
|
+
* @returns The fully-qualified element type string.
|
|
253
|
+
*/
|
|
254
|
+
declare function getElementFullType(node: TSESTreeJSXElementLike): string;
|
|
255
|
+
/**
|
|
256
|
+
* Get the **self name** (last dot-separated segment) of a JSX element type.
|
|
257
|
+
*
|
|
258
|
+
* - `<Foo.Bar.Baz>` -> `"Baz"`
|
|
259
|
+
* - `<div>` -> `"div"`
|
|
260
|
+
* - `<></>` -> `""`
|
|
261
|
+
*
|
|
262
|
+
* @param node - A `JSXElement` or `JSXFragment` node.
|
|
263
|
+
* @returns The last segment of the element type, or `""` for fragments.
|
|
264
|
+
*/
|
|
265
|
+
declare function getElementSelfType(node: TSESTreeJSXElementLike): string;
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region src/has-any-attribute.d.ts
|
|
268
|
+
/**
|
|
269
|
+
* Check whether a JSX element carries **at least one** of the given attributes.
|
|
270
|
+
*
|
|
271
|
+
* This is a batch variant of {@link hasAttribute} for the common pattern of
|
|
272
|
+
* short-circuiting on multiple prop names:
|
|
273
|
+
*
|
|
274
|
+
* ```ts
|
|
275
|
+
* // before
|
|
276
|
+
* if (hasAttribute(ctx, el, "key")) return;
|
|
277
|
+
* if (hasAttribute(ctx, el, "ref")) return;
|
|
278
|
+
*
|
|
279
|
+
* // after
|
|
280
|
+
* if (hasAnyAttribute(ctx, el, ["key", "ref"])) return;
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* Spread attributes are taken into account (see {@link findAttribute}).
|
|
284
|
+
*
|
|
285
|
+
* @param context - The ESLint rule context (needed for variable resolution in
|
|
286
|
+
* spread attributes).
|
|
287
|
+
* @param element - The `JSXElement` node to inspect.
|
|
288
|
+
* @param names - The attribute names to look for.
|
|
289
|
+
* @returns `true` when **at least one** of the attributes is present.
|
|
290
|
+
*/
|
|
291
|
+
declare function hasAnyAttribute(context: RuleContext, element: TSESTree.JSXElement, names: readonly string[]): boolean;
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/has-attribute.d.ts
|
|
294
|
+
/**
|
|
295
|
+
* Check whether a JSX element carries a given attribute (prop).
|
|
296
|
+
*
|
|
297
|
+
* This is a thin convenience wrapper around {@link findAttribute} for the
|
|
298
|
+
* common case where you only need a boolean answer.
|
|
299
|
+
*
|
|
300
|
+
* Spread attributes are taken into account: `<Comp {...{ disabled: true }} />`
|
|
301
|
+
* will report `true` for `"disabled"`.
|
|
302
|
+
*
|
|
303
|
+
* @param context - The ESLint rule context (needed for variable resolution in
|
|
304
|
+
* spread attributes).
|
|
305
|
+
* @param element - The `JSXElement` node to inspect.
|
|
306
|
+
* @param name - The attribute name to look for (e.g. `"className"`).
|
|
307
|
+
* @returns `true` when the attribute is present on the element.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```ts
|
|
311
|
+
* import { hasAttribute } from "@eslint-react/jsx";
|
|
312
|
+
*
|
|
313
|
+
* if (hasAttribute(context, node, "key")) {
|
|
314
|
+
* // element has a `key` prop
|
|
315
|
+
* }
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
declare function hasAttribute(context: RuleContext, element: TSESTree.JSXElement, name: string): boolean;
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/has-children.d.ts
|
|
321
|
+
/**
|
|
322
|
+
* Check whether a JSX element (or fragment) has **meaningful** children —
|
|
323
|
+
* that is, at least one child that is not purely whitespace text.
|
|
324
|
+
*
|
|
325
|
+
* A `JSXText` child whose `raw` content is empty after trimming is
|
|
326
|
+
* considered non-meaningful regardless of whether it contains a line break.
|
|
327
|
+
* This matches React's rendering behaviour where whitespace-only text nodes
|
|
328
|
+
* do not produce visible output.
|
|
329
|
+
*
|
|
330
|
+
* @param element - A `JSXElement` or `JSXFragment` node.
|
|
331
|
+
* @returns `true` when the element has at least one meaningful child.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* import { hasChildren } from "@eslint-react/jsx";
|
|
336
|
+
*
|
|
337
|
+
* // <div>hello</div> -> true
|
|
338
|
+
* // <div> {expr} </div> -> true
|
|
339
|
+
* // <div> </div> -> false (whitespace-only)
|
|
340
|
+
* // <div> -> false (whitespace-only, with newlines)
|
|
341
|
+
* // </div>
|
|
342
|
+
* // <div></div> -> false (no children at all)
|
|
343
|
+
*
|
|
344
|
+
* if (hasChildren(node)) {
|
|
345
|
+
* // element renders visible content
|
|
346
|
+
* }
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
declare function hasChildren(element: TSESTreeJSXElementLike): boolean;
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region src/has-every-attribute.d.ts
|
|
352
|
+
/**
|
|
353
|
+
* Check whether a JSX element carries **all** of the given attributes (props).
|
|
354
|
+
*
|
|
355
|
+
* This is a batch variant of {@link hasAttribute} for the common pattern
|
|
356
|
+
* where a rule needs to verify that a set of required props are all present.
|
|
357
|
+
*
|
|
358
|
+
* Spread attributes are taken into account (see {@link findAttribute}).
|
|
359
|
+
*
|
|
360
|
+
* @param context - The ESLint rule context (needed for variable resolution in
|
|
361
|
+
* spread attributes).
|
|
362
|
+
* @param element - The `JSXElement` node to inspect.
|
|
363
|
+
* @param names - The attribute names to look for.
|
|
364
|
+
* @returns `true` when **every** name in `names` is present on the element.
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```ts
|
|
368
|
+
* import { hasEveryAttribute } from "@eslint-react/jsx";
|
|
369
|
+
*
|
|
370
|
+
* // Ensure both `alt` and `src` are provided on an <img>
|
|
371
|
+
* if (hasEveryAttribute(context, node, ["alt", "src"])) {
|
|
372
|
+
* // element has both props
|
|
373
|
+
* }
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
declare function hasEveryAttribute(context: RuleContext, element: TSESTree.JSXElement, names: readonly string[]): boolean;
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/is-element.d.ts
|
|
379
|
+
/**
|
|
380
|
+
* A test that determines whether a JSX element matches.
|
|
381
|
+
*
|
|
382
|
+
* - `string` — matches against the full element type (e.g. `"div"`,
|
|
383
|
+
* `"React.Fragment"`)
|
|
384
|
+
* - `string[]` — matches when the element type equals **any** of the
|
|
385
|
+
* given strings
|
|
386
|
+
* - `function` — receives the element type string and returns a boolean
|
|
387
|
+
*/
|
|
388
|
+
type ElementTest = string | readonly string[] | ((elementType: string, node: TSESTreeJSXElementLike) => boolean);
|
|
389
|
+
/**
|
|
390
|
+
* Check whether a node is a `JSXElement` (or `JSXFragment`) and optionally
|
|
391
|
+
* matches a given test.
|
|
392
|
+
*
|
|
393
|
+
* Modelled after
|
|
394
|
+
* [`hast-util-is-element`](https://github.com/syntax-tree/hast-util-is-element):
|
|
395
|
+
* the `test` parameter controls what counts as a match.
|
|
396
|
+
*
|
|
397
|
+
* When called **without** a test, the function acts as a simple type-guard
|
|
398
|
+
* for `JSXElement | JSXFragment`.
|
|
399
|
+
*
|
|
400
|
+
* @param node - The AST node to test.
|
|
401
|
+
* @param test - Optional test to match the element type against.
|
|
402
|
+
* @returns `true` when the node is a matching JSX element.
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```ts
|
|
406
|
+
* import { isElement } from "@eslint-react/jsx";
|
|
407
|
+
*
|
|
408
|
+
* // Type-guard only — any JSX element or fragment
|
|
409
|
+
* if (isElement(node)) { … }
|
|
410
|
+
*
|
|
411
|
+
* // Match a single tag name
|
|
412
|
+
* if (isElement(node, "iframe")) { … }
|
|
413
|
+
*
|
|
414
|
+
* // Match one of several tag names
|
|
415
|
+
* if (isElement(node, ["button", "input", "select"])) { … }
|
|
416
|
+
*
|
|
417
|
+
* // Custom predicate
|
|
418
|
+
* if (isElement(node, (type) => type.endsWith(".Provider"))) { … }
|
|
419
|
+
* ```
|
|
420
|
+
*/
|
|
421
|
+
declare function isElement(node: TSESTree.Node | null | undefined, test?: ElementTest): node is TSESTreeJSXElementLike;
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region src/is-fragment-element.d.ts
|
|
424
|
+
/**
|
|
425
|
+
* Check whether a node is a React **Fragment** element.
|
|
426
|
+
*
|
|
427
|
+
* Recognises both the shorthand `<>…</>` syntax (`JSXFragment`) and the
|
|
428
|
+
* explicit `<Fragment>` / `<React.Fragment>` form (`JSXElement`).
|
|
429
|
+
*
|
|
430
|
+
* The comparison is performed against the **self name** (last dot‑separated
|
|
431
|
+
* segment) of both the node and the configured factory, so
|
|
432
|
+
* `<React.Fragment>` matches `"React.Fragment"` and `<Fragment>` matches
|
|
433
|
+
* `"Fragment"`.
|
|
434
|
+
*
|
|
435
|
+
* @param node - The AST node to test.
|
|
436
|
+
* @param jsxFragmentFactory - The configured fragment factory string
|
|
437
|
+
* (e.g. `"React.Fragment"`). Defaults to
|
|
438
|
+
* `"React.Fragment"`.
|
|
439
|
+
* @returns `true` when the node represents a React Fragment.
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```ts
|
|
443
|
+
* // Using the default factory
|
|
444
|
+
* if (isFragmentElement(node)) { … }
|
|
445
|
+
*
|
|
446
|
+
* // With a custom factory from jsxConfig
|
|
447
|
+
* const config = getJsxConfig(context);
|
|
448
|
+
* if (isFragmentElement(node, config.jsxFragmentFactory)) { … }
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
declare function isFragmentElement(node: TSESTree.Node, jsxFragmentFactory?: string): node is TSESTreeJSXElementLike;
|
|
452
|
+
//#endregion
|
|
453
|
+
//#region src/is-host-element.d.ts
|
|
454
|
+
/**
|
|
455
|
+
* Check whether a node is a **host** (intrinsic / DOM) element.
|
|
456
|
+
*
|
|
457
|
+
* A host element is a `JSXElement` whose tag name is a plain `JSXIdentifier`
|
|
458
|
+
* starting with a lowercase letter – the same heuristic React uses to
|
|
459
|
+
* distinguish `<div>` from `<MyComponent>`.
|
|
460
|
+
*
|
|
461
|
+
* @param node - The AST node to test.
|
|
462
|
+
* @returns `true` when the node is a `JSXElement` with a lowercase tag name.
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* ```ts
|
|
466
|
+
* // <div className="box" /> -> true
|
|
467
|
+
* // <span /> -> true
|
|
468
|
+
* // <MyComponent /> -> false
|
|
469
|
+
* // <Foo.Bar /> -> false
|
|
470
|
+
* isHostElement(node);
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
declare function isHostElement(node: TSESTree.Node): node is TSESTree.JSXElement;
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region src/jsx-detection-hint.d.ts
|
|
476
|
+
/**
|
|
477
|
+
* BitFlags for configuring JSX detection behavior.
|
|
478
|
+
*
|
|
479
|
+
* Used by {@link isJsxLike} to control which AST node kinds are
|
|
480
|
+
* considered "JSX-like". Combine flags with the `|` operator.
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* ```ts
|
|
484
|
+
* const hint = JsxDetectionHint.DoNotIncludeJsxWithBooleanValue
|
|
485
|
+
* | JsxDetectionHint.DoNotIncludeJsxWithStringValue;
|
|
486
|
+
*
|
|
487
|
+
* isJsxLike(context, node, hint);
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
type JsxDetectionHint = bigint;
|
|
491
|
+
declare const JsxDetectionHint: {
|
|
492
|
+
readonly None: 0n;
|
|
493
|
+
readonly DoNotIncludeJsxWithNullValue: bigint;
|
|
494
|
+
readonly DoNotIncludeJsxWithNumberValue: bigint;
|
|
495
|
+
readonly DoNotIncludeJsxWithBigIntValue: bigint;
|
|
496
|
+
readonly DoNotIncludeJsxWithStringValue: bigint;
|
|
497
|
+
readonly DoNotIncludeJsxWithBooleanValue: bigint;
|
|
498
|
+
readonly DoNotIncludeJsxWithUndefinedValue: bigint;
|
|
499
|
+
readonly DoNotIncludeJsxWithEmptyArrayValue: bigint;
|
|
500
|
+
readonly DoNotIncludeJsxWithCreateElementValue: bigint;
|
|
501
|
+
readonly RequireAllArrayElementsToBeJsx: bigint;
|
|
502
|
+
readonly RequireBothSidesOfLogicalExpressionToBeJsx: bigint;
|
|
503
|
+
readonly RequireBothBranchesOfConditionalExpressionToBeJsx: bigint;
|
|
72
504
|
};
|
|
73
|
-
declare const DEFAULT_JSX_DETECTION_HINT: bigint;
|
|
74
|
-
|
|
75
|
-
type TSESTreeJSX = TSESTree.JSXAttribute | TSESTree.JSXClosingElement | TSESTree.JSXClosingFragment | TSESTree.JSXElement | TSESTree.JSXEmptyExpression | TSESTree.JSXExpressionContainer | TSESTree.JSXFragment | TSESTree.JSXIdentifier | TSESTree.JSXMemberExpression | TSESTree.JSXNamespacedName | TSESTree.JSXOpeningElement | TSESTree.JSXOpeningFragment | TSESTree.JSXSpreadAttribute | TSESTree.JSXSpreadChild | TSESTree.JSXText;
|
|
76
|
-
declare const isJSX: (node: TSESTree.Node | null | undefined) => node is TSESTree.JSXIdentifier | TSESTree.JSXMemberExpression | TSESTree.JSXNamespacedName | TSESTree.JSXOpeningElement | TSESTree.JSXClosingElement | TSESTree.JSXOpeningFragment | TSESTree.JSXClosingFragment | TSESTree.JSXText | TSESTree.JSXAttribute | TSESTree.JSXSpreadAttribute | TSESTree.JSXElement | TSESTree.JSXFragment | TSESTree.JSXExpressionContainer | TSESTree.JSXSpreadChild | TSESTree.JSXEmptyExpression;
|
|
77
505
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
506
|
+
* Default JSX detection configuration.
|
|
507
|
+
*
|
|
508
|
+
* Skips number, bigint, boolean, string, and undefined literals –
|
|
509
|
+
* the value types that are commonly returned alongside JSX in React
|
|
510
|
+
* components but are not themselves renderable elements.
|
|
81
511
|
*/
|
|
82
|
-
declare
|
|
512
|
+
declare const DEFAULT_JSX_DETECTION_HINT: JsxDetectionHint;
|
|
513
|
+
//#endregion
|
|
514
|
+
//#region src/is-jsx-like.d.ts
|
|
83
515
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* @
|
|
516
|
+
* Determine whether a node represents JSX-like content based on heuristics.
|
|
517
|
+
*
|
|
518
|
+
* The detection behaviour is configurable through {@link JsxDetectionHint}
|
|
519
|
+
* bit-flags so that callers can opt individual value kinds in or out.
|
|
520
|
+
*
|
|
521
|
+
* @param context - The ESLint rule context (needed for variable resolution).
|
|
522
|
+
* @param node - The AST node to analyse.
|
|
523
|
+
* @param hint - Optional bit-flags to adjust detection behaviour.
|
|
524
|
+
* Defaults to {@link DEFAULT_JSX_DETECTION_HINT}.
|
|
525
|
+
* @returns Whether the node is considered JSX-like.
|
|
526
|
+
*
|
|
527
|
+
* @example
|
|
528
|
+
* ```ts
|
|
529
|
+
* import { isJsxLike } from "@eslint-react/jsx";
|
|
530
|
+
*
|
|
531
|
+
* if (isJsxLike(context, node)) {
|
|
532
|
+
* // node looks like it evaluates to a React element
|
|
533
|
+
* }
|
|
534
|
+
* ```
|
|
90
535
|
*/
|
|
91
|
-
declare function isJsxLike(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
536
|
+
declare function isJsxLike(context: RuleContext, node: TSESTree.Node | null, hint?: JsxDetectionHint): boolean;
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region src/is-jsx-text.d.ts
|
|
95
539
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
540
|
+
* Check whether a node is a JSX text node.
|
|
541
|
+
*
|
|
542
|
+
* Returns `true` for both `JSXText` nodes and `Literal` nodes that appear
|
|
543
|
+
* as direct children of a JSX element (the parser may represent inline text
|
|
544
|
+
* with either node type depending on context).
|
|
545
|
+
*
|
|
546
|
+
* @param node - The AST node to test.
|
|
547
|
+
* @returns `true` when `node` is a `JSXText` or `Literal`.
|
|
99
548
|
*/
|
|
100
|
-
declare function
|
|
101
|
-
|
|
102
|
-
|
|
549
|
+
declare function isJsxText(node: TSESTree.Node | null): node is TSESTree.JSXText | TSESTree.Literal;
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region src/is-whitespace.d.ts
|
|
552
|
+
/**
|
|
553
|
+
* Check whether a JSX child node is **whitespace padding** that React would
|
|
554
|
+
* trim away during rendering.
|
|
555
|
+
*
|
|
556
|
+
* A child is considered whitespace padding when it is a `JSXText` node whose
|
|
557
|
+
* raw content is empty after trimming **and** contains at least one newline.
|
|
558
|
+
* This is the whitespace that appears between JSX tags purely for formatting:
|
|
559
|
+
*
|
|
560
|
+
* ```jsx
|
|
561
|
+
* <div>
|
|
562
|
+
* <span /> ← the text between </span> and the next tag is padding
|
|
563
|
+
* <span />
|
|
564
|
+
* </div>
|
|
565
|
+
* ```
|
|
566
|
+
*
|
|
567
|
+
* Use {@link isWhitespaceText} for a looser check that also matches
|
|
568
|
+
* whitespace‑only text that does **not** contain a newline.
|
|
569
|
+
*
|
|
570
|
+
* @param node - A JSX child node.
|
|
571
|
+
* @returns `true` when the node is purely formatting whitespace.
|
|
572
|
+
*
|
|
573
|
+
* @example
|
|
574
|
+
* ```ts
|
|
575
|
+
* import { isWhitespace } from "@eslint-react/jsx";
|
|
576
|
+
*
|
|
577
|
+
* const meaningful = element.children.filter(
|
|
578
|
+
* (child) => !isWhitespace(child),
|
|
579
|
+
* );
|
|
580
|
+
* ```
|
|
581
|
+
*/
|
|
582
|
+
declare function isWhitespace(node: TSESTree.JSXChild): boolean;
|
|
583
|
+
/**
|
|
584
|
+
* Check whether a JSX child node is **any** whitespace‑only text.
|
|
585
|
+
*
|
|
586
|
+
* This is a looser variant of {@link isWhitespace} — it matches every
|
|
587
|
+
* `JSXText` node whose raw content is empty after trimming, regardless of
|
|
588
|
+
* whether it contains a newline.
|
|
589
|
+
*
|
|
590
|
+
* @param node - A JSX child node.
|
|
591
|
+
* @returns `true` when the node is a whitespace‑only `JSXText`.
|
|
592
|
+
*/
|
|
593
|
+
declare function isWhitespaceText(node: TSESTree.JSXChild): boolean;
|
|
594
|
+
//#endregion
|
|
595
|
+
//#region src/jsx-config.d.ts
|
|
596
|
+
/**
|
|
597
|
+
* TypeScript `jsx` compiler option values.
|
|
598
|
+
*
|
|
599
|
+
* Mirrors `ts.JsxEmit` so that consumers do not need a direct dependency on
|
|
600
|
+
* the TypeScript compiler.
|
|
601
|
+
*/
|
|
602
|
+
declare const JsxEmit: {
|
|
603
|
+
readonly None: 0;
|
|
604
|
+
readonly Preserve: 1;
|
|
605
|
+
readonly React: 2;
|
|
606
|
+
readonly ReactNative: 3;
|
|
607
|
+
readonly ReactJSX: 4;
|
|
608
|
+
readonly ReactJSXDev: 5;
|
|
609
|
+
};
|
|
610
|
+
/**
|
|
611
|
+
* Resolved JSX configuration derived from compiler options and / or pragma
|
|
612
|
+
* annotations found in the source file.
|
|
613
|
+
*/
|
|
614
|
+
interface JsxConfig {
|
|
615
|
+
jsx?: number;
|
|
616
|
+
jsxFactory?: string;
|
|
617
|
+
jsxFragmentFactory?: string;
|
|
618
|
+
jsxImportSource?: string;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Read JSX configuration from the TypeScript compiler options exposed by the
|
|
622
|
+
* parser services.
|
|
623
|
+
*
|
|
624
|
+
* Falls back to sensible React defaults when no compiler options are
|
|
625
|
+
* available (e.g. when the file is parsed without type information).
|
|
626
|
+
*
|
|
627
|
+
* @param context - The ESLint rule context.
|
|
628
|
+
* @returns Fully‑populated `JsxConfig` derived from compiler options.
|
|
629
|
+
*/
|
|
630
|
+
declare function getJsxConfigFromCompilerOptions(context: RuleContext): Required<JsxConfig>;
|
|
631
|
+
/**
|
|
632
|
+
* Extract JSX configuration from `@jsx`, `@jsxFrag`, `@jsxRuntime` and
|
|
633
|
+
* `@jsxImportSource` pragma comments in the source file.
|
|
634
|
+
*
|
|
635
|
+
* The result is cached per `sourceCode` instance via a `WeakMap` so that
|
|
636
|
+
* repeated calls from different rules analysing the same file are free.
|
|
637
|
+
*
|
|
638
|
+
* @param context - The ESLint rule context.
|
|
639
|
+
* @returns Partial `JsxConfig` containing only the values found in pragmas.
|
|
640
|
+
*/
|
|
641
|
+
declare function getJsxConfigFromAnnotation(context: RuleContext): JsxConfig;
|
|
642
|
+
/**
|
|
643
|
+
* Get the fully‑merged JSX configuration for the current file.
|
|
644
|
+
*
|
|
645
|
+
* Compiler options provide the base values; pragma annotations found in the
|
|
646
|
+
* source override them where present. The result is cached per `sourceCode`.
|
|
647
|
+
*
|
|
648
|
+
* This is the main entry‑point most consumers should use.
|
|
649
|
+
*
|
|
650
|
+
* @param context - The ESLint rule context.
|
|
651
|
+
* @returns Fully‑populated, merged `JsxConfig`.
|
|
652
|
+
*/
|
|
653
|
+
declare function getJsxConfig(context: RuleContext): Required<JsxConfig>;
|
|
654
|
+
//#endregion
|
|
655
|
+
//#region src/resolve-attribute-value.d.ts
|
|
656
|
+
/**
|
|
657
|
+
* Resolve the value of a JSX attribute (or spread attribute) into a
|
|
658
|
+
* {@link JsxAttributeValue} descriptor that can be inspected further.
|
|
659
|
+
*
|
|
660
|
+
* This is the low‑level building block – it operates on a single attribute
|
|
661
|
+
* node that the caller has already located. For the higher‑level "find by
|
|
662
|
+
* name **and** resolve" combo, see {@link getAttributeValue}.
|
|
663
|
+
*
|
|
664
|
+
* @param context - The ESLint rule context (needed for scope look‑ups).
|
|
665
|
+
* @param attribute - A `JSXAttribute` or `JSXSpreadAttribute` node.
|
|
666
|
+
* @returns A discriminated‑union descriptor of the attribute's value.
|
|
667
|
+
*
|
|
668
|
+
* @example
|
|
669
|
+
* ```ts
|
|
670
|
+
* import { findAttribute, resolveAttributeValue } from "@eslint-react/jsx";
|
|
671
|
+
*
|
|
672
|
+
* const attr = findAttribute(context, element, "sandbox");
|
|
673
|
+
* if (attr != null) {
|
|
674
|
+
* const value = resolveAttributeValue(context, attr);
|
|
675
|
+
* if (value.kind === "literal") {
|
|
676
|
+
* console.log(value.toStatic());
|
|
677
|
+
* }
|
|
678
|
+
* }
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
declare function resolveAttributeValue(context: RuleContext, attribute: TSESTreeJSXAttributeLike): JsxAttributeValue;
|
|
682
|
+
//#endregion
|
|
683
|
+
export { DEFAULT_JSX_DETECTION_HINT, ElementTest, JsxAttributeValue, JsxConfig, JsxDetectionHint, JsxEmit, findAttribute, findParentAttribute, getAttributeName, getAttributeStaticValue, getAttributeValue, getChildren, getElementFullType, getElementSelfType, getJsxConfig, getJsxConfigFromAnnotation, getJsxConfigFromCompilerOptions, hasAnyAttribute, hasAttribute, hasChildren, hasEveryAttribute, isElement, isFragmentElement, isHostElement, isJsxLike, isJsxText, isWhitespace, isWhitespaceText, resolveAttributeValue };
|