chore: tidy
This commit is contained in:
@@ -289,13 +289,14 @@ export const toStringFunc = (value: NixValue): NixString => {
|
||||
return coerceToStringWithContext(value, StringCoercionMode.ToString, false);
|
||||
};
|
||||
|
||||
export type JsonValue = number | boolean | string | null | { [key: string]: JsonValue } | Array<JsonValue>;
|
||||
export const nixValueToJson = (
|
||||
value: NixValue,
|
||||
strict: boolean,
|
||||
outContext: NixStringContext,
|
||||
copyToStore: boolean,
|
||||
seen: Set<NixValue> = new Set(),
|
||||
): unknown => {
|
||||
): JsonValue => {
|
||||
const v = strict ? force(value) : value;
|
||||
|
||||
if (isThunk(v) || typeof v === "function")
|
||||
@@ -358,7 +359,7 @@ export const nixValueToJson = (
|
||||
return nixValueToJson(v.get("outPath") as NixValue, strict, outContext, copyToStore, seen);
|
||||
}
|
||||
|
||||
const result: Record<string, unknown> = {};
|
||||
const result: { [key: string]: JsonValue } = {};
|
||||
const keys = Array.from(v.keys()).sort();
|
||||
for (const key of keys) {
|
||||
result[key] = nixValueToJson(v.get(key) as NixValue, strict, outContext, copyToStore, seen);
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import { force } from "../thunk";
|
||||
import { forceAttrs, forceList, forceStringNoCtx, forceStringValue } from "../type-assert";
|
||||
import type { NixAttrs, NixValue } from "../types";
|
||||
import { coerceToString, nixValueToJson, StringCoercionMode } from "./conversion";
|
||||
import { coerceToString, type JsonValue, nixValueToJson, StringCoercionMode } from "./conversion";
|
||||
|
||||
export interface OutputInfo {
|
||||
path: string;
|
||||
@@ -205,9 +205,9 @@ const structuredAttrsExcludedKeys = new Set([
|
||||
|
||||
const specialAttrs = new Set(["args", "__ignoreNulls", "__contentAddressed", "__impure"]);
|
||||
|
||||
const sortedJsonStringify = (obj: Record<string, unknown>): string => {
|
||||
const sortedJsonStringify = (obj: Record<string, JsonValue>): string => {
|
||||
const sortedKeys = Object.keys(obj).sort();
|
||||
const sortedObj: Record<string, unknown> = {};
|
||||
const sortedObj: Record<string, JsonValue> = {};
|
||||
for (const key of sortedKeys) {
|
||||
sortedObj[key] = obj[key];
|
||||
}
|
||||
@@ -224,14 +224,14 @@ const extractEnv = (
|
||||
const env = new Map<string, string>();
|
||||
|
||||
if (structuredAttrs) {
|
||||
const jsonAttrs: Record<string, unknown> = {};
|
||||
const jsonAttrs: Record<string, JsonValue> = {};
|
||||
for (const [key, value] of attrs) {
|
||||
if (!structuredAttrsExcludedKeys.has(key)) {
|
||||
const forcedValue = force(value as NixValue);
|
||||
const forcedValue = force(value);
|
||||
if (ignoreNulls && forcedValue === null) {
|
||||
continue;
|
||||
}
|
||||
jsonAttrs[key] = nixValueToJson(value as NixValue, true, outContext, true);
|
||||
jsonAttrs[key] = nixValueToJson(value, true, outContext, true);
|
||||
}
|
||||
|
||||
if (key === "allowedReferences") {
|
||||
|
||||
@@ -27,7 +27,7 @@ export const deepSeq =
|
||||
recurse(val);
|
||||
}
|
||||
} else if (isAttrs(forced)) {
|
||||
for (const [_, val] of Object.entries(forced)) {
|
||||
for (const [_, val] of forced.entries()) {
|
||||
recurse(val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createThunk, force } from "../thunk";
|
||||
import type { NixAttrs, NixValue } from "../types";
|
||||
import type { NixAttrs, NixFunction, NixValue } from "../types";
|
||||
import * as arithmetic from "./arithmetic";
|
||||
import * as attrs from "./attrs";
|
||||
import * as conversion from "./conversion";
|
||||
@@ -24,31 +24,31 @@ export interface PrimopMetadata {
|
||||
}
|
||||
|
||||
export const mkPrimop = (
|
||||
func: (...args: NixValue[]) => NixValue,
|
||||
func: NixFunction,
|
||||
name: string,
|
||||
arity: number,
|
||||
applied: number = 0,
|
||||
): ((...args: NixValue[]) => NixValue) => {
|
||||
(func as unknown as Record<symbol, unknown>)[PRIMOP_METADATA] = {
|
||||
func[PRIMOP_METADATA] = {
|
||||
name,
|
||||
arity,
|
||||
applied,
|
||||
} satisfies PrimopMetadata;
|
||||
|
||||
if (applied < arity - 1) {
|
||||
const wrappedFunc = ((...args: NixValue[]) => {
|
||||
const result = func(...args);
|
||||
const wrappedFunc: NixFunction = ((arg: NixValue) => {
|
||||
const result = func(arg);
|
||||
if (typeof result === "function") {
|
||||
return mkPrimop(result, name, arity, applied + args.length);
|
||||
return mkPrimop(result, name, arity, applied + 1);
|
||||
}
|
||||
return result;
|
||||
}) as (...args: NixValue[]) => NixValue;
|
||||
});
|
||||
|
||||
(wrappedFunc as unknown as Record<symbol, unknown>)[PRIMOP_METADATA] = {
|
||||
wrappedFunc[PRIMOP_METADATA] = {
|
||||
name,
|
||||
arity,
|
||||
applied,
|
||||
} satisfies PrimopMetadata;
|
||||
};
|
||||
|
||||
return wrappedFunc;
|
||||
}
|
||||
@@ -57,8 +57,8 @@ export const mkPrimop = (
|
||||
};
|
||||
|
||||
export const isPrimop = (
|
||||
value: unknown,
|
||||
): value is ((...args: never[]) => unknown) & { [PRIMOP_METADATA]: PrimopMetadata } => {
|
||||
value: NixValue,
|
||||
): value is NixFunction & { [PRIMOP_METADATA]: PrimopMetadata } => {
|
||||
return (
|
||||
typeof value === "function" &&
|
||||
PRIMOP_METADATA in value &&
|
||||
@@ -67,7 +67,7 @@ export const isPrimop = (
|
||||
);
|
||||
};
|
||||
|
||||
export const getPrimopMetadata = (func: unknown): PrimopMetadata | undefined => {
|
||||
export const getPrimopMetadata = (func: NixValue): PrimopMetadata | undefined => {
|
||||
if (isPrimop(func)) {
|
||||
return func[PRIMOP_METADATA];
|
||||
}
|
||||
|
||||
@@ -318,10 +318,12 @@ export const splitVersion = (s: NixValue): NixValue => {
|
||||
return components;
|
||||
};
|
||||
|
||||
export const traceVerbose = (_e1: NixValue, e2: NixValue): NixStrictValue => {
|
||||
// TODO: implement traceVerbose
|
||||
return force(e2);
|
||||
};
|
||||
export const traceVerbose =
|
||||
(_e1: NixValue) =>
|
||||
(e2: NixValue): NixStrictValue => {
|
||||
// TODO: implement traceVerbose
|
||||
return force(e2);
|
||||
};
|
||||
|
||||
export const tryEval = (e: NixValue): NixAttrs => {
|
||||
try {
|
||||
|
||||
@@ -39,36 +39,32 @@ export const printValue = (value: NixValue, seen: WeakSet<object> = new WeakSet(
|
||||
return "<LAMBDA>";
|
||||
}
|
||||
|
||||
if (typeof value === "object") {
|
||||
if (IS_CYCLE in value) {
|
||||
return "«repeated»";
|
||||
}
|
||||
|
||||
if (seen.has(value)) {
|
||||
return "«repeated»";
|
||||
}
|
||||
seen.add(value);
|
||||
|
||||
if (isNixPath(value)) {
|
||||
return value.value;
|
||||
}
|
||||
|
||||
if (isStringWithContext(value)) {
|
||||
return printString(value.value);
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
const items = value.map((v) => printValue(v, seen)).join(" ");
|
||||
return `[ ${items} ]`;
|
||||
}
|
||||
|
||||
const entries = Object.entries(value)
|
||||
.map(([k, v]) => `${printSymbol(k)} = ${printValue(v, seen)};`)
|
||||
.join(" ");
|
||||
return `{${entries ? ` ${entries} ` : " "}}`;
|
||||
if (IS_CYCLE in value) {
|
||||
return "«repeated»";
|
||||
}
|
||||
|
||||
throw new Error("unreachable");
|
||||
if (seen.has(value)) {
|
||||
return "«repeated»";
|
||||
}
|
||||
seen.add(value);
|
||||
|
||||
if (isNixPath(value)) {
|
||||
return value.value;
|
||||
}
|
||||
|
||||
if (isStringWithContext(value)) {
|
||||
return printString(value.value);
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
const items = value.map((v) => printValue(v, seen)).join(" ");
|
||||
return `[ ${items} ]`;
|
||||
}
|
||||
|
||||
const entries = [...value.entries()]
|
||||
.map(([k, v]) => `${printSymbol(k)} = ${printValue(v, seen)};`)
|
||||
.join(" ");
|
||||
return `{${entries ? ` ${entries} ` : " "}}`;
|
||||
};
|
||||
|
||||
const printString = (s: string): string => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { PRIMOP_METADATA, type PrimopMetadata } from "./builtins";
|
||||
import { HAS_CONTEXT, isStringWithContext, type StringWithContext } from "./string-context";
|
||||
import { type CYCLE_MARKER, force, type NixThunk } from "./thunk";
|
||||
import { forceAttrs, forceStringNoCtx } from "./type-assert";
|
||||
@@ -28,7 +29,10 @@ export type NixNull = null;
|
||||
export const ATTR_POSITIONS = Symbol("attrPositions");
|
||||
export type NixList = NixValue[];
|
||||
export type NixAttrs = Map<string, NixValue> & { [ATTR_POSITIONS]?: Map<string, number> };
|
||||
export type NixFunction = ((arg: NixValue) => NixValue) & { args?: NixArgs };
|
||||
export type NixFunction = ((arg: NixValue) => NixValue) & {
|
||||
args?: NixArgs;
|
||||
[PRIMOP_METADATA]?: PrimopMetadata;
|
||||
};
|
||||
export class NixArgs {
|
||||
required: string[];
|
||||
optional: string[];
|
||||
|
||||
7
nix-js/runtime-ts/src/types/global.d.ts
vendored
7
nix-js/runtime-ts/src/types/global.d.ts
vendored
@@ -1,5 +1,6 @@
|
||||
import type { NixRuntime } from "..";
|
||||
import type { builtins } from "../builtins";
|
||||
import { JsonValue } from "../builtins/conversion";
|
||||
import type { FetchGitResult, FetchTarballResult, FetchUrlResult } from "../builtins/io";
|
||||
import type {
|
||||
assert,
|
||||
@@ -15,7 +16,7 @@ import type {
|
||||
import type { op } from "../operators";
|
||||
import type { createThunk, force } from "../thunk";
|
||||
import type { forceBool } from "../type-assert";
|
||||
import type { mkAttrs, mkFunction, NixAttrs } from "../types";
|
||||
import type { mkAttrs, mkFunction, NixAttrs, NixStrictValue } from "../types";
|
||||
|
||||
declare global {
|
||||
var Nix: NixRuntime;
|
||||
@@ -92,8 +93,8 @@ declare global {
|
||||
function op_match(regex: string, text: string): (string | null)[] | null;
|
||||
function op_split(regex: string, text: string): (string | (string | null)[])[];
|
||||
|
||||
function op_from_json(json: string): unknown;
|
||||
function op_from_toml(toml: string): unknown;
|
||||
function op_from_json(json: string): NixStrictValue;
|
||||
function op_from_toml(toml: string): NixStrictValue;
|
||||
function op_to_xml(e: NixValue): [string, string[]];
|
||||
|
||||
function op_finalize_derivation(
|
||||
|
||||
@@ -120,11 +120,7 @@ pub(crate) struct Runtime<Ctx: RuntimeContext> {
|
||||
rt: tokio::runtime::Runtime,
|
||||
#[cfg(feature = "inspector")]
|
||||
wait_for_inspector: bool,
|
||||
is_thunk_symbol: v8::Global<v8::Symbol>,
|
||||
primop_metadata_symbol: v8::Global<v8::Symbol>,
|
||||
has_context_symbol: v8::Global<v8::Symbol>,
|
||||
is_path_symbol: v8::Global<v8::Symbol>,
|
||||
is_cycle_symbol: v8::Global<v8::Symbol>,
|
||||
symbols: GlobalSymbols,
|
||||
_marker: PhantomData<Ctx>,
|
||||
}
|
||||
|
||||
@@ -166,13 +162,7 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
|
||||
js_runtime.op_state().borrow_mut().put(RegexCache::new());
|
||||
js_runtime.op_state().borrow_mut().put(DrvHashCache::new());
|
||||
|
||||
let (
|
||||
is_thunk_symbol,
|
||||
primop_metadata_symbol,
|
||||
has_context_symbol,
|
||||
is_path_symbol,
|
||||
is_cycle_symbol,
|
||||
) = {
|
||||
let symbols = {
|
||||
deno_core::scope!(scope, &mut js_runtime);
|
||||
Self::get_symbols(scope)?
|
||||
};
|
||||
@@ -186,11 +176,7 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
|
||||
.expect("failed to build tokio runtime"),
|
||||
#[cfg(feature = "inspector")]
|
||||
wait_for_inspector: inspector_options.wait,
|
||||
is_thunk_symbol,
|
||||
primop_metadata_symbol,
|
||||
has_context_symbol,
|
||||
is_path_symbol,
|
||||
is_cycle_symbol,
|
||||
symbols,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
@@ -236,34 +222,12 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
|
||||
// Retrieve scope from JsRuntime
|
||||
deno_core::scope!(scope, self.js_runtime);
|
||||
let local_value = v8::Local::new(scope, &global_value);
|
||||
let is_thunk_symbol = v8::Local::new(scope, &self.is_thunk_symbol);
|
||||
let primop_metadata_symbol = v8::Local::new(scope, &self.primop_metadata_symbol);
|
||||
let has_context_symbol = v8::Local::new(scope, &self.has_context_symbol);
|
||||
let is_path_symbol = v8::Local::new(scope, &self.is_path_symbol);
|
||||
let is_cycle_symbol = v8::Local::new(scope, &self.is_cycle_symbol);
|
||||
let symbols = &self.symbols.local(scope);
|
||||
|
||||
Ok(to_value(
|
||||
local_value,
|
||||
scope,
|
||||
is_thunk_symbol,
|
||||
primop_metadata_symbol,
|
||||
has_context_symbol,
|
||||
is_path_symbol,
|
||||
is_cycle_symbol,
|
||||
))
|
||||
Ok(to_value(local_value, scope, symbols))
|
||||
}
|
||||
|
||||
/// get (IS_THUNK, PRIMOP_METADATA, HAS_CONTEXT, IS_PATH, IS_CYCLE)
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn get_symbols(
|
||||
scope: &ScopeRef,
|
||||
) -> Result<(
|
||||
v8::Global<v8::Symbol>,
|
||||
v8::Global<v8::Symbol>,
|
||||
v8::Global<v8::Symbol>,
|
||||
v8::Global<v8::Symbol>,
|
||||
v8::Global<v8::Symbol>,
|
||||
)> {
|
||||
fn get_symbols(scope: &ScopeRef) -> Result<GlobalSymbols> {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let nix_key = v8::String::new(scope, "Nix")
|
||||
.ok_or_else(|| Error::internal("failed to create V8 String".into()))?;
|
||||
@@ -295,18 +259,48 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
|
||||
let is_path = get_symbol("IS_PATH")?;
|
||||
let is_cycle = get_symbol("IS_CYCLE")?;
|
||||
|
||||
Ok((is_thunk, primop_metadata, has_context, is_path, is_cycle))
|
||||
Ok(GlobalSymbols {
|
||||
is_thunk,
|
||||
primop_metadata,
|
||||
has_context,
|
||||
is_path,
|
||||
is_cycle,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct GlobalSymbols {
|
||||
is_thunk: v8::Global<v8::Symbol>,
|
||||
primop_metadata: v8::Global<v8::Symbol>,
|
||||
has_context: v8::Global<v8::Symbol>,
|
||||
is_path: v8::Global<v8::Symbol>,
|
||||
is_cycle: v8::Global<v8::Symbol>,
|
||||
}
|
||||
|
||||
impl GlobalSymbols {
|
||||
fn local<'a>(&self, scope: &ScopeRef<'a, '_>) -> LocalSymbols<'a> {
|
||||
LocalSymbols {
|
||||
is_thunk: v8::Local::new(scope, &self.is_thunk),
|
||||
primop_metadata: v8::Local::new(scope, &self.primop_metadata),
|
||||
has_context: v8::Local::new(scope, &self.has_context),
|
||||
is_path: v8::Local::new(scope, &self.is_path),
|
||||
is_cycle: v8::Local::new(scope, &self.is_cycle),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalSymbols<'a> {
|
||||
is_thunk: v8::Local<'a, v8::Symbol>,
|
||||
primop_metadata: v8::Local<'a, v8::Symbol>,
|
||||
has_context: v8::Local<'a, v8::Symbol>,
|
||||
is_path: v8::Local<'a, v8::Symbol>,
|
||||
is_cycle: v8::Local<'a, v8::Symbol>,
|
||||
}
|
||||
|
||||
fn to_value<'a>(
|
||||
val: LocalValue<'a>,
|
||||
scope: &ScopeRef<'a, '_>,
|
||||
is_thunk_symbol: LocalSymbol<'a>,
|
||||
primop_metadata_symbol: LocalSymbol<'a>,
|
||||
has_context_symbol: LocalSymbol<'a>,
|
||||
is_path_symbol: LocalSymbol<'a>,
|
||||
is_cycle_symbol: LocalSymbol<'a>,
|
||||
symbols: &LocalSymbols<'a>,
|
||||
) -> Value {
|
||||
match () {
|
||||
_ if val.is_big_int() => {
|
||||
@@ -336,21 +330,13 @@ fn to_value<'a>(
|
||||
let list = (0..len)
|
||||
.map(|i| {
|
||||
let val = val.get_index(scope, i).expect("infallible index operation");
|
||||
to_value(
|
||||
val,
|
||||
scope,
|
||||
is_thunk_symbol,
|
||||
primop_metadata_symbol,
|
||||
has_context_symbol,
|
||||
is_path_symbol,
|
||||
is_cycle_symbol,
|
||||
)
|
||||
to_value(val, scope, symbols)
|
||||
})
|
||||
.collect();
|
||||
Value::List(List::new(list))
|
||||
}
|
||||
_ if val.is_function() => {
|
||||
if let Some(primop) = to_primop(val, scope, primop_metadata_symbol) {
|
||||
if let Some(primop) = to_primop(val, scope, symbols.primop_metadata) {
|
||||
primop
|
||||
} else {
|
||||
Value::Func
|
||||
@@ -369,34 +355,26 @@ fn to_value<'a>(
|
||||
let val = array
|
||||
.get_index(scope, i * 2 + 1)
|
||||
.expect("infallible index operation");
|
||||
let val = to_value(
|
||||
val,
|
||||
scope,
|
||||
is_thunk_symbol,
|
||||
primop_metadata_symbol,
|
||||
has_context_symbol,
|
||||
is_path_symbol,
|
||||
is_cycle_symbol,
|
||||
);
|
||||
let val = to_value(val, scope, symbols);
|
||||
(Symbol::new(Cow::Owned(key)), val)
|
||||
})
|
||||
.collect();
|
||||
Value::AttrSet(AttrSet::new(attrs))
|
||||
}
|
||||
_ if val.is_object() => {
|
||||
if is_thunk(val, scope, is_thunk_symbol) {
|
||||
if is_thunk(val, scope, symbols.is_thunk) {
|
||||
return Value::Thunk;
|
||||
}
|
||||
|
||||
if is_cycle(val, scope, is_cycle_symbol) {
|
||||
if is_cycle(val, scope, symbols.is_cycle) {
|
||||
return Value::Repeated;
|
||||
}
|
||||
|
||||
if let Some(path_val) = extract_path(val, scope, is_path_symbol) {
|
||||
if let Some(path_val) = extract_path(val, scope, symbols.is_path) {
|
||||
return Value::Path(path_val);
|
||||
}
|
||||
|
||||
if let Some(string_val) = extract_string_with_context(val, scope, has_context_symbol) {
|
||||
if let Some(string_val) = extract_string_with_context(val, scope, symbols.has_context) {
|
||||
return Value::String(string_val);
|
||||
}
|
||||
|
||||
@@ -412,18 +390,7 @@ fn to_value<'a>(
|
||||
.expect("infallible index operation");
|
||||
let val = val.get(scope, key).expect("infallible operation");
|
||||
let key = key.to_rust_string_lossy(scope);
|
||||
(
|
||||
Symbol::from(key),
|
||||
to_value(
|
||||
val,
|
||||
scope,
|
||||
is_thunk_symbol,
|
||||
primop_metadata_symbol,
|
||||
has_context_symbol,
|
||||
is_path_symbol,
|
||||
is_cycle_symbol,
|
||||
),
|
||||
)
|
||||
(Symbol::from(key), to_value(val, scope, symbols))
|
||||
})
|
||||
.collect();
|
||||
Value::AttrSet(AttrSet::new(attrs))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[files]
|
||||
extend-exclude = [
|
||||
"nix-js/tests/basic/regex.rs",
|
||||
"nix-js/tests/lang",
|
||||
"nix-js/tests/tests/regex.rs",
|
||||
"nix-js/tests/tests/lang",
|
||||
]
|
||||
|
||||
[default.extend-words]
|
||||
|
||||
Reference in New Issue
Block a user