@mondaydotcomorg/atp-compiler
Version:
Production-ready compiler for transforming async iteration patterns into resumable operations with checkpoint-based state management
131 lines • 4.01 kB
JavaScript
import * as t from '@babel/types';
import { isPausableCallExpression, getMemberExpressionPath } from './utils.js';
export class BatchParallelDetector {
canBatch(promiseAllNode) {
const arrayArg = promiseAllNode.arguments[0];
if (!t.isArrayExpression(arrayArg)) {
return false;
}
if (arrayArg.elements.length === 0) {
return false;
}
return arrayArg.elements.every((el) => {
if (!el || t.isSpreadElement(el)) {
return false;
}
return this.isDirectPausableCall(el);
});
}
isDirectPausableCall(node) {
if (t.isAwaitExpression(node)) {
node = node.argument;
}
if (!t.isCallExpression(node)) {
return false;
}
return isPausableCallExpression(node);
}
extractBatchCalls(arrayNode) {
const calls = [];
for (const el of arrayNode.elements) {
if (!el || t.isSpreadElement(el)) {
continue;
}
let callNode = el;
if (t.isAwaitExpression(callNode)) {
callNode = callNode.argument;
}
if (!t.isCallExpression(callNode)) {
continue;
}
const callInfo = this.extractCallInfo(callNode);
if (callInfo) {
calls.push(callInfo);
}
}
return calls;
}
extractCallInfo(callNode) {
if (!t.isMemberExpression(callNode.callee)) {
return null;
}
const path = getMemberExpressionPath(callNode.callee);
const parts = path.split('.');
if (parts.length < 3) {
return null;
}
const [namespace, service, method] = parts;
if (namespace !== 'atp' || !method) {
return null;
}
const type = service;
const payload = this.extractPayload(callNode.arguments);
return {
type,
operation: method,
payload,
};
}
/**
* Extract payload AST node directly
*/
extractPayloadNode(callNode) {
if (callNode.arguments.length === 0) {
return t.objectExpression([]);
}
const firstArg = callNode.arguments[0];
if (!firstArg || t.isSpreadElement(firstArg) || !t.isExpression(firstArg)) {
return null;
}
return firstArg;
}
extractPayload(args) {
if (args.length === 0) {
return {};
}
const firstArg = args[0];
if (t.isSpreadElement(firstArg)) {
return {};
}
if (t.isObjectExpression(firstArg)) {
return this.objectExpressionToRecord(firstArg);
}
if (t.isStringLiteral(firstArg)) {
return { message: firstArg.value };
}
return {};
}
objectExpressionToRecord(obj) {
const record = {};
for (const prop of obj.properties) {
if (t.isObjectProperty(prop) && !prop.computed) {
const key = t.isIdentifier(prop.key) ? prop.key.name : String(prop.key);
const value = this.extractValue(prop.value);
record[key] = value;
}
}
return record;
}
extractValue(node) {
if (t.isStringLiteral(node)) {
return node.value;
}
if (t.isNumericLiteral(node)) {
return node.value;
}
if (t.isBooleanLiteral(node)) {
return node.value;
}
if (t.isNullLiteral(node)) {
return null;
}
if (t.isArrayExpression(node)) {
return node.elements.map((el) => el && !t.isSpreadElement(el) ? this.extractValue(el) : null);
}
if (t.isObjectExpression(node)) {
return this.objectExpressionToRecord(node);
}
return undefined;
}
}
//# sourceMappingURL=batch-detector.js.map