///|
using @path {type SourcePath, type Path}

///|
using @devhub {type Devhub}

///|
using @string {parse_int}

///|
let shell_html_template =
  $|
  $|
  $|
  $|    
  $|    
  $|    warren dev
  $|    
  $|    
  $|
  $|
  $|    
$| $| ///| let app_html_template = $| $| $| $| $| $| warren preview $| $| $|
$| $| ///| let preview_base_patch = #| ///| let preview_entry_script_patch = #| ///| let preview_stylesheet_patch = #| ///| let direct_client_patch = #| ///| let direct_client_js = #|function connect() { #| const protocol = location.protocol === "https:" ? "wss:" : "ws:"; #| const socket = new WebSocket(`${protocol}//${location.host}/__warren/events`); #| socket.addEventListener("message", event => { #| if (event.data === "reload") { #| location.reload(); #| } #| }); #| socket.addEventListener("close", () => { #| setTimeout(connect, 1000); #| }); #|} #|connect(); ///| async fn main { let cli = @argparse.Command( "warren", subcommands=[ Command( "dev", positionals=[ PositionArg( "main-package-dir", about="Main package directory. Defaults to ./main when present, otherwise the current directory.", ), ], options=[ OptionArg( "public-dir", about="Static files directory. Defaults to ./public when present.", ), OptionArg("port", about="Local preview server port. Default: 4300."), ], flags=[ FlagArg( "direct", about="Serve the application as the top-level page without the Warren devtool iframe.", ), ], about="Start a local preview server with live reload.", ), Command( "build", positionals=[ PositionArg( "main-package-dir", about="Main package directory to build. Defaults to ./main when present, otherwise the current directory.", ), ], options=[ OptionArg("dist", about="Build output directory. Default: ./dist."), ], about="Build a release static site into ./dist by default.", ), Command( "new", positionals=[ PositionArg( "dir_name", about="Directory name for the new Warren project.", ), ], options=[ OptionArg( "template", about="Project template to use. Default: default. Available: default, minimized.", ), ], about="Create a minimal Rabbita project.", ), ], about="Preview and build MoonBit web applications.", ).parse() let cwd = @env.current_dir().unwrap() guard cli.subcommand is Some((subcmd, submatches)) else { return } match subcmd { "dev" => { let cwd_main = Path::join(cwd, "main").to_string() let main_pkg_dir = match submatches.values.get("main-package-dir") { Some([path]) => Path::resolve(path).to_string() _ if @fs.exists(cwd_main) => cwd_main _ => cwd } let cwd_public = Path::join(cwd, "public").to_string() let public_dir = match submatches.values.get("public-dir") { Some([path]) => Some(Path::resolve(path).to_string()) _ if @fs.exists(cwd_public) => Some(cwd_public) _ => None } let port = match submatches.values.get("port") { Some([raw]) => { let port = parse_int(raw) catch { _ => abort( "Invalid --port value `\{raw}`. Expected a number from 1 to 65535.", ) } guard port > 0 && port <= 65535 else { abort( "Invalid --port value `\{raw}`. Expected a number from 1 to 65535.", ) } port.reinterpret_as_uint() } _ => 4300U } let direct = submatches.flags.get("direct") is Some(true) let target_dir = @fs.tmpdir(prefix="warren") dev_server(main_pkg_dir~, target_dir~, public_dir~, port~, direct~) } "build" => { let cwd_main = Path::join(cwd, "main").to_string() let main_pkg_dir = match submatches.values.get("main-package-dir") { Some([path]) => Path::resolve(path).to_string() _ if @fs.exists(cwd_main) => cwd_main _ => cwd } let dist_dir = match submatches.values.get("dist") { Some([path]) => Path::resolve(path).to_string() _ => Path::join(cwd, "dist").to_string() } build_project( SourcePath::new(main_pkg_dir), dist_dir=SourcePath::new(dist_dir), ) } "new" => match submatches.values.get("dir_name") { Some([dir]) => { let template = match submatches.values.get("template") { Some([name]) => name _ => default_new_project_template } new_project(dir, template) } _ => println("Usage: warren new [--template