Spaces:
Runtime error
Runtime error
File size: 3,024 Bytes
19a950f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | const PYODIDE_CDN = "https://cdn.jsdelivr.net/pyodide/v0.26.2/full/pyodide.js"
export function buildCodeSandboxHtml(language: string, code: string): string {
const lang = language.toLowerCase()
if (lang === "html") return code
if (lang === "css") return buildCssHtml(code)
if (lang === "py" || lang === "python") return buildPythonHtml(code)
const runnableCode = isTypeScriptLanguage(lang) ? stripTypeScript(code) : code
return buildJavaScriptHtml(runnableCode)
}
function buildJavaScriptHtml(code: string): string {
return `<!DOCTYPE html>
<html><head><meta charset="utf-8"><style>body{font:13px monospace;margin:8px;color:#0a0a0a}.err{color:#dc2626}</style></head>
<body><div id="out"></div><script>
const out=document.getElementById('out');
function w(t,cls){const d=document.createElement('div');if(cls)d.className=cls;d.textContent=t;out.appendChild(d)}
const orig={log:console.log,error:console.error,warn:console.warn};
console.log=(...a)=>{w(a.map(String).join(' '));parent.postMessage({sb:'log',v:a.map(String).join(' ')},'*')};
console.error=(...a)=>{w(a.map(String).join(' '),'err');parent.postMessage({sb:'err',v:a.map(String).join(' ')},'*')};
console.warn=console.log;
window.onerror=(m)=>{w(String(m),'err');parent.postMessage({sb:'err',v:String(m)},'*')};
try{ ${escapeClosingScript(code)} }catch(e){console.error(e.message||String(e))}
</script></body></html>`
}
function buildPythonHtml(code: string): string {
const pyCode = JSON.stringify(code)
return buildJavaScriptHtml(`
(async()=>{
console.log('Đang tải Python (Pyodide)...');
const script=document.createElement('script');
script.src=${JSON.stringify(PYODIDE_CDN)};
script.onload=async()=>{
try{
const pyodide=await loadPyodide();
pyodide.setStdout({batched:(text)=>console.log(text)});
pyodide.setStderr({batched:(text)=>console.error(text)});
await pyodide.runPythonAsync(${pyCode});
}catch(e){console.error(e.message||String(e))}
};
script.onerror=()=>console.error('Không tải được Pyodide');
document.body.appendChild(script);
})()
`)
}
function buildCssHtml(code: string): string {
return `<!DOCTYPE html>
<html><head><meta charset="utf-8"><style>${escapeStyleContent(code)}</style></head><body><div class="demo">Demo</div></body></html>`
}
function stripTypeScript(code: string): string {
return code
.replace(/\binterface\s+[A-Za-z_$][\w$]*(?:\s+extends\s+[^{}]+)?\s*\{[^{}]*\}\s*/gs, "")
.replace(/^\s*type\s+[A-Za-z_$][\w$]*(?:<[^>]+>)?\s*=\s*[^;]+;?\s*$/gm, "")
.replace(/\s+as\s+[A-Za-z_$][\w$<>,\s\[\]{}|&?.]*/g, "")
.replace(/:\s*[A-Za-z_$][\w$<>,\s\[\]{}|&?.]*(?=\s*[,)=;])/g, "")
}
function isTypeScriptLanguage(language: string): boolean {
return language === "ts" || language === "tsx" || language === "typescript"
}
function escapeClosingScript(code: string): string {
return code.replace(/<\/script/gi, "<\\/script")
}
function escapeStyleContent(code: string): string {
return code.replace(/<\/style/gi, "<\\/style")
}
|