From df4edaf5bbbfc7c0a90d395eafb3957cbfa1cefa Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Fri, 13 Feb 2026 19:44:37 +0800 Subject: [PATCH] fix: preserve string context in `+` operator --- Justfile | 8 +++---- nix-js/runtime-ts/src/operators.ts | 13 +++++++---- nix-js/tests/derivation.rs | 36 ++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/Justfile b/Justfile index c3e6bae..ce51961 100644 --- a/Justfile +++ b/Justfile @@ -1,15 +1,15 @@ [no-exit-message] @repl: - RUST_LOG=none,nix_js=debug cargo run --bin repl + RUST_LOG=none cargo run --bin repl [no-exit-message] @eval expr: - RUST_LOG=none,nix_js=debug cargo run --bin eval -- '{{expr}}' + RUST_LOG=none cargo run --bin eval -- '{{expr}}' [no-exit-message] @replr: - RUST_LOG=info cargo run --bin repl --release + RUST_LOG=none cargo run --bin repl --release [no-exit-message] @evalr expr: - RUST_LOG=silent cargo run --bin eval --release -- '{{expr}}' + RUST_LOG=none cargo run --bin eval --release -- '{{expr}}' diff --git a/nix-js/runtime-ts/src/operators.ts b/nix-js/runtime-ts/src/operators.ts index e361300..cdbbf98 100644 --- a/nix-js/runtime-ts/src/operators.ts +++ b/nix-js/runtime-ts/src/operators.ts @@ -7,7 +7,7 @@ import type { NixValue, NixList, NixAttrs, NixString, NixPath } from "./types"; import { isNixPath } from "./types"; import { force } from "./thunk"; import { forceNumeric, forceList, forceAttrs, coerceNumeric } from "./type-assert"; -import { getStringValue, getStringContext, mergeContexts, mkStringWithContext } from "./string-context"; +import { type NixStringContext, getStringValue, getStringContext, mergeContexts, mkStringWithContext } from "./string-context"; import { coerceToString, StringCoercionMode } from "./builtins/conversion"; import { mkPath } from "./path"; import { typeOf, isNixString } from "./builtins/type-check"; @@ -146,9 +146,14 @@ export const op = { // Auto-coerce to string if possible if (canCoerceToString(a) && canCoerceToString(b)) { - const strA = coerceToString(a, StringCoercionMode.Interpolation, false); - const strB = coerceToString(b, StringCoercionMode.Interpolation, false); - return strA + strB; + const context: NixStringContext = new Set(); + const strA = coerceToString(a, StringCoercionMode.Interpolation, false, context); + const strB = coerceToString(b, StringCoercionMode.Interpolation, false, context); + const result = strA + strB; + if (context.size === 0) { + return result; + } + return mkStringWithContext(result, context); } // Numeric addition diff --git a/nix-js/tests/derivation.rs b/nix-js/tests/derivation.rs index e77cf15..46f1411 100644 --- a/nix-js/tests/derivation.rs +++ b/nix-js/tests/derivation.rs @@ -3,6 +3,42 @@ mod utils; use nix_js::value::Value; use utils::{eval_deep, eval_deep_result}; +#[test] +fn add_operator_preserves_derivation_context() { + let result = eval_deep( + r#" + let + dep = derivation { name = "dep"; builder = "/bin/sh"; system = "x86_64-linux"; outputs = ["out" "dev"]; }; + getOutput = output: pkg: pkg.${output} or pkg.out or pkg; + user = derivation { + name = "user"; + builder = "/bin/sh"; + system = "x86_64-linux"; + libPath = (getOutput "lib" dep) + "/lib"; + devPath = dep.dev + "/include"; + }; + in user.drvPath + "#, + ); + + let nix_result = eval_deep( + r#" + let + dep = derivation { name = "dep"; builder = "/bin/sh"; system = "x86_64-linux"; outputs = ["out" "dev"]; }; + user = derivation { + name = "user"; + builder = "/bin/sh"; + system = "x86_64-linux"; + libPath = "${dep.out}/lib"; + devPath = "${dep.dev}/include"; + }; + in user.drvPath + "#, + ); + + assert_eq!(result, nix_result); +} + #[test] fn derivation_minimal() { let result = eval_deep(