|
| 1 | +use quote::quote; |
| 2 | +use std::{ |
| 3 | + fs, |
| 4 | + process::{Command, Stdio}, |
| 5 | +}; |
| 6 | + |
| 7 | +fn main() { |
| 8 | + let node_version_path = ".node-version"; |
| 9 | + let node_version = fs::read_to_string(node_version_path) |
| 10 | + .expect("Failed to read .node-version") |
| 11 | + .trim() |
| 12 | + .to_string(); |
| 13 | + |
| 14 | + // Get Node.js major version |
| 15 | + let node_major_version = node_version.split('.').next().unwrap(); |
| 16 | + |
| 17 | + println!("Using Node.js version: {node_version}"); |
| 18 | + |
| 19 | + // Run Node.js command to get built-in modules |
| 20 | + let output = Command::new("node") |
| 21 | + .arg("-p") |
| 22 | + .arg("[...require('module').builtinModules].map(b => JSON.stringify(b)).join(',\\n')") |
| 23 | + .stdout(Stdio::piped()) |
| 24 | + .stderr(Stdio::piped()) |
| 25 | + .output() |
| 26 | + .expect("Failed to execute node command"); |
| 27 | + |
| 28 | + if !output.status.success() { |
| 29 | + eprintln!("Node.js command failed:"); |
| 30 | + eprintln!("{}", String::from_utf8_lossy(&output.stderr)); |
| 31 | + std::process::exit(1); |
| 32 | + } |
| 33 | + |
| 34 | + let modules_output = String::from_utf8(output.stdout).expect("Invalid UTF-8 output"); |
| 35 | + |
| 36 | + // Parse the module names (they're JSON strings separated by commas and newlines) |
| 37 | + let json_array_str = format!("[{}]", modules_output.trim()); |
| 38 | + let all_modules: Vec<String> = |
| 39 | + serde_json::from_str(&json_array_str).expect("Failed to parse module list"); |
| 40 | + |
| 41 | + // Separate modules with mandatory node: prefix from regular modules |
| 42 | + let mut mandatory_prefix_modules: Vec<String> = all_modules |
| 43 | + .iter() |
| 44 | + .filter(|m| m.starts_with("node:")) |
| 45 | + .map(|m| m.strip_prefix("node:").unwrap().to_string()) |
| 46 | + .collect(); |
| 47 | + mandatory_prefix_modules.sort(); |
| 48 | + |
| 49 | + let mut regular_modules: Vec<String> = all_modules |
| 50 | + .iter() |
| 51 | + .filter(|m| !m.starts_with("node:")) |
| 52 | + .cloned() |
| 53 | + .collect(); |
| 54 | + regular_modules.sort(); |
| 55 | + |
| 56 | + // Build the complete file with doc comments using quote! |
| 57 | + let regular_module_refs = ®ular_modules; |
| 58 | + let mandatory_module_refs = &mandatory_prefix_modules; |
| 59 | + |
| 60 | + let content = format!( |
| 61 | + r#"//! Node.js v{} built-in modules |
| 62 | +//! |
| 63 | +//! <https://nodejs.org/api/modules.html#built-in-modules> |
| 64 | +
|
| 65 | +/// Generated by |
| 66 | +/// |
| 67 | +/// `node -p "[...require('module').builtinModules].map(b => JSON.stringify(b)).join(',\n')"` |
| 68 | +/// |
| 69 | +/// with `node:` prefixed values moved [BUILTINS_WITH_MANDATORY_NODE_PREFIX]. |
| 70 | +{} |
| 71 | +
|
| 72 | +/// <https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix> |
| 73 | +{} |
| 74 | +
|
| 75 | +/// Is `specifier` a node.js built-in module? |
| 76 | +{} |
| 77 | +"#, |
| 78 | + node_major_version, |
| 79 | + quote! { pub static BUILTINS: &[&str] = &[#(#regular_module_refs,)*]; }, |
| 80 | + quote! { pub static BUILTINS_WITH_MANDATORY_NODE_PREFIX: &[&str] = &[#(#mandatory_module_refs),*]; }, |
| 81 | + quote! { |
| 82 | + pub fn is_nodejs_builtin_module(specifier: &str) -> bool { |
| 83 | + if let Some(stripped) = specifier.strip_prefix("node:") { |
| 84 | + return BUILTINS.contains(&stripped) |
| 85 | + || BUILTINS_WITH_MANDATORY_NODE_PREFIX.contains(&stripped); |
| 86 | + } |
| 87 | + BUILTINS.contains(&specifier) |
| 88 | + } |
| 89 | + } |
| 90 | + ); |
| 91 | + |
| 92 | + // Write to src/lib.rs |
| 93 | + fs::write("src/lib.rs", content).expect("Failed to write src/lib.rs"); |
| 94 | + |
| 95 | + println!("✓ Updated built-in modules for Node.js v{node_version}"); |
| 96 | + println!(" - {} regular modules", regular_modules.len()); |
| 97 | + println!( |
| 98 | + " - {} mandatory prefix modules", |
| 99 | + mandatory_prefix_modules.len() |
| 100 | + ); |
| 101 | +} |
0 commit comments