// gendocs: a build-time codegen tool for mymoon's bundled diagnostic docs.
//
// Reads the `moonbit-docs` markdown (error codes + attributes) from a directory
// and emits a MoonBit source file defining two `Map[String, String]` (key → raw
// markdown) plus accessors. mymoon declares this as a `bin-dep` and runs it from a
// `pre-build` rule, so the docs are embedded at BUILD time — no committed blob, no
// `include_str!` (which MoonBit lacks). Mirrors rust moon's `include_dir!` of its
// `resources/error_codes/`, but as a declarative bin-dep + codegen.
//
//   gendocs  
//
// `` must contain `error_codes/E*.md` (key = file stem, e.g.
// "E0001") and `attributes/*.md` (key = file stem, e.g. "alert").

///|
fn main {
  let args = @env.args()
  if args.length() < 3 {
    println("usage: gendocs  ")
    panic()
  }
  let base = args[1]
  let out = args[2]
  generate(base, out) catch {
    e => {
      println("gendocs: \{e}")
      panic()
    }
  }
}

///|
fn generate(base : String, out : String) -> Unit raise {
  let sb = StringBuilder::new()
  sb.write_string(
    "// Generated by tools/gendocs from moonbit-docs — DO NOT EDIT.\n\n",
  )
  // Emit ONLY the data maps; the accessors are a hand-written, stable API in the
  // consuming `diagdocs` package (so the package is discoverable before this
  // generated file exists, and the public surface isn't regenerated).
  emit_map(sb, "error_docs", base + "/error_codes")
  emit_map(sb, "attr_docs", base + "/attributes")
  @fs.write_string_to_file(out, sb.to_string())
}

///|
/// Emit `let  : Map[String, String] = { "": , … }`, reading every
/// `*.md` in `dir` (sorted, for deterministic output). Each markdown body is
/// emitted as a raw `#|` multiline literal — verbatim, no escaping, so backticks /
/// quotes / `$` in the docs pass through untouched.
fn emit_map(sb : StringBuilder, name : String, dir : String) -> Unit raise {
  let files = @fs.read_dir(dir)
  files.sort()
  sb.write_string("///|\nlet \{name} : Map[String, String] = {\n")
  for fname in files {
    guard fname.has_suffix(".md") else { continue }
    let key = fname[:fname.length() - 3].to_owned()
    let content = @fs.read_file_to_string(dir + "/" + fname)
    // Raw multiline literal, parenthesized (a bare `#|` as a map value is the
    // deprecated E0027 form; `( … )` is the blessed one), one `#|` per source
    // line — verbatim, no escaping.
    sb.write_string("  \"\{key}\": (\n")
    for line in content.split("\n") {
      sb.write_string("    #|")
      sb.write_string(line.to_owned())
      sb.write_string("\n")
    }
    sb.write_string("  ),\n")
  }
  sb.write_string("}\n\n")
}