Skip to main content

yog_cli/
script.rs

1//! A mod's Yog Script (`src/**/*.ys`, `*.yns`): each source checked by the
2//! compiler (`yog-script-build`), what's wrong reported at its file, line
3//! and column; errors stop the build.
4
5pub mod jvm;
6
7use std::path::Path;
8
9use yog_ids::Format;
10
11use crate::diagnostics;
12
13/// Where a mod's code is: its scripts beside its Rust.
14use crate::project::manifest::SOURCES_DIR as SOURCES;
15
16/// A script's text checked in the mod at `root`: what its `yog.toml` says
17/// it does (sending to the server) known.
18pub(crate) fn check_text(name: &str, text: &str, root: &Path) -> Vec<yog_data::Diagnostic> {
19    let to_server =
20        crate::project::manifest::YogToml::read(&root.join(crate::project::manifest::MANIFEST))
21            .is_ok_and(|m| m.to_server);
22    let project = yog_script_build::Project {
23        to_server,
24        ..Default::default()
25    };
26    yog_script_build::check_source_using(name, text, yog_script_build::index::load, project)
27}
28
29/// The mod a file is in: the nearest folder up from it with a `yog.toml`.
30pub(crate) fn mod_root(file: &Path) -> Option<&Path> {
31    file.ancestors()
32        .find(|dir| dir.join(crate::project::manifest::MANIFEST).is_file())
33}
34
35/// Checks every script of the mod at `root` (a `.yns` on each game version
36/// it targets); an error when one has errors.
37pub fn check(root: &Path) -> Result<(), String> {
38    let dir = root.join(SOURCES);
39    let files: Vec<_> = [Format::Script, Format::Nanites]
40        .into_iter()
41        .flat_map(|format| crate::files::of(&dir, format))
42        .collect();
43    if files.is_empty() {
44        return Ok(());
45    }
46    let mut errors = 0;
47    for file in files {
48        let text =
49            std::fs::read_to_string(&file).map_err(|e| format!("{}: {e}", file.display()))?;
50        let name = crate::shown_path(root, &file);
51        let problems = check_text(&name, &text, root);
52        errors += problems.iter().filter(|d| d.is_error()).count();
53        diagnostics::report_all(&problems);
54        for d in &problems {
55            match d.is_error() {
56                true => yog_logging::error!("{d}"),
57                false => yog_logging::warn!("{d}"),
58            }
59        }
60    }
61    match errors {
62        0 => Ok(()),
63        n => Err(format!("{n} error(s) in the mod's Yog Script")),
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn a_mods_scripts_are_checked() {
73        let root = std::env::temp_dir().join(format!("yog-script-check-{}", std::process::id()));
74        let src = root.join(SOURCES).join("power");
75        std::fs::create_dir_all(&src).unwrap();
76        std::fs::write(src.join("ok.ys"), "int Area(int w, int h) => w * h;\n").unwrap();
77        assert_eq!(check(&root), Ok(()));
78        std::fs::write(src.join("bad.ys"), "void F() {\n    break;\n}\n").unwrap();
79        assert!(check(&root).is_err());
80        std::fs::remove_dir_all(&root).unwrap();
81    }
82}