diff --git a/nix-js/runtime-ts/src/builtins/misc.ts b/nix-js/runtime-ts/src/builtins/misc.ts index 7499c54..0155aa6 100644 --- a/nix-js/runtime-ts/src/builtins/misc.ts +++ b/nix-js/runtime-ts/src/builtins/misc.ts @@ -262,8 +262,9 @@ export const parseFlakeRef = (s: NixValue): never => { throw new Error("Not implemented: parseFlakeRef"); }; -export const placeholder = (output: NixValue): never => { - throw new Error("Not implemented: placeholder"); +export const placeholder = (output: NixValue): NixValue => { + const outputStr = forceStringNoCtx(output); + return Deno.core.ops.op_make_placeholder(outputStr); }; export const replaceStrings = diff --git a/nix-js/runtime-ts/src/types/global.d.ts b/nix-js/runtime-ts/src/types/global.d.ts index 0eafc57..948ce0d 100644 --- a/nix-js/runtime-ts/src/types/global.d.ts +++ b/nix-js/runtime-ts/src/types/global.d.ts @@ -42,6 +42,7 @@ declare global { function op_read_dir(path: string): Record; function op_path_exists(path: string): boolean; function op_sha256_hex(data: string): string; + function op_make_placeholder(output: string): string; function op_decode_span(span: string): { file: string | null; line: number | null; column: number | null }; function op_make_store_path(ty: string, hash_hex: string, name: string): string; function op_output_path_name(drv_name: string, output_name: string): string; diff --git a/nix-js/src/runtime.rs b/nix-js/src/runtime.rs index 81dfe4d..53c605d 100644 --- a/nix-js/src/runtime.rs +++ b/nix-js/src/runtime.rs @@ -49,6 +49,7 @@ fn runtime_extension() -> Extension { op_path_exists(), op_resolve_path(), op_sha256_hex(), + op_make_placeholder(), op_decode_span::(), op_make_store_path::(), op_output_path_name(), @@ -132,12 +133,11 @@ fn op_import( } let current_dir = ctx.get_current_dir(); - let mut absolute_path = current_dir - .join(&path); - // Do NOT resolve symlinks (eval-okay-symlink-resolution) - // TODO: is this correct? - // .canonicalize() - // .map_err(|e| format!("Failed to resolve path {}: {}", path, e))?; + let mut absolute_path = current_dir.join(&path); + // Do NOT resolve symlinks (eval-okay-symlink-resolution) + // TODO: is this correct? + // .canonicalize() + // .map_err(|e| format!("Failed to resolve path {}: {}", path, e))?; if absolute_path.is_dir() { absolute_path.push("default.nix") } @@ -284,6 +284,18 @@ fn op_sha256_hex(#[string] data: String) -> String { crate::nix_hash::sha256_hex(&data) } +#[deno_core::op2] +#[string] +fn op_make_placeholder(#[string] output: String) -> String { + use sha2::{Digest, Sha256}; + let input = format!("nix-output:{}", output); + let mut hasher = Sha256::new(); + hasher.update(input.as_bytes()); + let hash: [u8; 32] = hasher.finalize().into(); + let encoded = crate::nix_hash::nix_base32_encode(&hash); + format!("/{}", encoded) +} + #[deno_core::op2] #[serde] fn op_decode_span(