@ -2,6 +2,7 @@ import fs from 'node:fs';
import path from 'node:path' ;
import { parseArgs } from 'node:util' ;
import { execSync } from 'node:child_process' ;
import readline from 'node:readline/promises' ;
import { chromium } from 'playwright' ;
const { values , positionals } = parseArgs ( {
@ -546,9 +547,9 @@ function convert_vite_project(repo_dir) {
/ * *
* Process a local or cloned directory
* @ param { string } dir _path
* @ returns { Array< { name : string , contents : string } > }
* @ returns { Promise< Array< { name : string , contents : string } > | null > }
* /
function process _directory ( dir _path ) {
async function process _directory ( dir _path ) {
const all _files = get _all _files ( dir _path ) ;
const project _info = detect _project _type ( all _files ) ;
@ -558,7 +559,18 @@ function process_directory(dir_path) {
if ( project _info . has _app _imports ) {
console . error ( 'Error: This SvelteKit project uses $app/* imports which cannot be converted.' ) ;
console . error ( 'The playground does not support SvelteKit runtime features.' ) ;
process . exit ( 1 ) ;
const fallback _dir = path . resolve ( base _dir , '..' , '..' , 'kit-sandbox-tmp' ) ;
const should _copy = await prompt _download _to _kit _sandbox _tmp ( fallback _dir ) ;
if ( ! should _copy ) {
process . exit ( 1 ) ;
}
copy _project _to _directory ( dir _path , fallback _dir ) ;
console . log ( ` Project copied to ${ fallback _dir } ` ) ;
return null ;
}
// Convert based on project type
@ -571,6 +583,66 @@ function process_directory(dir_path) {
}
}
/ * *
* Ask whether to copy the project to playgrounds / kit - sandbox - tmp
* @ param { string } fallback _dir
* @ returns { Promise < boolean > }
* /
async function prompt _download _to _kit _sandbox _tmp ( fallback _dir ) {
if ( ! process . stdin . isTTY || ! process . stdout . isTTY ) {
return false ;
}
const rl = readline . createInterface ( { input : process . stdin , output : process . stdout } ) ;
try {
const answer = await rl . question (
` Would you like to copy this project into ${ fallback _dir } instead? [y/N] `
) ;
return /^(y|yes)$/i . test ( answer . trim ( ) ) ;
} finally {
rl . close ( ) ;
}
}
/ * *
* Copy a project directory while skipping generated and dependency folders
* @ param { string } source _dir
* @ param { string } target _dir
* /
function copy _project _to _directory ( source _dir , target _dir ) {
const skip _dirs = new Set ( [ 'node_modules' , '.git' , '.svelte-kit' , 'build' , 'dist' ] ) ;
if ( fs . existsSync ( target _dir ) ) {
fs . rmSync ( target _dir , { recursive : true , force : true } ) ;
}
/** @param {string} from_dir */
function copy _recursive ( from _dir ) {
const relative _dir = path . relative ( source _dir , from _dir ) ;
const to _dir = relative _dir ? path . join ( target _dir , relative _dir ) : target _dir ;
fs . mkdirSync ( to _dir , { recursive : true } ) ;
for ( const entry of fs . readdirSync ( from _dir , { withFileTypes : true } ) ) {
if ( entry . isDirectory ( ) && skip _dirs . has ( entry . name ) ) {
continue ;
}
const source _path = path . join ( from _dir , entry . name ) ;
const target _path = path . join ( to _dir , entry . name ) ;
if ( entry . isDirectory ( ) ) {
copy _recursive ( source _path ) ;
} else if ( entry . isFile ( ) ) {
fs . copyFileSync ( source _path , target _path ) ;
}
}
}
copy _recursive ( source _dir ) ;
}
/ * *
* Reset a directory so it exists and is empty
* @ param { string } dir _path
@ -602,7 +674,7 @@ let files;
// Check if it's a local directory first (before URL parsing)
if ( is _local ) {
console . log ( ` Processing local directory: ${ url _arg } ` ) ;
files = process _directory ( url _arg ) ;
files = await process _directory ( url _arg ) ;
} else if ( resolved _test _path ) {
// Copy files from test
console . log ( ` Processing test ${ url _arg } ` ) ;
@ -616,21 +688,21 @@ if (is_local) {
} ) ;
} else if ( url && is _github _url ( url ) ) {
// GitHub repository handling
await with _tmp _dir ( base _dir , ( tmp _dir ) => {
await with _tmp _dir ( base _dir , async ( tmp _dir ) => {
clone _github _repo ( url , tmp _dir ) ;
files = process _directory ( tmp _dir ) ;
files = await process _directory ( tmp _dir ) ;
} ) ;
} else if ( url && is _stackblitz _github _url ( url ) ) {
// StackBlitz GitHub project handling (redirect to GitHub clone)
await with _tmp _dir ( base _dir , ( tmp _dir ) => {
await with _tmp _dir ( base _dir , async ( tmp _dir ) => {
clone _stackblitz _github _project ( url , tmp _dir ) ;
files = process _directory ( tmp _dir ) ;
files = await process _directory ( tmp _dir ) ;
} ) ;
} else if ( url && is _stackblitz _edit _url ( url ) ) {
// StackBlitz edit URLs - use browser automation to download
await with _tmp _dir ( base _dir , async ( tmp _dir ) => {
await download _stackblitz _project ( url , tmp _dir ) ;
files = process _directory ( tmp _dir ) ;
files = await process _directory ( tmp _dir ) ;
} ) ;
} else if ( url && url . origin === 'https://svelte.dev' && url . pathname . startsWith ( '/playground/' ) ) {
// Svelte playground URL handling (existing logic)
@ -680,6 +752,10 @@ if (is_local) {
process . exit ( 1 ) ;
}
if ( files === null ) {
process . exit ( 0 ) ;
}
// Output files
if ( create _test _name ) {
const test _parts = create _test _name . split ( '/' ) . filter ( Boolean ) ;