@trackunit/eslint-plugin-trackunit 0.0.2
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/CHANGELOG.md +9 -0
- package/README.md +117 -0
- package/package.json +31 -0
- package/src/index.d.ts +8 -0
- package/src/index.js +20 -0
- package/src/index.js.map +1 -0
- package/src/lib/config/fragments/ignores.d.ts +2 -0
- package/src/lib/config/fragments/ignores.js +18 -0
- package/src/lib/config/fragments/ignores.js.map +1 -0
- package/src/lib/config/fragments/import-rules.d.ts +3 -0
- package/src/lib/config/fragments/import-rules.js +58 -0
- package/src/lib/config/fragments/import-rules.js.map +1 -0
- package/src/lib/config/fragments/jest-overrides.d.ts +2 -0
- package/src/lib/config/fragments/jest-overrides.js +30 -0
- package/src/lib/config/fragments/jest-overrides.js.map +1 -0
- package/src/lib/config/fragments/jsdoc-rules.d.ts +3 -0
- package/src/lib/config/fragments/jsdoc-rules.js +71 -0
- package/src/lib/config/fragments/jsdoc-rules.js.map +1 -0
- package/src/lib/config/fragments/module-boundaries.d.ts +2 -0
- package/src/lib/config/fragments/module-boundaries.js +92 -0
- package/src/lib/config/fragments/module-boundaries.js.map +1 -0
- package/src/lib/config/fragments/react-rules.d.ts +5 -0
- package/src/lib/config/fragments/react-rules.js +137 -0
- package/src/lib/config/fragments/react-rules.js.map +1 -0
- package/src/lib/config/fragments/restricted-imports.d.ts +2 -0
- package/src/lib/config/fragments/restricted-imports.js +58 -0
- package/src/lib/config/fragments/restricted-imports.js.map +1 -0
- package/src/lib/config/fragments/testing-library.d.ts +2 -0
- package/src/lib/config/fragments/testing-library.js +7 -0
- package/src/lib/config/fragments/testing-library.js.map +1 -0
- package/src/lib/config/fragments/typescript-rules.d.ts +2 -0
- package/src/lib/config/fragments/typescript-rules.js +97 -0
- package/src/lib/config/fragments/typescript-rules.js.map +1 -0
- package/src/lib/config/index.d.ts +863 -0
- package/src/lib/config/index.js +10 -0
- package/src/lib/config/index.js.map +1 -0
- package/src/lib/config/plugins.d.ts +90 -0
- package/src/lib/config/plugins.js +44 -0
- package/src/lib/config/plugins.js.map +1 -0
- package/src/lib/config/presets/base.d.ts +265 -0
- package/src/lib/config/presets/base.js +145 -0
- package/src/lib/config/presets/base.js.map +1 -0
- package/src/lib/config/presets/e2e.d.ts +10 -0
- package/src/lib/config/presets/e2e.js +19 -0
- package/src/lib/config/presets/e2e.js.map +1 -0
- package/src/lib/config/presets/public-api.d.ts +147 -0
- package/src/lib/config/presets/public-api.js +62 -0
- package/src/lib/config/presets/public-api.js.map +1 -0
- package/src/lib/config/presets/react.d.ts +598 -0
- package/src/lib/config/presets/react.js +97 -0
- package/src/lib/config/presets/react.js.map +1 -0
- package/src/lib/config/presets/server.d.ts +36 -0
- package/src/lib/config/presets/server.js +37 -0
- package/src/lib/config/presets/server.js.map +1 -0
- package/src/lib/config/utils.d.ts +6 -0
- package/src/lib/config/utils.js +28 -0
- package/src/lib/config/utils.js.map +1 -0
- package/src/lib/config-helpers/create-skip-when.d.ts +35 -0
- package/src/lib/config-helpers/create-skip-when.js +54 -0
- package/src/lib/config-helpers/create-skip-when.js.map +1 -0
- package/src/lib/rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array.d.ts +16 -0
- package/src/lib/rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array.js +83 -0
- package/src/lib/rules/cva-merge-base-classes-as-array/cva-merge-base-classes-as-array.js.map +1 -0
- package/src/lib/rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match.d.ts +4 -0
- package/src/lib/rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match.js +297 -0
- package/src/lib/rules/design-guideline-button-icon-size-match/design-guideline-button-icon-size-match.js.map +1 -0
- package/src/lib/rules/no-internal-barrel-files/examples.d.ts +80 -0
- package/src/lib/rules/no-internal-barrel-files/examples.js +84 -0
- package/src/lib/rules/no-internal-barrel-files/examples.js.map +1 -0
- package/src/lib/rules/no-internal-barrel-files/no-internal-barrel-files.d.ts +29 -0
- package/src/lib/rules/no-internal-barrel-files/no-internal-barrel-files.js +178 -0
- package/src/lib/rules/no-internal-barrel-files/no-internal-barrel-files.js.map +1 -0
- package/src/lib/rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public.d.ts +5 -0
- package/src/lib/rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public.js +67 -0
- package/src/lib/rules/no-internal-graphql-when-tagged-with-gql-public/no-internal-graphql-when-tagged-with-gql-public.js.map +1 -0
- package/src/lib/rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks.d.ts +2 -0
- package/src/lib/rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks.js +34 -0
- package/src/lib/rules/no-jest-mock-trackunit-react-core-hooks/no-jest-mock-trackunit-react-core-hooks.js.map +1 -0
- package/src/lib/rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop.d.ts +16 -0
- package/src/lib/rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop.js +55 -0
- package/src/lib/rules/no-template-strings-in-classname-prop/no-template-strings-in-classname-prop.js.map +1 -0
- package/src/lib/rules/no-typescript-assertion/examples.d.ts +1 -0
- package/src/lib/rules/no-typescript-assertion/examples.js +45 -0
- package/src/lib/rules/no-typescript-assertion/examples.js.map +1 -0
- package/src/lib/rules/no-typescript-assertion/no-typescript-assertion.d.ts +20 -0
- package/src/lib/rules/no-typescript-assertion/no-typescript-assertion.js +83 -0
- package/src/lib/rules/no-typescript-assertion/no-typescript-assertion.js.map +1 -0
- package/src/lib/rules/prefer-destructured-imports/prefer-destructured-imports.d.ts +73 -0
- package/src/lib/rules/prefer-destructured-imports/prefer-destructured-imports.js +333 -0
- package/src/lib/rules/prefer-destructured-imports/prefer-destructured-imports.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/name-suggestion-strategies.d.ts +56 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/name-suggestion-strategies.js +225 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/name-suggestion-strategies.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming.d.ts +49 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming.js +75 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/prefer-event-specific-callback-naming.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/string-based.d.ts +32 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/string-based.js +143 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/string-based.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/type-based.d.ts +27 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/type-based.js +196 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/strategies/type-based.js.map +1 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/utils.d.ts +76 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/utils.js +245 -0
- package/src/lib/rules/prefer-event-specific-callback-naming/utils.js.map +1 -0
- package/src/lib/rules/prefer-field-components/prefer-field-components.d.ts +4 -0
- package/src/lib/rules/prefer-field-components/prefer-field-components.js +289 -0
- package/src/lib/rules/prefer-field-components/prefer-field-components.js.map +1 -0
- package/src/lib/rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props.d.ts +26 -0
- package/src/lib/rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props.js +402 -0
- package/src/lib/rules/prefer-mouse-event-handler-in-react-props/prefer-mouse-event-handler-in-react-props.js.map +1 -0
- package/src/lib/rules/require-classname-alternatives/require-classname-alternatives.d.ts +13 -0
- package/src/lib/rules/require-classname-alternatives/require-classname-alternatives.js +271 -0
- package/src/lib/rules/require-classname-alternatives/require-classname-alternatives.js.map +1 -0
- package/src/lib/rules/require-list-item-virtualization-props/require-list-item-virtualization-props.d.ts +15 -0
- package/src/lib/rules/require-list-item-virtualization-props/require-list-item-virtualization-props.js +245 -0
- package/src/lib/rules/require-list-item-virtualization-props/require-list-item-virtualization-props.js.map +1 -0
- package/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.d.ts +17 -0
- package/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.js +133 -0
- package/src/lib/rules/require-optional-prop-initialization/require-optional-prop-initialization.js.map +1 -0
- package/src/lib/rules/require-optional-prop-initialization/suggestion-utils.d.ts +12 -0
- package/src/lib/rules/require-optional-prop-initialization/suggestion-utils.js +128 -0
- package/src/lib/rules/require-optional-prop-initialization/suggestion-utils.js.map +1 -0
- package/src/lib/rules-map.d.ts +66 -0
- package/src/lib/rules-map.js +34 -0
- package/src/lib/rules-map.js.map +1 -0
- package/src/lib/utils/ast-utils.d.ts +85 -0
- package/src/lib/utils/ast-utils.js +530 -0
- package/src/lib/utils/ast-utils.js.map +1 -0
- package/src/lib/utils/classname-utils.d.ts +150 -0
- package/src/lib/utils/classname-utils.js +492 -0
- package/src/lib/utils/classname-utils.js.map +1 -0
- package/src/lib/utils/file-utils.d.ts +14 -0
- package/src/lib/utils/file-utils.js +106 -0
- package/src/lib/utils/file-utils.js.map +1 -0
- package/src/lib/utils/import-utils.d.ts +85 -0
- package/src/lib/utils/import-utils.js +193 -0
- package/src/lib/utils/import-utils.js.map +1 -0
- package/src/lib/utils/nx-utils.d.ts +59 -0
- package/src/lib/utils/nx-utils.js +103 -0
- package/src/lib/utils/nx-utils.js.map +1 -0
- package/src/lib/utils/package-utils.d.ts +38 -0
- package/src/lib/utils/package-utils.js +74 -0
- package/src/lib/utils/package-utils.js.map +1 -0
- package/src/lib/utils/typescript-utils.d.ts +29 -0
- package/src/lib/utils/typescript-utils.js +213 -0
- package/src/lib/utils/typescript-utils.js.map +1 -0
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isIdentifierFromRenderPropCallback = exports.isIdentifierFromParameter = exports.isParameterOnlyUsedInJSX = exports.isReactComponent = exports.isParameterUsedInFunction = exports.isParameterInitialized = exports.hasExistingBodyInitializations = exports.isParameterExplicitlyDestructured = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
/**
|
|
6
|
+
* Utility functions for analyzing AST nodes and function structure in ESLint rules.
|
|
7
|
+
*
|
|
8
|
+
* ## Core Utilities
|
|
9
|
+
* - `isInParameterList()` - Check if a node is in a function's parameter list
|
|
10
|
+
*
|
|
11
|
+
* ## Parameter Analysis (Parameter → Usage)
|
|
12
|
+
* - `isParameterExplicitlyDestructured()` - Check if parameter is explicitly destructured
|
|
13
|
+
* - `isParameterInitialized()` - Check if parameter has a default value
|
|
14
|
+
* - `isParameterUsedInFunction()` - Check if parameter is used in function body
|
|
15
|
+
* - `getParameterRestUsage()` - Get info about parameter accessed via rest params
|
|
16
|
+
* - `hasExistingBodyInitializations()` - Check for initialization patterns in function body
|
|
17
|
+
*
|
|
18
|
+
* ## Identifier Origin Analysis (Usage → Origin)
|
|
19
|
+
* - `getIdentifierParameterOrigin()` - Trace identifier back to see if it's from a parameter (rich return)
|
|
20
|
+
* - `isIdentifierFromParameter()` - Boolean helper to check if identifier is from a parameter
|
|
21
|
+
* - `isIdentifierFromRenderPropCallback()` - Check if identifier is from a render prop callback parameter
|
|
22
|
+
*
|
|
23
|
+
* ## JSX/React Specific
|
|
24
|
+
* - `isReactComponent()` - Check if function is likely a React component
|
|
25
|
+
* - `isParameterOnlyUsedInJSX()` - Check if parameter is only used in JSX attributes
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Helper function to check if a node is in the parameter list
|
|
29
|
+
*/
|
|
30
|
+
const isInParameterList = (node, functionNode) => {
|
|
31
|
+
let current = node.parent;
|
|
32
|
+
while (current) {
|
|
33
|
+
// Check if current node is one of the function parameters
|
|
34
|
+
const isParam = functionNode.params.some(param => param === current);
|
|
35
|
+
if (isParam) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
current = current.parent;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Check if a parameter is explicitly destructured in the parameter list
|
|
44
|
+
* (vs. captured in rest parameters like ...restOptions)
|
|
45
|
+
*/
|
|
46
|
+
const isParameterExplicitlyDestructured = (parameter, paramName) => {
|
|
47
|
+
if (parameter.type !== utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
// Check if the parameter is explicitly listed in the destructuring
|
|
51
|
+
return parameter.properties.some(property => {
|
|
52
|
+
if (property.type === utils_1.AST_NODE_TYPES.Property && property.key.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
53
|
+
return property.key.name === paramName;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
exports.isParameterExplicitlyDestructured = isParameterExplicitlyDestructured;
|
|
59
|
+
/**
|
|
60
|
+
* Check if there are any existing parameter initializations in the function body
|
|
61
|
+
*/
|
|
62
|
+
const hasExistingBodyInitializations = (functionBody) => {
|
|
63
|
+
for (const stmt of functionBody) {
|
|
64
|
+
// Check for destructuring with defaults: const { param = defaultValue } = params
|
|
65
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.VariableDeclaration &&
|
|
66
|
+
stmt.declarations.length === 1 &&
|
|
67
|
+
stmt.declarations[0].id.type === utils_1.AST_NODE_TYPES.ObjectPattern &&
|
|
68
|
+
stmt.declarations[0].id.properties.some(prop => prop.type === utils_1.AST_NODE_TYPES.Property && prop.value.type === utils_1.AST_NODE_TYPES.AssignmentPattern)) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
// Check for variable declarations with defaults: const param = params.param ?? defaultValue
|
|
72
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.VariableDeclaration &&
|
|
73
|
+
stmt.declarations.length === 1 &&
|
|
74
|
+
stmt.declarations[0].init?.type === utils_1.AST_NODE_TYPES.LogicalExpression &&
|
|
75
|
+
(stmt.declarations[0].init.operator === "??" || stmt.declarations[0].init.operator === "||")) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
};
|
|
81
|
+
exports.hasExistingBodyInitializations = hasExistingBodyInitializations;
|
|
82
|
+
/**
|
|
83
|
+
* Check if a parameter is initialized in the function body or parameter defaults
|
|
84
|
+
*/
|
|
85
|
+
const isParameterInitialized = (functionBody, paramName, parameter) => {
|
|
86
|
+
// First check if the parameter has a default value in the parameter destructuring
|
|
87
|
+
if (parameter && parameter.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
88
|
+
for (const property of parameter.properties) {
|
|
89
|
+
if (property.type === utils_1.AST_NODE_TYPES.Property && property.value.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
90
|
+
// Handle both identifier keys (paramName) and string literal keys ("param-name")
|
|
91
|
+
const keyName = property.key.type === utils_1.AST_NODE_TYPES.Identifier
|
|
92
|
+
? property.key.name
|
|
93
|
+
: property.key.type === utils_1.AST_NODE_TYPES.Literal && typeof property.key.value === "string"
|
|
94
|
+
? property.key.value
|
|
95
|
+
: null;
|
|
96
|
+
if (keyName === paramName) {
|
|
97
|
+
return true; // Found default value in parameter: {paramName = defaultValue}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Then check for initialization patterns in the function body
|
|
103
|
+
for (const stmt of functionBody) {
|
|
104
|
+
// Check for destructuring with defaults: const { param = defaultValue } = params
|
|
105
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.VariableDeclaration &&
|
|
106
|
+
stmt.declarations.length === 1 &&
|
|
107
|
+
stmt.declarations[0].id.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
108
|
+
const pattern = stmt.declarations[0].id;
|
|
109
|
+
for (const property of pattern.properties) {
|
|
110
|
+
if (property.type === utils_1.AST_NODE_TYPES.Property &&
|
|
111
|
+
property.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
112
|
+
property.key.name === paramName &&
|
|
113
|
+
property.value.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Check for variable declarations with defaults: const param = params.param ?? defaultValue
|
|
119
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.VariableDeclaration &&
|
|
120
|
+
stmt.declarations.length === 1 &&
|
|
121
|
+
stmt.declarations[0].id.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
122
|
+
stmt.declarations[0].id.name === paramName &&
|
|
123
|
+
stmt.declarations[0].init?.type === utils_1.AST_NODE_TYPES.LogicalExpression &&
|
|
124
|
+
(stmt.declarations[0].init.operator === "??" || stmt.declarations[0].init.operator === "||")) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
};
|
|
130
|
+
exports.isParameterInitialized = isParameterInitialized;
|
|
131
|
+
/**
|
|
132
|
+
* Check if a parameter is used within the function body
|
|
133
|
+
*/
|
|
134
|
+
const isParameterUsedInFunction = (context, functionNode, paramName) => {
|
|
135
|
+
// Use TypeScript-ESLint's built-in findVariable utility for more robust variable detection
|
|
136
|
+
const scope = context.sourceCode.getScope(functionNode);
|
|
137
|
+
const variable = utils_1.ASTUtils.findVariable(scope, paramName);
|
|
138
|
+
if (variable) {
|
|
139
|
+
// Check if the variable has any references (excluding the parameter definition)
|
|
140
|
+
const references = variable.references.filter(ref => {
|
|
141
|
+
// Exclude the parameter declaration itself
|
|
142
|
+
const refNode = ref.identifier;
|
|
143
|
+
return !isInParameterList(refNode, functionNode);
|
|
144
|
+
});
|
|
145
|
+
// Additional check: if the variable is only referenced in object literal shorthand property names
|
|
146
|
+
// (like { placement: result.placement }), it's not actually using the parameter variable
|
|
147
|
+
const actualUsageReferences = references.filter(ref => {
|
|
148
|
+
const parent = ref.identifier.parent;
|
|
149
|
+
// Skip if this is just a property key in an object literal
|
|
150
|
+
// Example: { placement: result.placement } - the first 'placement' is just a key, not usage
|
|
151
|
+
if (parent.type === utils_1.AST_NODE_TYPES.Property &&
|
|
152
|
+
parent.key === ref.identifier &&
|
|
153
|
+
parent.value !== ref.identifier &&
|
|
154
|
+
!parent.shorthand) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
});
|
|
159
|
+
if (actualUsageReferences.length > 0) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// If direct variable reference not found, check for member access on rest parameters
|
|
164
|
+
// e.g., rest.paramName, params.paramName, etc.
|
|
165
|
+
const restParameters = [];
|
|
166
|
+
// Look for rest elements in both direct params and inside object patterns
|
|
167
|
+
functionNode.params.forEach(param => {
|
|
168
|
+
if (param.type === utils_1.AST_NODE_TYPES.RestElement && param.argument.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
169
|
+
// Direct rest parameter: (...rest: Params)
|
|
170
|
+
restParameters.push({ name: param.argument.name, param });
|
|
171
|
+
}
|
|
172
|
+
else if (param.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
173
|
+
// Look for rest elements inside object patterns: ({ param1, ...rest }: Params)
|
|
174
|
+
param.properties.forEach(property => {
|
|
175
|
+
if (property.type === utils_1.AST_NODE_TYPES.RestElement && property.argument.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
176
|
+
restParameters.push({ name: property.argument.name, param });
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
if (restParameters.length === 0) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
// Check if the function body contains rest.paramName patterns
|
|
185
|
+
const functionText = context.sourceCode.getText(functionNode);
|
|
186
|
+
for (const restParam of restParameters) {
|
|
187
|
+
const pattern = new RegExp(`\\b${restParam.name}\\.${paramName}\\b`);
|
|
188
|
+
if (pattern.test(functionText)) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
};
|
|
194
|
+
exports.isParameterUsedInFunction = isParameterUsedInFunction;
|
|
195
|
+
/**
|
|
196
|
+
* Check if a parameter is accessed via rest parameters (e.g., rest.paramName)
|
|
197
|
+
* and return information about the rest parameter usage
|
|
198
|
+
*/
|
|
199
|
+
const getParameterRestUsage = (context, functionNode, paramName) => {
|
|
200
|
+
// Look for rest elements in both direct params and inside object patterns
|
|
201
|
+
const restParameters = [];
|
|
202
|
+
functionNode.params.forEach(param => {
|
|
203
|
+
if (param.type === utils_1.AST_NODE_TYPES.RestElement && param.argument.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
204
|
+
// Direct rest parameter: (...rest: Params)
|
|
205
|
+
restParameters.push({ name: param.argument.name, param });
|
|
206
|
+
}
|
|
207
|
+
else if (param.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
208
|
+
// Look for rest elements inside object patterns: ({ param1, ...rest }: Params)
|
|
209
|
+
param.properties.forEach(property => {
|
|
210
|
+
if (property.type === utils_1.AST_NODE_TYPES.RestElement && property.argument.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
211
|
+
restParameters.push({ name: property.argument.name, param });
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
if (restParameters.length === 0) {
|
|
217
|
+
return { isUsedViaRest: false };
|
|
218
|
+
}
|
|
219
|
+
// Check if the function body contains rest.paramName patterns
|
|
220
|
+
const functionText = context.sourceCode.getText(functionNode);
|
|
221
|
+
for (const restParam of restParameters) {
|
|
222
|
+
const pattern = new RegExp(`\\b${restParam.name}\\.${paramName}\\b`);
|
|
223
|
+
if (pattern.test(functionText)) {
|
|
224
|
+
return {
|
|
225
|
+
isUsedViaRest: true,
|
|
226
|
+
restParamName: restParam.name,
|
|
227
|
+
restParam: restParam.param,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return { isUsedViaRest: false };
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Check if a function is likely a React component based on naming and JSX usage
|
|
235
|
+
*/
|
|
236
|
+
const isReactComponent = (node) => {
|
|
237
|
+
// Check if function name starts with uppercase (React convention)
|
|
238
|
+
const functionName = node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ? node.id?.name : null;
|
|
239
|
+
const startsWithUppercase = /^[A-Z]/;
|
|
240
|
+
if (functionName && startsWithUppercase.test(functionName)) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
// Check if the function returns JSX
|
|
244
|
+
const hasJSXReturn = (body) => {
|
|
245
|
+
if (body.type === utils_1.AST_NODE_TYPES.JSXElement || body.type === utils_1.AST_NODE_TYPES.JSXFragment) {
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
// Handle conditional expressions that contain JSX: condition ? <JSX /> : null
|
|
249
|
+
if (body.type === utils_1.AST_NODE_TYPES.ConditionalExpression) {
|
|
250
|
+
return hasJSXReturn(body.consequent) || hasJSXReturn(body.alternate);
|
|
251
|
+
}
|
|
252
|
+
if (body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
253
|
+
return body.body.some(stmt => {
|
|
254
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.ReturnStatement && stmt.argument) {
|
|
255
|
+
return hasJSXReturn(stmt.argument);
|
|
256
|
+
}
|
|
257
|
+
return false;
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
261
|
+
};
|
|
262
|
+
return hasJSXReturn(node.body);
|
|
263
|
+
};
|
|
264
|
+
exports.isReactComponent = isReactComponent;
|
|
265
|
+
/**
|
|
266
|
+
* Check if a parameter is only used in JSX attributes (pass-through to child components)
|
|
267
|
+
* and nowhere else in the function body
|
|
268
|
+
*/
|
|
269
|
+
const isParameterOnlyUsedInJSX = (context, functionNode, paramName) => {
|
|
270
|
+
// Use TypeScript-ESLint's built-in findVariable utility for robust variable detection
|
|
271
|
+
const scope = context.sourceCode.getScope(functionNode);
|
|
272
|
+
const variable = utils_1.ASTUtils.findVariable(scope, paramName);
|
|
273
|
+
if (!variable) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
// Get all references to the parameter (excluding the parameter definition)
|
|
277
|
+
const references = variable.references.filter(ref => {
|
|
278
|
+
const refNode = ref.identifier;
|
|
279
|
+
return !isInParameterList(refNode, functionNode);
|
|
280
|
+
});
|
|
281
|
+
if (references.length === 0) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
// Check if all references are only in JSX attribute expressions
|
|
285
|
+
const allReferencesAreJSXAttributes = references.every(ref => {
|
|
286
|
+
const identifier = ref.identifier;
|
|
287
|
+
let current = identifier.parent;
|
|
288
|
+
// Walk up the AST to find if this identifier is used in a JSX attribute
|
|
289
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions
|
|
290
|
+
while (current) {
|
|
291
|
+
// Check if we're in a JSX attribute expression: <Component prop={value} />
|
|
292
|
+
if (current.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
293
|
+
const jsxParent = current.parent;
|
|
294
|
+
if (jsxParent.type === utils_1.AST_NODE_TYPES.JSXAttribute) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Check if we're in a JSX spread attribute: <Component {...props} />
|
|
299
|
+
if (current.type === utils_1.AST_NODE_TYPES.JSXSpreadAttribute) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
// Allow dependency arrays for React hooks (useEffect, useMemo, useCallback, etc.)
|
|
303
|
+
// These are acceptable for pass-through props since they're tracking the JSX usage
|
|
304
|
+
if (current.type === utils_1.AST_NODE_TYPES.ArrayExpression) {
|
|
305
|
+
const callParent = current.parent;
|
|
306
|
+
if (callParent.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
307
|
+
callParent.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
308
|
+
(callParent.callee.name.startsWith("use") ||
|
|
309
|
+
callParent.callee.name === "useMemo" ||
|
|
310
|
+
callParent.callee.name === "useCallback" ||
|
|
311
|
+
callParent.callee.name === "useEffect")) {
|
|
312
|
+
return true; // Allow dependency array usage
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Stop if we reach certain node types that indicate we're not in JSX context
|
|
316
|
+
if (current.type === utils_1.AST_NODE_TYPES.VariableDeclarator ||
|
|
317
|
+
current.type === utils_1.AST_NODE_TYPES.AssignmentExpression ||
|
|
318
|
+
current.type === utils_1.AST_NODE_TYPES.CallExpression ||
|
|
319
|
+
current.type === utils_1.AST_NODE_TYPES.LogicalExpression ||
|
|
320
|
+
current.type === utils_1.AST_NODE_TYPES.ConditionalExpression ||
|
|
321
|
+
current.type === utils_1.AST_NODE_TYPES.BinaryExpression) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
if (!current.parent) {
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
current = current.parent;
|
|
328
|
+
}
|
|
329
|
+
return false;
|
|
330
|
+
});
|
|
331
|
+
return allReferencesAreJSXAttributes;
|
|
332
|
+
};
|
|
333
|
+
exports.isParameterOnlyUsedInJSX = isParameterOnlyUsedInJSX;
|
|
334
|
+
/**
|
|
335
|
+
* Checks if a variable is a function parameter.
|
|
336
|
+
*/
|
|
337
|
+
const isVariableAParameter = (variable) => {
|
|
338
|
+
return variable.defs.some(def => def.type === "Parameter");
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* Traces an identifier back to determine if it originates from a function parameter.
|
|
342
|
+
* Returns detailed information about how the identifier relates to the parameter.
|
|
343
|
+
*
|
|
344
|
+
* This is used to distinguish between:
|
|
345
|
+
* - Props passed through: `({ onClose }) => <button onClick={onClose} />` - destructured-in-signature
|
|
346
|
+
* - Props destructured in body: `(props) => { const { onClose } = props; }` - destructured-in-body
|
|
347
|
+
* - Direct parameter: `(onClose) => ...` - direct-parameter
|
|
348
|
+
* - Internal functions: `const handleClose = () => {}; <button onClick={handleClose} />` - not from parameter
|
|
349
|
+
* - Hook results: `const { mutate } = useMutation(); <button onClick={mutate} />` - not from parameter
|
|
350
|
+
*
|
|
351
|
+
* @param identifier - The identifier node to check
|
|
352
|
+
* @param context - The ESLint rule context
|
|
353
|
+
* @returns ParameterOriginResult with isFromParameter and originType if applicable
|
|
354
|
+
* @example
|
|
355
|
+
* // Direct parameter
|
|
356
|
+
* const MyComponent = (onClose) => <button onClick={onClose} />;
|
|
357
|
+
* // getIdentifierParameterOrigin(onClose) => { isFromParameter: true, originType: "direct-parameter" }
|
|
358
|
+
* @example
|
|
359
|
+
* // Destructured in signature
|
|
360
|
+
* const MyComponent = ({ onClose }) => <button onClick={onClose} />;
|
|
361
|
+
* // getIdentifierParameterOrigin(onClose) => { isFromParameter: true, originType: "destructured-in-signature" }
|
|
362
|
+
* @example
|
|
363
|
+
* // Destructured in body
|
|
364
|
+
* const MyComponent = (props) => {
|
|
365
|
+
* const { onClose } = props;
|
|
366
|
+
* return <button onClick={onClose} />;
|
|
367
|
+
* };
|
|
368
|
+
* // getIdentifierParameterOrigin(onClose) => { isFromParameter: true, originType: "destructured-in-body" }
|
|
369
|
+
* @example
|
|
370
|
+
* // Not from parameter (internal function)
|
|
371
|
+
* const MyComponent = () => {
|
|
372
|
+
* const handleClose = () => {};
|
|
373
|
+
* return <button onClick={handleClose} />;
|
|
374
|
+
* };
|
|
375
|
+
* // getIdentifierParameterOrigin(handleClose) => { isFromParameter: false }
|
|
376
|
+
*/
|
|
377
|
+
const getIdentifierParameterOrigin = (identifier, context) => {
|
|
378
|
+
const scope = context.sourceCode.getScope(identifier);
|
|
379
|
+
const variable = scope.references.find(ref => ref.identifier === identifier)?.resolved;
|
|
380
|
+
if (!variable) {
|
|
381
|
+
return { isFromParameter: false };
|
|
382
|
+
}
|
|
383
|
+
// Check the variable's definitions
|
|
384
|
+
for (const definition of variable.defs) {
|
|
385
|
+
// Check if defined as a direct function parameter
|
|
386
|
+
if (definition.type === "Parameter") {
|
|
387
|
+
// Direct parameter: (onClose) => ...
|
|
388
|
+
return { isFromParameter: true, originType: "direct-parameter" };
|
|
389
|
+
}
|
|
390
|
+
// Check for destructured variable in body: const { onClose } = props
|
|
391
|
+
// definition.type is "Variable" and definition.node is VariableDeclarator
|
|
392
|
+
if (definition.type === "Variable") {
|
|
393
|
+
const declarator = definition.node;
|
|
394
|
+
// Check if the left side is an ObjectPattern (destructuring)
|
|
395
|
+
if (declarator.id.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
396
|
+
const init = declarator.init;
|
|
397
|
+
// Check if destructured from an identifier that is a parameter
|
|
398
|
+
if (init?.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
399
|
+
const initScope = context.sourceCode.getScope(init);
|
|
400
|
+
const initVariable = initScope.references.find(ref => ref.identifier === init)?.resolved;
|
|
401
|
+
if (initVariable && isVariableAParameter(initVariable)) {
|
|
402
|
+
return { isFromParameter: true, originType: "destructured-in-body" };
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Check if it's a destructured parameter directly in function signature
|
|
408
|
+
// Pattern: ({ onClose }) => ... or ({ onClose }: Props) => ...
|
|
409
|
+
if (definition.node.type === utils_1.AST_NODE_TYPES.Property) {
|
|
410
|
+
// Check direct parent - should be ObjectPattern for destructured props
|
|
411
|
+
const objectPattern = definition.node.parent;
|
|
412
|
+
if (objectPattern.type !== utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
// Check if this ObjectPattern is a function parameter
|
|
416
|
+
const objectPatternParent = objectPattern.parent;
|
|
417
|
+
if (objectPatternParent.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
418
|
+
objectPatternParent.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
419
|
+
objectPatternParent.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
|
|
420
|
+
// Check if the ObjectPattern is in the params
|
|
421
|
+
const isParam = objectPatternParent.params.includes(objectPattern);
|
|
422
|
+
if (isParam) {
|
|
423
|
+
return { isFromParameter: true, originType: "destructured-in-signature" };
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
// Also check for AssignmentPattern wrapper: ({ onClose = defaultFn }) => ...
|
|
427
|
+
if (objectPatternParent.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
428
|
+
const assignmentParent = objectPatternParent.parent;
|
|
429
|
+
if (assignmentParent.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
430
|
+
assignmentParent.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
431
|
+
assignmentParent.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
|
|
432
|
+
const isParam = assignmentParent.params.includes(objectPatternParent);
|
|
433
|
+
if (isParam) {
|
|
434
|
+
return { isFromParameter: true, originType: "destructured-in-signature" };
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return { isFromParameter: false };
|
|
441
|
+
};
|
|
442
|
+
/**
|
|
443
|
+
* Checks if an identifier originates from a function parameter.
|
|
444
|
+
* This is a simplified boolean helper that wraps `getIdentifierParameterOrigin`.
|
|
445
|
+
*
|
|
446
|
+
* Use this when you only need to know if an identifier comes from a parameter,
|
|
447
|
+
* without needing to know how it was destructured.
|
|
448
|
+
*
|
|
449
|
+
* @param identifier - The identifier node to check
|
|
450
|
+
* @param context - The ESLint rule context
|
|
451
|
+
* @returns true if the identifier originates from a function parameter
|
|
452
|
+
* @see getIdentifierParameterOrigin for detailed origin information
|
|
453
|
+
*/
|
|
454
|
+
const isIdentifierFromParameter = (identifier, context) => getIdentifierParameterOrigin(identifier, context).isFromParameter;
|
|
455
|
+
exports.isIdentifierFromParameter = isIdentifierFromParameter;
|
|
456
|
+
/**
|
|
457
|
+
* Checks if an identifier's parameter comes from a render prop callback.
|
|
458
|
+
*
|
|
459
|
+
* Render prop pattern: `{callback => <Component onClick={callback} />}`
|
|
460
|
+
*
|
|
461
|
+
* The function detects when:
|
|
462
|
+
* 1. The identifier comes from a parameter
|
|
463
|
+
* 2. That parameter's function is inside a JSXExpressionContainer
|
|
464
|
+
* 3. Which is a child of a JSXElement (render prop pattern)
|
|
465
|
+
*
|
|
466
|
+
* This is used to distinguish between:
|
|
467
|
+
* - React component props: `const Modal = ({ onClose }) => ...` - should be flagged
|
|
468
|
+
* - Render prop callbacks: `<MoreMenu>{close => <MenuItem onClick={close} />}</MoreMenu>` - should NOT be flagged
|
|
469
|
+
*
|
|
470
|
+
* @param identifier - The identifier node to check
|
|
471
|
+
* @param context - The ESLint rule context
|
|
472
|
+
* @returns true if the identifier comes from a render prop callback parameter
|
|
473
|
+
* @example
|
|
474
|
+
* // Render prop callback - returns true
|
|
475
|
+
* <MoreMenu>
|
|
476
|
+
* {close => <MenuItem onClick={close} />}
|
|
477
|
+
* </MoreMenu>
|
|
478
|
+
* // isIdentifierFromRenderPropCallback(close) => true
|
|
479
|
+
* @example
|
|
480
|
+
* // React component prop - returns false
|
|
481
|
+
* const Modal = ({ onClose }) => <button onClick={onClose} />;
|
|
482
|
+
* // isIdentifierFromRenderPropCallback(onClose) => false
|
|
483
|
+
*/
|
|
484
|
+
const isIdentifierFromRenderPropCallback = (identifier, context) => {
|
|
485
|
+
// First check if it even comes from a parameter
|
|
486
|
+
if (!(0, exports.isIdentifierFromParameter)(identifier, context)) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
// Get the variable that this identifier resolves to
|
|
490
|
+
const scope = context.sourceCode.getScope(identifier);
|
|
491
|
+
const variable = scope.references.find(ref => ref.identifier === identifier)?.resolved;
|
|
492
|
+
if (!variable) {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
// Check each definition of this variable
|
|
496
|
+
for (const definition of variable.defs) {
|
|
497
|
+
if (definition.type !== "Parameter") {
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
// Find the function that contains this parameter by walking up from the definition node
|
|
501
|
+
let functionNode = null;
|
|
502
|
+
let current = definition.node;
|
|
503
|
+
do {
|
|
504
|
+
if (current.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
505
|
+
current.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
506
|
+
current.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
|
|
507
|
+
functionNode = current;
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
current = current.parent;
|
|
511
|
+
} while (current !== undefined);
|
|
512
|
+
if (!functionNode) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
// Check if the function is inside a JSXExpressionContainer (render prop pattern)
|
|
516
|
+
// Pattern: <Component>{callback => ...}</Component>
|
|
517
|
+
const parent = functionNode.parent;
|
|
518
|
+
if (parent.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
519
|
+
// Verify the JSXExpressionContainer is a child of a JSXElement
|
|
520
|
+
const jsxContainerParent = parent.parent;
|
|
521
|
+
if (jsxContainerParent.type === utils_1.AST_NODE_TYPES.JSXElement ||
|
|
522
|
+
jsxContainerParent.type === utils_1.AST_NODE_TYPES.JSXFragment) {
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return false;
|
|
528
|
+
};
|
|
529
|
+
exports.isIdentifierFromRenderPropCallback = isIdentifierFromRenderPropCallback;
|
|
530
|
+
//# sourceMappingURL=ast-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-utils.js","sourceRoot":"","sources":["../../../../../../../libs/eslint/plugin-trackunit/src/lib/utils/ast-utils.ts"],"names":[],"mappings":";;;AAAA,oDAAwF;AAExF;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;GAEG;AACH,MAAM,iBAAiB,GAAG,CACxB,IAAmB,EACnB,YAA6E,EACpE,EAAE;IACX,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;IAC1B,OAAO,OAAO,EAAE,CAAC;QACf,0DAA0D;QAC1D,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;QACrE,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;GAGG;AACI,MAAM,iCAAiC,GAAG,CAAC,SAA6B,EAAE,SAAiB,EAAW,EAAE;IAC7G,IAAI,SAAS,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa,EAAE,CAAC;QACpD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,mEAAmE;IACnE,OAAO,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QAC1C,IAAI,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU,EAAE,CAAC;YACjG,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC;QACzC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAZW,QAAA,iCAAiC,qCAY5C;AAEF;;GAEG;AACI,MAAM,8BAA8B,GAAG,CAAC,YAAuC,EAAW,EAAE;IACjG,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,iFAAiF;QACjF,IACE,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB;YAChD,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;YAC9B,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa;YAC7D,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CACrC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,sBAAc,CAAC,iBAAiB,CACtG,EACD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,4FAA4F;QAC5F,IACE,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB;YAChD,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;YAC9B,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,sBAAc,CAAC,iBAAiB;YACpE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,EAC5F,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAzBW,QAAA,8BAA8B,kCAyBzC;AAEF;;GAEG;AACI,MAAM,sBAAsB,GAAG,CACpC,YAAuC,EACvC,SAAiB,EACjB,SAA8B,EACrB,EAAE;IACX,kFAAkF;IAClF,IAAI,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa,EAAE,CAAC;QACjE,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YAC5C,IAAI,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,sBAAc,CAAC,iBAAiB,EAAE,CAAC;gBAC1G,iFAAiF;gBACjF,MAAM,OAAO,GACX,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU;oBAC7C,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI;oBACnB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,sBAAc,CAAC,OAAO,IAAI,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,KAAK,QAAQ;wBACtF,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK;wBACpB,CAAC,CAAC,IAAI,CAAC;gBAEb,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC1B,OAAO,IAAI,CAAC,CAAC,+DAA+D;gBAC9E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,8DAA8D;IAC9D,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,iFAAiF;QACjF,IACE,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB;YAChD,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;YAC9B,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa,EAC7D,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBAC1C,IACE,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,QAAQ;oBACzC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU;oBAC/C,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS;oBAC/B,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,sBAAc,CAAC,iBAAiB,EACxD,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAED,4FAA4F;QAC5F,IACE,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB;YAChD,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;YAC9B,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU;YAC1D,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,SAAS;YAC1C,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,sBAAc,CAAC,iBAAiB;YACpE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,EAC5F,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AA3DW,QAAA,sBAAsB,0BA2DjC;AAEF;;GAEG;AACI,MAAM,yBAAyB,GAAG,CACvC,OAA6D,EAC7D,YAA6E,EAC7E,SAAiB,EACR,EAAE;IACX,2FAA2F;IAC3F,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,gBAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAEzD,IAAI,QAAQ,EAAE,CAAC;QACb,gFAAgF;QAChF,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YAClD,2CAA2C;YAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC;YAC/B,OAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,kGAAkG;QAClG,yFAAyF;QACzF,MAAM,qBAAqB,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YACpD,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;YAErC,2DAA2D;YAC3D,4FAA4F;YAC5F,IACE,MAAM,CAAC,IAAI,KAAK,sBAAc,CAAC,QAAQ;gBACvC,MAAM,CAAC,GAAG,KAAK,GAAG,CAAC,UAAU;gBAC7B,MAAM,CAAC,KAAK,KAAK,GAAG,CAAC,UAAU;gBAC/B,CAAC,MAAM,CAAC,SAAS,EACjB,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,IAAI,qBAAqB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,qFAAqF;IACrF,+CAA+C;IAC/C,MAAM,cAAc,GAAuD,EAAE,CAAC;IAE9E,0EAA0E;IAC1E,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAClC,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAc,CAAC,WAAW,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU,EAAE,CAAC;YACnG,2CAA2C;YAC3C,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa,EAAE,CAAC;YACvD,+EAA+E;YAC/E,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAClC,IAAI,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,WAAW,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU,EAAE,CAAC;oBACzG,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8DAA8D;IAC9D,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAE9D,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS,KAAK,CAAC,CAAC;QACrE,IAAI,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AA3EW,QAAA,yBAAyB,6BA2EpC;AAEF;;;GAGG;AACH,MAAM,qBAAqB,GAAG,CAC5B,OAA6D,EAC7D,YAA6E,EAC7E,SAAiB,EAC0E,EAAE;IAC7F,0EAA0E;IAC1E,MAAM,cAAc,GAAuD,EAAE,CAAC;IAE9E,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAClC,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAc,CAAC,WAAW,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU,EAAE,CAAC;YACnG,2CAA2C;YAC3C,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa,EAAE,CAAC;YACvD,+EAA+E;YAC/E,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAClC,IAAI,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,WAAW,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU,EAAE,CAAC;oBACzG,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAED,8DAA8D;IAC9D,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAE9D,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS,KAAK,CAAC,CAAC;QACrE,IAAI,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC/B,OAAO;gBACL,aAAa,EAAE,IAAI;gBACnB,aAAa,EAAE,SAAS,CAAC,IAAI;gBAC7B,SAAS,EAAE,SAAS,CAAC,KAAK;aAC3B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AAClC,CAAC,CAAC;AAEF;;GAEG;AACI,MAAM,gBAAgB,GAAG,CAAC,IAAqE,EAAW,EAAE;IACjH,kEAAkE;IAClE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7F,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACrC,IAAI,YAAY,IAAI,mBAAmB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oCAAoC;IACpC,MAAM,YAAY,GAAG,CAAC,IAAmB,EAAW,EAAE;QACpD,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,WAAW,EAAE,CAAC;YACxF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,8EAA8E;QAC9E,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,qBAAqB,EAAE,CAAC;YACvD,OAAO,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,cAAc,EAAE,CAAC;YAChD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC3B,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,eAAe,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAClE,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACrC,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC,CAAC;AA7BW,QAAA,gBAAgB,oBA6B3B;AAEF;;;GAGG;AACI,MAAM,wBAAwB,GAAG,CACtC,OAA6D,EAC7D,YAA6E,EAC7E,SAAiB,EACR,EAAE;IACX,sFAAsF;IACtF,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,gBAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAEzD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IAED,2EAA2E;IAC3E,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;QAClD,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC;QAC/B,OAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,gEAAgE;IAChE,MAAM,6BAA6B,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QAC3D,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;QAClC,IAAI,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC;QAEhC,wEAAwE;QACxE,sHAAsH;QACtH,OAAO,OAAO,EAAE,CAAC;YACf,2EAA2E;YAC3E,IAAI,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,sBAAsB,EAAE,CAAC;gBAC3D,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;gBACjC,IAAI,SAAS,CAAC,IAAI,KAAK,sBAAc,CAAC,YAAY,EAAE,CAAC;oBACnD,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YAED,qEAAqE;YACrE,IAAI,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,kBAAkB,EAAE,CAAC;gBACvD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,kFAAkF;YAClF,mFAAmF;YACnF,IAAI,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,eAAe,EAAE,CAAC;gBACpD,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;gBAClC,IACE,UAAU,CAAC,IAAI,KAAK,sBAAc,CAAC,cAAc;oBACjD,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU;oBACpD,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;wBACvC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;wBACpC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,aAAa;wBACxC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,CAAC,EACzC,CAAC;oBACD,OAAO,IAAI,CAAC,CAAC,+BAA+B;gBAC9C,CAAC;YACH,CAAC;YAED,6EAA6E;YAC7E,IACE,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,kBAAkB;gBAClD,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,oBAAoB;gBACpD,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,cAAc;gBAC9C,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,iBAAiB;gBACjD,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,qBAAqB;gBACrD,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,gBAAgB,EAChD,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,MAAM;YACR,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAC3B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,OAAO,6BAA6B,CAAC;AACvC,CAAC,CAAC;AAlFW,QAAA,wBAAwB,4BAkFnC;AAuBF;;GAEG;AACH,MAAM,oBAAoB,GAAG,CAAC,QAAmD,EAAW,EAAE;IAC5F,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;AAC7D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,4BAA4B,GAAG,CACnC,UAA+B,EAC/B,OAA6D,EACtC,EAAE;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,UAAU,CAAC,EAAE,QAAQ,CAAC;IAEvF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IAED,mCAAmC;IACnC,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,kDAAkD;QAClD,IAAI,UAAU,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACpC,qCAAqC;YACrC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;QACnE,CAAC;QAED,qEAAqE;QACrE,0EAA0E;QAC1E,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC;YAEnC,6DAA6D;YAC7D,IAAI,UAAU,CAAC,EAAE,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa,EAAE,CAAC;gBACxD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;gBAE7B,+DAA+D;gBAC/D,IAAI,IAAI,EAAE,IAAI,KAAK,sBAAc,CAAC,UAAU,EAAE,CAAC;oBAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACpD,MAAM,YAAY,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC,EAAE,QAAQ,CAAC;oBAEzF,IAAI,YAAY,IAAI,oBAAoB,CAAC,YAAY,CAAC,EAAE,CAAC;wBACvD,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,sBAAsB,EAAE,CAAC;oBACvE,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,wEAAwE;QACxE,+DAA+D;QAC/D,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,sBAAc,CAAC,QAAQ,EAAE,CAAC;YACrD,uEAAuE;YACvE,MAAM,aAAa,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YAC7C,IAAI,aAAa,CAAC,IAAI,KAAK,sBAAc,CAAC,aAAa,EAAE,CAAC;gBACxD,SAAS;YACX,CAAC;YAED,sDAAsD;YACtD,MAAM,mBAAmB,GAAG,aAAa,CAAC,MAAM,CAAC;YAEjD,IACE,mBAAmB,CAAC,IAAI,KAAK,sBAAc,CAAC,uBAAuB;gBACnE,mBAAmB,CAAC,IAAI,KAAK,sBAAc,CAAC,kBAAkB;gBAC9D,mBAAmB,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB,EAC/D,CAAC;gBACD,8CAA8C;gBAC9C,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;gBACnE,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,2BAA2B,EAAE,CAAC;gBAC5E,CAAC;YACH,CAAC;YAED,6EAA6E;YAC7E,IAAI,mBAAmB,CAAC,IAAI,KAAK,sBAAc,CAAC,iBAAiB,EAAE,CAAC;gBAClE,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,MAAM,CAAC;gBAEpD,IACE,gBAAgB,CAAC,IAAI,KAAK,sBAAc,CAAC,uBAAuB;oBAChE,gBAAgB,CAAC,IAAI,KAAK,sBAAc,CAAC,kBAAkB;oBAC3D,gBAAgB,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB,EAC5D,CAAC;oBACD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;oBACtE,IAAI,OAAO,EAAE,CAAC;wBACZ,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,2BAA2B,EAAE,CAAC;oBAC5E,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;AACpC,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACI,MAAM,yBAAyB,GAAG,CACvC,UAA+B,EAC/B,OAA6D,EACpD,EAAE,CAAC,4BAA4B,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,eAAe,CAAC;AAHnE,QAAA,yBAAyB,6BAG0C;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACI,MAAM,kCAAkC,GAAG,CAChD,UAA+B,EAC/B,OAA6D,EACpD,EAAE;IACX,gDAAgD;IAChD,IAAI,CAAC,IAAA,iCAAyB,EAAC,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC;QACpD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,oDAAoD;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,UAAU,CAAC,EAAE,QAAQ,CAAC;IAEvF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IAED,yCAAyC;IACzC,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,UAAU,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACpC,SAAS;QACX,CAAC;QAED,wFAAwF;QACxF,IAAI,YAAY,GAIL,IAAI,CAAC;QAEhB,IAAI,OAAO,GAA8B,UAAU,CAAC,IAAI,CAAC;QACzD,GAAG,CAAC;YACF,IACE,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,uBAAuB;gBACvD,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,kBAAkB;gBAClD,OAAO,CAAC,IAAI,KAAK,sBAAc,CAAC,mBAAmB,EACnD,CAAC;gBACD,YAAY,GAAG,OAAO,CAAC;gBACvB,MAAM;YACR,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAC3B,CAAC,QAAQ,OAAO,KAAK,SAAS,EAAE;QAEhC,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,SAAS;QACX,CAAC;QAED,iFAAiF;QACjF,oDAAoD;QACpD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;QACnC,IAAI,MAAM,CAAC,IAAI,KAAK,sBAAc,CAAC,sBAAsB,EAAE,CAAC;YAC1D,+DAA+D;YAC/D,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;YACzC,IACE,kBAAkB,CAAC,IAAI,KAAK,sBAAc,CAAC,UAAU;gBACrD,kBAAkB,CAAC,IAAI,KAAK,sBAAc,CAAC,WAAW,EACtD,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AA/DW,QAAA,kCAAkC,sCA+D7C","sourcesContent":["import { ASTUtils, AST_NODE_TYPES, TSESLint, TSESTree } from \"@typescript-eslint/utils\";\n\n/**\n * Utility functions for analyzing AST nodes and function structure in ESLint rules.\n *\n * ## Core Utilities\n * - `isInParameterList()` - Check if a node is in a function's parameter list\n *\n * ## Parameter Analysis (Parameter → Usage)\n * - `isParameterExplicitlyDestructured()` - Check if parameter is explicitly destructured\n * - `isParameterInitialized()` - Check if parameter has a default value\n * - `isParameterUsedInFunction()` - Check if parameter is used in function body\n * - `getParameterRestUsage()` - Get info about parameter accessed via rest params\n * - `hasExistingBodyInitializations()` - Check for initialization patterns in function body\n *\n * ## Identifier Origin Analysis (Usage → Origin)\n * - `getIdentifierParameterOrigin()` - Trace identifier back to see if it's from a parameter (rich return)\n * - `isIdentifierFromParameter()` - Boolean helper to check if identifier is from a parameter\n * - `isIdentifierFromRenderPropCallback()` - Check if identifier is from a render prop callback parameter\n *\n * ## JSX/React Specific\n * - `isReactComponent()` - Check if function is likely a React component\n * - `isParameterOnlyUsedInJSX()` - Check if parameter is only used in JSX attributes\n */\n\n/**\n * Helper function to check if a node is in the parameter list\n */\nconst isInParameterList = (\n node: TSESTree.Node,\n functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression\n): boolean => {\n let current = node.parent;\n while (current) {\n // Check if current node is one of the function parameters\n const isParam = functionNode.params.some(param => param === current);\n if (isParam) {\n return true;\n }\n current = current.parent;\n }\n return false;\n};\n\n/**\n * Check if a parameter is explicitly destructured in the parameter list\n * (vs. captured in rest parameters like ...restOptions)\n */\nexport const isParameterExplicitlyDestructured = (parameter: TSESTree.Parameter, paramName: string): boolean => {\n if (parameter.type !== AST_NODE_TYPES.ObjectPattern) {\n return false;\n }\n\n // Check if the parameter is explicitly listed in the destructuring\n return parameter.properties.some(property => {\n if (property.type === AST_NODE_TYPES.Property && property.key.type === AST_NODE_TYPES.Identifier) {\n return property.key.name === paramName;\n }\n return false;\n });\n};\n\n/**\n * Check if there are any existing parameter initializations in the function body\n */\nexport const hasExistingBodyInitializations = (functionBody: Array<TSESTree.Statement>): boolean => {\n for (const stmt of functionBody) {\n // Check for destructuring with defaults: const { param = defaultValue } = params\n if (\n stmt.type === AST_NODE_TYPES.VariableDeclaration &&\n stmt.declarations.length === 1 &&\n stmt.declarations[0].id.type === AST_NODE_TYPES.ObjectPattern &&\n stmt.declarations[0].id.properties.some(\n prop => prop.type === AST_NODE_TYPES.Property && prop.value.type === AST_NODE_TYPES.AssignmentPattern\n )\n ) {\n return true;\n }\n\n // Check for variable declarations with defaults: const param = params.param ?? defaultValue\n if (\n stmt.type === AST_NODE_TYPES.VariableDeclaration &&\n stmt.declarations.length === 1 &&\n stmt.declarations[0].init?.type === AST_NODE_TYPES.LogicalExpression &&\n (stmt.declarations[0].init.operator === \"??\" || stmt.declarations[0].init.operator === \"||\")\n ) {\n return true;\n }\n }\n return false;\n};\n\n/**\n * Check if a parameter is initialized in the function body or parameter defaults\n */\nexport const isParameterInitialized = (\n functionBody: Array<TSESTree.Statement>,\n paramName: string,\n parameter?: TSESTree.Parameter\n): boolean => {\n // First check if the parameter has a default value in the parameter destructuring\n if (parameter && parameter.type === AST_NODE_TYPES.ObjectPattern) {\n for (const property of parameter.properties) {\n if (property.type === AST_NODE_TYPES.Property && property.value.type === AST_NODE_TYPES.AssignmentPattern) {\n // Handle both identifier keys (paramName) and string literal keys (\"param-name\")\n const keyName =\n property.key.type === AST_NODE_TYPES.Identifier\n ? property.key.name\n : property.key.type === AST_NODE_TYPES.Literal && typeof property.key.value === \"string\"\n ? property.key.value\n : null;\n\n if (keyName === paramName) {\n return true; // Found default value in parameter: {paramName = defaultValue}\n }\n }\n }\n }\n\n // Then check for initialization patterns in the function body\n for (const stmt of functionBody) {\n // Check for destructuring with defaults: const { param = defaultValue } = params\n if (\n stmt.type === AST_NODE_TYPES.VariableDeclaration &&\n stmt.declarations.length === 1 &&\n stmt.declarations[0].id.type === AST_NODE_TYPES.ObjectPattern\n ) {\n const pattern = stmt.declarations[0].id;\n for (const property of pattern.properties) {\n if (\n property.type === AST_NODE_TYPES.Property &&\n property.key.type === AST_NODE_TYPES.Identifier &&\n property.key.name === paramName &&\n property.value.type === AST_NODE_TYPES.AssignmentPattern\n ) {\n return true;\n }\n }\n }\n\n // Check for variable declarations with defaults: const param = params.param ?? defaultValue\n if (\n stmt.type === AST_NODE_TYPES.VariableDeclaration &&\n stmt.declarations.length === 1 &&\n stmt.declarations[0].id.type === AST_NODE_TYPES.Identifier &&\n stmt.declarations[0].id.name === paramName &&\n stmt.declarations[0].init?.type === AST_NODE_TYPES.LogicalExpression &&\n (stmt.declarations[0].init.operator === \"??\" || stmt.declarations[0].init.operator === \"||\")\n ) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * Check if a parameter is used within the function body\n */\nexport const isParameterUsedInFunction = (\n context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>,\n functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n paramName: string\n): boolean => {\n // Use TypeScript-ESLint's built-in findVariable utility for more robust variable detection\n const scope = context.sourceCode.getScope(functionNode);\n const variable = ASTUtils.findVariable(scope, paramName);\n\n if (variable) {\n // Check if the variable has any references (excluding the parameter definition)\n const references = variable.references.filter(ref => {\n // Exclude the parameter declaration itself\n const refNode = ref.identifier;\n return !isInParameterList(refNode, functionNode);\n });\n\n // Additional check: if the variable is only referenced in object literal shorthand property names\n // (like { placement: result.placement }), it's not actually using the parameter variable\n const actualUsageReferences = references.filter(ref => {\n const parent = ref.identifier.parent;\n\n // Skip if this is just a property key in an object literal\n // Example: { placement: result.placement } - the first 'placement' is just a key, not usage\n if (\n parent.type === AST_NODE_TYPES.Property &&\n parent.key === ref.identifier &&\n parent.value !== ref.identifier &&\n !parent.shorthand\n ) {\n return false;\n }\n\n return true;\n });\n\n if (actualUsageReferences.length > 0) {\n return true;\n }\n }\n\n // If direct variable reference not found, check for member access on rest parameters\n // e.g., rest.paramName, params.paramName, etc.\n const restParameters: Array<{ name: string; param: TSESTree.Parameter }> = [];\n\n // Look for rest elements in both direct params and inside object patterns\n functionNode.params.forEach(param => {\n if (param.type === AST_NODE_TYPES.RestElement && param.argument.type === AST_NODE_TYPES.Identifier) {\n // Direct rest parameter: (...rest: Params)\n restParameters.push({ name: param.argument.name, param });\n } else if (param.type === AST_NODE_TYPES.ObjectPattern) {\n // Look for rest elements inside object patterns: ({ param1, ...rest }: Params)\n param.properties.forEach(property => {\n if (property.type === AST_NODE_TYPES.RestElement && property.argument.type === AST_NODE_TYPES.Identifier) {\n restParameters.push({ name: property.argument.name, param });\n }\n });\n }\n });\n\n if (restParameters.length === 0) {\n return false;\n }\n\n // Check if the function body contains rest.paramName patterns\n const functionText = context.sourceCode.getText(functionNode);\n\n for (const restParam of restParameters) {\n const pattern = new RegExp(`\\\\b${restParam.name}\\\\.${paramName}\\\\b`);\n if (pattern.test(functionText)) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * Check if a parameter is accessed via rest parameters (e.g., rest.paramName)\n * and return information about the rest parameter usage\n */\nconst getParameterRestUsage = (\n context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>,\n functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n paramName: string\n): { isUsedViaRest: boolean; restParamName?: string; restParam?: TSESTree.Parameter } | null => {\n // Look for rest elements in both direct params and inside object patterns\n const restParameters: Array<{ name: string; param: TSESTree.Parameter }> = [];\n\n functionNode.params.forEach(param => {\n if (param.type === AST_NODE_TYPES.RestElement && param.argument.type === AST_NODE_TYPES.Identifier) {\n // Direct rest parameter: (...rest: Params)\n restParameters.push({ name: param.argument.name, param });\n } else if (param.type === AST_NODE_TYPES.ObjectPattern) {\n // Look for rest elements inside object patterns: ({ param1, ...rest }: Params)\n param.properties.forEach(property => {\n if (property.type === AST_NODE_TYPES.RestElement && property.argument.type === AST_NODE_TYPES.Identifier) {\n restParameters.push({ name: property.argument.name, param });\n }\n });\n }\n });\n\n if (restParameters.length === 0) {\n return { isUsedViaRest: false };\n }\n\n // Check if the function body contains rest.paramName patterns\n const functionText = context.sourceCode.getText(functionNode);\n\n for (const restParam of restParameters) {\n const pattern = new RegExp(`\\\\b${restParam.name}\\\\.${paramName}\\\\b`);\n if (pattern.test(functionText)) {\n return {\n isUsedViaRest: true,\n restParamName: restParam.name,\n restParam: restParam.param,\n };\n }\n }\n\n return { isUsedViaRest: false };\n};\n\n/**\n * Check if a function is likely a React component based on naming and JSX usage\n */\nexport const isReactComponent = (node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression): boolean => {\n // Check if function name starts with uppercase (React convention)\n const functionName = node.type === AST_NODE_TYPES.FunctionDeclaration ? node.id?.name : null;\n const startsWithUppercase = /^[A-Z]/;\n if (functionName && startsWithUppercase.test(functionName)) {\n return true;\n }\n\n // Check if the function returns JSX\n const hasJSXReturn = (body: TSESTree.Node): boolean => {\n if (body.type === AST_NODE_TYPES.JSXElement || body.type === AST_NODE_TYPES.JSXFragment) {\n return true;\n }\n // Handle conditional expressions that contain JSX: condition ? <JSX /> : null\n if (body.type === AST_NODE_TYPES.ConditionalExpression) {\n return hasJSXReturn(body.consequent) || hasJSXReturn(body.alternate);\n }\n if (body.type === AST_NODE_TYPES.BlockStatement) {\n return body.body.some(stmt => {\n if (stmt.type === AST_NODE_TYPES.ReturnStatement && stmt.argument) {\n return hasJSXReturn(stmt.argument);\n }\n return false;\n });\n }\n return false;\n };\n\n return hasJSXReturn(node.body);\n};\n\n/**\n * Check if a parameter is only used in JSX attributes (pass-through to child components)\n * and nowhere else in the function body\n */\nexport const isParameterOnlyUsedInJSX = (\n context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>,\n functionNode: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression,\n paramName: string\n): boolean => {\n // Use TypeScript-ESLint's built-in findVariable utility for robust variable detection\n const scope = context.sourceCode.getScope(functionNode);\n const variable = ASTUtils.findVariable(scope, paramName);\n\n if (!variable) {\n return false;\n }\n\n // Get all references to the parameter (excluding the parameter definition)\n const references = variable.references.filter(ref => {\n const refNode = ref.identifier;\n return !isInParameterList(refNode, functionNode);\n });\n\n if (references.length === 0) {\n return false;\n }\n\n // Check if all references are only in JSX attribute expressions\n const allReferencesAreJSXAttributes = references.every(ref => {\n const identifier = ref.identifier;\n let current = identifier.parent;\n\n // Walk up the AST to find if this identifier is used in a JSX attribute\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions\n while (current) {\n // Check if we're in a JSX attribute expression: <Component prop={value} />\n if (current.type === AST_NODE_TYPES.JSXExpressionContainer) {\n const jsxParent = current.parent;\n if (jsxParent.type === AST_NODE_TYPES.JSXAttribute) {\n return true;\n }\n }\n\n // Check if we're in a JSX spread attribute: <Component {...props} />\n if (current.type === AST_NODE_TYPES.JSXSpreadAttribute) {\n return true;\n }\n\n // Allow dependency arrays for React hooks (useEffect, useMemo, useCallback, etc.)\n // These are acceptable for pass-through props since they're tracking the JSX usage\n if (current.type === AST_NODE_TYPES.ArrayExpression) {\n const callParent = current.parent;\n if (\n callParent.type === AST_NODE_TYPES.CallExpression &&\n callParent.callee.type === AST_NODE_TYPES.Identifier &&\n (callParent.callee.name.startsWith(\"use\") ||\n callParent.callee.name === \"useMemo\" ||\n callParent.callee.name === \"useCallback\" ||\n callParent.callee.name === \"useEffect\")\n ) {\n return true; // Allow dependency array usage\n }\n }\n\n // Stop if we reach certain node types that indicate we're not in JSX context\n if (\n current.type === AST_NODE_TYPES.VariableDeclarator ||\n current.type === AST_NODE_TYPES.AssignmentExpression ||\n current.type === AST_NODE_TYPES.CallExpression ||\n current.type === AST_NODE_TYPES.LogicalExpression ||\n current.type === AST_NODE_TYPES.ConditionalExpression ||\n current.type === AST_NODE_TYPES.BinaryExpression\n ) {\n return false;\n }\n\n if (!current.parent) {\n break;\n }\n current = current.parent;\n }\n\n return false;\n });\n\n return allReferencesAreJSXAttributes;\n};\n\n// ============================================================\n// Identifier Origin Analysis (traces usage back to definition)\n// ============================================================\n\n/**\n * Result of tracing an identifier back to its origin.\n * Used to distinguish between different ways an identifier can come from a function parameter.\n */\nexport type ParameterOriginResult =\n | {\n isFromParameter: true;\n /**\n * How the identifier relates to the parameter:\n * - \"direct-parameter\": Direct parameter, e.g., `(onClose) => ...`\n * - \"destructured-in-signature\": Destructured in function signature, e.g., `({ onClose }) => ...`\n * - \"destructured-in-body\": Destructured in function body, e.g., `const { onClose } = props`\n */\n originType: \"direct-parameter\" | \"destructured-in-signature\" | \"destructured-in-body\";\n }\n | { isFromParameter: false };\n\n/**\n * Checks if a variable is a function parameter.\n */\nconst isVariableAParameter = (variable: { defs: ReadonlyArray<{ type: string }> }): boolean => {\n return variable.defs.some(def => def.type === \"Parameter\");\n};\n\n/**\n * Traces an identifier back to determine if it originates from a function parameter.\n * Returns detailed information about how the identifier relates to the parameter.\n *\n * This is used to distinguish between:\n * - Props passed through: `({ onClose }) => <button onClick={onClose} />` - destructured-in-signature\n * - Props destructured in body: `(props) => { const { onClose } = props; }` - destructured-in-body\n * - Direct parameter: `(onClose) => ...` - direct-parameter\n * - Internal functions: `const handleClose = () => {}; <button onClick={handleClose} />` - not from parameter\n * - Hook results: `const { mutate } = useMutation(); <button onClick={mutate} />` - not from parameter\n *\n * @param identifier - The identifier node to check\n * @param context - The ESLint rule context\n * @returns ParameterOriginResult with isFromParameter and originType if applicable\n * @example\n * // Direct parameter\n * const MyComponent = (onClose) => <button onClick={onClose} />;\n * // getIdentifierParameterOrigin(onClose) => { isFromParameter: true, originType: \"direct-parameter\" }\n * @example\n * // Destructured in signature\n * const MyComponent = ({ onClose }) => <button onClick={onClose} />;\n * // getIdentifierParameterOrigin(onClose) => { isFromParameter: true, originType: \"destructured-in-signature\" }\n * @example\n * // Destructured in body\n * const MyComponent = (props) => {\n * const { onClose } = props;\n * return <button onClick={onClose} />;\n * };\n * // getIdentifierParameterOrigin(onClose) => { isFromParameter: true, originType: \"destructured-in-body\" }\n * @example\n * // Not from parameter (internal function)\n * const MyComponent = () => {\n * const handleClose = () => {};\n * return <button onClick={handleClose} />;\n * };\n * // getIdentifierParameterOrigin(handleClose) => { isFromParameter: false }\n */\nconst getIdentifierParameterOrigin = (\n identifier: TSESTree.Identifier,\n context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>\n): ParameterOriginResult => {\n const scope = context.sourceCode.getScope(identifier);\n const variable = scope.references.find(ref => ref.identifier === identifier)?.resolved;\n\n if (!variable) {\n return { isFromParameter: false };\n }\n\n // Check the variable's definitions\n for (const definition of variable.defs) {\n // Check if defined as a direct function parameter\n if (definition.type === \"Parameter\") {\n // Direct parameter: (onClose) => ...\n return { isFromParameter: true, originType: \"direct-parameter\" };\n }\n\n // Check for destructured variable in body: const { onClose } = props\n // definition.type is \"Variable\" and definition.node is VariableDeclarator\n if (definition.type === \"Variable\") {\n const declarator = definition.node;\n\n // Check if the left side is an ObjectPattern (destructuring)\n if (declarator.id.type === AST_NODE_TYPES.ObjectPattern) {\n const init = declarator.init;\n\n // Check if destructured from an identifier that is a parameter\n if (init?.type === AST_NODE_TYPES.Identifier) {\n const initScope = context.sourceCode.getScope(init);\n const initVariable = initScope.references.find(ref => ref.identifier === init)?.resolved;\n\n if (initVariable && isVariableAParameter(initVariable)) {\n return { isFromParameter: true, originType: \"destructured-in-body\" };\n }\n }\n }\n }\n\n // Check if it's a destructured parameter directly in function signature\n // Pattern: ({ onClose }) => ... or ({ onClose }: Props) => ...\n if (definition.node.type === AST_NODE_TYPES.Property) {\n // Check direct parent - should be ObjectPattern for destructured props\n const objectPattern = definition.node.parent;\n if (objectPattern.type !== AST_NODE_TYPES.ObjectPattern) {\n continue;\n }\n\n // Check if this ObjectPattern is a function parameter\n const objectPatternParent = objectPattern.parent;\n\n if (\n objectPatternParent.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n objectPatternParent.type === AST_NODE_TYPES.FunctionExpression ||\n objectPatternParent.type === AST_NODE_TYPES.FunctionDeclaration\n ) {\n // Check if the ObjectPattern is in the params\n const isParam = objectPatternParent.params.includes(objectPattern);\n if (isParam) {\n return { isFromParameter: true, originType: \"destructured-in-signature\" };\n }\n }\n\n // Also check for AssignmentPattern wrapper: ({ onClose = defaultFn }) => ...\n if (objectPatternParent.type === AST_NODE_TYPES.AssignmentPattern) {\n const assignmentParent = objectPatternParent.parent;\n\n if (\n assignmentParent.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n assignmentParent.type === AST_NODE_TYPES.FunctionExpression ||\n assignmentParent.type === AST_NODE_TYPES.FunctionDeclaration\n ) {\n const isParam = assignmentParent.params.includes(objectPatternParent);\n if (isParam) {\n return { isFromParameter: true, originType: \"destructured-in-signature\" };\n }\n }\n }\n }\n }\n\n return { isFromParameter: false };\n};\n\n/**\n * Checks if an identifier originates from a function parameter.\n * This is a simplified boolean helper that wraps `getIdentifierParameterOrigin`.\n *\n * Use this when you only need to know if an identifier comes from a parameter,\n * without needing to know how it was destructured.\n *\n * @param identifier - The identifier node to check\n * @param context - The ESLint rule context\n * @returns true if the identifier originates from a function parameter\n * @see getIdentifierParameterOrigin for detailed origin information\n */\nexport const isIdentifierFromParameter = (\n identifier: TSESTree.Identifier,\n context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>\n): boolean => getIdentifierParameterOrigin(identifier, context).isFromParameter;\n\n/**\n * Checks if an identifier's parameter comes from a render prop callback.\n *\n * Render prop pattern: `{callback => <Component onClick={callback} />}`\n *\n * The function detects when:\n * 1. The identifier comes from a parameter\n * 2. That parameter's function is inside a JSXExpressionContainer\n * 3. Which is a child of a JSXElement (render prop pattern)\n *\n * This is used to distinguish between:\n * - React component props: `const Modal = ({ onClose }) => ...` - should be flagged\n * - Render prop callbacks: `<MoreMenu>{close => <MenuItem onClick={close} />}</MoreMenu>` - should NOT be flagged\n *\n * @param identifier - The identifier node to check\n * @param context - The ESLint rule context\n * @returns true if the identifier comes from a render prop callback parameter\n * @example\n * // Render prop callback - returns true\n * <MoreMenu>\n * {close => <MenuItem onClick={close} />}\n * </MoreMenu>\n * // isIdentifierFromRenderPropCallback(close) => true\n * @example\n * // React component prop - returns false\n * const Modal = ({ onClose }) => <button onClick={onClose} />;\n * // isIdentifierFromRenderPropCallback(onClose) => false\n */\nexport const isIdentifierFromRenderPropCallback = (\n identifier: TSESTree.Identifier,\n context: TSESLint.RuleContext<string, ReadonlyArray<unknown>>\n): boolean => {\n // First check if it even comes from a parameter\n if (!isIdentifierFromParameter(identifier, context)) {\n return false;\n }\n\n // Get the variable that this identifier resolves to\n const scope = context.sourceCode.getScope(identifier);\n const variable = scope.references.find(ref => ref.identifier === identifier)?.resolved;\n\n if (!variable) {\n return false;\n }\n\n // Check each definition of this variable\n for (const definition of variable.defs) {\n if (definition.type !== \"Parameter\") {\n continue;\n }\n\n // Find the function that contains this parameter by walking up from the definition node\n let functionNode:\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression\n | TSESTree.FunctionDeclaration\n | null = null;\n\n let current: TSESTree.Node | undefined = definition.node;\n do {\n if (\n current.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n current.type === AST_NODE_TYPES.FunctionExpression ||\n current.type === AST_NODE_TYPES.FunctionDeclaration\n ) {\n functionNode = current;\n break;\n }\n current = current.parent;\n } while (current !== undefined);\n\n if (!functionNode) {\n continue;\n }\n\n // Check if the function is inside a JSXExpressionContainer (render prop pattern)\n // Pattern: <Component>{callback => ...}</Component>\n const parent = functionNode.parent;\n if (parent.type === AST_NODE_TYPES.JSXExpressionContainer) {\n // Verify the JSXExpressionContainer is a child of a JSXElement\n const jsxContainerParent = parent.parent;\n if (\n jsxContainerParent.type === AST_NODE_TYPES.JSXElement ||\n jsxContainerParent.type === AST_NODE_TYPES.JSXFragment\n ) {\n return true;\n }\n }\n }\n\n return false;\n};\n"]}
|