Files
sim/apps/sim/executor/variables/resolvers/loop.ts
Waleed d09fd6cf92 fix(import): fixed trigger save on export/import flow (#2239)
* fix(import): fixed trigger save on export/import flow

* optimized test runners

* ack PR comments
2025-12-07 23:00:28 -08:00

89 lines
2.3 KiB
TypeScript

import { createLogger } from '@/lib/logs/console/logger'
import { isReference, parseReferencePath, REFERENCE } from '@/executor/constants'
import { extractBaseBlockId } from '@/executor/utils/subflow-utils'
import {
navigatePath,
type ResolutionContext,
type Resolver,
} from '@/executor/variables/resolvers/reference'
import type { SerializedWorkflow } from '@/serializer/types'
const logger = createLogger('LoopResolver')
export class LoopResolver implements Resolver {
constructor(private workflow: SerializedWorkflow) {}
canResolve(reference: string): boolean {
if (!isReference(reference)) {
return false
}
const parts = parseReferencePath(reference)
if (parts.length === 0) {
return false
}
const [type] = parts
return type === REFERENCE.PREFIX.LOOP
}
resolve(reference: string, context: ResolutionContext): any {
const parts = parseReferencePath(reference)
if (parts.length < 2) {
logger.warn('Invalid loop reference - missing property', { reference })
return undefined
}
const [_, property, ...pathParts] = parts
let loopScope = context.loopScope
if (!loopScope) {
const loopId = this.findLoopForBlock(context.currentNodeId)
if (!loopId) {
return undefined
}
loopScope = context.executionContext.loopExecutions?.get(loopId)
}
if (!loopScope) {
logger.warn('Loop scope not found', { reference })
return undefined
}
let value: any
switch (property) {
case 'iteration':
case 'index':
value = loopScope.iteration
break
case 'item':
case 'currentItem':
value = loopScope.item
break
case 'items':
value = loopScope.items
break
default:
logger.warn('Unknown loop property', { property })
return undefined
}
// If there are additional path parts, navigate deeper
if (pathParts.length > 0) {
return navigatePath(value, pathParts)
}
return value
}
private findLoopForBlock(blockId: string): string | undefined {
const baseId = extractBaseBlockId(blockId)
for (const loopId of Object.keys(this.workflow.loops || {})) {
const loopConfig = this.workflow.loops[loopId]
if (loopConfig.nodes.includes(baseId)) {
return loopId
}
}
return undefined
}
}