@ 261107.5 · fetching
current
use std::{env, error::Error, fs, path::Path};

use milo_build_scripts::get_build_info;

fn prepend_version_and_method_map(header: &str) -> Result<String, Box<dyn Error>> {
  let header_matcher = "namespace milo_parser {";
  let info = get_build_info()?;
  let version = info.version;
  // Create the method map, required by Node.js.
  let methods = info
    .constants
    .iter()
    .filter_map(|(key, value)| {
      key
        .strip_prefix("METHOD_")
        .map(|method| format!("  EACH({value}, {method}, {method}) \\"))
    })
    .collect::<Vec<_>>()
    .join("\n");
  let updated_header = format!(
    r#"#define MILO_VERSION "{}"
#define MILO_VERSION_MAJOR {}
#define MILO_VERSION_MINOR {}
#define MILO_VERSION_PATCH {}
#define MILO_VERSION_PRERELEASE "{}"

#define MILO_METHODS_MAP(EACH) \
{methods}

namespace milo_parser {{

struct Parser;"#,
    version.raw, version.major, version.minor, version.patch, version.prerelease
  );

  // Replace the header with the new code.
  // Match the JavaScript normalization without changing other whitespace.
  let mut normalized = String::with_capacity(header.len());
  let mut newlines = 0;
  for character in header.chars() {
    if character == '\n' {
      newlines += 1;
    } else {
      newlines = 0;
    }
    if newlines <= 2 {
      normalized.push(character);
    }
  }
  Ok(normalized.replacen(header_matcher, &updated_header, 1))
}

fn main() -> Result<(), Box<dyn Error>> {
  let profile = env::args().nth(1).ok_or("Usage: postbuild-cpp <profile>")?;
  // Read the file.
  let header_path = Path::new(env!("CARGO_MANIFEST_DIR"))
    .join("../dist/cpp")
    .join(profile)
    .join("milo.h");
  let header = fs::read_to_string(&header_path)?;
  // Apply modifications.
  let header = prepend_version_and_method_map(&header)?;
  // Write the updated file.
  fs::write(header_path, header)?;
  Ok(())
}