feat: toJSON
This commit is contained in:
@@ -7,6 +7,7 @@ import { isStringWithContext } from "../types";
|
|||||||
import { force } from "../thunk";
|
import { force } from "../thunk";
|
||||||
import { type NixStringContext, mkStringWithContext, addBuiltContext } from "../string-context";
|
import { type NixStringContext, mkStringWithContext, addBuiltContext } from "../string-context";
|
||||||
import { forceFunction } from "../type-assert";
|
import { forceFunction } from "../type-assert";
|
||||||
|
import { nixValueToJson } from "../conversion";
|
||||||
|
|
||||||
const convertJsonToNix = (json: unknown): NixValue => {
|
const convertJsonToNix = (json: unknown): NixValue => {
|
||||||
if (json === null) {
|
if (json === null) {
|
||||||
@@ -55,8 +56,13 @@ export const fromTOML = (e: NixValue): never => {
|
|||||||
throw new Error("Not implemented: fromTOML");
|
throw new Error("Not implemented: fromTOML");
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toJSON = (e: NixValue): never => {
|
export const toJSON = (e: NixValue): NixString => {
|
||||||
throw new Error("Not implemented: toJSON");
|
const context: Set<string> = new Set();
|
||||||
|
const string = JSON.stringify(nixValueToJson(e, new Set(), context));
|
||||||
|
if (context.size === 0) {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
return mkStringWithContext(string, context);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toXML = (e: NixValue): never => {
|
export const toXML = (e: NixValue): never => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
isStringWithContext,
|
isStringWithContext,
|
||||||
HAS_CONTEXT,
|
HAS_CONTEXT,
|
||||||
} from "../string-context";
|
} from "../string-context";
|
||||||
|
import { nixValueToJson } from "../conversion";
|
||||||
|
|
||||||
const forceAttrs = (value: NixValue): NixAttrs => {
|
const forceAttrs = (value: NixValue): NixAttrs => {
|
||||||
const forced = force(value);
|
const forced = force(value);
|
||||||
@@ -80,57 +81,6 @@ const extractArgs = (attrs: NixAttrs, outContext: NixStringContext): string[] =>
|
|||||||
return argsList.map((a) => coerceToString(a, StringCoercionMode.ToString, false, outContext));
|
return argsList.map((a) => coerceToString(a, StringCoercionMode.ToString, false, outContext));
|
||||||
};
|
};
|
||||||
|
|
||||||
const nixValueToJson = (value: NixValue, seen = new Set<object>(), outContext?: NixStringContext): any => {
|
|
||||||
const v = force(value);
|
|
||||||
|
|
||||||
if (v === null) return null;
|
|
||||||
if (typeof v === "boolean") return v;
|
|
||||||
if (typeof v === "string") return v;
|
|
||||||
if (typeof v === "number") return v;
|
|
||||||
|
|
||||||
if (typeof v === "object" && HAS_CONTEXT in v && "context" in v) {
|
|
||||||
if (outContext) {
|
|
||||||
for (const elem of v.context) {
|
|
||||||
outContext.add(elem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof v === "bigint") {
|
|
||||||
const num = Number(v);
|
|
||||||
if (v > Number.MAX_SAFE_INTEGER || v < Number.MIN_SAFE_INTEGER) {
|
|
||||||
console.warn(`derivation: integer ${v} exceeds safe range, precision may be lost in __structuredAttrs`);
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof v === "object" && v !== null) {
|
|
||||||
if (seen.has(v)) {
|
|
||||||
throw new Error("derivation: circular reference detected in __structuredAttrs");
|
|
||||||
}
|
|
||||||
seen.add(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(v)) {
|
|
||||||
return v.map((item) => nixValueToJson(item, seen, outContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof v === "object") {
|
|
||||||
const result: Record<string, any> = {};
|
|
||||||
for (const [key, val] of Object.entries(v)) {
|
|
||||||
result[key] = nixValueToJson(val, seen, outContext);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof v === "function") {
|
|
||||||
throw new Error("derivation: cannot serialize function in __structuredAttrs");
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`derivation: cannot serialize ${typeof v} to JSON`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const extractEnv = (
|
const extractEnv = (
|
||||||
attrs: NixAttrs,
|
attrs: NixAttrs,
|
||||||
structuredAttrs: boolean,
|
structuredAttrs: boolean,
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ export const builtins: any = {
|
|||||||
|
|
||||||
builtins: createThunk(() => builtins),
|
builtins: createThunk(() => builtins),
|
||||||
currentSystem: createThunk(() => {
|
currentSystem: createThunk(() => {
|
||||||
return "x86_64-linux"
|
return "x86_64-linux";
|
||||||
}),
|
}),
|
||||||
currentTime: createThunk(() => Date.now()),
|
currentTime: createThunk(() => Date.now()),
|
||||||
|
|
||||||
|
|||||||
58
nix-js/runtime-ts/src/conversion.ts
Normal file
58
nix-js/runtime-ts/src/conversion.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { HAS_CONTEXT, NixStringContext } from "./string-context";
|
||||||
|
import { force } from "./thunk";
|
||||||
|
import type { NixValue } from "./types";
|
||||||
|
|
||||||
|
export const nixValueToJson = (
|
||||||
|
value: NixValue,
|
||||||
|
seen = new Set<object>(),
|
||||||
|
outContext?: NixStringContext,
|
||||||
|
): any => {
|
||||||
|
const v = force(value);
|
||||||
|
|
||||||
|
if (v === null) return null;
|
||||||
|
if (typeof v === "boolean") return v;
|
||||||
|
if (typeof v === "string") return v;
|
||||||
|
if (typeof v === "number") return v;
|
||||||
|
|
||||||
|
if (typeof v === "object" && HAS_CONTEXT in v && "context" in v) {
|
||||||
|
if (outContext) {
|
||||||
|
for (const elem of v.context) {
|
||||||
|
outContext.add(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof v === "bigint") {
|
||||||
|
const num = Number(v);
|
||||||
|
if (v > Number.MAX_SAFE_INTEGER || v < Number.MIN_SAFE_INTEGER) {
|
||||||
|
console.warn(`derivation: integer ${v} exceeds safe range, precision may be lost in __structuredAttrs`);
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof v === "object" && v !== null) {
|
||||||
|
if (seen.has(v)) {
|
||||||
|
throw new Error("derivation: circular reference detected in __structuredAttrs");
|
||||||
|
}
|
||||||
|
seen.add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
return v.map((item) => nixValueToJson(item, seen, outContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof v === "object") {
|
||||||
|
const result: Record<string, any> = {};
|
||||||
|
for (const [key, val] of Object.entries(v)) {
|
||||||
|
result[key] = nixValueToJson(val, seen, outContext);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof v === "function") {
|
||||||
|
throw new Error("derivation: cannot serialize function in __structuredAttrs");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`derivation: cannot serialize ${typeof v} to JSON`);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user