use std::fs;
use std::path::{Path, PathBuf};
use mlua::Lua;
use mlua_check::vm::register;
fn engine_crate() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}
fn workspace_root() -> PathBuf {
engine_crate()
.parent()
.and_then(|p| p.parent())
.map(Path::to_path_buf)
.expect("workspace root resolvable from engine crate")
}
fn make_vm() -> Lua {
let lua = Lua::new();
let setup = r#"
alc = {}
-- Service-layer stubs (normally injected by the Rust bridge)
alc.state = {
get = function(_, default) return default end,
set = function() end,
}
alc.json_encode = function() end
alc.json_decode = function() end
alc.log = function() end
alc.llm = function() end
alc.llm_batch = function() end
alc.eval = function() end
alc.time = function() return 0 end
alc.budget_remaining = function() return 0 end
alc.card = {
create = function() end,
get = function() end,
list = function() end,
find = function() end,
append = function() end,
}
alc._dirs = { scenarios = "/dev/null" }
"#;
lua.load(setup)
.set_name("@alc_stub_setup")
.exec()
.expect("alc stub setup must succeed");
let prelude = engine_crate().join("src").join("prelude.lua");
let code =
fs::read_to_string(&prelude).unwrap_or_else(|e| panic!("read {}: {e}", prelude.display()));
lua.load(&code)
.set_name(format!("@{}", prelude.display()))
.exec()
.expect("prelude.lua must load on stubbed alc");
lua
}
fn shipped_files() -> Vec<PathBuf> {
let root = workspace_root();
let shapes = root
.join("crates")
.join("algocline-app")
.join("src")
.join("service")
.join("gendoc")
.join("alc_shapes");
let docs = root
.join("crates")
.join("algocline-app")
.join("src")
.join("service")
.join("lua")
.join("gendoc");
let prelude = engine_crate().join("src").join("prelude.lua");
let mut out: Vec<PathBuf> = Vec::new();
for sub in [&shapes, &docs] {
if !sub.exists() {
continue;
}
collect_lua(sub, &mut out);
}
out.push(prelude);
out.sort();
out
}
fn collect_lua(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
collect_lua(&path, out);
} else if path.extension().and_then(|e| e.to_str()) == Some("lua") {
out.push(path);
}
}
}
fn chunk_name_for(file: &Path) -> String {
let s = file.to_string_lossy();
if let Some(idx) = s.find("/gendoc/alc_shapes/") {
let rel = &s[idx + "/gendoc/".len()..]; return format!("@{rel}");
}
if let Some(idx) = s.find("/lua/gendoc/docs/") {
let rel = &s[idx + "/lua/gendoc/".len()..]; return format!("@tools/{rel}");
}
if s.ends_with("/lua/gendoc/gen_docs.lua") {
return "@gen_docs.lua".to_string();
}
if s.ends_with("/prelude.lua") {
return "@prelude.lua".to_string();
}
format!("@{}", file.display())
}
#[test]
fn shipped_lua_is_lint_clean() {
let lua = make_vm();
let engine = register(&lua).expect("register(&lua) must succeed");
let files = shipped_files();
assert!(!files.is_empty(), "shipped_files() yielded zero entries");
println!("\n=== mlua-check library-direct spike ===");
println!("VM: alc stubs + prelude.lua loaded");
println!("Files: {}\n", files.len());
let sources: Vec<(PathBuf, String, String)> = files
.iter()
.filter_map(|file| {
let code = fs::read_to_string(file).ok()?;
let chunk = chunk_name_for(file);
Some((file.clone(), chunk, code))
})
.collect();
for (_, chunk, code) in &sources {
let _ = engine.lint(code, chunk);
}
let mut total_warnings = 0usize;
let mut total_errors = 0usize;
for (file, chunk, code) in &sources {
let result = engine.lint(code, chunk);
total_warnings += result.warning_count;
total_errors += result.error_count;
let rel = file
.strip_prefix(workspace_root())
.unwrap_or(file)
.display();
println!(
"{:>3} warn / {:>2} err {}",
result.warning_count, result.error_count, rel
);
for diag in result.diagnostics.iter().take(6) {
println!(
" [{:?}] L{}:{} {} ({})",
diag.severity, diag.line, diag.column, diag.message, diag.rule,
);
}
if result.diagnostics.len() > 6 {
println!(
" ... {} more diagnostics suppressed",
result.diagnostics.len() - 6
);
}
}
println!(
"\nTotal: {total_warnings} warnings / {total_errors} errors across {} files",
files.len()
);
assert_eq!(
total_errors, 0,
"shipped Lua produced {total_errors} mlua-check errors; \
fix the source or add `---@diagnostic disable: <rule>` at the top of the offending file"
);
assert_eq!(
total_warnings, 0,
"shipped Lua produced {total_warnings} mlua-check warnings; \
fix the source or add `---@diagnostic disable: <rule>` at the top of the offending file"
);
}