@base44-preview/vite-plugin 0.2.27-pr.41.77be9cb → 0.2.27-pr.43.93e5e43

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.
Files changed (149) hide show
  1. package/dist/consts.d.ts +12 -0
  2. package/dist/consts.d.ts.map +1 -0
  3. package/dist/consts.js +12 -0
  4. package/dist/consts.js.map +1 -0
  5. package/dist/injections/visual-edit-agent.d.ts +1 -1
  6. package/dist/injections/visual-edit-agent.d.ts.map +1 -1
  7. package/dist/injections/visual-edit-agent.js +566 -1
  8. package/dist/injections/visual-edit-agent.js.map +1 -1
  9. package/dist/jsx-processor.d.ts +4 -1
  10. package/dist/jsx-processor.d.ts.map +1 -1
  11. package/dist/jsx-processor.js +33 -6
  12. package/dist/jsx-processor.js.map +1 -1
  13. package/dist/jsx-utils.d.ts +9 -0
  14. package/dist/jsx-utils.d.ts.map +1 -1
  15. package/dist/jsx-utils.js +86 -0
  16. package/dist/jsx-utils.js.map +1 -1
  17. package/dist/processors/collection-id-processor.d.ts +20 -0
  18. package/dist/processors/collection-id-processor.d.ts.map +1 -0
  19. package/dist/processors/collection-id-processor.js +182 -0
  20. package/dist/processors/collection-id-processor.js.map +1 -0
  21. package/dist/processors/collection-item-field-processor.d.ts +39 -0
  22. package/dist/processors/collection-item-field-processor.d.ts.map +1 -0
  23. package/dist/processors/collection-item-field-processor.js +281 -0
  24. package/dist/processors/collection-item-field-processor.js.map +1 -0
  25. package/dist/processors/collection-item-id-processor.d.ts +12 -0
  26. package/dist/processors/collection-item-id-processor.d.ts.map +1 -0
  27. package/dist/processors/collection-item-id-processor.js +50 -0
  28. package/dist/processors/collection-item-id-processor.js.map +1 -0
  29. package/dist/processors/collection-reference-field-processor.d.ts +31 -0
  30. package/dist/processors/collection-reference-field-processor.d.ts.map +1 -0
  31. package/dist/processors/collection-reference-field-processor.js +174 -0
  32. package/dist/processors/collection-reference-field-processor.js.map +1 -0
  33. package/dist/processors/collection-tracing-utils.d.ts +36 -0
  34. package/dist/processors/collection-tracing-utils.d.ts.map +1 -0
  35. package/dist/processors/collection-tracing-utils.js +390 -0
  36. package/dist/processors/collection-tracing-utils.js.map +1 -0
  37. package/dist/processors/shared-utils.d.ts +77 -0
  38. package/dist/processors/shared-utils.d.ts.map +1 -1
  39. package/dist/processors/shared-utils.js +525 -0
  40. package/dist/processors/shared-utils.js.map +1 -1
  41. package/dist/processors/static-array-processor.d.ts +2 -3
  42. package/dist/processors/static-array-processor.d.ts.map +1 -1
  43. package/dist/processors/static-array-processor.js +2 -3
  44. package/dist/processors/static-array-processor.js.map +1 -1
  45. package/dist/statics/index.mjs +2 -2
  46. package/dist/statics/index.mjs.map +1 -1
  47. package/dist/types.d.ts +5 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +2 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/visual-edit-plugin.d.ts +0 -1
  52. package/dist/visual-edit-plugin.d.ts.map +1 -1
  53. package/dist/visual-edit-plugin.js +29 -178
  54. package/dist/visual-edit-plugin.js.map +1 -1
  55. package/package.json +1 -1
  56. package/src/consts.ts +12 -0
  57. package/src/injections/visual-edit-agent.ts +698 -1
  58. package/src/jsx-processor.ts +41 -14
  59. package/src/jsx-utils.ts +116 -0
  60. package/src/processors/collection-id-processor.ts +261 -0
  61. package/src/processors/collection-item-field-processor.ts +433 -0
  62. package/src/processors/collection-item-id-processor.ts +69 -0
  63. package/src/processors/collection-reference-field-processor.ts +225 -0
  64. package/src/processors/collection-tracing-utils.ts +507 -0
  65. package/src/processors/shared-utils.ts +671 -0
  66. package/src/processors/static-array-processor.ts +6 -3
  67. package/src/types.ts +4 -0
  68. package/src/visual-edit-plugin.ts +34 -215
  69. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.d.ts +0 -25
  70. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.d.ts.map +0 -1
  71. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.js +0 -95
  72. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.js.map +0 -1
  73. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.d.ts +0 -4
  74. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.d.ts.map +0 -1
  75. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.js +0 -4
  76. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.js.map +0 -1
  77. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.d.ts +0 -9
  78. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.d.ts.map +0 -1
  79. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.js +0 -26
  80. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.js.map +0 -1
  81. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.d.ts +0 -17
  82. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.d.ts.map +0 -1
  83. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.js +0 -76
  84. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.js.map +0 -1
  85. package/dist/injections/visual-edit-agent/constants.d.ts +0 -10
  86. package/dist/injections/visual-edit-agent/constants.d.ts.map +0 -1
  87. package/dist/injections/visual-edit-agent/constants.js +0 -10
  88. package/dist/injections/visual-edit-agent/constants.js.map +0 -1
  89. package/dist/injections/visual-edit-agent/handlers/click-handlers.d.ts +0 -10
  90. package/dist/injections/visual-edit-agent/handlers/click-handlers.d.ts.map +0 -1
  91. package/dist/injections/visual-edit-agent/handlers/click-handlers.js +0 -117
  92. package/dist/injections/visual-edit-agent/handlers/click-handlers.js.map +0 -1
  93. package/dist/injections/visual-edit-agent/handlers/hover-handlers.d.ts +0 -14
  94. package/dist/injections/visual-edit-agent/handlers/hover-handlers.d.ts.map +0 -1
  95. package/dist/injections/visual-edit-agent/handlers/hover-handlers.js +0 -64
  96. package/dist/injections/visual-edit-agent/handlers/hover-handlers.js.map +0 -1
  97. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.d.ts +0 -14
  98. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.d.ts.map +0 -1
  99. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.js +0 -114
  100. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.js.map +0 -1
  101. package/dist/injections/visual-edit-agent/handlers/message-handlers.d.ts +0 -26
  102. package/dist/injections/visual-edit-agent/handlers/message-handlers.d.ts.map +0 -1
  103. package/dist/injections/visual-edit-agent/handlers/message-handlers.js +0 -148
  104. package/dist/injections/visual-edit-agent/handlers/message-handlers.js.map +0 -1
  105. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.d.ts +0 -7
  106. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.d.ts.map +0 -1
  107. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.js +0 -54
  108. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.js.map +0 -1
  109. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.d.ts +0 -11
  110. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.d.ts.map +0 -1
  111. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.js +0 -32
  112. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.js.map +0 -1
  113. package/dist/injections/visual-edit-agent/handlers/messages/types.d.ts +0 -105
  114. package/dist/injections/visual-edit-agent/handlers/messages/types.d.ts.map +0 -1
  115. package/dist/injections/visual-edit-agent/handlers/messages/types.js +0 -28
  116. package/dist/injections/visual-edit-agent/handlers/messages/types.js.map +0 -1
  117. package/dist/injections/visual-edit-agent/index.d.ts +0 -6
  118. package/dist/injections/visual-edit-agent/index.d.ts.map +0 -1
  119. package/dist/injections/visual-edit-agent/index.js +0 -109
  120. package/dist/injections/visual-edit-agent/index.js.map +0 -1
  121. package/dist/injections/visual-edit-agent/state/agent-state.d.ts +0 -17
  122. package/dist/injections/visual-edit-agent/state/agent-state.d.ts.map +0 -1
  123. package/dist/injections/visual-edit-agent/state/agent-state.js +0 -18
  124. package/dist/injections/visual-edit-agent/state/agent-state.js.map +0 -1
  125. package/dist/injections/visual-edit-agent/ui/overlay.d.ts +0 -26
  126. package/dist/injections/visual-edit-agent/ui/overlay.d.ts.map +0 -1
  127. package/dist/injections/visual-edit-agent/ui/overlay.js +0 -104
  128. package/dist/injections/visual-edit-agent/ui/overlay.js.map +0 -1
  129. package/dist/injections/visual-edit-agent/utils/dom-utils.d.ts +0 -14
  130. package/dist/injections/visual-edit-agent/utils/dom-utils.d.ts.map +0 -1
  131. package/dist/injections/visual-edit-agent/utils/dom-utils.js +0 -34
  132. package/dist/injections/visual-edit-agent/utils/dom-utils.js.map +0 -1
  133. package/src/injections/visual-edit-agent/README.md +0 -222
  134. package/src/injections/visual-edit-agent/capabilities/inline-editing/core.ts +0 -120
  135. package/src/injections/visual-edit-agent/capabilities/inline-editing/index.ts +0 -10
  136. package/src/injections/visual-edit-agent/capabilities/inline-editing/styles.ts +0 -26
  137. package/src/injections/visual-edit-agent/capabilities/inline-editing/validation.ts +0 -87
  138. package/src/injections/visual-edit-agent/constants.ts +0 -9
  139. package/src/injections/visual-edit-agent/handlers/click-handlers.ts +0 -146
  140. package/src/injections/visual-edit-agent/handlers/hover-handlers.ts +0 -78
  141. package/src/injections/visual-edit-agent/handlers/inline-edit-handlers.ts +0 -146
  142. package/src/injections/visual-edit-agent/handlers/message-handlers.ts +0 -201
  143. package/src/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.ts +0 -65
  144. package/src/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.ts +0 -40
  145. package/src/injections/visual-edit-agent/handlers/messages/types.ts +0 -134
  146. package/src/injections/visual-edit-agent/index.ts +0 -121
  147. package/src/injections/visual-edit-agent/state/agent-state.ts +0 -31
  148. package/src/injections/visual-edit-agent/ui/overlay.ts +0 -126
  149. package/src/injections/visual-edit-agent/utils/dom-utils.ts +0 -39
@@ -1,14 +1,26 @@
1
1
  import type { NodePath } from "@babel/traverse";
2
2
  import type * as t from "@babel/types";
3
+ import { CollectionIdProcessor } from "./processors/collection-id-processor.js";
4
+ import { ReferenceFieldProcessor } from "./processors/collection-reference-field-processor.js";
5
+ import { DataItemIdProcessor } from "./processors/collection-item-id-processor.js";
6
+ import { DataItemFieldProcessor } from "./processors/collection-item-field-processor.js";
3
7
  import { StaticArrayProcessor } from "./processors/static-array-processor.js";
4
8
 
5
9
  export class JSXProcessor {
10
+ private collectionIdProcessor: CollectionIdProcessor;
11
+ private referenceFieldProcessor: ReferenceFieldProcessor;
12
+ private dataItemIdProcessor: DataItemIdProcessor;
13
+ private dataItemFieldProcessor: DataItemFieldProcessor;
6
14
  private staticArrayProcessor: StaticArrayProcessor;
7
15
 
8
16
  constructor(
9
17
  private types: typeof t,
10
18
  private filename: string
11
19
  ) {
20
+ this.collectionIdProcessor = new CollectionIdProcessor(types);
21
+ this.referenceFieldProcessor = new ReferenceFieldProcessor(types);
22
+ this.dataItemIdProcessor = new DataItemIdProcessor(types);
23
+ this.dataItemFieldProcessor = new DataItemFieldProcessor(types);
12
24
  this.staticArrayProcessor = new StaticArrayProcessor(types);
13
25
  }
14
26
 
@@ -17,8 +29,13 @@ export class JSXProcessor {
17
29
 
18
30
  this.addSourceLocationAttribute(path);
19
31
  this.addDynamicContentAttribute(path);
20
- this.addContentEditableAttribute(path);
32
+
33
+ this.collectionIdProcessor.process(path);
34
+ this.referenceFieldProcessor.process(path);
35
+ this.dataItemIdProcessor.process(path);
36
+ this.dataItemFieldProcessor.process(path);
21
37
  this.staticArrayProcessor.process(path);
38
+
22
39
  }
23
40
 
24
41
  private addSourceLocationAttribute(
@@ -27,7 +44,7 @@ export class JSXProcessor {
27
44
  const { line, column } = path.node.loc?.start || { line: 1, column: 0 };
28
45
  const value = `${this.filename}:${line}:${column}`;
29
46
 
30
- path.node.attributes.push(
47
+ path.node.attributes.unshift(
31
48
  this.types.jsxAttribute(
32
49
  this.types.jsxIdentifier("data-source-location"),
33
50
  this.types.stringLiteral(value)
@@ -45,21 +62,19 @@ export class JSXProcessor {
45
62
  parentElement.node as t.JSXElement
46
63
  );
47
64
 
48
- path.node.attributes.push(
49
- this.types.jsxAttribute(
50
- this.types.jsxIdentifier("data-dynamic-content"),
51
- this.types.stringLiteral(isDynamic ? "true" : "false")
52
- )
65
+ const sourceLocIdx = path.node.attributes.findIndex(
66
+ (attr) =>
67
+ this.types.isJSXAttribute(attr) &&
68
+ this.types.isJSXIdentifier(attr.name) &&
69
+ attr.name.name === "data-source-location"
53
70
  );
54
- }
55
71
 
56
- private addContentEditableAttribute(
57
- path: NodePath<t.JSXOpeningElement>
58
- ): void {
59
- path.node.attributes.push(
72
+ path.node.attributes.splice(
73
+ sourceLocIdx + 1,
74
+ 0,
60
75
  this.types.jsxAttribute(
61
- this.types.jsxIdentifier("content-editable"),
62
- this.types.stringLiteral("true")
76
+ this.types.jsxIdentifier("data-dynamic-content"),
77
+ this.types.stringLiteral(isDynamic ? "true" : "false")
63
78
  )
64
79
  );
65
80
  }
@@ -137,6 +152,18 @@ export class JSXProcessor {
137
152
  }
138
153
  };
139
154
 
155
+ const attributes = jsxElement.openingElement?.attributes || [];
156
+ for (const attr of attributes) {
157
+ if (hasDynamicContent) break;
158
+ if (this.types.isJSXSpreadAttribute(attr)) {
159
+ hasDynamicContent = true;
160
+ break;
161
+ }
162
+ if (this.types.isJSXAttribute(attr) && attr.value) {
163
+ traverseNode(attr.value as unknown as Record<string, unknown>);
164
+ }
165
+ }
166
+
140
167
  for (const child of jsxElement.children) {
141
168
  if (hasDynamicContent) break;
142
169
  traverseNode(child as unknown as Record<string, unknown>);
package/src/jsx-utils.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type * as t from "@babel/types";
2
+ import { ALLOWED_CUSTOM_COMPONENTS } from "./consts.js";
2
3
 
3
4
  export class JSXUtils {
4
5
  private static types: typeof t;
@@ -12,4 +13,119 @@ export class JSXUtils {
12
13
  ? `${attr.name.namespace.name}:${attr.name.name.name}`
13
14
  : attr.name.name;
14
15
  }
16
+
17
+ static getElementName(node: t.JSXOpeningElement): string | null {
18
+ const name = node.name;
19
+
20
+ if (this.types.isJSXIdentifier(name)) {
21
+ return name.name;
22
+ }
23
+
24
+ if (this.types.isJSXNamespacedName(name)) {
25
+ return `${name.namespace.name}:${name.name.name}`;
26
+ }
27
+
28
+ if (this.types.isJSXMemberExpression(name)) {
29
+ return this.collectJSXMemberName(name);
30
+ }
31
+
32
+ return null;
33
+ }
34
+
35
+ private static collectJSXMemberName(
36
+ node: t.JSXMemberExpression
37
+ ): string {
38
+ const parts: string[] = [node.property.name];
39
+ let current: t.JSXMemberExpression["object"] = node.object;
40
+
41
+ while (this.types.isJSXMemberExpression(current)) {
42
+ parts.unshift(current.property.name);
43
+ current = current.object;
44
+ }
45
+
46
+ if (this.types.isJSXIdentifier(current)) {
47
+ parts.unshift(current.name);
48
+ }
49
+
50
+ return parts.join(".");
51
+ }
52
+
53
+ static isCustomComponent(name: string): boolean {
54
+ return name.length > 0 && name.charAt(0) === name.charAt(0).toUpperCase();
55
+ }
56
+
57
+ static isAllowedCustomComponent(name: string): boolean {
58
+ return ALLOWED_CUSTOM_COMPONENTS.includes(name);
59
+ }
60
+
61
+ static isDOMElement(name: string): boolean {
62
+ return name.length > 0 && name.charAt(0) === name.charAt(0).toLowerCase();
63
+ }
64
+
65
+ static isDOMOrAllowed(name: string): boolean {
66
+ return this.isDOMElement(name) || this.isAllowedCustomComponent(name);
67
+ }
68
+
69
+ static producesJSX(node: t.Expression | t.Node): boolean {
70
+ const types = this.types;
71
+
72
+ if (types.isJSXElement(node) || types.isJSXFragment(node)) return true;
73
+
74
+ if (types.isConditionalExpression(node)) {
75
+ return (
76
+ this.producesJSX(node.consequent) || this.producesJSX(node.alternate)
77
+ );
78
+ }
79
+
80
+ if (types.isLogicalExpression(node)) {
81
+ return this.producesJSX(node.left) || this.producesJSX(node.right);
82
+ }
83
+
84
+ if (types.isCallExpression(node)) {
85
+ if (types.isMemberExpression(node.callee)) {
86
+ const prop = node.callee.property;
87
+ if (
88
+ types.isIdentifier(prop) &&
89
+ (prop.name === "map" || prop.name === "flatMap")
90
+ ) {
91
+ const callback = node.arguments[0];
92
+ if (callback) return this.callbackProducesJSX(callback);
93
+ }
94
+ }
95
+ }
96
+
97
+ if (types.isParenthesizedExpression(node)) {
98
+ return this.producesJSX(node.expression);
99
+ }
100
+
101
+ return false;
102
+ }
103
+
104
+ private static callbackProducesJSX(
105
+ callback: t.Expression | t.SpreadElement | t.ArgumentPlaceholder
106
+ ): boolean {
107
+ const types = this.types;
108
+
109
+ if (types.isArrowFunctionExpression(callback)) {
110
+ if (types.isBlockStatement(callback.body)) {
111
+ return this.doesBlockReturnJSX(callback.body);
112
+ }
113
+ return this.producesJSX(callback.body);
114
+ }
115
+
116
+ if (types.isFunctionExpression(callback)) {
117
+ return this.doesBlockReturnJSX(callback.body);
118
+ }
119
+
120
+ return false;
121
+ }
122
+
123
+ static doesBlockReturnJSX(block: t.BlockStatement): boolean {
124
+ for (const stmt of block.body) {
125
+ if (this.types.isReturnStatement(stmt) && stmt.argument) {
126
+ if (this.producesJSX(stmt.argument)) return true;
127
+ }
128
+ }
129
+ return false;
130
+ }
15
131
  }
@@ -0,0 +1,261 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type * as t from "@babel/types";
3
+ import type { CollectionInfo } from "../types.js";
4
+ import {
5
+ DATA_COLLECTION_ID,
6
+ DATA_COLLECTION_REFERENCE,
7
+ MAX_JSX_DEPTH,
8
+ } from "../consts.js";
9
+ import { JSXUtils } from "../jsx-utils.js";
10
+ import {
11
+ JSXAttributeUtils,
12
+ PathNavigationUtils,
13
+ ExpressionAnalysisUtils,
14
+ } from "./shared-utils.js";
15
+ import { CollectionTracingUtils } from "./collection-tracing-utils.js";
16
+
17
+ export class CollectionIdProcessor {
18
+ private attributeUtils: JSXAttributeUtils;
19
+ private pathUtils: PathNavigationUtils;
20
+ private expressionUtils: ExpressionAnalysisUtils;
21
+ private tracingUtils: CollectionTracingUtils;
22
+
23
+ constructor(private types: typeof t) {
24
+ this.attributeUtils = new JSXAttributeUtils(types);
25
+ this.pathUtils = new PathNavigationUtils(types);
26
+ this.expressionUtils = new ExpressionAnalysisUtils(types);
27
+ this.tracingUtils = new CollectionTracingUtils(types);
28
+ }
29
+
30
+ process(path: NodePath<t.JSXOpeningElement>): void {
31
+ if (this.attributeUtils.hasAttribute(path, DATA_COLLECTION_ID)) return;
32
+
33
+ const info =
34
+ this.tryDirectMapInChildren(path) ??
35
+ this.tryGetByIdInChildren(path) ??
36
+ this.tryComponentRootWithCollectionProp(path);
37
+
38
+ if (!info) return;
39
+
40
+ const target = this.pathUtils.findDOMElementTarget(path) ?? path;
41
+
42
+ this.attributeUtils.addStringAttribute(target, DATA_COLLECTION_ID, info.id);
43
+
44
+ if (info.references.length > 0) {
45
+ this.attributeUtils.addStringAttribute(
46
+ target,
47
+ DATA_COLLECTION_REFERENCE,
48
+ info.references.join(",")
49
+ );
50
+ }
51
+ }
52
+
53
+ private tryDirectMapInChildren(
54
+ path: NodePath<t.JSXOpeningElement>
55
+ ): CollectionInfo | null {
56
+ const jsxElement = path.parentPath;
57
+ if (!jsxElement?.isJSXElement()) return null;
58
+
59
+ const children = jsxElement.get("children");
60
+ for (const child of children) {
61
+ if (!child.isJSXExpressionContainer()) continue;
62
+
63
+ const expression = child.get("expression");
64
+ if (expression.isJSXEmptyExpression()) continue;
65
+
66
+ const mapSource = this.extractMapSource(
67
+ expression as NodePath<t.Expression>
68
+ );
69
+ if (mapSource) return mapSource;
70
+ }
71
+
72
+ return null;
73
+ }
74
+
75
+ private extractMapSource(
76
+ expr: NodePath<t.Expression>
77
+ ): CollectionInfo | null {
78
+ if (expr.isCallExpression()) {
79
+ return this.traceMapCall(expr);
80
+ }
81
+
82
+ if (expr.isLogicalExpression()) {
83
+ if (expr.node.operator === "&&") {
84
+ const right = expr.get("right") as NodePath<t.Expression>;
85
+ return this.extractMapSource(right);
86
+ }
87
+ }
88
+
89
+ if (expr.isConditionalExpression()) {
90
+ const consequent = expr.get("consequent") as NodePath<t.Expression>;
91
+ const alternate = expr.get("alternate") as NodePath<t.Expression>;
92
+ return (
93
+ this.extractMapSource(consequent) ?? this.extractMapSource(alternate)
94
+ );
95
+ }
96
+
97
+ if (expr.isOptionalCallExpression()) {
98
+ return this.traceOptionalMapCall(expr);
99
+ }
100
+
101
+ return null;
102
+ }
103
+
104
+ private traceMapCall(
105
+ callPath: NodePath<t.CallExpression>
106
+ ): CollectionInfo | null {
107
+ const callee = callPath.get("callee");
108
+ if (!callee.isMemberExpression()) return null;
109
+
110
+ const property = callee.get("property") as NodePath;
111
+ if (
112
+ !property.isIdentifier() ||
113
+ (property.node.name !== "map" && property.node.name !== "flatMap")
114
+ ) {
115
+ return null;
116
+ }
117
+
118
+ if (!this.callbackProducesJSX(callPath)) return null;
119
+
120
+ const arrayObj = callee.get("object") as NodePath<t.Expression>;
121
+ return this.tracingUtils.traceCollectionSource(arrayObj);
122
+ }
123
+
124
+ private traceOptionalMapCall(
125
+ callPath: NodePath<t.OptionalCallExpression>
126
+ ): CollectionInfo | null {
127
+ const callee = callPath.get("callee");
128
+ if (
129
+ !callee.isMemberExpression() &&
130
+ !callee.isOptionalMemberExpression()
131
+ ) {
132
+ return null;
133
+ }
134
+
135
+ const property = (callee as NodePath<t.MemberExpression>).get(
136
+ "property"
137
+ ) as NodePath;
138
+ if (
139
+ !property.isIdentifier() ||
140
+ (property.node.name !== "map" && property.node.name !== "flatMap")
141
+ ) {
142
+ return null;
143
+ }
144
+
145
+ const arrayObj = (callee as NodePath<t.MemberExpression>).get(
146
+ "object"
147
+ ) as NodePath<t.Expression>;
148
+ return this.tracingUtils.traceCollectionSource(arrayObj);
149
+ }
150
+
151
+ private callbackProducesJSX(
152
+ callPath: NodePath<t.CallExpression>
153
+ ): boolean {
154
+ const args = callPath.get("arguments");
155
+ const callback = args[0];
156
+ if (!callback) return false;
157
+
158
+ if (callback.isArrowFunctionExpression()) {
159
+ const body = callback.get("body");
160
+ if (body.isBlockStatement()) {
161
+ return JSXUtils.doesBlockReturnJSX(body.node);
162
+ }
163
+ return JSXUtils.producesJSX(body.node);
164
+ }
165
+
166
+ if (callback.isFunctionExpression()) {
167
+ return JSXUtils.doesBlockReturnJSX(callback.node.body);
168
+ }
169
+
170
+ return false;
171
+ }
172
+
173
+ private tryGetByIdInChildren(
174
+ path: NodePath<t.JSXOpeningElement>,
175
+ depth: number = 0
176
+ ): CollectionInfo | null {
177
+ if (depth > MAX_JSX_DEPTH) return null;
178
+
179
+ const jsxElement = path.parentPath;
180
+ if (!jsxElement?.isJSXElement()) return null;
181
+
182
+ const children = jsxElement.get("children");
183
+ for (const child of children) {
184
+ const info = this.checkChildForGetById(child, depth);
185
+ if (info) return info;
186
+ }
187
+
188
+ for (const attr of path.node.attributes) {
189
+ if (
190
+ this.types.isJSXAttribute(attr) &&
191
+ attr.value &&
192
+ this.types.isJSXExpressionContainer(attr.value)
193
+ ) {
194
+ const expr = attr.value.expression;
195
+ if (this.types.isMemberExpression(expr)) {
196
+ const info = this.tracingUtils.traceGetByIdSource(path);
197
+ if (info) return info;
198
+ }
199
+ }
200
+ }
201
+
202
+ return null;
203
+ }
204
+
205
+ private checkChildForGetById(
206
+ child: NodePath,
207
+ depth: number
208
+ ): CollectionInfo | null {
209
+ if (child.isJSXExpressionContainer()) {
210
+ const expr = child.get("expression");
211
+ if (
212
+ expr.isMemberExpression() ||
213
+ expr.isOptionalMemberExpression()
214
+ ) {
215
+ return this.tracingUtils.traceGetByIdSource(child);
216
+ }
217
+ }
218
+
219
+ if (child.isJSXElement()) {
220
+ const childOpening = child.get("openingElement");
221
+ return this.tryGetByIdInChildren(childOpening, depth + 1);
222
+ }
223
+
224
+ return null;
225
+ }
226
+
227
+ private tryComponentRootWithCollectionProp(
228
+ path: NodePath<t.JSXOpeningElement>
229
+ ): CollectionInfo | null {
230
+ if (!this.pathUtils.isRootReturnElement(path)) return null;
231
+
232
+ const fn = this.pathUtils.findEnclosingFunction(path);
233
+ if (!fn) return null;
234
+
235
+ let info: CollectionInfo | null = null;
236
+
237
+ fn.traverse({
238
+ CallExpression: (callPath: NodePath<t.CallExpression>) => {
239
+ if (info) return;
240
+
241
+ const callee = callPath.get("callee");
242
+ if (!callee.isMemberExpression()) return;
243
+
244
+ const prop = callee.get("property") as NodePath;
245
+ if (
246
+ !prop.isIdentifier() ||
247
+ (prop.node.name !== "map" && prop.node.name !== "flatMap")
248
+ ) {
249
+ return;
250
+ }
251
+
252
+ if (!this.callbackProducesJSX(callPath)) return;
253
+
254
+ const arrayObj = callee.get("object") as NodePath<t.Expression>;
255
+ info = this.tracingUtils.traceCollectionSource(arrayObj);
256
+ },
257
+ });
258
+
259
+ return info;
260
+ }
261
+ }