first commit

This commit is contained in:
2026-06-24 09:48:54 +02:00
commit 41e62ddcad
33739 changed files with 4266226 additions and 0 deletions
@@ -0,0 +1,36 @@
import type { NodePath } from "@babel/traverse";
import type * as t from "@babel/types";
import type { CollectionInfo } from "../../capabilities/inline-edit/types.js";
export declare class CollectionTracingUtils {
private types;
private bindingUtils;
private callUtils;
private visitedSetters;
private visitedGetByIdSetters;
constructor(types: typeof t);
resetVisited(): void;
traceCollectionSource(path: NodePath<t.Expression>): CollectionInfo | null;
private traceExpression;
private traceIdentifierToCollection;
private traceVariableDeclarator;
private traceUseStateSetter;
private findThenCallWithSetter;
private traceMemberExpression;
private traceCallExpression;
/**
* Trace useQuery({ queryFn: () => base44.entities.X.list() }) patterns.
* Extracts the collection from the queryFn return expression.
*/
private traceUseQueryCall;
private checkDirectServiceCall;
private traceArrayDestructuring;
private traceObjectDestructuring;
private tracePromiseAllElement;
private traceParameterToCollection;
private traceArrayExpression;
private getFunctionName;
private getJSXElementName;
traceGetByIdSource(path: NodePath): CollectionInfo | null;
private findGetByIdInScope;
}
//# sourceMappingURL=collection-tracing-utils.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"collection-tracing-utils.d.ts","sourceRoot":"","sources":["../../../src/processors/utils/collection-tracing-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,KAAK,CAAC,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAM9E,qBAAa,sBAAsB;IAMrB,OAAO,CAAC,KAAK;IALzB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,qBAAqB,CAAqB;gBAE9B,KAAK,EAAE,OAAO,CAAC;IAKnC,YAAY,IAAI,IAAI;IAKpB,qBAAqB,CACnB,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,GAC3B,cAAc,GAAG,IAAI;IAKxB,OAAO,CAAC,eAAe;IA6BvB,OAAO,CAAC,2BAA2B;IAkBnC,OAAO,CAAC,uBAAuB;IA0D/B,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,qBAAqB;IAgC7B,OAAO,CAAC,mBAAmB;IAoB3B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAyCzB,OAAO,CAAC,sBAAsB;IAgC9B,OAAO,CAAC,uBAAuB;IA4B/B,OAAO,CAAC,wBAAwB;IAmChC,OAAO,CAAC,sBAAsB;IA2B9B,OAAO,CAAC,0BAA0B;IAgElC,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,iBAAiB;IAOzB,kBAAkB,CAChB,IAAI,EAAE,QAAQ,GACb,cAAc,GAAG,IAAI;IAKxB,OAAO,CAAC,kBAAkB;CA0B3B"}
@@ -0,0 +1,428 @@
import { BindingUtils, CallExpressionUtils, } from "./shared-utils.js";
export class CollectionTracingUtils {
types;
bindingUtils;
callUtils;
visitedSetters = new Set();
visitedGetByIdSetters = new Set();
constructor(types) {
this.types = types;
this.bindingUtils = new BindingUtils(types);
this.callUtils = new CallExpressionUtils(types);
}
resetVisited() {
this.visitedSetters.clear();
this.visitedGetByIdSetters.clear();
}
traceCollectionSource(path) {
this.resetVisited();
return this.traceExpression(path);
}
traceExpression(path) {
if (path.isIdentifier()) {
return this.traceIdentifierToCollection(path);
}
if (path.isMemberExpression()) {
return this.traceMemberExpression(path);
}
if (path.isCallExpression()) {
return this.traceCallExpression(path);
}
if (path.isAwaitExpression()) {
const argument = path.get("argument");
if (argument.isExpression()) {
return this.traceExpression(argument);
}
}
if (path.isArrayExpression()) {
return this.traceArrayExpression(path);
}
return null;
}
traceIdentifierToCollection(path) {
const name = path.node.name;
const binding = path.scope.getBinding(name);
if (!binding)
return null;
if (binding.path.isVariableDeclarator()) {
return this.traceVariableDeclarator(binding.path, name);
}
if (this.bindingUtils.isFunctionParameter(name, path)) {
return this.traceParameterToCollection(name, path);
}
return null;
}
traceVariableDeclarator(declaratorPath, variableName) {
const init = declaratorPath.get("init");
if (init.isCallExpression()) {
const directResult = this.checkDirectServiceCall(init);
if (directResult)
return directResult;
const useStateInfo = this.bindingUtils.isUseStateCall(init);
if (useStateInfo?.setterName) {
return this.traceUseStateSetter(useStateInfo.setterName, declaratorPath);
}
}
if (init.isAwaitExpression()) {
const awaitArg = init.get("argument");
if (awaitArg.isCallExpression()) {
const directResult = this.checkDirectServiceCall(awaitArg);
if (directResult)
return directResult;
}
return this.traceExpression(init);
}
if (init.isConditionalExpression()) {
const consequent = init.get("consequent");
const alternate = init.get("alternate");
const result = this.traceExpression(consequent);
if (result)
return result;
return this.traceExpression(alternate);
}
if (init.isMemberExpression()) {
return this.traceExpression(init);
}
if (init.isIdentifier()) {
return this.traceExpression(init);
}
if (init.isCallExpression()) {
return this.traceExpression(init);
}
const id = declaratorPath.get("id");
if (id.isArrayPattern()) {
return this.traceArrayDestructuring(declaratorPath, id, variableName);
}
if (id.isObjectPattern()) {
return this.traceObjectDestructuring(declaratorPath, id, variableName);
}
return null;
}
traceUseStateSetter(setterName, declaratorPath) {
if (this.visitedSetters.has(setterName))
return null;
this.visitedSetters.add(setterName);
const functionScope = declaratorPath.getFunctionParent() ?? declaratorPath.scope.path;
// Pattern 1: setData(result) — direct call
const setterCall = this.bindingUtils.findSetterCallInScope(setterName, functionScope);
if (setterCall) {
const args = setterCall.get("arguments");
const firstArg = args[0];
if (!firstArg || !firstArg.isExpression())
return null;
return this.traceExpression(firstArg);
}
// Pattern 2: somePromise.then(setData) — setter passed as .then callback
const thenCall = this.findThenCallWithSetter(setterName, functionScope);
if (thenCall) {
const callee = thenCall.get("callee");
if (callee.isMemberExpression()) {
const promiseExpr = callee.get("object");
return this.traceExpression(promiseExpr);
}
}
return null;
}
findThenCallWithSetter(setterName, scope) {
let result = null;
scope.traverse({
CallExpression: (callPath) => {
if (result) {
callPath.stop();
return;
}
const callee = callPath.node.callee;
if (this.types.isMemberExpression(callee) &&
this.types.isIdentifier(callee.property) &&
callee.property.name === "then" &&
callPath.node.arguments.length > 0 &&
this.types.isIdentifier(callPath.node.arguments[0]) &&
callPath.node.arguments[0].name === setterName) {
result = callPath;
}
},
});
return result;
}
traceMemberExpression(path) {
const property = path.get("property");
const object = path.get("object");
if (property.isIdentifier() &&
property.node.name === "items") {
if (object.isExpression()) {
return this.traceExpression(object);
}
}
if (object.isIdentifier()) {
const objResult = this.traceIdentifierToCollection(object);
if (objResult && property.isIdentifier()) {
if (objResult.references.includes(property.node.name)) {
return { id: property.node.name, references: [] };
}
}
return objResult;
}
if (object.isExpression()) {
return this.traceExpression(object);
}
return null;
}
traceCallExpression(path) {
const directResult = this.checkDirectServiceCall(path);
if (directResult)
return directResult;
const useQueryResult = this.traceUseQueryCall(path);
if (useQueryResult)
return useQueryResult;
if (this.callUtils.isChainedArrayMethod(path.node)) {
const callee = path.get("callee");
if (callee.isMemberExpression()) {
const obj = callee.get("object");
return this.traceExpression(obj);
}
}
return null;
}
/**
* Trace useQuery({ queryFn: () => base44.entities.X.list() }) patterns.
* Extracts the collection from the queryFn return expression.
*/
traceUseQueryCall(path) {
const callee = path.get("callee");
if (!callee.isIdentifier() || callee.node.name !== "useQuery")
return null;
const args = path.get("arguments");
const configArg = args[0];
if (!configArg?.isObjectExpression())
return null;
for (const prop of configArg.get("properties")) {
if (!prop.isObjectProperty())
continue;
const key = prop.get("key");
if (!key.isIdentifier() || key.node.name !== "queryFn")
continue;
const value = prop.get("value");
if (value.isArrowFunctionExpression() || value.isFunctionExpression()) {
const fnBody = value.get("body");
if (fnBody.isCallExpression()) {
return this.checkDirectServiceCall(fnBody);
}
if (fnBody.isBlockStatement()) {
let result = null;
fnBody.traverse({
ReturnStatement: (retPath) => {
if (result)
return;
const arg = retPath.get("argument");
if (arg.isCallExpression()) {
result = this.checkDirectServiceCall(arg);
}
},
});
if (result)
return result;
}
}
}
return null;
}
checkDirectServiceCall(path) {
const getAllInfo = this.callUtils.isGetAllCall(path.node);
if (getAllInfo) {
return {
id: getAllInfo.collectionName,
references: getAllInfo.references,
};
}
const getByIdInfo = this.callUtils.isGetByIdCall(path.node);
if (getByIdInfo) {
return {
id: getByIdInfo.collectionName,
references: getByIdInfo.multiRefFields,
};
}
const base44List = this.callUtils.isBase44EntityListCall(path.node);
if (base44List) {
return { id: base44List.collectionName, references: [] };
}
const base44Get = this.callUtils.isBase44EntityGetCall(path.node);
if (base44Get) {
return { id: base44Get.collectionName, references: [] };
}
return null;
}
traceArrayDestructuring(declaratorPath, pattern, variableName) {
const elements = pattern.get("elements");
const index = elements.findIndex((el) => el.isIdentifier() && el.node.name === variableName);
if (index === -1)
return null;
const init = declaratorPath.get("init");
if (init.hasNode() && this.bindingUtils.isPromiseAllCall(init)) {
return this.tracePromiseAllElement(init, index);
}
if (init.isCallExpression()) {
const useStateInfo = this.bindingUtils.isUseStateCall(init);
if (useStateInfo && index === 0 && useStateInfo.setterName) {
return this.traceUseStateSetter(useStateInfo.setterName, declaratorPath);
}
}
return null;
}
traceObjectDestructuring(declaratorPath, pattern, variableName) {
const init = declaratorPath.get("init");
if (!init.isExpression())
return null;
const prop = pattern.node.properties.find((p) => this.types.isObjectProperty(p) &&
((this.types.isIdentifier(p.value) && p.value.name === variableName) ||
(this.types.isAssignmentPattern(p.value) &&
this.types.isIdentifier(p.value.left) &&
p.value.left.name === variableName)));
if (!prop || !this.types.isObjectProperty(prop))
return null;
const key = prop.key;
const propertyName = this.types.isIdentifier(key)
? key.name
: this.types.isStringLiteral(key)
? key.value
: null;
if (propertyName === "items") {
return this.traceExpression(init);
}
return this.traceExpression(init);
}
tracePromiseAllElement(init, index) {
let callExpr;
if (init.isAwaitExpression()) {
const arg = init.get("argument");
if (!arg.isCallExpression())
return null;
callExpr = arg;
}
else if (init.isCallExpression()) {
callExpr = init;
}
else {
return null;
}
const args = callExpr.get("arguments");
const firstArg = args[0];
if (!firstArg?.isArrayExpression())
return null;
const elements = firstArg.get("elements");
const targetElement = elements[index];
if (!targetElement || !targetElement.isExpression())
return null;
return this.traceExpression(targetElement);
}
traceParameterToCollection(paramName, path) {
const fn = path.getFunctionParent();
if (!fn)
return null;
const fnName = this.getFunctionName(fn);
if (!fnName)
return null;
const programPath = fn.findParent((p) => p.isProgram());
if (!programPath)
return null;
let result = null;
programPath.traverse({
JSXOpeningElement: (jsxPath) => {
if (result)
return;
const elementName = this.getJSXElementName(jsxPath.node);
if (elementName !== fnName)
return;
for (const attr of jsxPath.node.attributes) {
if (!this.types.isJSXAttribute(attr))
continue;
if (!this.types.isJSXIdentifier(attr.name))
continue;
if (attr.name.name !== paramName)
continue;
if (attr.value &&
this.types.isJSXExpressionContainer(attr.value) &&
this.types.isExpression(attr.value.expression)) {
const exprPath = jsxPath
.get("attributes")
.find((a) => a.isJSXAttribute() &&
this.types.isJSXIdentifier(a.node.name) &&
a.node.name.name === paramName);
if (exprPath && exprPath.isJSXAttribute()) {
const valPath = exprPath.get("value");
if (valPath.isJSXExpressionContainer()) {
const expr = valPath.get("expression");
if (expr.isExpression()) {
result = this.traceExpression(expr);
}
}
}
}
}
},
});
if (!result) {
return { id: paramName, references: [] };
}
return result;
}
traceArrayExpression(path) {
const elements = path.get("elements");
for (const el of elements) {
if (el.isSpreadElement()) {
const arg = el.get("argument");
if (arg.isExpression()) {
const result = this.traceExpression(arg);
if (result)
return result;
}
}
}
return null;
}
getFunctionName(fn) {
if (fn.isFunctionDeclaration() && fn.node.id) {
return fn.node.id.name;
}
const parent = fn.parentPath;
if (parent?.isVariableDeclarator()) {
const id = parent.get("id");
if (id.isIdentifier())
return id.node.name;
}
return null;
}
getJSXElementName(node) {
if (this.types.isJSXIdentifier(node.name)) {
return node.name.name;
}
return null;
}
traceGetByIdSource(path) {
this.visitedGetByIdSetters.clear();
return this.findGetByIdInScope(path);
}
findGetByIdInScope(path) {
const fn = path.getFunctionParent() ?? path.scope.path;
let result = null;
fn.traverse({
CallExpression: (callPath) => {
if (result)
return;
const info = this.callUtils.isGetByIdCall(callPath.node);
if (info) {
result = {
id: info.collectionName,
references: info.multiRefFields,
};
return;
}
const base44Get = this.callUtils.isBase44EntityGetCall(callPath.node);
if (base44Get) {
result = { id: base44Get.collectionName, references: [] };
}
},
});
return result;
}
}
//# sourceMappingURL=collection-tracing-utils.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,96 @@
import type { NodePath } from "@babel/traverse";
import type * as t from "@babel/types";
export declare class JSXAttributeUtils {
private types;
constructor(types: typeof t);
hasAttribute(path: NodePath<t.JSXOpeningElement>, attributeName: string): boolean;
getAttributeValue(path: NodePath<t.JSXOpeningElement>, attributeName: string): t.JSXAttribute["value"] | null;
getAttributeStringValue(path: NodePath<t.JSXOpeningElement>, attributeName: string): string | null;
addStringAttribute(path: NodePath<t.JSXOpeningElement>, attributeName: string, value: string): void;
addExpressionAttribute(path: NodePath<t.JSXOpeningElement>, attributeName: string, expression: t.Expression): void;
findAncestorWithAttribute(path: NodePath, attributeName: string): NodePath<t.JSXOpeningElement> | null;
}
export declare class PathNavigationUtils {
private types;
constructor(types: typeof t);
findParentJSXElement(path: NodePath): NodePath<t.JSXElement> | null;
findEnclosingFunction(path: NodePath): NodePath<t.Function> | null;
findReturnStatement(path: NodePath): NodePath<t.ReturnStatement> | null;
isRootReturnElement(path: NodePath<t.JSXOpeningElement>): boolean;
findDOMElementTarget(path: NodePath<t.JSXOpeningElement>): NodePath<t.JSXOpeningElement> | null;
private isDOMOrAllowedElement;
}
export declare class ExpressionAnalysisUtils {
private types;
constructor(types: typeof t);
isIdAccess(node: t.Expression): boolean;
isItemsAccess(node: t.Expression): boolean;
isLengthAccess(node: t.Expression): boolean;
extractRootIdentifier(node: t.Expression): t.Identifier | null;
unwrapLogicalExpression(node: t.Expression): t.Expression;
collectMemberExpressionPath(node: t.Expression): string[];
createOptionalChainExpression(node: t.MemberExpression): t.OptionalMemberExpression;
getFieldPathFromExpression(node: t.Expression, rootName: string): string | null;
}
export declare class BindingUtils {
private types;
constructor(types: typeof t);
isFunctionParameter(identifierName: string, path: NodePath): boolean;
isUseStateCall(init: NodePath<t.Node>): {
stateIndex: number;
setterName: string | null;
} | null;
isPromiseAllCall(init: NodePath<t.Node>): boolean;
private isPromiseAllCallee;
extractDestructuredProperties(pattern: t.ObjectPattern): string[];
findSetterCallInScope(setterName: string, scope: NodePath): NodePath<t.CallExpression> | null;
}
export declare class CallExpressionUtils {
private types;
constructor(types: typeof t);
isGetAllCall(node: t.CallExpression): {
collectionName: string;
references: string[];
} | null;
isGetByIdCall(node: t.CallExpression): {
collectionName: string;
multiRefFields: string[];
} | null;
private extractReferencesFromArg;
private extractMultiRefFromOptions;
isArrayMethod(node: t.CallExpression, methodName: string): boolean;
isChainedArrayMethod(node: t.CallExpression): boolean;
/**
* Detect base44.entities.EntityName.list() or .getAll() patterns.
* Returns the entity name as the collection name.
*/
isBase44EntityListCall(node: t.CallExpression): {
collectionName: string;
} | null;
/**
* Detect base44.entities.EntityName.getById() or .get() patterns.
*/
isBase44EntityGetCall(node: t.CallExpression): {
collectionName: string;
} | null;
getCallbackArgument(callExpr: t.CallExpression): t.ArrowFunctionExpression | t.FunctionExpression | null;
}
export declare class StaticValueUtils {
private types;
constructor(types: typeof t);
isPrimitiveLiteral(path: NodePath<t.Node>): boolean;
isStaticValue(path: NodePath<t.Node>, visited?: Set<string>): boolean;
isStaticIdentifier(path: NodePath<t.Identifier>, visited?: Set<string>): boolean;
isStaticObject(path: NodePath<t.ObjectExpression>, visited?: Set<string>): boolean;
isStaticArrayExpression(arrayExpression: NodePath<t.ArrayExpression>, visited?: Set<string>): boolean;
isDerivedFromStaticData(identifierName: string, path: NodePath): boolean;
}
export declare class TypeCheckUtils {
private types;
constructor(types: typeof t);
isArrayIsArrayCheck(node: t.Expression): boolean;
isTypeofObjectCheck(node: t.Expression): boolean;
isReferenceTypeCheck(node: t.Expression): boolean;
isLengthCheck(node: t.Expression): boolean;
}
//# sourceMappingURL=shared-utils.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"shared-utils.d.ts","sourceRoot":"","sources":["../../../src/processors/utils/shared-utils.ts"],"names":[],"mappings":"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"}
+600
View File
@@ -0,0 +1,600 @@
import { JSXUtils } from "../../jsx-utils.js";
import { ALLOWED_CUSTOM_COMPONENTS, EXCLUDED_FIELDS } from "../../consts.js";
export class JSXAttributeUtils {
types;
constructor(types) {
this.types = types;
}
hasAttribute(path, attributeName) {
return path.node.attributes.some((attr) => this.types.isJSXAttribute(attr) &&
JSXUtils.getAttributeName(attr) === attributeName);
}
getAttributeValue(path, attributeName) {
for (const attr of path.node.attributes) {
if (this.types.isJSXAttribute(attr) &&
JSXUtils.getAttributeName(attr) === attributeName) {
return attr.value;
}
}
return null;
}
getAttributeStringValue(path, attributeName) {
const value = this.getAttributeValue(path, attributeName);
if (value && this.types.isStringLiteral(value)) {
return value.value;
}
return null;
}
addStringAttribute(path, attributeName, value) {
if (!this.hasAttribute(path, attributeName)) {
path.node.attributes.push(this.types.jsxAttribute(this.types.jsxIdentifier(attributeName), this.types.stringLiteral(value)));
}
}
addExpressionAttribute(path, attributeName, expression) {
if (!this.hasAttribute(path, attributeName)) {
path.node.attributes.push(this.types.jsxAttribute(this.types.jsxIdentifier(attributeName), this.types.jsxExpressionContainer(expression)));
}
}
findAncestorWithAttribute(path, attributeName) {
let current = path.parentPath;
while (current) {
if (current.isJSXElement()) {
const opening = current.get("openingElement");
if (this.hasAttribute(opening, attributeName)) {
return opening;
}
}
current = current.parentPath;
}
return null;
}
}
export class PathNavigationUtils {
types;
constructor(types) {
this.types = types;
}
findParentJSXElement(path) {
let current = path.parentPath;
while (current) {
if (current.isJSXElement())
return current;
current = current.parentPath;
}
return null;
}
findEnclosingFunction(path) {
let current = path.parentPath;
while (current) {
if (current.isFunction())
return current;
current = current.parentPath;
}
return null;
}
findReturnStatement(path) {
let current = path.parentPath;
while (current) {
if (current.isReturnStatement())
return current;
current = current.parentPath;
}
return null;
}
isRootReturnElement(path) {
const jsxElement = path.parentPath;
if (!jsxElement?.isJSXElement())
return false;
const parent = jsxElement.parentPath;
if (!parent)
return false;
if (parent.isReturnStatement())
return true;
if (parent.isArrowFunctionExpression())
return true;
if (parent.isParenthesizedExpression()) {
const grandparent = parent.parentPath;
if (grandparent?.isReturnStatement())
return true;
if (grandparent?.isArrowFunctionExpression())
return true;
}
return false;
}
findDOMElementTarget(path) {
if (this.isDOMOrAllowedElement(path))
return path;
let current = path.parentPath;
while (current) {
if (current.isJSXElement()) {
const opening = current.get("openingElement");
if (this.isDOMOrAllowedElement(opening))
return opening;
}
current = current.parentPath;
}
return null;
}
isDOMOrAllowedElement(path) {
const name = JSXUtils.getElementName(path.node);
if (!name)
return false;
if (name.charAt(0) === name.charAt(0).toLowerCase())
return true;
return ALLOWED_CUSTOM_COMPONENTS.includes(name);
}
}
export class ExpressionAnalysisUtils {
types;
constructor(types) {
this.types = types;
}
isIdAccess(node) {
if (!this.types.isMemberExpression(node))
return false;
if (this.types.isIdentifier(node.property)) {
return node.property.name === "_id" || node.property.name === "id";
}
if (this.types.isStringLiteral(node.property)) {
return node.property.value === "_id" || node.property.value === "id";
}
return false;
}
isItemsAccess(node) {
return (this.types.isMemberExpression(node) &&
this.types.isIdentifier(node.property) &&
node.property.name === "items");
}
isLengthAccess(node) {
return (this.types.isMemberExpression(node) &&
this.types.isIdentifier(node.property) &&
node.property.name === "length");
}
extractRootIdentifier(node) {
if (this.types.isIdentifier(node))
return node;
if (this.types.isMemberExpression(node)) {
return this.extractRootIdentifier(node.object);
}
if (this.types.isOptionalMemberExpression(node)) {
return this.extractRootIdentifier(node.object);
}
if (this.types.isCallExpression(node) && this.types.isMemberExpression(node.callee)) {
return this.extractRootIdentifier(node.callee.object);
}
return null;
}
unwrapLogicalExpression(node) {
if (this.types.isLogicalExpression(node)) {
if (node.operator === "&&")
return node.right;
if (node.operator === "||" || node.operator === "??") {
return node.left;
}
}
return node;
}
collectMemberExpressionPath(node) {
const parts = [];
let current = node;
while (this.types.isMemberExpression(current) ||
this.types.isOptionalMemberExpression(current)) {
const prop = current.property;
if (this.types.isIdentifier(prop)) {
parts.unshift(prop.name);
}
else if (this.types.isStringLiteral(prop)) {
parts.unshift(prop.value);
}
current = current.object;
}
if (this.types.isIdentifier(current)) {
parts.unshift(current.name);
}
return parts;
}
createOptionalChainExpression(node) {
const object = this.types.isOptionalMemberExpression(node.object)
? node.object
: this.types.isMemberExpression(node.object)
? this.createOptionalChainExpression(node.object)
: node.object;
const property = node.property;
return this.types.optionalMemberExpression(object, property, node.computed, true);
}
getFieldPathFromExpression(node, rootName) {
const parts = this.collectMemberExpressionPath(node);
if (parts.length < 2)
return null;
if (parts[0] !== rootName)
return null;
const fieldParts = parts.slice(1);
const fieldPath = fieldParts.join(".");
if (EXCLUDED_FIELDS.includes(fieldPath))
return null;
return fieldPath;
}
}
export class BindingUtils {
types;
constructor(types) {
this.types = types;
}
isFunctionParameter(identifierName, path) {
const fn = path.getFunctionParent();
if (!fn)
return false;
const params = fn.get("params");
for (const param of (Array.isArray(params) ? params : [params])) {
if (param.isIdentifier() && param.node.name === identifierName) {
return true;
}
if (param.isObjectPattern()) {
for (const prop of param.get("properties")) {
if (prop.isObjectProperty() &&
this.types.isIdentifier(prop.node.value) &&
prop.node.value.name === identifierName) {
return true;
}
}
}
if (param.isArrayPattern()) {
for (const el of param.get("elements")) {
if (el.isIdentifier() && el.node.name === identifierName) {
return true;
}
}
}
}
return false;
}
isUseStateCall(init) {
if (!init.isCallExpression())
return null;
const callee = init.get("callee");
if (!callee.isIdentifier() || callee.node.name !== "useState")
return null;
const declarator = init.parentPath;
if (!declarator?.isVariableDeclarator())
return null;
const id = declarator.get("id");
if (!id.isArrayPattern())
return null;
const elements = id.get("elements");
const setterEl = elements[1];
const setterName = setterEl && setterEl.isIdentifier() ? setterEl.node.name : null;
return { stateIndex: 0, setterName };
}
isPromiseAllCall(init) {
if (!init.isAwaitExpression()) {
if (init.isCallExpression()) {
const callee = init.get("callee");
return this.isPromiseAllCallee(callee);
}
return false;
}
const argument = init.get("argument");
if (!argument.isCallExpression())
return false;
const callee = argument.get("callee");
return this.isPromiseAllCallee(callee);
}
isPromiseAllCallee(callee) {
if (!callee.isMemberExpression())
return false;
const obj = callee.get("object");
const prop = callee.get("property");
return (obj.isIdentifier() &&
obj.node.name === "Promise" &&
prop.isIdentifier() &&
prop.node.name === "all");
}
extractDestructuredProperties(pattern) {
const properties = [];
for (const prop of pattern.properties) {
if (this.types.isObjectProperty(prop)) {
if (this.types.isIdentifier(prop.key)) {
properties.push(prop.key.name);
}
else if (this.types.isStringLiteral(prop.key)) {
properties.push(prop.key.value);
}
}
}
return properties;
}
findSetterCallInScope(setterName, scope) {
let result = null;
scope.traverse({
CallExpression(callPath) {
if (result)
return;
const callee = callPath.get("callee");
if (callee.isIdentifier() && callee.node.name === setterName) {
result = callPath;
}
},
});
return result;
}
}
export class CallExpressionUtils {
types;
constructor(types) {
this.types = types;
}
isGetAllCall(node) {
const callee = node.callee;
if (!this.types.isMemberExpression(callee))
return null;
const obj = callee.object;
const prop = callee.property;
if (!this.types.isIdentifier(obj) ||
!this.types.isIdentifier(prop) ||
prop.name !== "getAll") {
return null;
}
const args = node.arguments;
if (args.length < 1)
return null;
const firstArg = args[0];
if (!this.types.isStringLiteral(firstArg))
return null;
const collectionName = firstArg.value;
const references = this.extractReferencesFromArg(args[1]);
return { collectionName, references };
}
isGetByIdCall(node) {
const callee = node.callee;
if (!this.types.isMemberExpression(callee))
return null;
const obj = callee.object;
const prop = callee.property;
if (!this.types.isIdentifier(obj) ||
!this.types.isIdentifier(prop) ||
prop.name !== "getById") {
return null;
}
const args = node.arguments;
if (args.length < 1)
return null;
const firstArg = args[0];
if (!this.types.isStringLiteral(firstArg))
return null;
const collectionName = firstArg.value;
const multiRefFields = this.extractMultiRefFromOptions(args[2]);
return { collectionName, multiRefFields };
}
extractReferencesFromArg(arg) {
if (!arg || !this.types.isArrayExpression(arg))
return [];
return arg.elements
.filter((el) => this.types.isStringLiteral(el))
.map((el) => el.value);
}
extractMultiRefFromOptions(arg) {
if (!arg || !this.types.isObjectExpression(arg))
return [];
for (const prop of arg.properties) {
if (this.types.isObjectProperty(prop) &&
this.types.isIdentifier(prop.key) &&
prop.key.name === "multiRef" &&
this.types.isArrayExpression(prop.value)) {
return prop.value.elements
.filter((el) => this.types.isStringLiteral(el))
.map((el) => el.value);
}
}
return [];
}
isArrayMethod(node, methodName) {
const callee = node.callee;
return (this.types.isMemberExpression(callee) &&
this.types.isIdentifier(callee.property) &&
callee.property.name === methodName);
}
isChainedArrayMethod(node) {
const chainMethods = ["filter", "sort", "slice", "concat", "reverse", "flat"];
return chainMethods.some((m) => this.isArrayMethod(node, m));
}
/**
* Detect base44.entities.EntityName.list() or .getAll() patterns.
* Returns the entity name as the collection name.
*/
isBase44EntityListCall(node) {
const callee = node.callee;
if (!this.types.isMemberExpression(callee))
return null;
const method = callee.property;
if (!this.types.isIdentifier(method) ||
(method.name !== "list" && method.name !== "getAll" && method.name !== "filter")) {
return null;
}
const entityAccess = callee.object;
if (!this.types.isMemberExpression(entityAccess))
return null;
const entityName = entityAccess.property;
if (!this.types.isIdentifier(entityName))
return null;
const entitiesAccess = entityAccess.object;
if (!this.types.isMemberExpression(entitiesAccess))
return null;
const entitiesProp = entitiesAccess.property;
if (!this.types.isIdentifier(entitiesProp) ||
entitiesProp.name !== "entities") {
return null;
}
return { collectionName: entityName.name };
}
/**
* Detect base44.entities.EntityName.getById() or .get() patterns.
*/
isBase44EntityGetCall(node) {
const callee = node.callee;
if (!this.types.isMemberExpression(callee))
return null;
const method = callee.property;
if (!this.types.isIdentifier(method) ||
(method.name !== "get" && method.name !== "getById")) {
return null;
}
const entityAccess = callee.object;
if (!this.types.isMemberExpression(entityAccess))
return null;
const entityName = entityAccess.property;
if (!this.types.isIdentifier(entityName))
return null;
const entitiesAccess = entityAccess.object;
if (!this.types.isMemberExpression(entitiesAccess))
return null;
const entitiesProp = entitiesAccess.property;
if (!this.types.isIdentifier(entitiesProp) ||
entitiesProp.name !== "entities") {
return null;
}
return { collectionName: entityName.name };
}
getCallbackArgument(callExpr) {
const firstArg = callExpr.arguments[0];
if (this.types.isArrowFunctionExpression(firstArg) ||
this.types.isFunctionExpression(firstArg)) {
return firstArg;
}
return null;
}
}
export class StaticValueUtils {
types;
constructor(types) {
this.types = types;
}
isPrimitiveLiteral(path) {
return (path.isStringLiteral() ||
path.isNumericLiteral() ||
path.isBooleanLiteral() ||
path.isNullLiteral());
}
isStaticValue(path, visited = new Set()) {
if (this.isPrimitiveLiteral(path))
return true;
if (path.isIdentifier())
return this.isStaticIdentifier(path, visited);
if (path.isObjectExpression())
return this.isStaticObject(path, visited);
if (path.isArrayExpression())
return this.isStaticArrayExpression(path, visited);
return false;
}
isStaticIdentifier(path, visited = new Set()) {
const binding = path.scope.getBinding(path.node.name);
if (!binding)
return false;
if (binding.kind === "module")
return true;
if (binding.kind === "const" && binding.path.isVariableDeclarator()) {
const name = path.node.name;
if (visited.has(name))
return false;
visited.add(name);
const init = binding.path.get("init");
if (init.hasNode()) {
return this.isStaticValue(init, visited);
}
}
return false;
}
isStaticObject(path, visited = new Set()) {
return path.get("properties").every((prop) => {
if (!prop.isObjectProperty())
return false;
return this.isStaticValue(prop.get("value"), visited);
});
}
isStaticArrayExpression(arrayExpression, visited = new Set()) {
return arrayExpression.get("elements").every((element) => {
if (!element.node || element.isSpreadElement())
return true;
return this.isStaticValue(element, visited);
});
}
isDerivedFromStaticData(identifierName, path) {
const binding = path.scope.getBinding(identifierName);
if (!binding)
return false;
if (binding.path.isVariableDeclarator()) {
const init = binding.path.get("init");
if (init.isArrayExpression() || init.isObjectExpression()) {
return this.isStaticValue(init);
}
}
const fnParent = path.getFunctionParent();
if (!fnParent)
return false;
const params = fnParent.get("params");
for (const param of (Array.isArray(params) ? params : [params])) {
if (param.isIdentifier() && param.node.name === identifierName) {
const mapCall = fnParent.parentPath;
if (mapCall?.isCallExpression()) {
const callee = mapCall.get("callee");
if (callee.isMemberExpression() &&
callee.get("property").isIdentifier()) {
const propName = callee.get("property").node.name;
if (propName === "map" || propName === "flatMap") {
const arrayObj = callee.get("object");
if (arrayObj.isIdentifier()) {
return this.isDerivedFromStaticData(arrayObj.node.name, arrayObj);
}
if (arrayObj.isArrayExpression()) {
return this.isStaticArrayExpression(arrayObj);
}
}
}
}
}
}
return false;
}
}
export class TypeCheckUtils {
types;
constructor(types) {
this.types = types;
}
isArrayIsArrayCheck(node) {
if (!this.types.isCallExpression(node))
return false;
const callee = node.callee;
return (this.types.isMemberExpression(callee) &&
this.types.isIdentifier(callee.object) &&
callee.object.name === "Array" &&
this.types.isIdentifier(callee.property) &&
callee.property.name === "isArray");
}
isTypeofObjectCheck(node) {
if (!this.types.isBinaryExpression(node))
return false;
if (node.operator !== "===" && node.operator !== "==")
return false;
const isTypeof = (side) => this.types.isUnaryExpression(side) && side.operator === "typeof";
const isObjectString = (side) => this.types.isStringLiteral(side) && side.value === "object";
return ((isTypeof(node.left) &&
isObjectString(node.right)) ||
(isObjectString(node.left) &&
isTypeof(node.right)));
}
isReferenceTypeCheck(node) {
return this.isArrayIsArrayCheck(node) || this.isTypeofObjectCheck(node);
}
isLengthCheck(node) {
if (this.types.isMemberExpression(node)) {
return (this.types.isIdentifier(node.property) &&
node.property.name === "length");
}
if (this.types.isOptionalMemberExpression(node)) {
return (this.types.isIdentifier(node.property) &&
node.property.name === "length");
}
return false;
}
}
//# sourceMappingURL=shared-utils.js.map
File diff suppressed because one or more lines are too long