UNPKG

@mondaydotcomorg/atp-compiler

Version:

Production-ready compiler for transforming async iteration patterns into resumable operations with checkpoint-based state management

133 lines 5.4 kB
import * as t from '@babel/types'; import { generateUniqueId } from '../runtime/context.js'; import { BatchParallelDetector } from './batch-detector.js'; import { RuntimeFunction } from '../runtime/runtime-functions.js'; export class PromiseTransformer { transformCount = 0; batchDetector; enableBatchParallel; constructor(enableBatchParallel = true) { this.batchDetector = new BatchParallelDetector(); this.enableBatchParallel = enableBatchParallel; } transformPromiseAll(path) { const node = path.node; if (!this.isPromiseAll(node)) { return false; } const arrayArg = node.arguments[0]; if (this.enableBatchParallel && this.batchDetector.canBatch(node)) { return this.transformToBatchParallel(path, node); } if (t.isArrayExpression(arrayArg)) { return this.transformToSequential(path, node); } return false; } transformPromiseAllSettled(path) { const node = path.node; if (!this.isPromiseAllSettled(node)) { return false; } const arrayArg = node.arguments[0]; if (t.isArrayExpression(arrayArg)) { const parallelId = generateUniqueId('allSettled'); const runtimeCall = t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('__runtime'), t.identifier(RuntimeFunction.RESUMABLE_PROMISE_ALL_SETTLED)), [arrayArg, t.stringLiteral(parallelId)])); path.replaceWith(runtimeCall); this.transformCount++; return true; } return false; } transformToBatchParallel(path, node) { const arrayArg = node.arguments[0]; if (!t.isArrayExpression(arrayArg)) { return false; } const batchId = generateUniqueId('batch'); const batchCallsArray = t.arrayExpression(arrayArg.elements.map((el) => { if (!el || t.isSpreadElement(el)) { return t.nullLiteral(); } let callNode = el; if (t.isAwaitExpression(callNode)) { callNode = callNode.argument; } if (!t.isCallExpression(callNode) || !t.isMemberExpression(callNode.callee)) { return t.nullLiteral(); } const callInfo = this.batchDetector.extractCallInfo(callNode); if (!callInfo) { return t.nullLiteral(); } const payloadArg = callNode.arguments[0]; return t.objectExpression([ t.objectProperty(t.identifier('type'), t.stringLiteral(callInfo.type)), t.objectProperty(t.identifier('operation'), t.stringLiteral(callInfo.operation)), t.objectProperty(t.identifier('payload'), payloadArg && t.isExpression(payloadArg) ? payloadArg : t.objectExpression([])), ]); })); const runtimeCall = t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('__runtime'), t.identifier(RuntimeFunction.BATCH_PARALLEL)), [batchCallsArray, t.stringLiteral(batchId)])); path.replaceWith(runtimeCall); this.transformCount++; return true; } transformToSequential(path, node) { const arrayArg = node.arguments[0]; if (!t.isArrayExpression(arrayArg)) { return false; } const parallelId = generateUniqueId('parallel'); const runtimeCall = t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('__runtime'), t.identifier(RuntimeFunction.RESUMABLE_PROMISE_ALL)), [arrayArg, t.stringLiteral(parallelId)])); path.replaceWith(runtimeCall); this.transformCount++; return true; } payloadToExpression(payload) { const properties = []; for (const [key, value] of Object.entries(payload)) { properties.push(t.objectProperty(t.identifier(key), this.valueToExpression(value))); } return t.objectExpression(properties); } valueToExpression(value) { if (typeof value === 'string') { return t.stringLiteral(value); } if (typeof value === 'number') { return t.numericLiteral(value); } if (typeof value === 'boolean') { return t.booleanLiteral(value); } if (value === null) { return t.nullLiteral(); } if (Array.isArray(value)) { return t.arrayExpression(value.map((v) => this.valueToExpression(v))); } if (typeof value === 'object') { return this.payloadToExpression(value); } return t.identifier('undefined'); } isPromiseAll(node) { const callee = node.callee; return (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: 'Promise' }) && t.isIdentifier(callee.property, { name: 'all' })); } isPromiseAllSettled(node) { const callee = node.callee; return (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: 'Promise' }) && t.isIdentifier(callee.property, { name: 'allSettled' })); } getTransformCount() { return this.transformCount; } resetTransformCount() { this.transformCount = 0; } } //# sourceMappingURL=promise-transformer.js.map