@depup/base44__vite-plugin 1.0.4-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/README.md +34 -0
  2. package/changes.json +22 -0
  3. package/compat/agents.cjs +13 -0
  4. package/compat/base44Client.cjs +6 -0
  5. package/compat/entities.cjs +25 -0
  6. package/compat/functions.cjs +9 -0
  7. package/compat/integrations.cjs +9 -0
  8. package/dist/ErrorOverlay.d.ts +12 -0
  9. package/dist/ErrorOverlay.d.ts.map +1 -0
  10. package/dist/ErrorOverlay.js +51 -0
  11. package/dist/ErrorOverlay.js.map +1 -0
  12. package/dist/bridge.d.ts +8 -0
  13. package/dist/bridge.d.ts.map +1 -0
  14. package/dist/bridge.js +8 -0
  15. package/dist/bridge.js.map +1 -0
  16. package/dist/capabilities/inline-edit/controller.d.ts +3 -0
  17. package/dist/capabilities/inline-edit/controller.d.ts.map +1 -0
  18. package/dist/capabilities/inline-edit/controller.js +203 -0
  19. package/dist/capabilities/inline-edit/controller.js.map +1 -0
  20. package/dist/capabilities/inline-edit/dom-utils.d.ts +7 -0
  21. package/dist/capabilities/inline-edit/dom-utils.d.ts.map +1 -0
  22. package/dist/capabilities/inline-edit/dom-utils.js +59 -0
  23. package/dist/capabilities/inline-edit/dom-utils.js.map +1 -0
  24. package/dist/capabilities/inline-edit/index.d.ts +3 -0
  25. package/dist/capabilities/inline-edit/index.d.ts.map +1 -0
  26. package/dist/capabilities/inline-edit/index.js +2 -0
  27. package/dist/capabilities/inline-edit/index.js.map +1 -0
  28. package/dist/capabilities/inline-edit/types.d.ts +29 -0
  29. package/dist/capabilities/inline-edit/types.d.ts.map +1 -0
  30. package/dist/capabilities/inline-edit/types.js +2 -0
  31. package/dist/capabilities/inline-edit/types.js.map +1 -0
  32. package/dist/consts.d.ts +11 -0
  33. package/dist/consts.d.ts.map +1 -0
  34. package/dist/consts.js +11 -0
  35. package/dist/consts.js.map +1 -0
  36. package/dist/error-overlay-plugin.d.ts +3 -0
  37. package/dist/error-overlay-plugin.d.ts.map +1 -0
  38. package/dist/error-overlay-plugin.js +15 -0
  39. package/dist/error-overlay-plugin.js.map +1 -0
  40. package/dist/html-injections-plugin.d.ts +8 -0
  41. package/dist/html-injections-plugin.d.ts.map +1 -0
  42. package/dist/html-injections-plugin.js +132 -0
  43. package/dist/html-injections-plugin.js.map +1 -0
  44. package/dist/index.d.ts +9 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +158 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/injections/layer-dropdown/consts.d.ts +20 -0
  49. package/dist/injections/layer-dropdown/consts.d.ts.map +1 -0
  50. package/dist/injections/layer-dropdown/consts.js +41 -0
  51. package/dist/injections/layer-dropdown/consts.js.map +1 -0
  52. package/dist/injections/layer-dropdown/controller.d.ts +4 -0
  53. package/dist/injections/layer-dropdown/controller.d.ts.map +1 -0
  54. package/dist/injections/layer-dropdown/controller.js +88 -0
  55. package/dist/injections/layer-dropdown/controller.js.map +1 -0
  56. package/dist/injections/layer-dropdown/dropdown-ui.d.ts +13 -0
  57. package/dist/injections/layer-dropdown/dropdown-ui.d.ts.map +1 -0
  58. package/dist/injections/layer-dropdown/dropdown-ui.js +186 -0
  59. package/dist/injections/layer-dropdown/dropdown-ui.js.map +1 -0
  60. package/dist/injections/layer-dropdown/types.d.ts +26 -0
  61. package/dist/injections/layer-dropdown/types.d.ts.map +1 -0
  62. package/dist/injections/layer-dropdown/types.js +3 -0
  63. package/dist/injections/layer-dropdown/types.js.map +1 -0
  64. package/dist/injections/layer-dropdown/utils.d.ts +25 -0
  65. package/dist/injections/layer-dropdown/utils.d.ts.map +1 -0
  66. package/dist/injections/layer-dropdown/utils.js +143 -0
  67. package/dist/injections/layer-dropdown/utils.js.map +1 -0
  68. package/dist/injections/navigation-notifier.d.ts +2 -0
  69. package/dist/injections/navigation-notifier.d.ts.map +1 -0
  70. package/dist/injections/navigation-notifier.js +34 -0
  71. package/dist/injections/navigation-notifier.js.map +1 -0
  72. package/dist/injections/sandbox-hmr-notifier.d.ts +2 -0
  73. package/dist/injections/sandbox-hmr-notifier.d.ts.map +1 -0
  74. package/dist/injections/sandbox-hmr-notifier.js +10 -0
  75. package/dist/injections/sandbox-hmr-notifier.js.map +1 -0
  76. package/dist/injections/sandbox-mount-observer.d.ts +2 -0
  77. package/dist/injections/sandbox-mount-observer.d.ts.map +1 -0
  78. package/dist/injections/sandbox-mount-observer.js +18 -0
  79. package/dist/injections/sandbox-mount-observer.js.map +1 -0
  80. package/dist/injections/unhandled-errors-handlers.d.ts +2 -0
  81. package/dist/injections/unhandled-errors-handlers.d.ts.map +1 -0
  82. package/dist/injections/unhandled-errors-handlers.js +93 -0
  83. package/dist/injections/unhandled-errors-handlers.js.map +1 -0
  84. package/dist/injections/utils.d.ts +65 -0
  85. package/dist/injections/utils.d.ts.map +1 -0
  86. package/dist/injections/utils.js +186 -0
  87. package/dist/injections/utils.js.map +1 -0
  88. package/dist/injections/visual-edit-agent.d.ts +2 -0
  89. package/dist/injections/visual-edit-agent.d.ts.map +1 -0
  90. package/dist/injections/visual-edit-agent.js +583 -0
  91. package/dist/injections/visual-edit-agent.js.map +1 -0
  92. package/dist/jsx-processor.d.ts +17 -0
  93. package/dist/jsx-processor.d.ts.map +1 -0
  94. package/dist/jsx-processor.js +129 -0
  95. package/dist/jsx-processor.js.map +1 -0
  96. package/dist/jsx-utils.d.ts +16 -0
  97. package/dist/jsx-utils.d.ts.map +1 -0
  98. package/dist/jsx-utils.js +98 -0
  99. package/dist/jsx-utils.js.map +1 -0
  100. package/dist/processors/collection-id-processor.d.ts +20 -0
  101. package/dist/processors/collection-id-processor.d.ts.map +1 -0
  102. package/dist/processors/collection-id-processor.js +182 -0
  103. package/dist/processors/collection-id-processor.js.map +1 -0
  104. package/dist/processors/collection-item-field-processor.d.ts +39 -0
  105. package/dist/processors/collection-item-field-processor.d.ts.map +1 -0
  106. package/dist/processors/collection-item-field-processor.js +289 -0
  107. package/dist/processors/collection-item-field-processor.js.map +1 -0
  108. package/dist/processors/collection-item-id-processor.d.ts +12 -0
  109. package/dist/processors/collection-item-id-processor.d.ts.map +1 -0
  110. package/dist/processors/collection-item-id-processor.js +50 -0
  111. package/dist/processors/collection-item-id-processor.js.map +1 -0
  112. package/dist/processors/static-array-processor.d.ts +28 -0
  113. package/dist/processors/static-array-processor.d.ts.map +1 -0
  114. package/dist/processors/static-array-processor.js +173 -0
  115. package/dist/processors/static-array-processor.js.map +1 -0
  116. package/dist/processors/utils/collection-tracing-utils.d.ts +36 -0
  117. package/dist/processors/utils/collection-tracing-utils.d.ts.map +1 -0
  118. package/dist/processors/utils/collection-tracing-utils.js +390 -0
  119. package/dist/processors/utils/collection-tracing-utils.js.map +1 -0
  120. package/dist/processors/utils/shared-utils.d.ts +96 -0
  121. package/dist/processors/utils/shared-utils.d.ts.map +1 -0
  122. package/dist/processors/utils/shared-utils.js +600 -0
  123. package/dist/processors/utils/shared-utils.js.map +1 -0
  124. package/dist/statics/index.mjs +16 -0
  125. package/dist/statics/index.mjs.map +1 -0
  126. package/dist/utils.d.ts +2 -0
  127. package/dist/utils.d.ts.map +1 -0
  128. package/dist/utils.js +22 -0
  129. package/dist/utils.js.map +1 -0
  130. package/dist/visual-edit-plugin.d.ts +3 -0
  131. package/dist/visual-edit-plugin.d.ts.map +1 -0
  132. package/dist/visual-edit-plugin.js +100 -0
  133. package/dist/visual-edit-plugin.js.map +1 -0
  134. package/package.json +75 -0
  135. package/src/ErrorOverlay.ts +71 -0
  136. package/src/bridge.ts +8 -0
  137. package/src/capabilities/inline-edit/controller.ts +254 -0
  138. package/src/capabilities/inline-edit/dom-utils.ts +58 -0
  139. package/src/capabilities/inline-edit/index.ts +2 -0
  140. package/src/capabilities/inline-edit/types.ts +35 -0
  141. package/src/consts.ts +11 -0
  142. package/src/error-overlay-plugin.ts +19 -0
  143. package/src/html-injections-plugin.ts +166 -0
  144. package/src/index.ts +225 -0
  145. package/src/injections/layer-dropdown/LAYERS.md +258 -0
  146. package/src/injections/layer-dropdown/consts.ts +51 -0
  147. package/src/injections/layer-dropdown/controller.ts +109 -0
  148. package/src/injections/layer-dropdown/dropdown-ui.ts +242 -0
  149. package/src/injections/layer-dropdown/types.ts +30 -0
  150. package/src/injections/layer-dropdown/utils.ts +175 -0
  151. package/src/injections/navigation-notifier.ts +43 -0
  152. package/src/injections/sandbox-hmr-notifier.ts +8 -0
  153. package/src/injections/sandbox-mount-observer.ts +25 -0
  154. package/src/injections/unhandled-errors-handlers.ts +114 -0
  155. package/src/injections/utils.ts +208 -0
  156. package/src/injections/visual-edit-agent.ts +706 -0
  157. package/src/jsx-processor.ts +169 -0
  158. package/src/jsx-utils.ts +131 -0
  159. package/src/processors/collection-id-processor.ts +261 -0
  160. package/src/processors/collection-item-field-processor.ts +439 -0
  161. package/src/processors/collection-item-id-processor.ts +69 -0
  162. package/src/processors/static-array-processor.ts +260 -0
  163. package/src/processors/utils/collection-tracing-utils.ts +507 -0
  164. package/src/processors/utils/shared-utils.ts +785 -0
  165. package/src/utils.ts +27 -0
  166. package/src/visual-edit-plugin.md +358 -0
  167. package/src/visual-edit-plugin.ts +110 -0
@@ -0,0 +1,785 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type * as t from "@babel/types";
3
+ import { JSXUtils } from "../../jsx-utils.js";
4
+ import { ALLOWED_CUSTOM_COMPONENTS, EXCLUDED_FIELDS } from "../../consts.js";
5
+
6
+ export class JSXAttributeUtils {
7
+ constructor(private types: typeof t) {}
8
+
9
+ hasAttribute(
10
+ path: NodePath<t.JSXOpeningElement>,
11
+ attributeName: string
12
+ ): boolean {
13
+ return path.node.attributes.some(
14
+ (attr: t.JSXAttribute | t.JSXSpreadAttribute) =>
15
+ this.types.isJSXAttribute(attr) &&
16
+ JSXUtils.getAttributeName(attr) === attributeName
17
+ );
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
+
46
+ addStringAttribute(
47
+ path: NodePath<t.JSXOpeningElement>,
48
+ attributeName: string,
49
+ value: string
50
+ ): void {
51
+ if (!this.hasAttribute(path, attributeName)) {
52
+ path.node.attributes.push(
53
+ this.types.jsxAttribute(
54
+ this.types.jsxIdentifier(attributeName),
55
+ this.types.stringLiteral(value)
56
+ )
57
+ );
58
+ }
59
+ }
60
+
61
+ addExpressionAttribute(
62
+ path: NodePath<t.JSXOpeningElement>,
63
+ attributeName: string,
64
+ expression: t.Expression
65
+ ): void {
66
+ if (!this.hasAttribute(path, attributeName)) {
67
+ path.node.attributes.push(
68
+ this.types.jsxAttribute(
69
+ this.types.jsxIdentifier(attributeName),
70
+ this.types.jsxExpressionContainer(expression)
71
+ )
72
+ );
73
+ }
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
+ !this.types.isIdentifier(prop) ||
433
+ prop.name !== "getAll"
434
+ ) {
435
+ return null;
436
+ }
437
+
438
+ const args = node.arguments;
439
+ if (args.length < 1) return null;
440
+
441
+ const firstArg = args[0];
442
+ if (!this.types.isStringLiteral(firstArg)) return null;
443
+
444
+ const collectionName = firstArg.value;
445
+ const references = this.extractReferencesFromArg(args[1]);
446
+
447
+ return { collectionName, references };
448
+ }
449
+
450
+ isGetByIdCall(
451
+ node: t.CallExpression
452
+ ): {
453
+ collectionName: string;
454
+ multiRefFields: string[];
455
+ } | null {
456
+ const callee = node.callee;
457
+ if (!this.types.isMemberExpression(callee)) return null;
458
+
459
+ const obj = callee.object;
460
+ const prop = callee.property;
461
+
462
+ if (
463
+ !this.types.isIdentifier(obj) ||
464
+ !this.types.isIdentifier(prop) ||
465
+ prop.name !== "getById"
466
+ ) {
467
+ return null;
468
+ }
469
+
470
+ const args = node.arguments;
471
+ if (args.length < 1) return null;
472
+
473
+ const firstArg = args[0];
474
+ if (!this.types.isStringLiteral(firstArg)) return null;
475
+
476
+ const collectionName = firstArg.value;
477
+ const multiRefFields = this.extractMultiRefFromOptions(args[2]);
478
+
479
+ return { collectionName, multiRefFields };
480
+ }
481
+
482
+ private extractReferencesFromArg(
483
+ arg: t.Expression | t.SpreadElement | t.ArgumentPlaceholder | undefined
484
+ ): string[] {
485
+ if (!arg || !this.types.isArrayExpression(arg)) return [];
486
+
487
+ return arg.elements
488
+ .filter((el): el is t.StringLiteral => this.types.isStringLiteral(el))
489
+ .map((el) => el.value);
490
+ }
491
+
492
+ private extractMultiRefFromOptions(
493
+ arg: t.Expression | t.SpreadElement | t.ArgumentPlaceholder | undefined
494
+ ): string[] {
495
+ if (!arg || !this.types.isObjectExpression(arg)) return [];
496
+
497
+ for (const prop of arg.properties) {
498
+ if (
499
+ this.types.isObjectProperty(prop) &&
500
+ this.types.isIdentifier(prop.key) &&
501
+ prop.key.name === "multiRef" &&
502
+ this.types.isArrayExpression(prop.value)
503
+ ) {
504
+ return prop.value.elements
505
+ .filter((el): el is t.StringLiteral =>
506
+ this.types.isStringLiteral(el)
507
+ )
508
+ .map((el) => el.value);
509
+ }
510
+ }
511
+ return [];
512
+ }
513
+
514
+ isArrayMethod(
515
+ node: t.CallExpression,
516
+ methodName: string
517
+ ): boolean {
518
+ const callee = node.callee;
519
+ return (
520
+ this.types.isMemberExpression(callee) &&
521
+ this.types.isIdentifier(callee.property) &&
522
+ callee.property.name === methodName
523
+ );
524
+ }
525
+
526
+ isChainedArrayMethod(node: t.CallExpression): boolean {
527
+ const chainMethods = ["filter", "sort", "slice", "concat", "reverse", "flat"];
528
+ return chainMethods.some((m) => this.isArrayMethod(node, m));
529
+ }
530
+
531
+ /**
532
+ * Detect base44.entities.EntityName.list() or .getAll() patterns.
533
+ * Returns the entity name as the collection name.
534
+ */
535
+ isBase44EntityListCall(
536
+ node: t.CallExpression
537
+ ): { collectionName: string } | null {
538
+ const callee = node.callee;
539
+ if (!this.types.isMemberExpression(callee)) return null;
540
+
541
+ const method = callee.property;
542
+ if (
543
+ !this.types.isIdentifier(method) ||
544
+ (method.name !== "list" && method.name !== "getAll")
545
+ ) {
546
+ return null;
547
+ }
548
+
549
+ const entityAccess = callee.object;
550
+ if (!this.types.isMemberExpression(entityAccess)) return null;
551
+
552
+ const entityName = entityAccess.property;
553
+ if (!this.types.isIdentifier(entityName)) return null;
554
+
555
+ const entitiesAccess = entityAccess.object;
556
+ if (!this.types.isMemberExpression(entitiesAccess)) return null;
557
+
558
+ const entitiesProp = entitiesAccess.property;
559
+ if (
560
+ !this.types.isIdentifier(entitiesProp) ||
561
+ entitiesProp.name !== "entities"
562
+ ) {
563
+ return null;
564
+ }
565
+
566
+ return { collectionName: entityName.name };
567
+ }
568
+
569
+ /**
570
+ * Detect base44.entities.EntityName.getById() or .get() patterns.
571
+ */
572
+ isBase44EntityGetCall(
573
+ node: t.CallExpression
574
+ ): { collectionName: string } | null {
575
+ const callee = node.callee;
576
+ if (!this.types.isMemberExpression(callee)) return null;
577
+
578
+ const method = callee.property;
579
+ if (
580
+ !this.types.isIdentifier(method) ||
581
+ (method.name !== "get" && method.name !== "getById")
582
+ ) {
583
+ return null;
584
+ }
585
+
586
+ const entityAccess = callee.object;
587
+ if (!this.types.isMemberExpression(entityAccess)) return null;
588
+
589
+ const entityName = entityAccess.property;
590
+ if (!this.types.isIdentifier(entityName)) return null;
591
+
592
+ const entitiesAccess = entityAccess.object;
593
+ if (!this.types.isMemberExpression(entitiesAccess)) return null;
594
+
595
+ const entitiesProp = entitiesAccess.property;
596
+ if (
597
+ !this.types.isIdentifier(entitiesProp) ||
598
+ entitiesProp.name !== "entities"
599
+ ) {
600
+ return null;
601
+ }
602
+
603
+ return { collectionName: entityName.name };
604
+ }
605
+
606
+ getCallbackArgument(
607
+ callExpr: t.CallExpression
608
+ ): t.ArrowFunctionExpression | t.FunctionExpression | null {
609
+ const firstArg = callExpr.arguments[0];
610
+ if (
611
+ this.types.isArrowFunctionExpression(firstArg) ||
612
+ this.types.isFunctionExpression(firstArg)
613
+ ) {
614
+ return firstArg;
615
+ }
616
+ return null;
617
+ }
618
+ }
619
+
620
+ export class StaticValueUtils {
621
+ constructor(private types: typeof t) {}
622
+
623
+ isPrimitiveLiteral(path: NodePath<t.Node>): boolean {
624
+ return (
625
+ path.isStringLiteral() ||
626
+ path.isNumericLiteral() ||
627
+ path.isBooleanLiteral() ||
628
+ path.isNullLiteral()
629
+ );
630
+ }
631
+
632
+ isStaticValue(
633
+ path: NodePath<t.Node>,
634
+ visited: Set<string> = new Set()
635
+ ): boolean {
636
+ if (this.isPrimitiveLiteral(path)) return true;
637
+ if (path.isIdentifier()) return this.isStaticIdentifier(path, visited);
638
+ if (path.isObjectExpression()) return this.isStaticObject(path, visited);
639
+ if (path.isArrayExpression())
640
+ return this.isStaticArrayExpression(path, visited);
641
+ return false;
642
+ }
643
+
644
+ isStaticIdentifier(
645
+ path: NodePath<t.Identifier>,
646
+ visited: Set<string> = new Set()
647
+ ): boolean {
648
+ const binding = path.scope.getBinding(path.node.name);
649
+ if (!binding) return false;
650
+
651
+ if (binding.kind === "module") return true;
652
+
653
+ if (binding.kind === "const" && binding.path.isVariableDeclarator()) {
654
+ const name = path.node.name;
655
+ if (visited.has(name)) return false;
656
+ visited.add(name);
657
+
658
+ const init = binding.path.get("init");
659
+ if (init.hasNode()) {
660
+ return this.isStaticValue(init as NodePath<t.Node>, visited);
661
+ }
662
+ }
663
+
664
+ return false;
665
+ }
666
+
667
+ isStaticObject(
668
+ path: NodePath<t.ObjectExpression>,
669
+ visited: Set<string> = new Set()
670
+ ): boolean {
671
+ return path.get("properties").every((prop: NodePath) => {
672
+ if (!prop.isObjectProperty()) return false;
673
+ return this.isStaticValue(prop.get("value") as NodePath<t.Node>, visited);
674
+ });
675
+ }
676
+
677
+ isStaticArrayExpression(
678
+ arrayExpression: NodePath<t.ArrayExpression>,
679
+ visited: Set<string> = new Set()
680
+ ): boolean {
681
+ return arrayExpression.get("elements").every((element) => {
682
+ if (!element.node || element.isSpreadElement()) return true;
683
+ return this.isStaticValue(element as unknown as NodePath<t.Node>, visited);
684
+ });
685
+ }
686
+
687
+ isDerivedFromStaticData(
688
+ identifierName: string,
689
+ path: NodePath
690
+ ): boolean {
691
+ const binding = path.scope.getBinding(identifierName);
692
+ if (!binding) return false;
693
+
694
+ if (binding.path.isVariableDeclarator()) {
695
+ const init = binding.path.get("init");
696
+ if (init.isArrayExpression() || init.isObjectExpression()) {
697
+ return this.isStaticValue(init as NodePath<t.Node>);
698
+ }
699
+ }
700
+
701
+ const fnParent = path.getFunctionParent();
702
+ if (!fnParent) return false;
703
+
704
+ const params = fnParent.get("params");
705
+ for (const param of (Array.isArray(params) ? params : [params])) {
706
+ if (param.isIdentifier() && param.node.name === identifierName) {
707
+ const mapCall = fnParent.parentPath;
708
+ if (mapCall?.isCallExpression()) {
709
+ const callee = mapCall.get("callee");
710
+ if (
711
+ callee.isMemberExpression() &&
712
+ (callee.get("property") as NodePath).isIdentifier()
713
+ ) {
714
+ const propName = ((callee.get("property") as NodePath).node as t.Identifier).name;
715
+ if (propName === "map" || propName === "flatMap") {
716
+ const arrayObj = callee.get("object") as NodePath<t.Expression>;
717
+ if (arrayObj.isIdentifier()) {
718
+ return this.isDerivedFromStaticData(arrayObj.node.name, arrayObj);
719
+ }
720
+ if (arrayObj.isArrayExpression()) {
721
+ return this.isStaticArrayExpression(arrayObj);
722
+ }
723
+ }
724
+ }
725
+ }
726
+ }
727
+ }
728
+
729
+ return false;
730
+ }
731
+ }
732
+
733
+ export class TypeCheckUtils {
734
+ constructor(private types: typeof t) {}
735
+
736
+ isArrayIsArrayCheck(node: t.Expression): boolean {
737
+ if (!this.types.isCallExpression(node)) return false;
738
+
739
+ const callee = node.callee;
740
+ return (
741
+ this.types.isMemberExpression(callee) &&
742
+ this.types.isIdentifier(callee.object) &&
743
+ callee.object.name === "Array" &&
744
+ this.types.isIdentifier(callee.property) &&
745
+ callee.property.name === "isArray"
746
+ );
747
+ }
748
+
749
+ isTypeofObjectCheck(node: t.Expression): boolean {
750
+ if (!this.types.isBinaryExpression(node)) return false;
751
+ if (node.operator !== "===" && node.operator !== "==") return false;
752
+
753
+ const isTypeof = (side: t.Expression) =>
754
+ this.types.isUnaryExpression(side) && side.operator === "typeof";
755
+ const isObjectString = (side: t.Expression) =>
756
+ this.types.isStringLiteral(side) && side.value === "object";
757
+
758
+ return (
759
+ (isTypeof(node.left as t.Expression) &&
760
+ isObjectString(node.right as t.Expression)) ||
761
+ (isObjectString(node.left as t.Expression) &&
762
+ isTypeof(node.right as t.Expression))
763
+ );
764
+ }
765
+
766
+ isReferenceTypeCheck(node: t.Expression): boolean {
767
+ return this.isArrayIsArrayCheck(node) || this.isTypeofObjectCheck(node);
768
+ }
769
+
770
+ isLengthCheck(node: t.Expression): boolean {
771
+ if (this.types.isMemberExpression(node)) {
772
+ return (
773
+ this.types.isIdentifier(node.property) &&
774
+ node.property.name === "length"
775
+ );
776
+ }
777
+ if (this.types.isOptionalMemberExpression(node)) {
778
+ return (
779
+ this.types.isIdentifier(node.property) &&
780
+ node.property.name === "length"
781
+ );
782
+ }
783
+ return false;
784
+ }
785
+ }