UNPKG

mlld

Version:

mlld: llm scripting language

310 lines (308 loc) 12.2 kB
import { normalizeIterableValue } from './chunk-JVJPPTN3.mjs'; import { logger } from './chunk-M3R2H5KU.mjs'; import { extractSecurityDescriptor, varMxToSecurityDescriptor, isStructuredValue, asData, ensureStructuredValue, mergeDescriptors, setExpressionProvenance } from './chunk-RKGZ44GZ.mjs'; import { isExecutable } from './chunk-EIWSEMQ4.mjs'; import { __name } from './chunk-NJQT543K.mjs'; // interpreter/eval/foreach.ts function hasArrayData(value) { if (!value || typeof value !== "object") { return false; } if (!("data" in value)) { return false; } const { data } = value; return Array.isArray(data); } __name(hasArrayData, "hasArrayData"); async function evaluateForeachCommand(foreachExpr, env) { if (process.env.MLLD_DEBUG === "true") { logger.debug("evaluateForeachCommand called with:", { foreachExpr }); } const node = foreachExpr && typeof foreachExpr === "object" && "value" in foreachExpr ? foreachExpr.value : foreachExpr; const { execInvocation, arrays } = node; let commandName; let commandArgs = []; if (execInvocation.type === "ExecInvocation") { commandName = execInvocation.commandRef.name; commandArgs = execInvocation.commandRef.args || []; } else if (execInvocation.identifier) { commandName = execInvocation.identifier; } else { throw new Error("Invalid foreach command structure"); } const cmdVariable = env.getVariable(commandName); if (!cmdVariable) { throw new Error(`Command not found: ${commandName}`); } if (!isExecutable(cmdVariable)) { throw new Error(`Variable '${commandName}' cannot be used with foreach. Expected an @exec command or @text template with parameters, but got type: ${cmdVariable.type}`); } const { evaluateDataValue } = await import('./data-value-evaluator-6G4NQGOF.mjs'); const evaluatedArrays = []; const arraySecurityDescriptors = []; const arrayNodes = arrays || commandArgs; for (let i = 0; i < arrayNodes.length; i++) { const arrayVar = arrayNodes[i]; if (process.env.MLLD_DEBUG_FOREACH === "true") { console.error("[foreach] array node type:", arrayVar?.type); } const arrayValue = await evaluateDataValue(arrayVar, env); let sourceDescriptor = extractSecurityDescriptor(arrayValue); if (!sourceDescriptor && arrayVar && typeof arrayVar === "object") { let referencedName; if ("identifier" in arrayVar && typeof arrayVar.identifier === "string") { referencedName = arrayVar.identifier; } else if ("variable" in arrayVar && arrayVar.variable?.identifier) { referencedName = arrayVar.variable.identifier; } const referencedVar = referencedName ? env.getVariable(referencedName) : void 0; sourceDescriptor = referencedVar?.mx ? varMxToSecurityDescriptor(referencedVar.mx) : void 0; } if (isStructuredValue(arrayValue)) { let structuredData = asData(arrayValue); if (!Array.isArray(structuredData)) { if (hasArrayData(structuredData)) { structuredData = structuredData.data; } else if (typeof structuredData === "string") { try { const parsed = JSON.parse(structuredData); if (Array.isArray(parsed)) { structuredData = parsed; } } catch { } } } if (!Array.isArray(structuredData) && typeof arrayValue.text === "string") { try { const parsed = JSON.parse(arrayValue.text); if (Array.isArray(parsed)) { structuredData = parsed; } } catch { } } if (!Array.isArray(structuredData)) { throw new Error(`Argument ${i + 1} to foreach must be an array, got structured ${arrayValue.type}`); } const normalizedStructured = normalizeIterableValue(structuredData); attachDescriptorRecursively(normalizedStructured, sourceDescriptor); evaluatedArrays.push(normalizedStructured); arraySecurityDescriptors.push(sourceDescriptor); continue; } if (!Array.isArray(arrayValue)) { throw new Error(`Argument ${i + 1} to foreach must be an array, got ${typeof arrayValue}`); } const normalizedArray = normalizeIterableValue(arrayValue); attachDescriptorRecursively(normalizedArray, sourceDescriptor); evaluatedArrays.push(normalizedArray); arraySecurityDescriptors.push(sourceDescriptor); } validateArrayInputs(evaluatedArrays); if (!isWithinPerformanceLimit(evaluatedArrays)) { const totalCombinations = evaluatedArrays.reduce((total, arr) => total * arr.length, 1); throw new Error(`Foreach operation would generate ${totalCombinations} combinations, which exceeds the performance limit. Consider reducing array sizes or using more specific filtering.`); } const definition = cmdVariable.value; const paramCount = cmdVariable.paramNames?.length || definition.paramNames?.length || 0; if (evaluatedArrays.length !== paramCount) { const paramType = definition.sourceDirective === "text" ? "Text template" : "Command"; throw new Error(`${paramType} '${commandName}' expects ${paramCount} parameter${paramCount !== 1 ? "s" : ""}, but foreach is passing ${evaluatedArrays.length} array${evaluatedArrays.length !== 1 ? "s" : ""}`); } const tuples = cartesianProduct(evaluatedArrays); const { evaluateExecInvocation } = await import('./exec-invocation-M54PNM33.mjs'); const results = []; const mergeTupleDescriptor = /* @__PURE__ */ __name(() => { let descriptor; for (const candidate of arraySecurityDescriptors) { if (!candidate) continue; descriptor = descriptor ? mergeDescriptors(descriptor, candidate) : candidate; } return descriptor; }, "mergeTupleDescriptor"); for (let i = 0; i < tuples.length; i++) { const tuple = tuples[i]; try { const execInvocationNode = { type: "ExecInvocation", commandRef: { identifier: commandName, args: tuple }, withClause: null }; const result = await evaluateExecInvocation(execInvocationNode, env); const tupleDescriptor = mergeTupleDescriptor(); let structuredResult = isStructuredValue(result.value) ? result.value : ensureStructuredValue(result.value); if (tupleDescriptor) { const existingDescriptor = extractSecurityDescriptor(structuredResult); const merged = existingDescriptor ? mergeDescriptors(existingDescriptor, tupleDescriptor) : tupleDescriptor; structuredResult = ensureStructuredValue(structuredResult, structuredResult.type, structuredResult.text, { security: merged }); } results.push(structuredResult); } catch (error) { const params = cmdVariable.paramNames || definition.paramNames || []; const iterationContext = params.map((param, index) => `${param}: ${JSON.stringify(tuple[index])}`).join(", "); throw new Error(`Error in foreach iteration ${i + 1} (${iterationContext}): ${error instanceof Error ? error.message : String(error)}`); } } let finalResults = results; const withClause = node.with || foreachExpr.with; const batchPipelineConfig = node.batchPipeline || withClause?.batchPipeline || foreachExpr.batchPipeline; const batchStages = Array.isArray(batchPipelineConfig) ? batchPipelineConfig : batchPipelineConfig?.pipeline; if (batchStages && batchStages.length > 0) { const { processPipeline } = await import('./unified-processor-GTJC5G2K.mjs'); const { createArrayVariable } = await import('./variable-FNPDYIEH.mjs'); const batchInput = createArrayVariable("foreach-batch-input", results, false, { directive: "foreach", syntax: "expression", hasInterpolation: false, isMultiLine: false }, { internal: { isBatchInput: true } }); try { const pipelineResult = await processPipeline({ value: batchInput, env, pipeline: batchStages, identifier: `foreach-batch-${commandName}`, location: foreachExpr.location, isRetryable: false }); const { isVariable, extractVariableValue } = await import('./variable-resolution-HFG3FTZK.mjs'); if (isStructuredValue(pipelineResult)) { finalResults = pipelineResult; } else if (isVariable(pipelineResult)) { finalResults = await extractVariableValue(pipelineResult, env); } else { finalResults = pipelineResult; } } catch (error) { logger.warn(`Batch pipeline failed for foreach: ${error instanceof Error ? error.message : String(error)}`); finalResults = results; } } return finalResults; } __name(evaluateForeachCommand, "evaluateForeachCommand"); async function evaluateForeachSection(foreachExpr, env) { return evaluateForeachCommand(foreachExpr, env); } __name(evaluateForeachSection, "evaluateForeachSection"); async function validateForeachExpression(foreachExpr, env) { const errors = []; try { if (!foreachExpr || typeof foreachExpr !== "object") { errors.push("Foreach expression must be an object"); return { valid: false, errors }; } const { execInvocation } = foreachExpr.value || foreachExpr; if (!execInvocation) { errors.push("Foreach expression missing exec invocation"); return { valid: false, errors }; } let commandName; if (execInvocation.type === "ExecInvocation") { commandName = execInvocation.commandRef.name; } else if (execInvocation.identifier) { commandName = execInvocation.identifier; } else { errors.push("Invalid foreach command structure"); return { valid: false, errors }; } const cmdVariable = env.getVariable(commandName); if (!cmdVariable) { errors.push(`Command not found: ${commandName}`); } else if (!isExecutable(cmdVariable)) { errors.push(`Variable '${commandName}' is not executable`); } return { valid: errors.length === 0, errors }; } catch (error) { errors.push(`Validation error: ${error instanceof Error ? error.message : String(error)}`); return { valid: false, errors }; } } __name(validateForeachExpression, "validateForeachExpression"); function validateArrayInputs(arrays) { if (arrays.length === 0) { throw new Error("Foreach requires at least one array argument"); } for (let i = 0; i < arrays.length; i++) { const arr = arrays[i]; if (!Array.isArray(arr)) { throw new Error(`Argument ${i + 1} must be an array`); } if (arr.length === 0) { throw new Error(`Array ${i + 1} cannot be empty`); } } } __name(validateArrayInputs, "validateArrayInputs"); function isWithinPerformanceLimit(arrays) { const MAX_COMBINATIONS = 1e4; const totalCombinations = arrays.reduce((total, arr) => total * arr.length, 1); return totalCombinations <= MAX_COMBINATIONS; } __name(isWithinPerformanceLimit, "isWithinPerformanceLimit"); function cartesianProduct(arrays) { if (arrays.length === 0) return []; if (arrays.length === 1) return arrays[0].map((item) => [ item ]); const result = []; const [head, ...tail] = arrays; const tailProduct = cartesianProduct(tail); for (const headItem of head) { for (const tailItem of tailProduct) { result.push([ headItem, ...tailItem ]); } } return result; } __name(cartesianProduct, "cartesianProduct"); function attachDescriptorRecursively(value, descriptor) { if (!descriptor || !value || typeof value !== "object") { return; } setExpressionProvenance(value, descriptor); if (Array.isArray(value)) { for (const entry of value) { attachDescriptorRecursively(entry, descriptor); } return; } for (const child of Object.values(value)) { attachDescriptorRecursively(child, descriptor); } } __name(attachDescriptorRecursively, "attachDescriptorRecursively"); export { evaluateForeachCommand, evaluateForeachSection, validateForeachExpression }; //# sourceMappingURL=chunk-2NIKWPWP.mjs.map //# sourceMappingURL=chunk-2NIKWPWP.mjs.map