///|
async fn main {
  let matches = cli_command().parse()
  let input = matches.values.get("input").bind(paths => paths.get(0))
  let requested_output = matches.values
    .get("output")
    .bind(paths => paths.get(0))
  guard output_path(input, requested_output) is Some(path) else {
    return fail("specify --output when reading stdin")
  }
  let rename_top_level = !matches.flags.get("top").unwrap_or(false)
  let source = read_source(input)
  let output = @minifier.minify_with(source, rename_top_level)
  guard path != "-" else { return @stdio.stdout.write(output) }
  @fs.write_file(path, output)
}

///|
fn cli_command() -> @argparse.Command {
  @argparse.Command::Command(
    "evol",
    about="Minify a JavaScript file",
    version="0.1.0",
    flags=[
      @argparse.FlagArg::FlagArg(
        "top",
        long="top",
        about="keep top-level binding names",
      ),
    ],
    options=[
      @argparse.OptionArg::OptionArg(
        "output",
        long="output",
        about="output file (- for stdout)",
      ),
    ],
    positionals=[
      @argparse.PositionArg::PositionArg(
        "input",
        about="input file (reads stdin when omitted)",
        num_args=@argparse.ValueRange::ValueRange(lower=0, upper=1),
      ),
    ],
  )
}

///|
fn output_path(input : String?, requested : String?) -> String? {
  guard requested is Some(path) && path.length() > 0 else {
    return input.map(minified_path)
  }
  Some(path)
}

///|
fn minified_path(input : String) -> String {
  lexmatch input {
    re"^" + (re".+" as stem) + re"\.[^./\\]+$" => "\{stem}.min.js"
    _ => "\{input}.min.js"
  }
}

///|
async fn read_source(input : String?) -> String {
  guard input is Some(path) else { return @stdio.stdin.read_all().text() }
  @fs.read_file(path).text()
}