import { loadScript } from './utils.js'; let tsLoaded = false; let babelLoaded = false; let svelteLoaded = false; let markedLoaded = false; async function ensureTypeScript() { if (tsLoaded) return; await loadScript('https://cdnjs.cloudflare.com/ajax/libs/typescript/5.6.3/typescript.min.js'); if (typeof ts === 'undefined' && typeof window.ts === 'undefined') { await new Promise((resolve) => { const check = setInterval(() => { if (typeof ts !== 'undefined') { clearInterval(check); resolve(); } }, 50); }); } tsLoaded = true; } async function ensureBabel() { if (babelLoaded) return; await loadScript('https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.4/babel.min.js'); // Wait for global to be available if (typeof Babel === 'undefined') { await new Promise((resolve) => { const check = setInterval(() => { if (typeof Babel !== 'undefined') { clearInterval(check); resolve(); } }, 50); }); } babelLoaded = true; } async function ensureMarked() { if (markedLoaded) return; await loadScript('https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.7/marked.min.js'); if (typeof marked === 'undefined') { await new Promise((resolve) => { const check = setInterval(() => { if (typeof marked !== 'undefined') { clearInterval(check); resolve(); } }, 50); }); } markedLoaded = true; } async function ensureSvelte() { if (svelteLoaded) return; await loadScript('https://unpkg.com/svelte@4.2.19/compiler.cjs'); svelteLoaded = true; } /** * Compile JS/TS/JSX/TSX/Vue/Svelte code based on mode. * Returns { js, extraCss?, warnings? } */ export async function compileJs(code, mode) { if (!code.trim()) return { js: '' }; switch (mode) { case 'html-css-js': { const isModule = /(?:^|\n)\s*(?:import\s|export\s)/m.test(code); return { js: code, isModule }; } case 'typescript': return compileTypeScript(code); case 'react': return compileJsx(code); case 'react-ts': return compileTsx(code); case 'vue': return compileVue(code); case 'svelte': return compileSvelte(code); case 'markdown': return compileMarkdown(code); case 'wasm': { // WASM starter uses top-level await, always treat as module const hasModuleSyntax = /(?:^|\n)\s*(?:import\s|export\s)/m.test(code); const hasTopLevelAwait = /(?:^|\n)\s*(?:const|let|var)\s+.*=\s*await\b/m.test(code) || /(?:^|\n)\s*await\s/m.test(code); return { js: code, isModule: hasModuleSyntax || hasTopLevelAwait }; } default: return { js: code }; } } async function compileTypeScript(code) { await ensureTypeScript(); const result = ts.transpileModule(code, { compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.None, strict: false, }, }); return { js: result.outputText }; } async function compileJsx(code) { await ensureBabel(); const result = Babel.transform(code, { presets: ['react'], filename: 'fiddle.jsx', }); return { js: result.code }; } async function compileTsx(code) { await ensureBabel(); const result = Babel.transform(code, { presets: ['react', 'typescript'], filename: 'fiddle.tsx', }); return { js: result.code }; } function compileVue(code) { // Simple regex-based SFC parser const templateMatch = code.match(/