/**
 * Utilities for recursively walking the block tree in an API definition.
 *
 * The block structure supports nesting via loop, tryCatch, conditional,
 * parallel, and stream containers. These helpers factor out that traversal
 * so callers only need to provide a per-step visitor callback.
 */
/** Built-in integration types that do not reference external integrations. */
const BUILT_IN_INTEGRATION_TYPES = new Set(["javascript", "python"]);
/**
 * Recursively walk every step in a block tree, invoking `visitor` for each
 * object that contains a `step` property (i.e. regular blocks and stream
 * triggers).
 *
 * Handles all nested block containers: loop, tryCatch (try/catch/finally),
 * conditional (if/elseIf/else), parallel (static paths + dynamic), and
 * stream (trigger + process).
 */
export function forEachStep(blocks, visitor) {
    for (const block of blocks) {
        // Direct step
        if (block.step) {
            visitor(block);
        }
        // Loop
        if (block.loop?.blocks) {
            forEachStep(block.loop.blocks, visitor);
        }
        // TryCatch
        if (block.tryCatch) {
            for (const branch of ["try", "catch", "finally"]) {
                if (block.tryCatch[branch]?.blocks) {
                    forEachStep(block.tryCatch[branch].blocks, visitor);
                }
            }
        }
        // Conditional
        if (block.conditional) {
            if (block.conditional.if?.blocks) {
                forEachStep(block.conditional.if.blocks, visitor);
            }
            if (Array.isArray(block.conditional.elseIf)) {
                for (const branch of block.conditional.elseIf) {
                    if (branch?.blocks) {
                        forEachStep(branch.blocks, visitor);
                    }
                }
            }
            if (block.conditional.else?.blocks) {
                forEachStep(block.conditional.else.blocks, visitor);
            }
        }
        // Parallel (static paths + dynamic blocks)
        if (block.parallel) {
            if (block.parallel.static?.paths) {
                for (const pathBlocks of Object.values(block.parallel.static.paths)) {
                    if (pathBlocks?.blocks) {
                        forEachStep(pathBlocks.blocks, visitor);
                    }
                }
            }
            if (block.parallel.dynamic?.blocks) {
                forEachStep(block.parallel.dynamic.blocks, visitor);
            }
        }
        // Stream
        if (block.stream) {
            if (block.stream.trigger?.step) {
                visitor(block.stream.trigger);
            }
            if (block.stream.process?.blocks) {
                forEachStep(block.stream.process.blocks, visitor);
            }
        }
    }
}
/**
 * Collect all external (non-built-in) integration IDs from an array of
 * blocks.
 */
export function extractIntegrationIdsFromBlocks(blocks) {
    const ids = new Set();
    forEachStep(blocks, (owner) => {
        const id = owner.step?.integration;
        if (id && !BUILT_IN_INTEGRATION_TYPES.has(id)) {
            ids.add(id);
        }
    });
    return ids;
}
/**
 * Replace steps whose integration ID is not in `availableIntegrationIds`
 * with a javascript stub.
 *
 * @returns The set of integration IDs that were sanitized.
 */
export function sanitizeBlockIntegrations(blocks, availableIntegrationIds) {
    const sanitizedIds = new Set();
    forEachStep(blocks, (owner) => {
        const id = owner.step?.integration;
        if (!id || BUILT_IN_INTEGRATION_TYPES.has(id))
            return;
        if (availableIntegrationIds.has(id))
            return;
        // Remove all existing keys from the step
        for (const key of Object.keys(owner.step)) {
            delete owner.step[key];
        }
        // Replace with a javascript stub
        owner.step.integration = "javascript";
        owner.step.javascript = {
            body: `return null; // This step has been replaced (originally ${id})`,
        };
        sanitizedIds.add(id);
    });
    return sanitizedIds;
}
//# sourceMappingURL=block-traversal.js.map