deno_features 0.1.0

Provides definitions of Deno unstable features.
Documentation
// Copyright 2018-2025 the Deno authors. MIT license.

#![allow(clippy::disallowed_methods)]

use std::path::Path;

mod data;
mod structs;

fn main() {
  let crate_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));

  let mut js_list = String::from(
    "// Copyright 2018-2025 the Deno authors. MIT license.

/**
 * Don't modify this file manually.
 *
 * This file is auto-generated by the build script, modify `data.rs` instead.
 */

export const unstableIds = {
",
  );

  let mut rs_list = String::from(
    "// Copyright 2018-2025 the Deno authors. MIT license.

/// Don't modify this file manually.
///
/// This file is auto-generated by the build script, modify `data.rs` instead.
use crate::structs::UnstableFeatureDefinition;
use crate::structs::UnstableFeatureKind;

pub static UNSTABLE_FEATURES: &[UnstableFeatureDefinition] = &[",
  );

  let mut descriptions = data::FEATURE_DESCRIPTIONS.to_vec();
  descriptions.sort_by_key(|desc| desc.name);

  for (id, feature) in descriptions.into_iter().enumerate() {
    let flag_name = format!("unstable-{}", feature.name);
    let feature_kind = match feature.kind {
      structs::UnstableFeatureKind::Cli => "UnstableFeatureKind::Cli",
      structs::UnstableFeatureKind::Runtime => "UnstableFeatureKind::Runtime",
    };
    let env_var = match feature.env_var {
      Some(var_name) => format!(r#"Some("{}")"#, var_name),
      None => "None".to_string(),
    };

    rs_list += &format!(
      r#"  UnstableFeatureDefinition {{
    name: "{}",
    flag_name: "{}",
    help_text: "{}",
    show_in_help: {},
    id: {},
    kind: {},
    env_var: {},
    config_file_option: "{}",
  }},
"#,
      feature.name,
      flag_name,
      feature.help_text,
      feature.show_in_help,
      id,
      feature_kind,
      env_var,
      match feature.config_option {
        data::ConfigFileOption::SameAsFlagName => feature.name,
        data::ConfigFileOption::Renamed(alias) => alias,
      }
    );

    if matches!(feature.kind, structs::UnstableFeatureKind::Runtime) {
      let camel = camel_case(feature.name);
      js_list += &format!("  {}: {},\n", camel, id);
    }
  }

  js_list += "};\n";
  rs_list += "];\n";

  write_if_changed(&crate_dir.join("gen.js"), &js_list);
  write_if_changed(&crate_dir.join("gen.rs"), &rs_list);
}

fn write_if_changed(path: &Path, new_text: &str) {
  let current_text = std::fs::read_to_string(path).unwrap_or_default();
  if current_text != new_text {
    std::fs::write(path, new_text).unwrap();
  }
}

fn camel_case(name: &str) -> String {
  let mut output = String::new();
  let mut upper = false;
  for c in name.chars() {
    if c == '-' {
      upper = true;
    } else if upper {
      upper = false;
      output.push(c.to_ascii_uppercase());
    } else {
      output.push(c);
    }
  }
  output
}