mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-15 00:44:56 -05:00
* fix(import): fixed trigger save on export/import flow * optimized test runners * ack PR comments
89 lines
2.3 KiB
TypeScript
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
|
|
}
|
|
}
|