@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,6 +1,7 @@
1
1
  import type { NodePath } from "@babel/traverse";
2
2
  import type * as t from "@babel/types";
3
3
  import { JSXUtils } from "../jsx-utils.js";
4
+ import { ALLOWED_CUSTOM_COMPONENTS, EXCLUDED_FIELDS } from "../consts.js";
4
5
 
5
6
  export class JSXAttributeUtils {
6
7
  constructor(private types: typeof t) {}
@@ -16,6 +17,32 @@ export class JSXAttributeUtils {
16
17
  );
17
18
  }
18
19
 
20
+ getAttributeValue(
21
+ path: NodePath<t.JSXOpeningElement>,
22
+ attributeName: string
23
+ ): t.JSXAttribute["value"] | null {
24
+ for (const attr of path.node.attributes) {
25
+ if (
26
+ this.types.isJSXAttribute(attr) &&
27
+ JSXUtils.getAttributeName(attr) === attributeName
28
+ ) {
29
+ return attr.value;
30
+ }
31
+ }
32
+ return null;
33
+ }
34
+
35
+ getAttributeStringValue(
36
+ path: NodePath<t.JSXOpeningElement>,
37
+ attributeName: string
38
+ ): string | null {
39
+ const value = this.getAttributeValue(path, attributeName);
40
+ if (value && this.types.isStringLiteral(value)) {
41
+ return value.value;
42
+ }
43
+ return null;
44
+ }
45
+
19
46
  addStringAttribute(
20
47
  path: NodePath<t.JSXOpeningElement>,
21
48
  attributeName: string,
@@ -45,6 +72,551 @@ export class JSXAttributeUtils {
45
72
  );
46
73
  }
47
74
  }
75
+
76
+ findAncestorWithAttribute(
77
+ path: NodePath,
78
+ attributeName: string
79
+ ): NodePath<t.JSXOpeningElement> | null {
80
+ let current: NodePath | null = path.parentPath;
81
+ while (current) {
82
+ if (current.isJSXElement()) {
83
+ const opening = current.get("openingElement");
84
+ if (this.hasAttribute(opening, attributeName)) {
85
+ return opening;
86
+ }
87
+ }
88
+ current = current.parentPath;
89
+ }
90
+ return null;
91
+ }
92
+ }
93
+
94
+ export class PathNavigationUtils {
95
+ constructor(private types: typeof t) {}
96
+
97
+ findParentJSXElement(
98
+ path: NodePath
99
+ ): NodePath<t.JSXElement> | null {
100
+ let current: NodePath | null = path.parentPath;
101
+ while (current) {
102
+ if (current.isJSXElement()) return current;
103
+ current = current.parentPath;
104
+ }
105
+ return null;
106
+ }
107
+
108
+ findEnclosingFunction(
109
+ path: NodePath
110
+ ): NodePath<t.Function> | null {
111
+ let current: NodePath | null = path.parentPath;
112
+ while (current) {
113
+ if (current.isFunction()) return current as NodePath<t.Function>;
114
+ current = current.parentPath;
115
+ }
116
+ return null;
117
+ }
118
+
119
+ findReturnStatement(
120
+ path: NodePath
121
+ ): NodePath<t.ReturnStatement> | null {
122
+ let current: NodePath | null = path.parentPath;
123
+ while (current) {
124
+ if (current.isReturnStatement()) return current;
125
+ current = current.parentPath;
126
+ }
127
+ return null;
128
+ }
129
+
130
+ isRootReturnElement(
131
+ path: NodePath<t.JSXOpeningElement>
132
+ ): boolean {
133
+ const jsxElement = path.parentPath;
134
+ if (!jsxElement?.isJSXElement()) return false;
135
+
136
+ const parent = jsxElement.parentPath;
137
+ if (!parent) return false;
138
+
139
+ if (parent.isReturnStatement()) return true;
140
+
141
+ if (parent.isArrowFunctionExpression()) return true;
142
+
143
+ if (parent.isParenthesizedExpression()) {
144
+ const grandparent = parent.parentPath;
145
+ if (grandparent?.isReturnStatement()) return true;
146
+ if (grandparent?.isArrowFunctionExpression()) return true;
147
+ }
148
+
149
+ return false;
150
+ }
151
+
152
+ findDOMElementTarget(
153
+ path: NodePath<t.JSXOpeningElement>
154
+ ): NodePath<t.JSXOpeningElement> | null {
155
+ if (this.isDOMOrAllowedElement(path)) return path;
156
+
157
+ let current: NodePath | null = path.parentPath;
158
+ while (current) {
159
+ if (current.isJSXElement()) {
160
+ const opening = current.get("openingElement");
161
+ if (this.isDOMOrAllowedElement(opening)) return opening;
162
+ }
163
+ current = current.parentPath;
164
+ }
165
+ return null;
166
+ }
167
+
168
+ private isDOMOrAllowedElement(
169
+ path: NodePath<t.JSXOpeningElement>
170
+ ): boolean {
171
+ const name = JSXUtils.getElementName(path.node);
172
+ if (!name) return false;
173
+
174
+ if (name.charAt(0) === name.charAt(0).toLowerCase()) return true;
175
+
176
+ return ALLOWED_CUSTOM_COMPONENTS.includes(name);
177
+ }
178
+ }
179
+
180
+ export class ExpressionAnalysisUtils {
181
+ constructor(private types: typeof t) {}
182
+
183
+ isIdAccess(node: t.Expression): boolean {
184
+ if (!this.types.isMemberExpression(node)) return false;
185
+ if (this.types.isIdentifier(node.property)) {
186
+ return node.property.name === "_id" || node.property.name === "id";
187
+ }
188
+ if (this.types.isStringLiteral(node.property)) {
189
+ return node.property.value === "_id" || node.property.value === "id";
190
+ }
191
+ return false;
192
+ }
193
+
194
+ isItemsAccess(node: t.Expression): boolean {
195
+ return (
196
+ this.types.isMemberExpression(node) &&
197
+ this.types.isIdentifier(node.property) &&
198
+ node.property.name === "items"
199
+ );
200
+ }
201
+
202
+ isLengthAccess(node: t.Expression): boolean {
203
+ return (
204
+ this.types.isMemberExpression(node) &&
205
+ this.types.isIdentifier(node.property) &&
206
+ node.property.name === "length"
207
+ );
208
+ }
209
+
210
+ extractRootIdentifier(node: t.Expression): t.Identifier | null {
211
+ if (this.types.isIdentifier(node)) return node;
212
+ if (this.types.isMemberExpression(node)) {
213
+ return this.extractRootIdentifier(node.object as t.Expression);
214
+ }
215
+ if (this.types.isOptionalMemberExpression(node)) {
216
+ return this.extractRootIdentifier(node.object as t.Expression);
217
+ }
218
+ if (this.types.isCallExpression(node) && this.types.isMemberExpression(node.callee)) {
219
+ return this.extractRootIdentifier(node.callee.object as t.Expression);
220
+ }
221
+ return null;
222
+ }
223
+
224
+ unwrapLogicalExpression(node: t.Expression): t.Expression {
225
+ if (this.types.isLogicalExpression(node)) {
226
+ if (node.operator === "&&") return node.right as t.Expression;
227
+ if (node.operator === "||" || node.operator === "??") {
228
+ return node.left as t.Expression;
229
+ }
230
+ }
231
+ return node;
232
+ }
233
+
234
+ collectMemberExpressionPath(node: t.Expression): string[] {
235
+ const parts: string[] = [];
236
+ let current: t.Expression = node;
237
+
238
+ while (
239
+ this.types.isMemberExpression(current) ||
240
+ this.types.isOptionalMemberExpression(current)
241
+ ) {
242
+ const prop = (current as t.MemberExpression).property;
243
+ if (this.types.isIdentifier(prop)) {
244
+ parts.unshift(prop.name);
245
+ } else if (this.types.isStringLiteral(prop)) {
246
+ parts.unshift(prop.value);
247
+ }
248
+ current = (current as t.MemberExpression).object as t.Expression;
249
+ }
250
+
251
+ if (this.types.isIdentifier(current)) {
252
+ parts.unshift(current.name);
253
+ }
254
+
255
+ return parts;
256
+ }
257
+
258
+ createOptionalChainExpression(
259
+ node: t.MemberExpression
260
+ ): t.OptionalMemberExpression {
261
+ const object = this.types.isOptionalMemberExpression(node.object)
262
+ ? node.object
263
+ : this.types.isMemberExpression(node.object)
264
+ ? this.createOptionalChainExpression(node.object)
265
+ : node.object;
266
+
267
+ const property = node.property as t.Expression;
268
+
269
+ return this.types.optionalMemberExpression(
270
+ object,
271
+ property,
272
+ node.computed,
273
+ true
274
+ );
275
+ }
276
+
277
+ getFieldPathFromExpression(
278
+ node: t.Expression,
279
+ rootName: string
280
+ ): string | null {
281
+ const parts = this.collectMemberExpressionPath(node);
282
+ if (parts.length < 2) return null;
283
+ if (parts[0] !== rootName) return null;
284
+
285
+ const fieldParts = parts.slice(1);
286
+ const fieldPath = fieldParts.join(".");
287
+
288
+ if (EXCLUDED_FIELDS.includes(fieldPath)) return null;
289
+ return fieldPath;
290
+ }
291
+ }
292
+
293
+ export class BindingUtils {
294
+ constructor(private types: typeof t) {}
295
+
296
+ isFunctionParameter(
297
+ identifierName: string,
298
+ path: NodePath
299
+ ): boolean {
300
+ const fn = path.getFunctionParent();
301
+ if (!fn) return false;
302
+
303
+ const params = fn.get("params");
304
+ for (const param of (Array.isArray(params) ? params : [params])) {
305
+ if (param.isIdentifier() && param.node.name === identifierName) {
306
+ return true;
307
+ }
308
+ if (param.isObjectPattern()) {
309
+ for (const prop of param.get("properties")) {
310
+ if (
311
+ prop.isObjectProperty() &&
312
+ this.types.isIdentifier(prop.node.value) &&
313
+ prop.node.value.name === identifierName
314
+ ) {
315
+ return true;
316
+ }
317
+ }
318
+ }
319
+ if (param.isArrayPattern()) {
320
+ for (const el of param.get("elements")) {
321
+ if (el.isIdentifier() && el.node.name === identifierName) {
322
+ return true;
323
+ }
324
+ }
325
+ }
326
+ }
327
+ return false;
328
+ }
329
+
330
+ isUseStateCall(
331
+ init: NodePath<t.Node>
332
+ ): { stateIndex: number; setterName: string | null } | null {
333
+ if (!init.isCallExpression()) return null;
334
+
335
+ const callee = init.get("callee");
336
+ if (!callee.isIdentifier() || callee.node.name !== "useState") return null;
337
+
338
+ const declarator = init.parentPath;
339
+ if (!declarator?.isVariableDeclarator()) return null;
340
+
341
+ const id = declarator.get("id");
342
+ if (!id.isArrayPattern()) return null;
343
+
344
+ const elements = id.get("elements");
345
+ const setterEl = elements[1];
346
+ const setterName =
347
+ setterEl && setterEl.isIdentifier() ? setterEl.node.name : null;
348
+
349
+ return { stateIndex: 0, setterName };
350
+ }
351
+
352
+ isPromiseAllCall(
353
+ init: NodePath<t.Node>
354
+ ): boolean {
355
+ if (!init.isAwaitExpression()) {
356
+ if (init.isCallExpression()) {
357
+ const callee = init.get("callee");
358
+ return this.isPromiseAllCallee(callee);
359
+ }
360
+ return false;
361
+ }
362
+
363
+ const argument = init.get("argument");
364
+ if (!argument.isCallExpression()) return false;
365
+
366
+ const callee = argument.get("callee");
367
+ return this.isPromiseAllCallee(callee);
368
+ }
369
+
370
+ private isPromiseAllCallee(callee: NodePath): boolean {
371
+ if (!callee.isMemberExpression()) return false;
372
+ const obj = callee.get("object") as NodePath;
373
+ const prop = callee.get("property") as NodePath;
374
+ return (
375
+ obj.isIdentifier() &&
376
+ obj.node.name === "Promise" &&
377
+ prop.isIdentifier() &&
378
+ prop.node.name === "all"
379
+ );
380
+ }
381
+
382
+ extractDestructuredProperties(
383
+ pattern: t.ObjectPattern
384
+ ): string[] {
385
+ const properties: string[] = [];
386
+ for (const prop of pattern.properties) {
387
+ if (this.types.isObjectProperty(prop)) {
388
+ if (this.types.isIdentifier(prop.key)) {
389
+ properties.push(prop.key.name);
390
+ } else if (this.types.isStringLiteral(prop.key)) {
391
+ properties.push(prop.key.value);
392
+ }
393
+ }
394
+ }
395
+ return properties;
396
+ }
397
+
398
+ findSetterCallInScope(
399
+ setterName: string,
400
+ scope: NodePath
401
+ ): NodePath<t.CallExpression> | null {
402
+ let result: NodePath<t.CallExpression> | null = null;
403
+
404
+ scope.traverse({
405
+ CallExpression(callPath) {
406
+ if (result) return;
407
+ const callee = callPath.get("callee");
408
+ if (callee.isIdentifier() && callee.node.name === setterName) {
409
+ result = callPath;
410
+ }
411
+ },
412
+ });
413
+
414
+ return result;
415
+ }
416
+ }
417
+
418
+ export class CallExpressionUtils {
419
+ constructor(private types: typeof t) {}
420
+
421
+ isGetAllCall(
422
+ node: t.CallExpression
423
+ ): { collectionName: string; references: string[] } | null {
424
+ const callee = node.callee;
425
+ if (!this.types.isMemberExpression(callee)) return null;
426
+
427
+ const obj = callee.object;
428
+ const prop = callee.property;
429
+
430
+ if (
431
+ !this.types.isIdentifier(obj) ||
432
+ obj.name !== "BaseCrudService" ||
433
+ !this.types.isIdentifier(prop) ||
434
+ prop.name !== "getAll"
435
+ ) {
436
+ return null;
437
+ }
438
+
439
+ const args = node.arguments;
440
+ if (args.length < 1) return null;
441
+
442
+ const firstArg = args[0];
443
+ if (!this.types.isStringLiteral(firstArg)) return null;
444
+
445
+ const collectionName = firstArg.value;
446
+ const references = this.extractReferencesFromArg(args[1]);
447
+
448
+ return { collectionName, references };
449
+ }
450
+
451
+ isGetByIdCall(
452
+ node: t.CallExpression
453
+ ): {
454
+ collectionName: string;
455
+ multiRefFields: string[];
456
+ } | null {
457
+ const callee = node.callee;
458
+ if (!this.types.isMemberExpression(callee)) return null;
459
+
460
+ const obj = callee.object;
461
+ const prop = callee.property;
462
+
463
+ if (
464
+ !this.types.isIdentifier(obj) ||
465
+ obj.name !== "BaseCrudService" ||
466
+ !this.types.isIdentifier(prop) ||
467
+ prop.name !== "getById"
468
+ ) {
469
+ return null;
470
+ }
471
+
472
+ const args = node.arguments;
473
+ if (args.length < 1) return null;
474
+
475
+ const firstArg = args[0];
476
+ if (!this.types.isStringLiteral(firstArg)) return null;
477
+
478
+ const collectionName = firstArg.value;
479
+ const multiRefFields = this.extractMultiRefFromOptions(args[2]);
480
+
481
+ return { collectionName, multiRefFields };
482
+ }
483
+
484
+ private extractReferencesFromArg(
485
+ arg: t.Expression | t.SpreadElement | t.ArgumentPlaceholder | undefined
486
+ ): string[] {
487
+ if (!arg || !this.types.isArrayExpression(arg)) return [];
488
+
489
+ return arg.elements
490
+ .filter((el): el is t.StringLiteral => this.types.isStringLiteral(el))
491
+ .map((el) => el.value);
492
+ }
493
+
494
+ private extractMultiRefFromOptions(
495
+ arg: t.Expression | t.SpreadElement | t.ArgumentPlaceholder | undefined
496
+ ): string[] {
497
+ if (!arg || !this.types.isObjectExpression(arg)) return [];
498
+
499
+ for (const prop of arg.properties) {
500
+ if (
501
+ this.types.isObjectProperty(prop) &&
502
+ this.types.isIdentifier(prop.key) &&
503
+ prop.key.name === "multiRef" &&
504
+ this.types.isArrayExpression(prop.value)
505
+ ) {
506
+ return prop.value.elements
507
+ .filter((el): el is t.StringLiteral =>
508
+ this.types.isStringLiteral(el)
509
+ )
510
+ .map((el) => el.value);
511
+ }
512
+ }
513
+ return [];
514
+ }
515
+
516
+ isArrayMethod(
517
+ node: t.CallExpression,
518
+ methodName: string
519
+ ): boolean {
520
+ const callee = node.callee;
521
+ return (
522
+ this.types.isMemberExpression(callee) &&
523
+ this.types.isIdentifier(callee.property) &&
524
+ callee.property.name === methodName
525
+ );
526
+ }
527
+
528
+ isChainedArrayMethod(node: t.CallExpression): boolean {
529
+ const chainMethods = ["filter", "sort", "slice", "concat", "reverse", "flat"];
530
+ return chainMethods.some((m) => this.isArrayMethod(node, m));
531
+ }
532
+
533
+ /**
534
+ * Detect base44.entities.EntityName.list() or .getAll() patterns.
535
+ * Returns the entity name as the collection name.
536
+ */
537
+ isBase44EntityListCall(
538
+ node: t.CallExpression
539
+ ): { collectionName: string } | null {
540
+ const callee = node.callee;
541
+ if (!this.types.isMemberExpression(callee)) return null;
542
+
543
+ const method = callee.property;
544
+ if (
545
+ !this.types.isIdentifier(method) ||
546
+ (method.name !== "list" && method.name !== "getAll")
547
+ ) {
548
+ return null;
549
+ }
550
+
551
+ const entityAccess = callee.object;
552
+ if (!this.types.isMemberExpression(entityAccess)) return null;
553
+
554
+ const entityName = entityAccess.property;
555
+ if (!this.types.isIdentifier(entityName)) return null;
556
+
557
+ const entitiesAccess = entityAccess.object;
558
+ if (!this.types.isMemberExpression(entitiesAccess)) return null;
559
+
560
+ const entitiesProp = entitiesAccess.property;
561
+ if (
562
+ !this.types.isIdentifier(entitiesProp) ||
563
+ entitiesProp.name !== "entities"
564
+ ) {
565
+ return null;
566
+ }
567
+
568
+ return { collectionName: entityName.name };
569
+ }
570
+
571
+ /**
572
+ * Detect base44.entities.EntityName.getById() or .get() patterns.
573
+ */
574
+ isBase44EntityGetCall(
575
+ node: t.CallExpression
576
+ ): { collectionName: string } | null {
577
+ const callee = node.callee;
578
+ if (!this.types.isMemberExpression(callee)) return null;
579
+
580
+ const method = callee.property;
581
+ if (
582
+ !this.types.isIdentifier(method) ||
583
+ (method.name !== "get" && method.name !== "getById")
584
+ ) {
585
+ return null;
586
+ }
587
+
588
+ const entityAccess = callee.object;
589
+ if (!this.types.isMemberExpression(entityAccess)) return null;
590
+
591
+ const entityName = entityAccess.property;
592
+ if (!this.types.isIdentifier(entityName)) return null;
593
+
594
+ const entitiesAccess = entityAccess.object;
595
+ if (!this.types.isMemberExpression(entitiesAccess)) return null;
596
+
597
+ const entitiesProp = entitiesAccess.property;
598
+ if (
599
+ !this.types.isIdentifier(entitiesProp) ||
600
+ entitiesProp.name !== "entities"
601
+ ) {
602
+ return null;
603
+ }
604
+
605
+ return { collectionName: entityName.name };
606
+ }
607
+
608
+ getCallbackArgument(
609
+ callExpr: t.CallExpression
610
+ ): t.ArrowFunctionExpression | t.FunctionExpression | null {
611
+ const firstArg = callExpr.arguments[0];
612
+ if (
613
+ this.types.isArrowFunctionExpression(firstArg) ||
614
+ this.types.isFunctionExpression(firstArg)
615
+ ) {
616
+ return firstArg;
617
+ }
618
+ return null;
619
+ }
48
620
  }
49
621
 
50
622
  export class StaticValueUtils {
@@ -113,4 +685,103 @@ export class StaticValueUtils {
113
685
  return this.isStaticValue(element as unknown as NodePath<t.Node>, visited);
114
686
  });
115
687
  }
688
+
689
+ isDerivedFromStaticData(
690
+ identifierName: string,
691
+ path: NodePath
692
+ ): boolean {
693
+ const binding = path.scope.getBinding(identifierName);
694
+ if (!binding) return false;
695
+
696
+ if (binding.path.isVariableDeclarator()) {
697
+ const init = binding.path.get("init");
698
+ if (init.isArrayExpression() || init.isObjectExpression()) {
699
+ return this.isStaticValue(init as NodePath<t.Node>);
700
+ }
701
+ }
702
+
703
+ const fnParent = path.getFunctionParent();
704
+ if (!fnParent) return false;
705
+
706
+ const params = fnParent.get("params");
707
+ for (const param of (Array.isArray(params) ? params : [params])) {
708
+ if (param.isIdentifier() && param.node.name === identifierName) {
709
+ const mapCall = fnParent.parentPath;
710
+ if (mapCall?.isCallExpression()) {
711
+ const callee = mapCall.get("callee");
712
+ if (
713
+ callee.isMemberExpression() &&
714
+ (callee.get("property") as NodePath).isIdentifier()
715
+ ) {
716
+ const propName = ((callee.get("property") as NodePath).node as t.Identifier).name;
717
+ if (propName === "map" || propName === "flatMap") {
718
+ const arrayObj = callee.get("object") as NodePath<t.Expression>;
719
+ if (arrayObj.isIdentifier()) {
720
+ return this.isDerivedFromStaticData(arrayObj.node.name, arrayObj);
721
+ }
722
+ if (arrayObj.isArrayExpression()) {
723
+ return this.isStaticArrayExpression(arrayObj);
724
+ }
725
+ }
726
+ }
727
+ }
728
+ }
729
+ }
730
+
731
+ return false;
732
+ }
733
+ }
734
+
735
+ export class TypeCheckUtils {
736
+ constructor(private types: typeof t) {}
737
+
738
+ isArrayIsArrayCheck(node: t.Expression): boolean {
739
+ if (!this.types.isCallExpression(node)) return false;
740
+
741
+ const callee = node.callee;
742
+ return (
743
+ this.types.isMemberExpression(callee) &&
744
+ this.types.isIdentifier(callee.object) &&
745
+ callee.object.name === "Array" &&
746
+ this.types.isIdentifier(callee.property) &&
747
+ callee.property.name === "isArray"
748
+ );
749
+ }
750
+
751
+ isTypeofObjectCheck(node: t.Expression): boolean {
752
+ if (!this.types.isBinaryExpression(node)) return false;
753
+ if (node.operator !== "===" && node.operator !== "==") return false;
754
+
755
+ const isTypeof = (side: t.Expression) =>
756
+ this.types.isUnaryExpression(side) && side.operator === "typeof";
757
+ const isObjectString = (side: t.Expression) =>
758
+ this.types.isStringLiteral(side) && side.value === "object";
759
+
760
+ return (
761
+ (isTypeof(node.left as t.Expression) &&
762
+ isObjectString(node.right as t.Expression)) ||
763
+ (isObjectString(node.left as t.Expression) &&
764
+ isTypeof(node.right as t.Expression))
765
+ );
766
+ }
767
+
768
+ isReferenceTypeCheck(node: t.Expression): boolean {
769
+ return this.isArrayIsArrayCheck(node) || this.isTypeofObjectCheck(node);
770
+ }
771
+
772
+ isLengthCheck(node: t.Expression): boolean {
773
+ if (this.types.isMemberExpression(node)) {
774
+ return (
775
+ this.types.isIdentifier(node.property) &&
776
+ node.property.name === "length"
777
+ );
778
+ }
779
+ if (this.types.isOptionalMemberExpression(node)) {
780
+ return (
781
+ this.types.isIdentifier(node.property) &&
782
+ node.property.name === "length"
783
+ );
784
+ }
785
+ return false;
786
+ }
116
787
  }
@@ -1,10 +1,13 @@
1
1
  import type { NodePath } from "@babel/traverse";
2
2
  import type * as t from "@babel/types";
3
+ import {
4
+ DATA_ARR_INDEX,
5
+ DATA_ARR_VARIABLE_NAME,
6
+ DATA_ARR_FIELD,
7
+ } from "../consts.js";
3
8
  import { JSXAttributeUtils, StaticValueUtils } from "./shared-utils.js";
4
9
 
5
- export const DATA_ARR_INDEX = "data-arr-index";
6
- export const DATA_ARR_VARIABLE_NAME = "data-arr-variable-name";
7
- export const DATA_ARR_FIELD = "data-arr-field";
10
+ export { DATA_ARR_INDEX, DATA_ARR_VARIABLE_NAME, DATA_ARR_FIELD };
8
11
  const GENERATED_INDEX_PARAM = "__arrIdx__";
9
12
 
10
13
  interface ArrayMapInfo {
package/src/types.ts ADDED
@@ -0,0 +1,4 @@
1
+ export interface CollectionInfo {
2
+ id: string;
3
+ references: string[];
4
+ }