| 204 | } |
| 205 | |
| 206 | function wrapCodeForValidation(block: CodeBlock): string { |
| 207 | let code = block.code; |
| 208 | |
| 209 | // Python: auto-detect async code and wrap if needed |
| 210 | if (block.language === "python") { |
| 211 | const hasAwait = /\bawait\b/.test(code); |
| 212 | const hasAsyncDef = /\basync\s+def\b/.test(code); |
| 213 | |
| 214 | // Check if await is used outside of any async def |
| 215 | // Simple heuristic: if await appears at column 0 or after assignment at column 0 |
| 216 | const lines = code.split("\n"); |
| 217 | let awaitOutsideFunction = false; |
| 218 | let inAsyncFunction = false; |
| 219 | let indentLevel = 0; |
| 220 | |
| 221 | for (const line of lines) { |
| 222 | const trimmed = line.trimStart(); |
| 223 | const leadingSpaces = line.length - trimmed.length; |
| 224 | |
| 225 | // Track if we're in an async function |
| 226 | if (trimmed.startsWith("async def ")) { |
| 227 | inAsyncFunction = true; |
| 228 | indentLevel = leadingSpaces; |
| 229 | } else if (inAsyncFunction && leadingSpaces <= indentLevel && trimmed && !trimmed.startsWith("#")) { |
| 230 | // Dedented back, we're out of the function |
| 231 | inAsyncFunction = false; |
| 232 | } |
| 233 | |
| 234 | // Check for await outside function |
| 235 | if (trimmed.includes("await ") && !inAsyncFunction) { |
| 236 | awaitOutsideFunction = true; |
| 237 | break; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | const needsWrap = block.wrapAsync || awaitOutsideFunction || (hasAwait && !hasAsyncDef); |
| 242 | |
| 243 | if (needsWrap) { |
| 244 | const indented = code |
| 245 | .split("\n") |
| 246 | .map((l) => " " + l) |
| 247 | .join("\n"); |
| 248 | code = `import asyncio\n\nasync def main():\n${indented}\n\nasyncio.run(main())`; |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | // Go: ensure package declaration |
| 253 | if (block.language === "go" && !code.includes("package ")) { |
| 254 | code = `package main\n\n${code}`; |
| 255 | } |
| 256 | |
| 257 | // Go: add main function if missing and has statements outside functions |
| 258 | if (block.language === "go" && !code.includes("func main()")) { |
| 259 | // Check if code has statements that need to be in main |
| 260 | const hasStatements = /^[a-z]/.test(code.trim().split("\n").pop() || ""); |
| 261 | if (hasStatements) { |
| 262 | // This is a snippet, wrap it |
| 263 | const lines = code.split("\n"); |