From b6a6630a9371dd08ffa455d20666ef52c83d96fc Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Wed, 14 Jan 2026 21:33:18 +0800 Subject: [PATCH] feat: always resolve path at runtime --- nix-js/src/codegen.rs | 2 +- nix-js/src/context/downgrade.rs | 4 -- nix-js/src/ir.rs | 2 - nix-js/src/ir/downgrade.rs | 70 ++++++--------------------------- nix-js/src/runtime.rs | 23 +++++++---- 5 files changed, 29 insertions(+), 72 deletions(-) diff --git a/nix-js/src/codegen.rs b/nix-js/src/codegen.rs index 96e20be..28c296a 100644 --- a/nix-js/src/codegen.rs +++ b/nix-js/src/codegen.rs @@ -43,7 +43,7 @@ impl Compile for Ir { Ir::Null(_) => "null".to_string(), Ir::Str(s) => s.val.escape_quote(), Ir::Path(p) => { - // Path needs runtime resolution for interpolated paths + // Path needs runtime resolution let path_expr = ctx.get_ir(p.expr).compile(ctx); format!("Nix.resolvePath({})", path_expr) } diff --git a/nix-js/src/context/downgrade.rs b/nix-js/src/context/downgrade.rs index 5669547..9105067 100644 --- a/nix-js/src/context/downgrade.rs +++ b/nix-js/src/context/downgrade.rs @@ -231,10 +231,6 @@ impl DowngradeContext for DowngradeCtx<'_> { f(guard.as_ctx()) } - fn get_current_dir(&self) -> std::path::PathBuf { - self.ctx.get_current_dir() - } - fn push_dep_tracker(&mut self, slots: &[ExprId]) { let mut graph = Graph::new(); let mut expr_to_node = HashMap::new(); diff --git a/nix-js/src/ir.rs b/nix-js/src/ir.rs index 1dc9ad4..95f7806 100644 --- a/nix-js/src/ir.rs +++ b/nix-js/src/ir.rs @@ -38,8 +38,6 @@ pub trait DowngradeContext { where F: FnOnce(&mut Self) -> R; - fn get_current_dir(&self) -> std::path::PathBuf; - fn push_dep_tracker(&mut self, slots: &[ExprId]); fn push_dep_tracker_with_owner(&mut self, slots: &[ExprId], owner: ExprId); fn get_current_binding(&self) -> Option; diff --git a/nix-js/src/ir/downgrade.rs b/nix-js/src/ir/downgrade.rs index 64d210a..bd3a017 100644 --- a/nix-js/src/ir/downgrade.rs +++ b/nix-js/src/ir/downgrade.rs @@ -2,28 +2,10 @@ #![allow(clippy::unwrap_used)] use rnix::ast::{self, Expr, HasEntry}; -use std::path::{Component, Path as StdPath, PathBuf}; use crate::error::{Error, Result}; - use super::*; -fn normalize_path(path: &StdPath) -> String { - let mut normalized = PathBuf::new(); - for component in path.components() { - match component { - Component::Prefix(p) => normalized.push(p.as_os_str()), - Component::RootDir => normalized.push("/"), - Component::CurDir => {} - Component::ParentDir => { - normalized.pop(); - } - Component::Normal(c) => normalized.push(c), - } - } - normalized.to_string_lossy().to_string() -} - pub trait Downgrade { fn downgrade(self, ctx: &mut Ctx) -> Result; } @@ -75,46 +57,20 @@ impl Downgrade for ast::IfElse { impl Downgrade for ast::Path { fn downgrade(self, ctx: &mut Ctx) -> Result { - let parts_ast: Vec<_> = self.parts().collect(); - let has_interpolation = parts_ast - .iter() - .any(|part| matches!(part, ast::InterpolPart::Interpolation(_))); - - let parts = if !has_interpolation { - // Resolve at compile time - let path_str: String = parts_ast - .into_iter() - .filter_map(|part| match part { - ast::InterpolPart::Literal(lit) => Some(lit.to_string()), - _ => None, - }) - .collect(); - - let resolved_path = if path_str.starts_with('/') { - normalize_path(&std::path::PathBuf::from(&path_str)) - } else { - let current_dir = ctx.get_current_dir(); - normalize_path(¤t_dir.join(&path_str)) - }; - - vec![ctx.new_expr(Str { val: resolved_path }.to_ir())] - } else { - // Resolve at runtime - parts_ast - .into_iter() - .map(|part| match part { - ast::InterpolPart::Literal(lit) => Ok(ctx.new_expr( - Str { - val: lit.to_string(), - } - .to_ir(), - )), - ast::InterpolPart::Interpolation(interpol) => { - interpol.expr().unwrap().downgrade(ctx) + let parts = self + .parts() + .map(|part| match part { + ast::InterpolPart::Literal(lit) => Ok(ctx.new_expr( + Str { + val: lit.to_string(), } - }) - .collect::>>()? - }; + .to_ir(), + )), + ast::InterpolPart::Interpolation(interpol) => { + interpol.expr().unwrap().downgrade(ctx) + } + }) + .collect::>>()?; let expr = if parts.len() == 1 { parts.into_iter().next().unwrap() diff --git a/nix-js/src/runtime.rs b/nix-js/src/runtime.rs index da209aa..f7d3269 100644 --- a/nix-js/src/runtime.rs +++ b/nix-js/src/runtime.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::marker::PhantomData; use std::ops::DerefMut; -use std::path::PathBuf; +use std::path::{Component, PathBuf}; use std::sync::Once; use deno_core::{Extension, ExtensionFileSource, JsRuntime, OpState, RuntimeOptions, v8}; @@ -125,13 +125,20 @@ fn op_resolve_path( } // Resolve relative path against current file directory (or CWD) - let current_dir = ctx.get_current_dir(); - - Ok(current_dir - .join(&path) - .canonicalize() - .map(|p| p.to_string_lossy().to_string()) - .map_err(|e| format!("Failed to resolve path {}: {}", path, e))?) + let current_dir = ctx.get_current_dir().join(&path); + let mut normalized = PathBuf::new(); + for component in current_dir.components() { + match component { + Component::Prefix(p) => normalized.push(p.as_os_str()), + Component::RootDir => normalized.push("/"), + Component::CurDir => {} + Component::ParentDir => { + normalized.pop(); + } + Component::Normal(c) => normalized.push(c), + } + } + Ok(normalized.to_string_lossy().to_string()) } #[deno_core::op2]