nichlink-run-method 0.1.3

Runtime registry trees, transactions, tracing, plugins, and authoring for NichLink
Documentation
//! Resolve generated registration faces without escaping the active package.
//! 在不越出当前包的前提下解析生成的注册面。

use super::*;

pub(super) fn generated_paths(
    registry: &Registry,
    id: NodeId,
) -> Result<(String, PathBuf), String> {
    let face = registry
        .find(id)
        .ok_or_else(|| format!("node `{id}` is not registered"))?;
    let declared = Path::new(&face.source.file);
    let root = source_root();
    let source = if declared.is_absolute() {
        // Absolute collector paths are editable only after canonicalization
        // proves that they still live below this package's source root.
        let canonical_root = fs::canonicalize(&root)
            .map_err(|error| format!("cannot resolve package source root: {error}"))?;
        let canonical_source = fs::canonicalize(declared)
            .map_err(|error| format!("cannot resolve registration source: {error}"))?;
        if !canonical_source.starts_with(&canonical_root) {
            return Err("only package-local generated modules can be edited".to_owned());
        }
        canonical_source
    } else {
        if declared.components().any(is_parent_component) {
            return Err("only package-local generated modules can be edited".to_owned());
        }
        root.join(declared)
    };
    let relative = source.strip_prefix(&root).unwrap_or(declared);
    let text = fs::read_to_string(&source)
        .map_err(|_| "this module was not generated by NichLink".to_owned())?;
    if !is_nichlink_owned_source(relative, &text) {
        return Err("this module was not generated by NichLink".to_owned());
    }
    Ok((face.registry_name.to_owned(), source))
}

fn is_nichlink_owned_source(relative: &Path, text: &str) -> bool {
    text.lines().any(|line| line == GENERATED_MARKER)
        || (relative == Path::new("control/control.rs")
            && text.contains("pub struct ControlRegistry;")
            && text.contains("registry_rule_path:")
            && text.contains("registry_rule:"))
}