Compare commits
2 Commits
new
...
182470d92d
| Author | SHA1 | Date | |
|---|---|---|---|
| 182470d92d | |||
| 62e48cabd6 |
@@ -3,6 +3,15 @@ vim.lsp.config("biome", {
|
|||||||
on_dir(vim.fn.getcwd())
|
on_dir(vim.fn.getcwd())
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
vim.lsp.config("eslint", {
|
||||||
|
settings = {
|
||||||
|
eslint = {
|
||||||
|
options = {
|
||||||
|
configFile = "./nix-js/runtime-ts/eslint.config.mts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
vim.lsp.config("rust_analyzer", {
|
vim.lsp.config("rust_analyzer", {
|
||||||
settings = {
|
settings = {
|
||||||
["rust-analyzer"] = {
|
["rust-analyzer"] = {
|
||||||
|
|||||||
20
nix-js/runtime-ts/eslint.config.mts
Normal file
20
nix-js/runtime-ts/eslint.config.mts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import js from "@eslint/js";
|
||||||
|
import { defineConfig } from "eslint/config";
|
||||||
|
import globals from "globals";
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
js.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
{
|
||||||
|
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
|
||||||
|
languageOptions: { globals: globals.browser },
|
||||||
|
rules: {
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": ["error", { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignores: ["dist/**/*"],
|
||||||
|
},
|
||||||
|
]);
|
||||||
1405
nix-js/runtime-ts/package-lock.json
generated
1405
nix-js/runtime-ts/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"check": "tsc --noEmit && npx eslint && biome check",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"build": "node build.mjs",
|
"build": "node build.mjs",
|
||||||
"dev": "npm run typecheck && npm run build"
|
"dev": "npm run typecheck && npm run build"
|
||||||
@@ -12,6 +13,9 @@
|
|||||||
"typescript": "^5.7.2"
|
"typescript": "^5.7.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"js-sdsl": "^4.4.2"
|
"eslint": "^9.39.2",
|
||||||
|
"globals": "^17.3.0",
|
||||||
|
"js-sdsl": "^4.4.2",
|
||||||
|
"typescript-eslint": "^8.55.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { mkPos } from "../helpers";
|
import { mkPos, select } from "../helpers";
|
||||||
import { createThunk } from "../thunk";
|
import { createThunk } from "../thunk";
|
||||||
import { forceAttrs, forceFunction, forceList, forceStringValue } from "../type-assert";
|
import { forceAttrs, forceFunction, forceList, forceStringValue } from "../type-assert";
|
||||||
import { ATTR_POSITIONS, type NixAttrs, type NixList, type NixValue } from "../types";
|
import { ATTR_POSITIONS, type NixAttrs, type NixList, type NixValue } from "../types";
|
||||||
|
|
||||||
export const attrNames = (set: NixValue): string[] => Object.keys(forceAttrs(set)).sort();
|
export const attrNames = (set: NixValue): string[] => Array.from(forceAttrs(set).keys()).sort();
|
||||||
|
|
||||||
export const attrValues = (set: NixValue): NixValue[] =>
|
export const attrValues = (set: NixValue): NixValue[] =>
|
||||||
Object.entries(forceAttrs(set))
|
Array.from(forceAttrs(set).entries())
|
||||||
.sort(([a], [b]) => {
|
.sort(([a], [b]) => {
|
||||||
if (a < b) {
|
if (a < b) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -21,21 +21,24 @@ export const attrValues = (set: NixValue): NixValue[] =>
|
|||||||
export const getAttr =
|
export const getAttr =
|
||||||
(s: NixValue) =>
|
(s: NixValue) =>
|
||||||
(set: NixValue): NixValue =>
|
(set: NixValue): NixValue =>
|
||||||
forceAttrs(set)[forceStringValue(s)];
|
select(forceAttrs(set), [s]);
|
||||||
|
|
||||||
export const hasAttr =
|
export const hasAttr =
|
||||||
(s: NixValue) =>
|
(s: NixValue) =>
|
||||||
(set: NixValue): boolean =>
|
(set: NixValue): boolean =>
|
||||||
Object.hasOwn(forceAttrs(set), forceStringValue(s));
|
forceAttrs(set).has(forceStringValue(s));
|
||||||
|
|
||||||
export const mapAttrs =
|
export const mapAttrs =
|
||||||
(f: NixValue) =>
|
(f: NixValue) =>
|
||||||
(attrs: NixValue): NixAttrs => {
|
(attrs: NixValue): NixAttrs => {
|
||||||
const forcedAttrs = forceAttrs(attrs);
|
const forcedAttrs = forceAttrs(attrs);
|
||||||
const forcedF = forceFunction(f);
|
const forcedF = forceFunction(f);
|
||||||
const newAttrs: NixAttrs = {};
|
const newAttrs: NixAttrs = new Map();
|
||||||
for (const key in forcedAttrs) {
|
for (const [key, val] of forcedAttrs) {
|
||||||
newAttrs[key] = createThunk(() => forceFunction(forcedF(key))(forcedAttrs[key]), "created by mapAttrs");
|
newAttrs.set(
|
||||||
|
key,
|
||||||
|
createThunk(() => forceFunction(forcedF(key))(val), "created by mapAttrs"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return newAttrs;
|
return newAttrs;
|
||||||
};
|
};
|
||||||
@@ -43,25 +46,20 @@ export const mapAttrs =
|
|||||||
export const removeAttrs =
|
export const removeAttrs =
|
||||||
(attrs: NixValue) =>
|
(attrs: NixValue) =>
|
||||||
(list: NixValue): NixAttrs => {
|
(list: NixValue): NixAttrs => {
|
||||||
const newAttrs: NixAttrs = {};
|
const newAttrs: NixAttrs = new Map(forceAttrs(attrs));
|
||||||
const forcedAttrs = forceAttrs(attrs);
|
|
||||||
const forcedList = forceList(list);
|
const forcedList = forceList(list);
|
||||||
const keysToRemove = new Set(forcedList.map(forceStringValue));
|
for (const item of forcedList) {
|
||||||
|
newAttrs.delete(forceStringValue(item));
|
||||||
for (const key in forcedAttrs) {
|
|
||||||
if (!keysToRemove.has(key)) {
|
|
||||||
newAttrs[key] = forcedAttrs[key];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return newAttrs;
|
return newAttrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const listToAttrs = (e: NixValue): NixAttrs => {
|
export const listToAttrs = (e: NixValue): NixAttrs => {
|
||||||
const attrs: NixAttrs = {};
|
const attrs: NixAttrs = new Map();
|
||||||
const forcedE = [...forceList(e)].reverse();
|
const forcedE = [...forceList(e)].reverse();
|
||||||
for (const obj of forcedE) {
|
for (const obj of forcedE) {
|
||||||
const item = forceAttrs(obj);
|
const item = forceAttrs(obj);
|
||||||
attrs[forceStringValue(item.name)] = item.value;
|
attrs.set(forceStringValue(select(item, ["name"])), select(item, ["value"]));
|
||||||
}
|
}
|
||||||
return attrs;
|
return attrs;
|
||||||
};
|
};
|
||||||
@@ -71,21 +69,17 @@ export const intersectAttrs =
|
|||||||
(e2: NixValue): NixAttrs => {
|
(e2: NixValue): NixAttrs => {
|
||||||
const f1 = forceAttrs(e1);
|
const f1 = forceAttrs(e1);
|
||||||
const f2 = forceAttrs(e2);
|
const f2 = forceAttrs(e2);
|
||||||
const attrs: NixAttrs = {};
|
const attrs: NixAttrs = new Map();
|
||||||
const k1 = Object.keys(f1);
|
if (f1.size < f2.size) {
|
||||||
const k2 = Object.keys(f2);
|
for (const [key] of f1) {
|
||||||
if (k1.length < k2.length) {
|
if (f2.has(key)) {
|
||||||
for (let i = 0; i < k1.length; i++) {
|
attrs.set(key, f2.get(key) as NixValue);
|
||||||
const key = k1[i];
|
|
||||||
if (key in f2) {
|
|
||||||
attrs[key] = f2[key];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < k2.length; i++) {
|
for (const [key] of f2) {
|
||||||
const key = k2[i];
|
if (f1.has(key)) {
|
||||||
if (key in f1) {
|
attrs.set(key, f2.get(key) as NixValue);
|
||||||
attrs[key] = f2[key];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,20 +91,20 @@ export const catAttrs =
|
|||||||
(list: NixValue): NixList => {
|
(list: NixValue): NixList => {
|
||||||
const key = forceStringValue(attr);
|
const key = forceStringValue(attr);
|
||||||
return forceList(list)
|
return forceList(list)
|
||||||
.map((set) => forceAttrs(set)[key])
|
.map((set) => forceAttrs(set).get(key))
|
||||||
.filter((val) => val !== undefined);
|
.filter((val) => val !== undefined) as NixList;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const groupBy =
|
export const groupBy =
|
||||||
(f: NixValue) =>
|
(f: NixValue) =>
|
||||||
(list: NixValue): NixAttrs => {
|
(list: NixValue): NixAttrs => {
|
||||||
const attrs: NixAttrs = {};
|
const attrs: NixAttrs = new Map();
|
||||||
const forcedF = forceFunction(f);
|
const forcedF = forceFunction(f);
|
||||||
const forcedList = forceList(list);
|
const forcedList = forceList(list);
|
||||||
for (const elem of forcedList) {
|
for (const elem of forcedList) {
|
||||||
const key = forceStringValue(forcedF(elem));
|
const key = forceStringValue(forcedF(elem));
|
||||||
if (!attrs[key]) attrs[key] = [];
|
if (!attrs.has(key)) attrs.set(key, []);
|
||||||
(attrs[key] as NixList).push(elem);
|
(attrs.get(key) as NixList).push(elem);
|
||||||
}
|
}
|
||||||
return attrs;
|
return attrs;
|
||||||
};
|
};
|
||||||
@@ -125,7 +119,7 @@ export const zipAttrsWith =
|
|||||||
for (const item of listForced) {
|
for (const item of listForced) {
|
||||||
const attrs = forceAttrs(item);
|
const attrs = forceAttrs(item);
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(attrs)) {
|
for (const [key, value] of attrs) {
|
||||||
if (!attrMap.has(key)) {
|
if (!attrMap.has(key)) {
|
||||||
attrMap.set(key, []);
|
attrMap.set(key, []);
|
||||||
}
|
}
|
||||||
@@ -133,10 +127,13 @@ export const zipAttrsWith =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: Record<string, NixValue> = {};
|
const result: NixAttrs = new Map();
|
||||||
|
|
||||||
for (const [name, values] of attrMap.entries()) {
|
for (const [name, values] of attrMap.entries()) {
|
||||||
result[name] = createThunk(() => forceFunction(forceFunction(f)(name))(values));
|
result.set(
|
||||||
|
name,
|
||||||
|
createThunk(() => forceFunction(forceFunction(f)(name))(values)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -148,7 +145,7 @@ export const unsafeGetAttrPos =
|
|||||||
const name = forceStringValue(attrName);
|
const name = forceStringValue(attrName);
|
||||||
const attrs = forceAttrs(attrSet);
|
const attrs = forceAttrs(attrSet);
|
||||||
|
|
||||||
if (!(name in attrs)) {
|
if (!attrs.has(name)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,20 +113,20 @@ export const getContext = (value: NixValue): NixAttrs => {
|
|||||||
const context = getStringContext(s);
|
const context = getStringContext(s);
|
||||||
|
|
||||||
const infoMap = parseContextToInfoMap(context);
|
const infoMap = parseContextToInfoMap(context);
|
||||||
const result: NixAttrs = {};
|
const result: NixAttrs = new Map();
|
||||||
|
|
||||||
for (const [path, info] of infoMap) {
|
for (const [path, info] of infoMap) {
|
||||||
const attrs: NixAttrs = {};
|
const attrs: NixAttrs = new Map();
|
||||||
if (info.path) {
|
if (info.path) {
|
||||||
attrs.path = true;
|
attrs.set("path", true);
|
||||||
}
|
}
|
||||||
if (info.allOutputs) {
|
if (info.allOutputs) {
|
||||||
attrs.allOutputs = true;
|
attrs.set("allOutputs", true);
|
||||||
}
|
}
|
||||||
if (info.outputs.length > 0) {
|
if (info.outputs.length > 0) {
|
||||||
attrs.outputs = info.outputs;
|
attrs.set("outputs", info.outputs);
|
||||||
}
|
}
|
||||||
result[path] = attrs;
|
result.set(path, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -154,22 +154,22 @@ export const appendContext =
|
|||||||
const ctxAttrs = forceAttrs(ctxValue);
|
const ctxAttrs = forceAttrs(ctxValue);
|
||||||
const newContext: NixStringContext = new Set(existingContext);
|
const newContext: NixStringContext = new Set(existingContext);
|
||||||
|
|
||||||
for (const [path, infoVal] of Object.entries(ctxAttrs)) {
|
for (const [path, infoVal] of ctxAttrs) {
|
||||||
if (!path.startsWith("/nix/store/")) {
|
if (!path.startsWith("/nix/store/")) {
|
||||||
throw new Error(`context key '${path}' is not a store path`);
|
throw new Error(`context key '${path}' is not a store path`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const info = forceAttrs(infoVal);
|
const info = forceAttrs(infoVal as NixValue);
|
||||||
|
|
||||||
if ("path" in info) {
|
if (info.has("path")) {
|
||||||
const pathVal = force(info.path);
|
const pathVal = force(info.get("path") as NixValue);
|
||||||
if (pathVal === true) {
|
if (pathVal === true) {
|
||||||
newContext.add(path);
|
newContext.add(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("allOutputs" in info) {
|
if (info.has("allOutputs")) {
|
||||||
const allOutputs = force(info.allOutputs);
|
const allOutputs = force(info.get("allOutputs") as NixValue);
|
||||||
if (allOutputs === true) {
|
if (allOutputs === true) {
|
||||||
if (!path.endsWith(".drv")) {
|
if (!path.endsWith(".drv")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -180,8 +180,8 @@ export const appendContext =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("outputs" in info) {
|
if (info.has("outputs")) {
|
||||||
const outputs = forceList(info.outputs);
|
const outputs = forceList(info.get("outputs") as NixValue);
|
||||||
if (outputs.length > 0 && !path.endsWith(".drv")) {
|
if (outputs.length > 0 && !path.endsWith(".drv")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`tried to add derivation output context of ${path}, which is not a derivation, to a string`,
|
`tried to add derivation output context of ${path}, which is not a derivation, to a string`,
|
||||||
|
|||||||
@@ -118,37 +118,31 @@ export const coerceToString = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof v === "object" && v !== null && !Array.isArray(v)) {
|
if (typeof v === "object" && v !== null && !Array.isArray(v)) {
|
||||||
// First, try the __toString method if present
|
if (v instanceof Map) {
|
||||||
// This allows custom types to define their own string representation
|
if (v.has("__toString")) {
|
||||||
if ("__toString" in v) {
|
const toStringMethod = forceFunction(v.get("__toString") as NixValue);
|
||||||
// Force the method in case it's a thunk
|
const result = force(toStringMethod(v));
|
||||||
const toStringMethod = forceFunction(v.__toString);
|
return coerceToString(result, mode, copyToStore, outContext);
|
||||||
const result = force(toStringMethod(v));
|
}
|
||||||
// Recursively coerceToString
|
|
||||||
return coerceToString(result, mode, copyToStore, outContext);
|
if (v.has("outPath")) {
|
||||||
}
|
const outPath = coerceToString(v.get("outPath") as NixValue, mode, copyToStore, outContext);
|
||||||
|
if (v.has("type") && v.get("type") === "derivation" && v.has("drvPath") && outContext) {
|
||||||
// If no __toString, try outPath (used for derivations and store paths)
|
const drvPathValue = force(v.get("drvPath") as NixValue);
|
||||||
// This allows derivation objects like { outPath = "/nix/store/..."; } to be coerced
|
const drvPathStr = isStringWithContext(drvPathValue)
|
||||||
if ("outPath" in v) {
|
? drvPathValue.value
|
||||||
// Recursively coerce the outPath value
|
: typeof drvPathValue === "string"
|
||||||
const outPath = coerceToString(v.outPath, mode, copyToStore, outContext);
|
? drvPathValue
|
||||||
if ("type" in v && v.type === "derivation" && "drvPath" in v && outContext) {
|
: null;
|
||||||
const drvPathValue = force(v.drvPath);
|
if (drvPathStr) {
|
||||||
const drvPathStr = isStringWithContext(drvPathValue)
|
const outputName = v.has("outputName") ? String(force(v.get("outputName") as NixValue)) : "out";
|
||||||
? drvPathValue.value
|
addBuiltContext(outContext, drvPathStr, outputName);
|
||||||
: typeof drvPathValue === "string"
|
}
|
||||||
? drvPathValue
|
}
|
||||||
: null;
|
return outPath;
|
||||||
if (drvPathStr) {
|
|
||||||
const outputName = "outputName" in v ? String(force(v.outputName)) : "out";
|
|
||||||
addBuiltContext(outContext, drvPathStr, outputName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return outPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute sets without __toString or outPath cannot be coerced
|
|
||||||
throw new TypeError(`cannot coerce ${typeOf(v)} to a string`);
|
throw new TypeError(`cannot coerce ${typeOf(v)} to a string`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,8 +253,8 @@ export const coerceToPath = (value: NixValue, outContext: NixStringContext): str
|
|||||||
if (isPath(forced)) {
|
if (isPath(forced)) {
|
||||||
return forced.value;
|
return forced.value;
|
||||||
}
|
}
|
||||||
if (isAttrs(forced) && Object.hasOwn(forced, "__toString")) {
|
if (isAttrs(forced) && forced.has("__toString")) {
|
||||||
const toStringFunc = forceFunction(forced.__toString);
|
const toStringFunc = forceFunction(forced.get("__toString") as NixValue);
|
||||||
return coerceToPath(toStringFunc(forced), outContext);
|
return coerceToPath(toStringFunc(forced), outContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,30 +333,33 @@ export const nixValueToJson = (
|
|||||||
return v.map((item) => nixValueToJson(item, strict, outContext, copyToStore, seen));
|
return v.map((item) => nixValueToJson(item, strict, outContext, copyToStore, seen));
|
||||||
}
|
}
|
||||||
|
|
||||||
// NixAttrs
|
if (v instanceof Map) {
|
||||||
if ("__toString" in v && typeof force(v.__toString) === "function") {
|
if (v.has("__toString") && typeof force(v.get("__toString") as NixValue) === "function") {
|
||||||
const toStringMethod = force(v.__toString) as (self: typeof v) => NixValue;
|
const toStringMethod = force(v.get("__toString") as NixValue) as (self: typeof v) => NixValue;
|
||||||
const result = force(toStringMethod(v));
|
const result = force(toStringMethod(v));
|
||||||
if (typeof result === "string") {
|
if (typeof result === "string") {
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
if (isStringWithContext(result)) {
|
|
||||||
for (const elem of result.context) {
|
|
||||||
outContext.add(elem);
|
|
||||||
}
|
}
|
||||||
return result.value;
|
if (isStringWithContext(result)) {
|
||||||
|
for (const elem of result.context) {
|
||||||
|
outContext.add(elem);
|
||||||
|
}
|
||||||
|
return result.value;
|
||||||
|
}
|
||||||
|
return nixValueToJson(result, strict, outContext, copyToStore, seen);
|
||||||
}
|
}
|
||||||
return nixValueToJson(result, strict, outContext, copyToStore, seen);
|
|
||||||
|
if (v.has("outPath")) {
|
||||||
|
return nixValueToJson(v.get("outPath") as NixValue, strict, outContext, copyToStore, seen);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: Record<string, unknown> = {};
|
||||||
|
const keys = Array.from(v.keys()).sort();
|
||||||
|
for (const key of keys) {
|
||||||
|
result[key] = nixValueToJson(v.get(key) as NixValue, strict, outContext, copyToStore, seen);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("outPath" in v) {
|
throw new Error(`cannot convert ${typeof v} to JSON`);
|
||||||
return nixValueToJson(v.outPath, strict, outContext, copyToStore, seen);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result: Record<string, unknown> = {};
|
|
||||||
const keys = Object.keys(v).sort();
|
|
||||||
for (const key of keys) {
|
|
||||||
result[key] = nixValueToJson(v[key], strict, outContext, copyToStore, seen);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -116,10 +116,10 @@ export const generateAtermModulo = (drv: DerivationData, inputDrvHashes: Map<str
|
|||||||
return `Derive([${outputs}],[${inputDrvs}],[${inputSrcs}],${quoteString(drv.platform)},${escapeString(drv.builder)},[${args}],[${envs}])`;
|
return `Derive([${outputs}],[${inputDrvs}],[${inputSrcs}],${quoteString(drv.platform)},${escapeString(drv.builder)},[${args}],[${envs}])`;
|
||||||
};
|
};
|
||||||
const validateName = (attrs: NixAttrs): string => {
|
const validateName = (attrs: NixAttrs): string => {
|
||||||
if (!("name" in attrs)) {
|
if (!attrs.has("name")) {
|
||||||
throw new Error("derivation: missing required attribute 'name'");
|
throw new Error("derivation: missing required attribute 'name'");
|
||||||
}
|
}
|
||||||
const name = forceStringValue(attrs.name);
|
const name = forceStringValue(attrs.get("name") as NixValue);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
throw new Error("derivation: 'name' cannot be empty");
|
throw new Error("derivation: 'name' cannot be empty");
|
||||||
}
|
}
|
||||||
@@ -130,17 +130,17 @@ const validateName = (attrs: NixAttrs): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const validateBuilder = (attrs: NixAttrs, outContext: NixStringContext): string => {
|
const validateBuilder = (attrs: NixAttrs, outContext: NixStringContext): string => {
|
||||||
if (!("builder" in attrs)) {
|
if (!attrs.has("builder")) {
|
||||||
throw new Error("derivation: missing required attribute 'builder'");
|
throw new Error("derivation: missing required attribute 'builder'");
|
||||||
}
|
}
|
||||||
return coerceToString(attrs.builder, StringCoercionMode.ToString, true, outContext);
|
return coerceToString(attrs.get("builder") as NixValue, StringCoercionMode.ToString, true, outContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateSystem = (attrs: NixAttrs): string => {
|
const validateSystem = (attrs: NixAttrs): string => {
|
||||||
if (!("system" in attrs)) {
|
if (!attrs.has("system")) {
|
||||||
throw new Error("derivation: missing required attribute 'system'");
|
throw new Error("derivation: missing required attribute 'system'");
|
||||||
}
|
}
|
||||||
return forceStringValue(attrs.system);
|
return forceStringValue(attrs.get("system") as NixValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateOutputs = (outputs: string[]): void => {
|
const validateOutputs = (outputs: string[]): void => {
|
||||||
@@ -162,17 +162,25 @@ const validateOutputs = (outputs: string[]): void => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const extractOutputs = (attrs: NixAttrs, structuredAttrs: boolean): string[] => {
|
const extractOutputs = (attrs: NixAttrs, structuredAttrs: boolean): string[] => {
|
||||||
if (!("outputs" in attrs)) {
|
if (!attrs.has("outputs")) {
|
||||||
return ["out"];
|
return ["out"];
|
||||||
}
|
}
|
||||||
|
|
||||||
let outputs: string[];
|
let outputs: string[];
|
||||||
if (structuredAttrs) {
|
if (structuredAttrs) {
|
||||||
const outputsList = forceList(attrs.outputs);
|
const outputsList = forceList(attrs.get("outputs") as NixValue);
|
||||||
outputs = outputsList.map((o) => forceStringValue(o));
|
outputs = outputsList.map((o) => forceStringValue(o));
|
||||||
} else {
|
} else {
|
||||||
const outputsStr = coerceToString(attrs.outputs, StringCoercionMode.ToString, false, new Set());
|
const outputsStr = coerceToString(
|
||||||
outputs = outputsStr.split(/\s+/).filter((s) => s.length > 0);
|
attrs.get("outputs") as NixValue,
|
||||||
|
StringCoercionMode.ToString,
|
||||||
|
false,
|
||||||
|
new Set(),
|
||||||
|
);
|
||||||
|
outputs = outputsStr
|
||||||
|
.trim()
|
||||||
|
.split(/\s+/)
|
||||||
|
.filter((s) => s.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateOutputs(outputs);
|
validateOutputs(outputs);
|
||||||
@@ -180,10 +188,10 @@ const extractOutputs = (attrs: NixAttrs, structuredAttrs: boolean): string[] =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
const extractArgs = (attrs: NixAttrs, outContext: NixStringContext): string[] => {
|
const extractArgs = (attrs: NixAttrs, outContext: NixStringContext): string[] => {
|
||||||
if (!("args" in attrs)) {
|
if (!attrs.has("args")) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const argsList = forceList(attrs.args);
|
const argsList = forceList(attrs.get("args") as NixValue);
|
||||||
return argsList.map((a) => coerceToString(a, StringCoercionMode.ToString, true, outContext));
|
return argsList.map((a) => coerceToString(a, StringCoercionMode.ToString, true, outContext));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -217,13 +225,13 @@ const extractEnv = (
|
|||||||
|
|
||||||
if (structuredAttrs) {
|
if (structuredAttrs) {
|
||||||
const jsonAttrs: Record<string, unknown> = {};
|
const jsonAttrs: Record<string, unknown> = {};
|
||||||
for (const [key, value] of Object.entries(attrs)) {
|
for (const [key, value] of attrs) {
|
||||||
if (!structuredAttrsExcludedKeys.has(key)) {
|
if (!structuredAttrsExcludedKeys.has(key)) {
|
||||||
const forcedValue = force(value);
|
const forcedValue = force(value as NixValue);
|
||||||
if (ignoreNulls && forcedValue === null) {
|
if (ignoreNulls && forcedValue === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
jsonAttrs[key] = nixValueToJson(value, true, outContext, true);
|
jsonAttrs[key] = nixValueToJson(value as NixValue, true, outContext, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === "allowedReferences") {
|
if (key === "allowedReferences") {
|
||||||
@@ -271,13 +279,13 @@ const extractEnv = (
|
|||||||
}
|
}
|
||||||
env.set("__json", sortedJsonStringify(jsonAttrs));
|
env.set("__json", sortedJsonStringify(jsonAttrs));
|
||||||
} else {
|
} else {
|
||||||
for (const [key, value] of Object.entries(attrs)) {
|
for (const [key, value] of attrs) {
|
||||||
if (!specialAttrs.has(key)) {
|
if (!specialAttrs.has(key)) {
|
||||||
const forcedValue = force(value);
|
const forcedValue = force(value as NixValue);
|
||||||
if (ignoreNulls && forcedValue === null) {
|
if (ignoreNulls && forcedValue === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
env.set(key, coerceToString(value, StringCoercionMode.ToString, true, outContext));
|
env.set(key, coerceToString(value as NixValue, StringCoercionMode.ToString, true, outContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,29 +300,29 @@ interface FixedOutputInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const extractFixedOutputInfo = (attrs: NixAttrs, ignoreNulls: boolean): FixedOutputInfo | null => {
|
const extractFixedOutputInfo = (attrs: NixAttrs, ignoreNulls: boolean): FixedOutputInfo | null => {
|
||||||
if (!("outputHash" in attrs)) {
|
if (!attrs.has("outputHash")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashValue = force(attrs.outputHash);
|
const hashValue = force(attrs.get("outputHash") as NixValue);
|
||||||
if (ignoreNulls && hashValue === null) {
|
if (ignoreNulls && hashValue === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const hashRaw = forceStringNoCtx(attrs.outputHash);
|
const hashRaw = forceStringNoCtx(hashValue);
|
||||||
|
|
||||||
let hashAlgo = null;
|
let hashAlgo = null;
|
||||||
if ("outputHashAlgo" in attrs) {
|
if (attrs.has("outputHashAlgo")) {
|
||||||
const algoValue = force(attrs.outputHashAlgo);
|
const algoValue = force(attrs.get("outputHashAlgo") as NixValue);
|
||||||
if (!(ignoreNulls && algoValue === null)) {
|
if (!(ignoreNulls && algoValue === null)) {
|
||||||
hashAlgo = forceStringNoCtx(attrs.outputHashAlgo);
|
hashAlgo = forceStringNoCtx(algoValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let hashMode = "flat";
|
let hashMode = "flat";
|
||||||
if ("outputHashMode" in attrs) {
|
if (attrs.has("outputHashMode")) {
|
||||||
const modeValue = force(attrs.outputHashMode);
|
const modeValue = force(attrs.get("outputHashMode") as NixValue);
|
||||||
if (!(ignoreNulls && modeValue === null)) {
|
if (!(ignoreNulls && modeValue === null)) {
|
||||||
hashMode = forceStringValue(attrs.outputHashMode);
|
hashMode = forceStringValue(modeValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,18 +349,22 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
|
|||||||
const builder = validateBuilder(attrs, collectedContext);
|
const builder = validateBuilder(attrs, collectedContext);
|
||||||
const platform = validateSystem(attrs);
|
const platform = validateSystem(attrs);
|
||||||
|
|
||||||
const structuredAttrs = "__structuredAttrs" in attrs ? force(attrs.__structuredAttrs) === true : false;
|
const structuredAttrs = attrs.has("__structuredAttrs")
|
||||||
const ignoreNulls = "__ignoreNulls" in attrs ? force(attrs.__ignoreNulls) === true : false;
|
? force(attrs.get("__structuredAttrs") as NixValue) === true
|
||||||
|
: false;
|
||||||
|
const ignoreNulls = attrs.has("__ignoreNulls")
|
||||||
|
? force(attrs.get("__ignoreNulls") as NixValue) === true
|
||||||
|
: false;
|
||||||
|
|
||||||
const outputs = extractOutputs(attrs, structuredAttrs);
|
const outputs = extractOutputs(attrs, structuredAttrs);
|
||||||
const fixedOutputInfo = extractFixedOutputInfo(attrs, ignoreNulls);
|
const fixedOutputInfo = extractFixedOutputInfo(attrs, ignoreNulls);
|
||||||
validateFixedOutputConstraints(fixedOutputInfo, outputs);
|
validateFixedOutputConstraints(fixedOutputInfo, outputs);
|
||||||
|
|
||||||
if ("__contentAddressed" in attrs && force(attrs.__contentAddressed) === true) {
|
if (attrs.has("__contentAddressed") && force(attrs.get("__contentAddressed") as NixValue) === true) {
|
||||||
throw new Error("ca derivations are not supported");
|
throw new Error("ca derivations are not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("__impure" in attrs && force(attrs.__impure) === true) {
|
if (attrs.has("__impure") && force(attrs.get("__impure") as NixValue) === true) {
|
||||||
throw new Error("impure derivations are not supported");
|
throw new Error("impure derivations are not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,16 +388,16 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
|
|||||||
fixedOutput: fixedOutputInfo,
|
fixedOutput: fixedOutputInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result: NixAttrs = {};
|
const result: NixAttrs = new Map();
|
||||||
|
|
||||||
const drvPathContext = new Set<string>();
|
const drvPathContext = new Set<string>();
|
||||||
addDrvDeepContext(drvPathContext, rustResult.drvPath);
|
addDrvDeepContext(drvPathContext, rustResult.drvPath);
|
||||||
result.drvPath = mkStringWithContext(rustResult.drvPath, drvPathContext);
|
result.set("drvPath", mkStringWithContext(rustResult.drvPath, drvPathContext));
|
||||||
|
|
||||||
for (const [outputName, outputPath] of rustResult.outputs) {
|
for (const [outputName, outputPath] of rustResult.outputs) {
|
||||||
const outputContext = new Set<string>();
|
const outputContext = new Set<string>();
|
||||||
addBuiltContext(outputContext, rustResult.drvPath, outputName);
|
addBuiltContext(outputContext, rustResult.drvPath, outputName);
|
||||||
result[outputName] = mkStringWithContext(outputPath, outputContext);
|
result.set(outputName, mkStringWithContext(outputPath, outputContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { select } from "../helpers";
|
||||||
import { forceAttrs, forceStringNoCtx, forceStringValue } from "../type-assert";
|
import { forceAttrs, forceStringNoCtx, forceStringValue } from "../type-assert";
|
||||||
import type { NixValue } from "../types";
|
import type { NixValue } from "../types";
|
||||||
import { realisePath } from "./io";
|
import { realisePath } from "./io";
|
||||||
@@ -20,14 +21,14 @@ export const hashString =
|
|||||||
|
|
||||||
export const convertHash = (args: NixValue): string => {
|
export const convertHash = (args: NixValue): string => {
|
||||||
const attrs = forceAttrs(args);
|
const attrs = forceAttrs(args);
|
||||||
const hash = forceStringNoCtx(attrs.hash);
|
const hash = forceStringNoCtx(select(attrs, ["hash"]));
|
||||||
|
|
||||||
let hashAlgo: string | null = null;
|
let hashAlgo: string | null = null;
|
||||||
if ("hashAlgo" in attrs) {
|
if (attrs.has("hashAlgo")) {
|
||||||
hashAlgo = forceStringNoCtx(attrs.hashAlgo);
|
hashAlgo = forceStringNoCtx(select(attrs, ["hashAlgo"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const toHashFormat = forceStringNoCtx(attrs.toHashFormat);
|
const toHashFormat = forceStringNoCtx(select(attrs, ["toHashFormat"]));
|
||||||
|
|
||||||
return Deno.core.ops.op_convert_hash({
|
return Deno.core.ops.op_convert_hash({
|
||||||
hash,
|
hash,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createThunk, force } from "../thunk";
|
import { createThunk, force } from "../thunk";
|
||||||
import type { NixValue } from "../types";
|
import type { NixAttrs, NixValue } from "../types";
|
||||||
import * as arithmetic from "./arithmetic";
|
import * as arithmetic from "./arithmetic";
|
||||||
import * as attrs from "./attrs";
|
import * as attrs from "./attrs";
|
||||||
import * as conversion from "./conversion";
|
import * as conversion from "./conversion";
|
||||||
@@ -74,149 +74,151 @@ export const getPrimopMetadata = (func: unknown): PrimopMetadata | undefined =>
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const builtins: Record<string, NixValue> = {
|
export const builtins: NixAttrs = new Map<string, NixValue>(
|
||||||
add: mkPrimop(arithmetic.add, "add", 2),
|
Object.entries({
|
||||||
sub: mkPrimop(arithmetic.sub, "sub", 2),
|
add: mkPrimop(arithmetic.add, "add", 2),
|
||||||
mul: mkPrimop(arithmetic.mul, "mul", 2),
|
sub: mkPrimop(arithmetic.sub, "sub", 2),
|
||||||
div: mkPrimop(arithmetic.div, "div", 2),
|
mul: mkPrimop(arithmetic.mul, "mul", 2),
|
||||||
bitAnd: mkPrimop(arithmetic.bitAnd, "bitAnd", 2),
|
div: mkPrimop(arithmetic.div, "div", 2),
|
||||||
bitOr: mkPrimop(arithmetic.bitOr, "bitOr", 2),
|
bitAnd: mkPrimop(arithmetic.bitAnd, "bitAnd", 2),
|
||||||
bitXor: mkPrimop(arithmetic.bitXor, "bitXor", 2),
|
bitOr: mkPrimop(arithmetic.bitOr, "bitOr", 2),
|
||||||
lessThan: mkPrimop(arithmetic.lessThan, "lessThan", 2),
|
bitXor: mkPrimop(arithmetic.bitXor, "bitXor", 2),
|
||||||
|
lessThan: mkPrimop(arithmetic.lessThan, "lessThan", 2),
|
||||||
|
|
||||||
ceil: mkPrimop(math.ceil, "ceil", 1),
|
ceil: mkPrimop(math.ceil, "ceil", 1),
|
||||||
floor: mkPrimop(math.floor, "floor", 1),
|
floor: mkPrimop(math.floor, "floor", 1),
|
||||||
|
|
||||||
isAttrs: mkPrimop((e: NixValue) => typeCheck.isAttrs(force(e)), "isAttrs", 1),
|
isAttrs: mkPrimop((e: NixValue) => typeCheck.isAttrs(force(e)), "isAttrs", 1),
|
||||||
isBool: mkPrimop((e: NixValue) => typeCheck.isBool(force(e)), "isBool", 1),
|
isBool: mkPrimop((e: NixValue) => typeCheck.isBool(force(e)), "isBool", 1),
|
||||||
isFloat: mkPrimop((e: NixValue) => typeCheck.isFloat(force(e)), "isFloat", 1),
|
isFloat: mkPrimop((e: NixValue) => typeCheck.isFloat(force(e)), "isFloat", 1),
|
||||||
isFunction: mkPrimop((e: NixValue) => typeCheck.isFunction(force(e)), "isFunction", 1),
|
isFunction: mkPrimop((e: NixValue) => typeCheck.isFunction(force(e)), "isFunction", 1),
|
||||||
isInt: mkPrimop((e: NixValue) => typeCheck.isInt(force(e)), "isInt", 1),
|
isInt: mkPrimop((e: NixValue) => typeCheck.isInt(force(e)), "isInt", 1),
|
||||||
isList: mkPrimop((e: NixValue) => typeCheck.isList(force(e)), "isList", 1),
|
isList: mkPrimop((e: NixValue) => typeCheck.isList(force(e)), "isList", 1),
|
||||||
isNull: mkPrimop((e: NixValue) => typeCheck.isNull(force(e)), "isNull", 1),
|
isNull: mkPrimop((e: NixValue) => typeCheck.isNull(force(e)), "isNull", 1),
|
||||||
isPath: mkPrimop((e: NixValue) => typeCheck.isPath(force(e)), "isPath", 1),
|
isPath: mkPrimop((e: NixValue) => typeCheck.isPath(force(e)), "isPath", 1),
|
||||||
isString: mkPrimop((e: NixValue) => typeCheck.isString(force(e)), "isString", 1),
|
isString: mkPrimop((e: NixValue) => typeCheck.isString(force(e)), "isString", 1),
|
||||||
typeOf: mkPrimop((e: NixValue) => typeCheck.typeOf(force(e)), "typeOf", 1),
|
typeOf: mkPrimop((e: NixValue) => typeCheck.typeOf(force(e)), "typeOf", 1),
|
||||||
|
|
||||||
map: mkPrimop(list.map, "map", 2),
|
map: mkPrimop(list.map, "map", 2),
|
||||||
filter: mkPrimop(list.filter, "filter", 2),
|
filter: mkPrimop(list.filter, "filter", 2),
|
||||||
length: mkPrimop(list.length, "length", 1),
|
length: mkPrimop(list.length, "length", 1),
|
||||||
head: mkPrimop(list.head, "head", 1),
|
head: mkPrimop(list.head, "head", 1),
|
||||||
tail: mkPrimop(list.tail, "tail", 1),
|
tail: mkPrimop(list.tail, "tail", 1),
|
||||||
elem: mkPrimop(list.elem, "elem", 2),
|
elem: mkPrimop(list.elem, "elem", 2),
|
||||||
elemAt: mkPrimop(list.elemAt, "elemAt", 2),
|
elemAt: mkPrimop(list.elemAt, "elemAt", 2),
|
||||||
concatLists: mkPrimop(list.concatLists, "concatLists", 1),
|
concatLists: mkPrimop(list.concatLists, "concatLists", 1),
|
||||||
concatMap: mkPrimop(list.concatMap, "concatMap", 2),
|
concatMap: mkPrimop(list.concatMap, "concatMap", 2),
|
||||||
"foldl'": mkPrimop(list.foldlPrime, "foldl'", 3),
|
"foldl'": mkPrimop(list.foldlPrime, "foldl'", 3),
|
||||||
sort: mkPrimop(list.sort, "sort", 2),
|
sort: mkPrimop(list.sort, "sort", 2),
|
||||||
partition: mkPrimop(list.partition, "partition", 2),
|
partition: mkPrimop(list.partition, "partition", 2),
|
||||||
genList: mkPrimop(list.genList, "genList", 2),
|
genList: mkPrimop(list.genList, "genList", 2),
|
||||||
all: mkPrimop(list.all, "all", 2),
|
all: mkPrimop(list.all, "all", 2),
|
||||||
any: mkPrimop(list.any, "any", 2),
|
any: mkPrimop(list.any, "any", 2),
|
||||||
|
|
||||||
attrNames: mkPrimop(attrs.attrNames, "attrNames", 1),
|
attrNames: mkPrimop(attrs.attrNames, "attrNames", 1),
|
||||||
attrValues: mkPrimop(attrs.attrValues, "attrValues", 1),
|
attrValues: mkPrimop(attrs.attrValues, "attrValues", 1),
|
||||||
getAttr: mkPrimop(attrs.getAttr, "getAttr", 2),
|
getAttr: mkPrimop(attrs.getAttr, "getAttr", 2),
|
||||||
hasAttr: mkPrimop(attrs.hasAttr, "hasAttr", 2),
|
hasAttr: mkPrimop(attrs.hasAttr, "hasAttr", 2),
|
||||||
mapAttrs: mkPrimop(attrs.mapAttrs, "mapAttrs", 2),
|
mapAttrs: mkPrimop(attrs.mapAttrs, "mapAttrs", 2),
|
||||||
removeAttrs: mkPrimop(attrs.removeAttrs, "removeAttrs", 2),
|
removeAttrs: mkPrimop(attrs.removeAttrs, "removeAttrs", 2),
|
||||||
listToAttrs: mkPrimop(attrs.listToAttrs, "listToAttrs", 1),
|
listToAttrs: mkPrimop(attrs.listToAttrs, "listToAttrs", 1),
|
||||||
intersectAttrs: mkPrimop(attrs.intersectAttrs, "intersectAttrs", 2),
|
intersectAttrs: mkPrimop(attrs.intersectAttrs, "intersectAttrs", 2),
|
||||||
catAttrs: mkPrimop(attrs.catAttrs, "catAttrs", 2),
|
catAttrs: mkPrimop(attrs.catAttrs, "catAttrs", 2),
|
||||||
groupBy: mkPrimop(attrs.groupBy, "groupBy", 2),
|
groupBy: mkPrimop(attrs.groupBy, "groupBy", 2),
|
||||||
zipAttrsWith: mkPrimop(attrs.zipAttrsWith, "zipAttrsWith", 2),
|
zipAttrsWith: mkPrimop(attrs.zipAttrsWith, "zipAttrsWith", 2),
|
||||||
unsafeGetAttrPos: mkPrimop(attrs.unsafeGetAttrPos, "unsafeGetAttrPos", 2),
|
unsafeGetAttrPos: mkPrimop(attrs.unsafeGetAttrPos, "unsafeGetAttrPos", 2),
|
||||||
|
|
||||||
stringLength: mkPrimop(string.stringLength, "stringLength", 1),
|
stringLength: mkPrimop(string.stringLength, "stringLength", 1),
|
||||||
substring: mkPrimop(string.substring, "substring", 3),
|
substring: mkPrimop(string.substring, "substring", 3),
|
||||||
concatStringsSep: mkPrimop(string.concatStringsSep, "concatStringsSep", 2),
|
concatStringsSep: mkPrimop(string.concatStringsSep, "concatStringsSep", 2),
|
||||||
baseNameOf: mkPrimop(pathOps.baseNameOf, "baseNameOf", 1),
|
baseNameOf: mkPrimop(pathOps.baseNameOf, "baseNameOf", 1),
|
||||||
dirOf: mkPrimop(pathOps.dirOf, "dirOf", 1),
|
dirOf: mkPrimop(pathOps.dirOf, "dirOf", 1),
|
||||||
toPath: mkPrimop(pathOps.toPath, "toPath", 1),
|
toPath: mkPrimop(pathOps.toPath, "toPath", 1),
|
||||||
match: mkPrimop(string.match, "match", 2),
|
match: mkPrimop(string.match, "match", 2),
|
||||||
split: mkPrimop(string.split, "split", 2),
|
split: mkPrimop(string.split, "split", 2),
|
||||||
|
|
||||||
seq: mkPrimop(functional.seq, "seq", 2),
|
seq: mkPrimop(functional.seq, "seq", 2),
|
||||||
deepSeq: mkPrimop(functional.deepSeq, "deepSeq", 2),
|
deepSeq: mkPrimop(functional.deepSeq, "deepSeq", 2),
|
||||||
abort: mkPrimop(functional.abort, "abort", 1),
|
abort: mkPrimop(functional.abort, "abort", 1),
|
||||||
throw: mkPrimop(functional.throwFunc, "throw", 1),
|
throw: mkPrimop(functional.throwFunc, "throw", 1),
|
||||||
trace: mkPrimop(functional.trace, "trace", 2),
|
trace: mkPrimop(functional.trace, "trace", 2),
|
||||||
warn: mkPrimop(functional.warn, "warn", 2),
|
warn: mkPrimop(functional.warn, "warn", 2),
|
||||||
break: mkPrimop(functional.breakFunc, "break", 1),
|
break: mkPrimop(functional.breakFunc, "break", 1),
|
||||||
|
|
||||||
derivation: mkPrimop(derivation.derivationStub, "derivation", 1),
|
derivation: mkPrimop(derivation.derivationStub, "derivation", 1),
|
||||||
derivationStrict: mkPrimop(derivation.derivationStrict, "derivationStrict", 1),
|
derivationStrict: mkPrimop(derivation.derivationStrict, "derivationStrict", 1),
|
||||||
|
|
||||||
import: mkPrimop(io.importFunc, "import", 1),
|
import: mkPrimop(io.importFunc, "import", 1),
|
||||||
scopedImport: mkPrimop(io.scopedImport, "scopedImport", 2),
|
scopedImport: mkPrimop(io.scopedImport, "scopedImport", 2),
|
||||||
storePath: mkPrimop(io.storePath, "storePath", 1),
|
storePath: mkPrimop(io.storePath, "storePath", 1),
|
||||||
fetchClosure: mkPrimop(io.fetchClosure, "fetchClosure", 1),
|
fetchClosure: mkPrimop(io.fetchClosure, "fetchClosure", 1),
|
||||||
fetchMercurial: mkPrimop(io.fetchMercurial, "fetchMercurial", 1),
|
fetchMercurial: mkPrimop(io.fetchMercurial, "fetchMercurial", 1),
|
||||||
fetchGit: mkPrimop(io.fetchGit, "fetchGit", 1),
|
fetchGit: mkPrimop(io.fetchGit, "fetchGit", 1),
|
||||||
fetchTarball: mkPrimop(io.fetchTarball, "fetchTarball", 1),
|
fetchTarball: mkPrimop(io.fetchTarball, "fetchTarball", 1),
|
||||||
fetchTree: mkPrimop(io.fetchTree, "fetchTree", 1),
|
fetchTree: mkPrimop(io.fetchTree, "fetchTree", 1),
|
||||||
fetchurl: mkPrimop(io.fetchurl, "fetchurl", 1),
|
fetchurl: mkPrimop(io.fetchurl, "fetchurl", 1),
|
||||||
readDir: mkPrimop(io.readDir, "readDir", 1),
|
readDir: mkPrimop(io.readDir, "readDir", 1),
|
||||||
readFile: mkPrimop(io.readFile, "readFile", 1),
|
readFile: mkPrimop(io.readFile, "readFile", 1),
|
||||||
readFileType: mkPrimop(io.readFileType, "readFileType", 1),
|
readFileType: mkPrimop(io.readFileType, "readFileType", 1),
|
||||||
pathExists: mkPrimop(io.pathExists, "pathExists", 1),
|
pathExists: mkPrimop(io.pathExists, "pathExists", 1),
|
||||||
path: mkPrimop(io.path, "path", 1),
|
path: mkPrimop(io.path, "path", 1),
|
||||||
toFile: mkPrimop(io.toFile, "toFile", 2),
|
toFile: mkPrimop(io.toFile, "toFile", 2),
|
||||||
filterSource: mkPrimop(io.filterSource, "filterSource", 2),
|
filterSource: mkPrimop(io.filterSource, "filterSource", 2),
|
||||||
findFile: mkPrimop(io.findFile, "findFile", 2),
|
findFile: mkPrimop(io.findFile, "findFile", 2),
|
||||||
getEnv: mkPrimop(io.getEnv, "getEnv", 1),
|
getEnv: mkPrimop(io.getEnv, "getEnv", 1),
|
||||||
|
|
||||||
fromJSON: mkPrimop(conversion.fromJSON, "fromJSON", 1),
|
fromJSON: mkPrimop(conversion.fromJSON, "fromJSON", 1),
|
||||||
fromTOML: mkPrimop(conversion.fromTOML, "fromTOML", 1),
|
fromTOML: mkPrimop(conversion.fromTOML, "fromTOML", 1),
|
||||||
toJSON: mkPrimop(conversion.toJSON, "toJSON", 1),
|
toJSON: mkPrimop(conversion.toJSON, "toJSON", 1),
|
||||||
toXML: mkPrimop(conversion.toXML, "toXML", 1),
|
toXML: mkPrimop(conversion.toXML, "toXML", 1),
|
||||||
toString: mkPrimop(conversion.toStringFunc, "toString", 1),
|
toString: mkPrimop(conversion.toStringFunc, "toString", 1),
|
||||||
|
|
||||||
hashFile: mkPrimop(hash.hashFile, "hashFile", 2),
|
hashFile: mkPrimop(hash.hashFile, "hashFile", 2),
|
||||||
hashString: mkPrimop(hash.hashString, "hashString", 2),
|
hashString: mkPrimop(hash.hashString, "hashString", 2),
|
||||||
convertHash: mkPrimop(hash.convertHash, "convertHash", 2),
|
convertHash: mkPrimop(hash.convertHash, "convertHash", 2),
|
||||||
|
|
||||||
flakeRefToString: mkPrimop(flake.flakeRefToString, "flakeRefToString", 1),
|
flakeRefToString: mkPrimop(flake.flakeRefToString, "flakeRefToString", 1),
|
||||||
getFlake: mkPrimop(flake.getFlake, "getFlake", 1),
|
getFlake: mkPrimop(flake.getFlake, "getFlake", 1),
|
||||||
parseFlakeName: mkPrimop(flake.parseFlakeName, "parseFlakeName", 1),
|
parseFlakeName: mkPrimop(flake.parseFlakeName, "parseFlakeName", 1),
|
||||||
parseFlakeRef: mkPrimop(flake.parseFlakeRef, "parseFlakeRef", 1),
|
parseFlakeRef: mkPrimop(flake.parseFlakeRef, "parseFlakeRef", 1),
|
||||||
|
|
||||||
addErrorContext: mkPrimop(misc.addErrorContext, "addErrorContext", 1),
|
addErrorContext: mkPrimop(misc.addErrorContext, "addErrorContext", 1),
|
||||||
appendContext: mkPrimop(misc.appendContext, "appendContext", 1),
|
appendContext: mkPrimop(misc.appendContext, "appendContext", 1),
|
||||||
getContext: mkPrimop(misc.getContext, "getContext", 1),
|
getContext: mkPrimop(misc.getContext, "getContext", 1),
|
||||||
hasContext: mkPrimop(misc.hasContext, "hasContext", 1),
|
hasContext: mkPrimop(misc.hasContext, "hasContext", 1),
|
||||||
unsafeDiscardOutputDependency: mkPrimop(
|
unsafeDiscardOutputDependency: mkPrimop(
|
||||||
misc.unsafeDiscardOutputDependency,
|
misc.unsafeDiscardOutputDependency,
|
||||||
"unsafeDiscardOutputDependency",
|
"unsafeDiscardOutputDependency",
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
unsafeDiscardStringContext: mkPrimop(misc.unsafeDiscardStringContext, "unsafeDiscardStringContext", 1),
|
unsafeDiscardStringContext: mkPrimop(misc.unsafeDiscardStringContext, "unsafeDiscardStringContext", 1),
|
||||||
addDrvOutputDependencies: mkPrimop(misc.addDrvOutputDependencies, "addDrvOutputDependencies", 2),
|
addDrvOutputDependencies: mkPrimop(misc.addDrvOutputDependencies, "addDrvOutputDependencies", 2),
|
||||||
compareVersions: mkPrimop(misc.compareVersions, "compareVersions", 2),
|
compareVersions: mkPrimop(misc.compareVersions, "compareVersions", 2),
|
||||||
functionArgs: mkPrimop(misc.functionArgs, "functionArgs", 1),
|
functionArgs: mkPrimop(misc.functionArgs, "functionArgs", 1),
|
||||||
genericClosure: mkPrimop(misc.genericClosure, "genericClosure", 1),
|
genericClosure: mkPrimop(misc.genericClosure, "genericClosure", 1),
|
||||||
outputOf: mkPrimop(misc.outputOf, "outputOf", 2),
|
outputOf: mkPrimop(misc.outputOf, "outputOf", 2),
|
||||||
parseDrvName: mkPrimop(misc.parseDrvName, "parseDrvName", 1),
|
parseDrvName: mkPrimop(misc.parseDrvName, "parseDrvName", 1),
|
||||||
placeholder: mkPrimop(misc.placeholder, "placeholder", 1),
|
placeholder: mkPrimop(misc.placeholder, "placeholder", 1),
|
||||||
replaceStrings: mkPrimop(misc.replaceStrings, "replaceStrings", 3),
|
replaceStrings: mkPrimop(misc.replaceStrings, "replaceStrings", 3),
|
||||||
splitVersion: mkPrimop(misc.splitVersion, "splitVersion", 1),
|
splitVersion: mkPrimop(misc.splitVersion, "splitVersion", 1),
|
||||||
traceVerbose: mkPrimop(misc.traceVerbose, "traceVerbose", 2),
|
traceVerbose: mkPrimop(misc.traceVerbose, "traceVerbose", 2),
|
||||||
tryEval: mkPrimop(misc.tryEval, "tryEval", 1),
|
tryEval: mkPrimop(misc.tryEval, "tryEval", 1),
|
||||||
|
|
||||||
builtins: createThunk(() => builtins, "builtins"),
|
builtins: createThunk(() => builtins, "builtins"),
|
||||||
currentSystem: createThunk(() => {
|
currentSystem: createThunk(() => {
|
||||||
return "x86_64-linux";
|
return "x86_64-linux";
|
||||||
}, "currentSystem"),
|
}, "currentSystem"),
|
||||||
currentTime: createThunk(() => Date.now(), "currentTime"),
|
currentTime: createThunk(() => Date.now(), "currentTime"),
|
||||||
|
|
||||||
false: false,
|
false: false,
|
||||||
true: true,
|
true: true,
|
||||||
null: null,
|
null: null,
|
||||||
|
|
||||||
langVersion: 6,
|
langVersion: 6,
|
||||||
nixPath: [],
|
nixPath: [],
|
||||||
nixVersion: "2.31.2",
|
nixVersion: "2.31.2",
|
||||||
storeDir: createThunk(() => {
|
storeDir: createThunk(() => {
|
||||||
throw new Error("stub storeDir evaluated");
|
throw new Error("stub storeDir evaluated");
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
};
|
);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { select } from "../helpers";
|
||||||
import { getPathValue } from "../path";
|
import { getPathValue } from "../path";
|
||||||
import type { NixStringContext, StringWithContext } from "../string-context";
|
import type { NixStringContext, StringWithContext } from "../string-context";
|
||||||
import { addOpaqueContext, decodeContextElem, mkStringWithContext } from "../string-context";
|
import { addOpaqueContext, decodeContextElem, mkStringWithContext } from "../string-context";
|
||||||
@@ -59,7 +60,7 @@ export const scopedImport =
|
|||||||
(scope: NixValue) =>
|
(scope: NixValue) =>
|
||||||
(path: NixValue): NixValue => {
|
(path: NixValue): NixValue => {
|
||||||
const scopeAttrs = forceAttrs(scope);
|
const scopeAttrs = forceAttrs(scope);
|
||||||
const scopeKeys = Object.keys(scopeAttrs);
|
const scopeKeys = Array.from(scopeAttrs.keys());
|
||||||
|
|
||||||
const pathStr = realisePath(path);
|
const pathStr = realisePath(path);
|
||||||
|
|
||||||
@@ -112,25 +113,23 @@ const normalizeUrlInput = (
|
|||||||
return { url: forced };
|
return { url: forced };
|
||||||
}
|
}
|
||||||
const attrs = forceAttrs(args);
|
const attrs = forceAttrs(args);
|
||||||
const url = forceStringValue(attrs.url);
|
const url = forceStringValue(select(attrs, ["url"]));
|
||||||
const hash =
|
const hash = attrs.has("sha256")
|
||||||
"sha256" in attrs
|
? forceStringValue(attrs.get("sha256") as NixValue)
|
||||||
? forceStringValue(attrs.sha256)
|
: attrs.has("hash")
|
||||||
: "hash" in attrs
|
? forceStringValue(attrs.get("hash") as NixValue)
|
||||||
? forceStringValue(attrs.hash)
|
: undefined;
|
||||||
: undefined;
|
const name = attrs.has("name") ? forceStringValue(attrs.get("name") as NixValue) : undefined;
|
||||||
const name = "name" in attrs ? forceStringValue(attrs.name) : undefined;
|
const executable = attrs.has("executable") ? forceBool(attrs.get("executable") as NixValue) : false;
|
||||||
const executable = "executable" in attrs ? forceBool(attrs.executable) : false;
|
|
||||||
return { url, hash, name, executable };
|
return { url, hash, name, executable };
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizeTarballInput = (args: NixValue): { url: string; sha256?: string; name?: string } => {
|
const normalizeTarballInput = (args: NixValue): { url: string; sha256?: string; name?: string } => {
|
||||||
const forced = force(args);
|
const forced = force(args);
|
||||||
if (isAttrs(forced)) {
|
if (isAttrs(forced)) {
|
||||||
const url = resolvePseudoUrl(forceStringNoCtx(forced.url));
|
const url = resolvePseudoUrl(forceStringNoCtx(select(forced, ["url"])));
|
||||||
const sha256 = "sha256" in forced ? forceStringNoCtx(forced.sha256) : undefined;
|
const sha256 = forced.has("sha256") ? forceStringNoCtx(forced.get("sha256") as NixValue) : undefined;
|
||||||
const nameRaw = "name" in forced ? forceStringNoCtx(forced.name) : undefined;
|
const nameRaw = forced.has("name") ? forceStringNoCtx(forced.get("name") as NixValue) : undefined;
|
||||||
// FIXME: extract baseNameOfRaw
|
|
||||||
const name = nameRaw === "" ? (baseNameOf(nameRaw) as string) : nameRaw;
|
const name = nameRaw === "" ? (baseNameOf(nameRaw) as string) : nameRaw;
|
||||||
return { url, sha256, name };
|
return { url, sha256, name };
|
||||||
} else {
|
} else {
|
||||||
@@ -175,25 +174,25 @@ export const fetchGit = (args: NixValue): NixAttrs => {
|
|||||||
const result = Deno.core.ops.op_fetch_git(url, null, null, false, false, false, null);
|
const result = Deno.core.ops.op_fetch_git(url, null, null, false, false, false, null);
|
||||||
const outContext: NixStringContext = new Set();
|
const outContext: NixStringContext = new Set();
|
||||||
addOpaqueContext(outContext, result.out_path);
|
addOpaqueContext(outContext, result.out_path);
|
||||||
return {
|
return new Map<string, NixValue>([
|
||||||
outPath: mkStringWithContext(result.out_path, outContext),
|
["outPath", mkStringWithContext(result.out_path, outContext)],
|
||||||
rev: result.rev,
|
["rev", result.rev],
|
||||||
shortRev: result.short_rev,
|
["shortRev", result.short_rev],
|
||||||
revCount: BigInt(result.rev_count),
|
["revCount", BigInt(result.rev_count)],
|
||||||
lastModified: BigInt(result.last_modified),
|
["lastModified", BigInt(result.last_modified)],
|
||||||
lastModifiedDate: result.last_modified_date,
|
["lastModifiedDate", result.last_modified_date],
|
||||||
submodules: result.submodules,
|
["submodules", result.submodules],
|
||||||
narHash: result.nar_hash,
|
["narHash", result.nar_hash],
|
||||||
};
|
]);
|
||||||
}
|
}
|
||||||
const attrs = forceAttrs(args);
|
const attrs = forceAttrs(args);
|
||||||
const url = forceStringValue(attrs.url);
|
const url = forceStringValue(select("attrs", ["url"]));
|
||||||
const gitRef = "ref" in attrs ? forceStringValue(attrs.ref) : null;
|
const gitRef = attrs.has("ref") ? forceStringValue(attrs.get("ref") as NixValue) : null;
|
||||||
const rev = "rev" in attrs ? forceStringValue(attrs.rev) : null;
|
const rev = attrs.has("rev") ? forceStringValue(attrs.get("rev") as NixValue) : null;
|
||||||
const shallow = "shallow" in attrs ? forceBool(attrs.shallow) : false;
|
const shallow = attrs.has("shallow") ? forceBool(attrs.get("shallow") as NixValue) : false;
|
||||||
const submodules = "submodules" in attrs ? forceBool(attrs.submodules) : false;
|
const submodules = attrs.has("submodules") ? forceBool(attrs.get("submodules") as NixValue) : false;
|
||||||
const allRefs = "allRefs" in attrs ? forceBool(attrs.allRefs) : false;
|
const allRefs = attrs.has("allRefs") ? forceBool(attrs.get("allRefs") as NixValue) : false;
|
||||||
const name = "name" in attrs ? forceStringValue(attrs.name) : null;
|
const name = attrs.has("name") ? forceStringValue(attrs.get("name") as NixValue) : null;
|
||||||
|
|
||||||
const result: FetchGitResult = Deno.core.ops.op_fetch_git(
|
const result: FetchGitResult = Deno.core.ops.op_fetch_git(
|
||||||
url,
|
url,
|
||||||
@@ -207,16 +206,16 @@ export const fetchGit = (args: NixValue): NixAttrs => {
|
|||||||
|
|
||||||
const outContext: NixStringContext = new Set();
|
const outContext: NixStringContext = new Set();
|
||||||
addOpaqueContext(outContext, result.out_path);
|
addOpaqueContext(outContext, result.out_path);
|
||||||
return {
|
return new Map<string, NixValue>([
|
||||||
outPath: mkStringWithContext(result.out_path, outContext),
|
["outPath", mkStringWithContext(result.out_path, outContext)],
|
||||||
rev: result.rev,
|
["rev", result.rev],
|
||||||
shortRev: result.short_rev,
|
["shortRev", result.short_rev],
|
||||||
revCount: BigInt(result.rev_count),
|
["revCount", BigInt(result.rev_count)],
|
||||||
lastModified: BigInt(result.last_modified),
|
["lastModified", BigInt(result.last_modified)],
|
||||||
lastModifiedDate: result.last_modified_date,
|
["lastModifiedDate", result.last_modified_date],
|
||||||
submodules: result.submodules,
|
["submodules", result.submodules],
|
||||||
narHash: result.nar_hash,
|
["narHash", result.nar_hash],
|
||||||
};
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchMercurial = (_args: NixValue): NixAttrs => {
|
export const fetchMercurial = (_args: NixValue): NixAttrs => {
|
||||||
@@ -225,7 +224,7 @@ export const fetchMercurial = (_args: NixValue): NixAttrs => {
|
|||||||
|
|
||||||
export const fetchTree = (args: NixValue): NixAttrs => {
|
export const fetchTree = (args: NixValue): NixAttrs => {
|
||||||
const attrs = forceAttrs(args);
|
const attrs = forceAttrs(args);
|
||||||
const type = "type" in attrs ? forceStringValue(attrs.type) : "auto";
|
const type = attrs.has("type") ? forceStringValue(attrs.get("type") as NixValue) : "auto";
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "git":
|
case "git":
|
||||||
@@ -234,12 +233,12 @@ export const fetchTree = (args: NixValue): NixAttrs => {
|
|||||||
case "mercurial":
|
case "mercurial":
|
||||||
return fetchMercurial(args);
|
return fetchMercurial(args);
|
||||||
case "tarball":
|
case "tarball":
|
||||||
return { outPath: fetchTarball(args) };
|
return new Map<string, NixValue>([["outPath", fetchTarball(args)]]);
|
||||||
case "file":
|
case "file":
|
||||||
return { outPath: fetchurl(args) };
|
return new Map<string, NixValue>([["outPath", fetchurl(args)]]);
|
||||||
case "path": {
|
case "path": {
|
||||||
const path = forceStringValue(attrs.path);
|
const path = forceStringValue(select(attrs, ["path"]));
|
||||||
return { outPath: path };
|
return new Map<string, NixValue>([["outPath", path]]);
|
||||||
}
|
}
|
||||||
case "github":
|
case "github":
|
||||||
case "gitlab":
|
case "gitlab":
|
||||||
@@ -251,11 +250,14 @@ export const fetchTree = (args: NixValue): NixAttrs => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchGitForge = (forge: string, attrs: NixAttrs): NixAttrs => {
|
const fetchGitForge = (forge: string, attrs: NixAttrs): NixAttrs => {
|
||||||
const owner = forceStringValue(attrs.owner);
|
const owner = forceStringValue(select(forge, ["owner"]));
|
||||||
const repo = forceStringValue(attrs.repo);
|
const repo = forceStringValue(select(forge, ["repo"]));
|
||||||
const rev =
|
const rev = attrs.has("rev")
|
||||||
"rev" in attrs ? forceStringValue(attrs.rev) : "ref" in attrs ? forceStringValue(attrs.ref) : "HEAD";
|
? forceStringValue(attrs.get("rev") as NixValue)
|
||||||
const host = "host" in attrs ? forceStringValue(attrs.host) : undefined;
|
: attrs.has("ref")
|
||||||
|
? forceStringValue(attrs.get("ref") as NixValue)
|
||||||
|
: "HEAD";
|
||||||
|
const host = attrs.has("host") ? forceStringValue(attrs.get("host") as NixValue) : undefined;
|
||||||
|
|
||||||
let tarballUrl: string;
|
let tarballUrl: string;
|
||||||
switch (forge) {
|
switch (forge) {
|
||||||
@@ -278,17 +280,17 @@ const fetchGitForge = (forge: string, attrs: NixAttrs): NixAttrs => {
|
|||||||
throw new Error(`Unknown forge type: ${forge}`);
|
throw new Error(`Unknown forge type: ${forge}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const outPath = fetchTarball({ url: tarballUrl, ...attrs });
|
const outPath = fetchTarball(new Map<string, NixValue>([["url", tarballUrl], ...attrs]));
|
||||||
|
|
||||||
return {
|
return new Map<string, NixValue>([
|
||||||
outPath,
|
["outPath", outPath],
|
||||||
rev,
|
["rev", rev],
|
||||||
shortRev: rev.substring(0, 7),
|
["shortRev", rev.substring(0, 7)],
|
||||||
};
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const autoDetectAndFetch = (attrs: NixAttrs): NixAttrs => {
|
const autoDetectAndFetch = (attrs: NixAttrs): NixAttrs => {
|
||||||
const url = forceStringValue(attrs.url);
|
const url = forceStringValue(select(attrs, ["url"]));
|
||||||
if (url.endsWith(".git") || url.includes("github.com") || url.includes("gitlab.com")) {
|
if (url.endsWith(".git") || url.includes("github.com") || url.includes("gitlab.com")) {
|
||||||
return fetchGit(attrs);
|
return fetchGit(attrs);
|
||||||
}
|
}
|
||||||
@@ -298,17 +300,17 @@ const autoDetectAndFetch = (attrs: NixAttrs): NixAttrs => {
|
|||||||
url.endsWith(".tar.bz2") ||
|
url.endsWith(".tar.bz2") ||
|
||||||
url.endsWith(".tgz")
|
url.endsWith(".tgz")
|
||||||
) {
|
) {
|
||||||
return { outPath: fetchTarball(attrs) };
|
return new Map<string, NixValue>([["outPath", fetchTarball(attrs)]]);
|
||||||
}
|
}
|
||||||
return { outPath: fetchurl(attrs) };
|
return new Map<string, NixValue>([["outPath", fetchurl(attrs)]]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const readDir = (path: NixValue): NixAttrs => {
|
export const readDir = (path: NixValue): NixAttrs => {
|
||||||
const pathStr = realisePath(path);
|
const pathStr = realisePath(path);
|
||||||
const entries: Record<string, string> = Deno.core.ops.op_read_dir(pathStr);
|
const entries: Record<string, string> = Deno.core.ops.op_read_dir(pathStr);
|
||||||
const result: NixAttrs = {};
|
const result: NixAttrs = new Map();
|
||||||
for (const [name, type] of Object.entries(entries)) {
|
for (const [name, type] of Object.entries(entries)) {
|
||||||
result[name] = type;
|
result.set(name, type);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@@ -348,11 +350,11 @@ export const pathExists = (path: NixValue): boolean => {
|
|||||||
export const path = (args: NixValue): NixString => {
|
export const path = (args: NixValue): NixString => {
|
||||||
const attrs = forceAttrs(args);
|
const attrs = forceAttrs(args);
|
||||||
|
|
||||||
if (!("path" in attrs)) {
|
if (!attrs.has("path")) {
|
||||||
throw new TypeError("builtins.path: 'path' attribute is required");
|
throw new TypeError("builtins.path: 'path' attribute is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathValue = force(attrs.path);
|
const pathValue = force(attrs.get("path") as NixValue);
|
||||||
let pathStr: string;
|
let pathStr: string;
|
||||||
|
|
||||||
if (isNixPath(pathValue)) {
|
if (isNixPath(pathValue)) {
|
||||||
@@ -361,14 +363,14 @@ export const path = (args: NixValue): NixString => {
|
|||||||
pathStr = forceStringValue(pathValue);
|
pathStr = forceStringValue(pathValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = "name" in attrs ? forceStringValue(attrs.name) : null;
|
const name = attrs.has("name") ? forceStringValue(attrs.get("name") as NixValue) : null;
|
||||||
const recursive = "recursive" in attrs ? forceBool(attrs.recursive) : true;
|
const recursive = attrs.has("recursive") ? forceBool(attrs.get("recursive") as NixValue) : true;
|
||||||
const sha256 = "sha256" in attrs ? forceStringValue(attrs.sha256) : null;
|
const sha256 = attrs.has("sha256") ? forceStringValue(attrs.get("sha256") as NixValue) : null;
|
||||||
|
|
||||||
let storePath: string;
|
let storePath: string;
|
||||||
|
|
||||||
if ("filter" in attrs) {
|
if (attrs.has("filter")) {
|
||||||
const filterFn = forceFunction(attrs.filter);
|
const filterFn = forceFunction(attrs.get("filter") as NixValue);
|
||||||
|
|
||||||
const entries: [string, string][] = Deno.core.ops.op_walk_dir(pathStr);
|
const entries: [string, string][] = Deno.core.ops.op_walk_dir(pathStr);
|
||||||
|
|
||||||
@@ -445,9 +447,9 @@ export const findFile =
|
|||||||
for (const item of forcedSearchPath) {
|
for (const item of forcedSearchPath) {
|
||||||
const attrs = forceAttrs(item);
|
const attrs = forceAttrs(item);
|
||||||
|
|
||||||
const prefix = "prefix" in attrs ? forceStringNoCtx(attrs.prefix) : "";
|
const prefix = attrs.has("prefix") ? forceStringNoCtx(attrs.get("prefix") as NixValue) : "";
|
||||||
|
|
||||||
if (!("path" in attrs)) {
|
if (!attrs.has("path")) {
|
||||||
throw new Error("findFile: search path element is missing 'path' attribute");
|
throw new Error("findFile: search path element is missing 'path' attribute");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +459,12 @@ export const findFile =
|
|||||||
}
|
}
|
||||||
|
|
||||||
const context: NixStringContext = new Set();
|
const context: NixStringContext = new Set();
|
||||||
const pathVal = coerceToString(attrs.path, StringCoercionMode.Interpolation, false, context);
|
const pathVal = coerceToString(
|
||||||
|
attrs.get("path") as NixValue,
|
||||||
|
StringCoercionMode.Interpolation,
|
||||||
|
false,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
|
||||||
if (context.size > 0) {
|
if (context.size > 0) {
|
||||||
throw new Error("findFile: path with string context is not yet supported");
|
throw new Error("findFile: path with string context is not yet supported");
|
||||||
|
|||||||
@@ -95,18 +95,19 @@ export const partition =
|
|||||||
(list: NixValue): NixAttrs => {
|
(list: NixValue): NixAttrs => {
|
||||||
const forcedList = forceList(list);
|
const forcedList = forceList(list);
|
||||||
const forcedPred = forceFunction(pred);
|
const forcedPred = forceFunction(pred);
|
||||||
const attrs = {
|
const right: NixList = [];
|
||||||
right: [] as NixList,
|
const wrong: NixList = [];
|
||||||
wrong: [] as NixList,
|
|
||||||
};
|
|
||||||
for (const elem of forcedList) {
|
for (const elem of forcedList) {
|
||||||
if (force(forcedPred(elem))) {
|
if (force(forcedPred(elem))) {
|
||||||
attrs.right.push(elem);
|
right.push(elem);
|
||||||
} else {
|
} else {
|
||||||
attrs.wrong.push(elem);
|
wrong.push(elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return attrs;
|
return new Map<string, NixValue>([
|
||||||
|
["right", right],
|
||||||
|
["wrong", wrong],
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const genList =
|
export const genList =
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { OrderedSet } from "js-sdsl";
|
import { OrderedSet } from "js-sdsl";
|
||||||
|
import { select } from "../helpers";
|
||||||
import { compareValues } from "../operators";
|
import { compareValues } from "../operators";
|
||||||
import {
|
import {
|
||||||
getStringContext,
|
getStringContext,
|
||||||
@@ -15,7 +16,7 @@ import {
|
|||||||
forceStringNoCtx,
|
forceStringNoCtx,
|
||||||
forceStringValue,
|
forceStringValue,
|
||||||
} from "../type-assert";
|
} from "../type-assert";
|
||||||
import type { NixAttrs, NixBool, NixStrictValue, NixValue } from "../types";
|
import type { NixAttrs, NixStrictValue, NixValue } from "../types";
|
||||||
import { ATTR_POSITIONS, CatchableError } from "../types";
|
import { ATTR_POSITIONS, CatchableError } from "../types";
|
||||||
import * as context from "./context";
|
import * as context from "./context";
|
||||||
import { isBool, isFloat, isInt, isList, isString, typeOf } from "./type-check";
|
import { isBool, isFloat, isInt, isList, isString, typeOf } from "./type-check";
|
||||||
@@ -137,24 +138,20 @@ function componentsLt(c1: string, c2: string): boolean {
|
|||||||
export const functionArgs = (f: NixValue): NixAttrs => {
|
export const functionArgs = (f: NixValue): NixAttrs => {
|
||||||
const func = forceFunction(f);
|
const func = forceFunction(f);
|
||||||
if (func.args) {
|
if (func.args) {
|
||||||
const ret: NixAttrs = {};
|
const ret: NixAttrs = new Map();
|
||||||
for (const key of func.args.required) {
|
for (const key of func.args.required) {
|
||||||
ret[key] = false;
|
ret.set(key, false);
|
||||||
}
|
}
|
||||||
for (const key of func.args.optional) {
|
for (const key of func.args.optional) {
|
||||||
ret[key] = true;
|
ret.set(key, true);
|
||||||
}
|
}
|
||||||
const positions = func.args.positions;
|
const positions = func.args.positions;
|
||||||
if (positions && Object.keys(positions).length > 0) {
|
if (positions && Object.keys(positions).length > 0) {
|
||||||
Object.defineProperty(ret, ATTR_POSITIONS, {
|
ret[ATTR_POSITIONS] = positions;
|
||||||
value: positions,
|
|
||||||
enumerable: false,
|
|
||||||
writable: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return {};
|
return new Map();
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkComparable = (value: NixStrictValue): void => {
|
const checkComparable = (value: NixStrictValue): void => {
|
||||||
@@ -166,7 +163,8 @@ const checkComparable = (value: NixStrictValue): void => {
|
|||||||
|
|
||||||
export const genericClosure = (args: NixValue): NixValue => {
|
export const genericClosure = (args: NixValue): NixValue => {
|
||||||
const forcedArgs = forceAttrs(args);
|
const forcedArgs = forceAttrs(args);
|
||||||
const { startSet, operator } = forcedArgs;
|
const startSet = select(forcedArgs, ["startSet"]);
|
||||||
|
const operator = select(forcedArgs, ["operator"]);
|
||||||
|
|
||||||
const initialList = forceList(startSet);
|
const initialList = forceList(startSet);
|
||||||
const opFunction = forceFunction(operator);
|
const opFunction = forceFunction(operator);
|
||||||
@@ -177,7 +175,7 @@ export const genericClosure = (args: NixValue): NixValue => {
|
|||||||
|
|
||||||
for (const item of initialList) {
|
for (const item of initialList) {
|
||||||
const itemAttrs = forceAttrs(item);
|
const itemAttrs = forceAttrs(item);
|
||||||
const key = force(itemAttrs.key);
|
const key = force(select(itemAttrs, ["key"]));
|
||||||
checkComparable(key);
|
checkComparable(key);
|
||||||
if (resultSet.find(key).equals(resultSet.end())) {
|
if (resultSet.find(key).equals(resultSet.end())) {
|
||||||
resultSet.insert(key);
|
resultSet.insert(key);
|
||||||
@@ -193,7 +191,7 @@ export const genericClosure = (args: NixValue): NixValue => {
|
|||||||
|
|
||||||
for (const newItem of newItems) {
|
for (const newItem of newItems) {
|
||||||
const newItemAttrs = forceAttrs(newItem);
|
const newItemAttrs = forceAttrs(newItem);
|
||||||
const key = force(newItemAttrs.key);
|
const key = force(select(newItemAttrs, ["key"]));
|
||||||
checkComparable(key);
|
checkComparable(key);
|
||||||
if (resultSet.find(key).equals(resultSet.end())) {
|
if (resultSet.find(key).equals(resultSet.end())) {
|
||||||
resultSet.insert(key);
|
resultSet.insert(key);
|
||||||
@@ -223,10 +221,10 @@ export const parseDrvName = (s: NixValue): NixAttrs => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return new Map<string, NixValue>([
|
||||||
name,
|
["name", name],
|
||||||
version,
|
["version", version],
|
||||||
};
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const placeholder = (output: NixValue): NixValue => {
|
export const placeholder = (output: NixValue): NixValue => {
|
||||||
@@ -322,21 +320,21 @@ export const splitVersion = (s: NixValue): NixValue => {
|
|||||||
|
|
||||||
export const traceVerbose = (_e1: NixValue, e2: NixValue): NixStrictValue => {
|
export const traceVerbose = (_e1: NixValue, e2: NixValue): NixStrictValue => {
|
||||||
// TODO: implement traceVerbose
|
// TODO: implement traceVerbose
|
||||||
return force(e2)
|
return force(e2);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tryEval = (e: NixValue): { success: NixBool; value: NixStrictValue } => {
|
export const tryEval = (e: NixValue): NixAttrs => {
|
||||||
try {
|
try {
|
||||||
return {
|
return new Map<string, NixValue>([
|
||||||
success: true,
|
["success", true],
|
||||||
value: force(e),
|
["value", force(e)],
|
||||||
};
|
]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof CatchableError) {
|
if (err instanceof CatchableError) {
|
||||||
return {
|
return new Map<string, NixValue>([
|
||||||
success: false,
|
["success", false],
|
||||||
value: false,
|
["value", false],
|
||||||
};
|
]);
|
||||||
} else {
|
} else {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
HAS_CONTEXT,
|
|
||||||
isNixPath,
|
isNixPath,
|
||||||
isStringWithContext,
|
isStringWithContext,
|
||||||
type NixAttrs,
|
type NixAttrs,
|
||||||
@@ -19,10 +18,7 @@ export const isNixString = (v: NixStrictValue): v is NixString => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const isAttrs = (e: NixStrictValue): e is NixAttrs => {
|
export const isAttrs = (e: NixStrictValue): e is NixAttrs => {
|
||||||
const val = e;
|
return e instanceof Map;
|
||||||
return (
|
|
||||||
typeof val === "object" && !Array.isArray(val) && val !== null && !(HAS_CONTEXT in val) && !isPath(val)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isBool = (e: NixStrictValue): e is NixBool => typeof e === "boolean";
|
export const isBool = (e: NixStrictValue): e is NixBool => typeof e === "boolean";
|
||||||
@@ -60,7 +56,7 @@ export const typeOf = (e: NixStrictValue): NixType => {
|
|||||||
if (isNixString(e)) return "string";
|
if (isNixString(e)) return "string";
|
||||||
if (isNixPath(e)) return "path";
|
if (isNixPath(e)) return "path";
|
||||||
if (Array.isArray(e)) return "list";
|
if (Array.isArray(e)) return "list";
|
||||||
if (typeof e === "object") return "set";
|
if (e instanceof Map) return "set";
|
||||||
if (typeof e === "function") return "lambda";
|
if (typeof e === "function") return "lambda";
|
||||||
|
|
||||||
throw new TypeError(`Unknown Nix type: ${typeof e}`);
|
throw new TypeError(`Unknown Nix type: ${typeof e}`);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { isAttrs, typeOf } from "./builtins/type-check";
|
|||||||
import { mkPath } from "./path";
|
import { mkPath } from "./path";
|
||||||
import { isStringWithContext, mkStringWithContext, type NixStringContext } from "./string-context";
|
import { isStringWithContext, mkStringWithContext, type NixStringContext } from "./string-context";
|
||||||
import { force } from "./thunk";
|
import { force } from "./thunk";
|
||||||
import { forceAttrs, forceBool, forceFunction, forceStringValue } from "./type-assert";
|
import { forceAttrs, forceBool, forceFunction, forceStringNoCtx, forceStringValue } from "./type-assert";
|
||||||
import type { NixAttrs, NixBool, NixPath, NixString, NixValue } from "./types";
|
import type { NixAttrs, NixBool, NixPath, NixString, NixValue } from "./types";
|
||||||
import { CatchableError, isNixPath } from "./types";
|
import { CatchableError, isNixPath } from "./types";
|
||||||
|
|
||||||
@@ -169,18 +169,18 @@ function selectImpl(obj: NixValue, attrpath: NixValue[]): NixValue {
|
|||||||
|
|
||||||
for (const attr of attrpath.slice(0, -1)) {
|
for (const attr of attrpath.slice(0, -1)) {
|
||||||
const key = forceStringValue(attr);
|
const key = forceStringValue(attr);
|
||||||
if (!(key in attrs)) {
|
if (!attrs.has(key)) {
|
||||||
throw new Error(`Attribute '${key}' not found`);
|
throw new Error(`Attribute '${key}' not found`);
|
||||||
}
|
}
|
||||||
const cur = forceAttrs(attrs[forceStringValue(attr)]);
|
const cur = forceAttrs(attrs.get(key) as NixValue);
|
||||||
attrs = cur;
|
attrs = cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
const last = forceStringValue(attrpath[attrpath.length - 1]);
|
const last = forceStringValue(attrpath[attrpath.length - 1]);
|
||||||
if (!(last in attrs)) {
|
if (!attrs.has(last)) {
|
||||||
throw new Error(`Attribute '${last}' not found`);
|
throw new Error(`Attribute '${last}' not found`);
|
||||||
}
|
}
|
||||||
return attrs[last];
|
return attrs.get(last) as NixValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectWithDefault = (
|
export const selectWithDefault = (
|
||||||
@@ -218,10 +218,10 @@ function selectWithDefaultImpl(obj: NixValue, attrpath: NixValue[], defaultVal:
|
|||||||
|
|
||||||
for (const attr of attrpath.slice(0, -1)) {
|
for (const attr of attrpath.slice(0, -1)) {
|
||||||
const key = forceStringValue(attr);
|
const key = forceStringValue(attr);
|
||||||
if (!(key in attrs)) {
|
if (!attrs.has(key)) {
|
||||||
return defaultVal;
|
return defaultVal;
|
||||||
}
|
}
|
||||||
const cur = force(attrs[key]);
|
const cur = force(attrs.get(key) as NixValue);
|
||||||
if (!isAttrs(cur)) {
|
if (!isAttrs(cur)) {
|
||||||
return defaultVal;
|
return defaultVal;
|
||||||
}
|
}
|
||||||
@@ -229,8 +229,8 @@ function selectWithDefaultImpl(obj: NixValue, attrpath: NixValue[], defaultVal:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const last = forceStringValue(attrpath[attrpath.length - 1]);
|
const last = forceStringValue(attrpath[attrpath.length - 1]);
|
||||||
if (last in attrs) {
|
if (attrs.has(last)) {
|
||||||
return attrs[last];
|
return attrs.get(last) as NixValue;
|
||||||
}
|
}
|
||||||
return defaultVal;
|
return defaultVal;
|
||||||
}
|
}
|
||||||
@@ -243,14 +243,18 @@ export const hasAttr = (obj: NixValue, attrpath: NixValue[]): NixBool => {
|
|||||||
let attrs = forced;
|
let attrs = forced;
|
||||||
|
|
||||||
for (const attr of attrpath.slice(0, -1)) {
|
for (const attr of attrpath.slice(0, -1)) {
|
||||||
const cur = force(attrs[forceStringValue(attr)]);
|
const key = forceStringNoCtx(attr);
|
||||||
|
if (!attrs.has(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const cur = force(attrs.get(key) as NixValue);
|
||||||
if (!isAttrs(cur)) {
|
if (!isAttrs(cur)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
attrs = cur;
|
attrs = cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
return forceStringValue(attrpath[attrpath.length - 1]) in attrs;
|
return attrs.has(forceStringValue(attrpath[attrpath.length - 1]));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const call = (func: NixValue, arg: NixValue, span?: string): NixValue => {
|
export const call = (func: NixValue, arg: NixValue, span?: string): NixValue => {
|
||||||
@@ -277,13 +281,8 @@ function callImpl(func: NixValue, arg: NixValue): NixValue {
|
|||||||
forcedFunc.args?.check(arg);
|
forcedFunc.args?.check(arg);
|
||||||
return forcedFunc(arg);
|
return forcedFunc(arg);
|
||||||
}
|
}
|
||||||
if (
|
if (forcedFunc instanceof Map && forcedFunc.has("__functor")) {
|
||||||
typeof forcedFunc === "object" &&
|
const functor = forceFunction(forcedFunc.get("__functor") as NixValue);
|
||||||
!Array.isArray(forcedFunc) &&
|
|
||||||
forcedFunc !== null &&
|
|
||||||
"__functor" in forcedFunc
|
|
||||||
) {
|
|
||||||
const functor = forceFunction(forcedFunc.__functor);
|
|
||||||
return call(functor(forcedFunc), arg);
|
return call(functor(forcedFunc), arg);
|
||||||
}
|
}
|
||||||
throw new Error(`attempt to call something which is not a function but ${typeOf(forcedFunc)}`);
|
throw new Error(`attempt to call something which is not a function but ${typeOf(forcedFunc)}`);
|
||||||
@@ -307,7 +306,7 @@ export const ifFunc = (cond: NixValue, consq: NixValue, alter: NixValue) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const mkPos = (span: string): NixAttrs => {
|
export const mkPos = (span: string): NixAttrs => {
|
||||||
return Deno.core.ops.op_decode_span(span);
|
return new Map(Object.entries(Deno.core.ops.op_decode_span(span)));
|
||||||
};
|
};
|
||||||
|
|
||||||
interface WithScope {
|
interface WithScope {
|
||||||
@@ -319,8 +318,8 @@ export const lookupWith = (name: string, withScope: WithScope | null): NixValue
|
|||||||
let current = withScope;
|
let current = withScope;
|
||||||
while (current !== null) {
|
while (current !== null) {
|
||||||
const attrs = forceAttrs(current.env);
|
const attrs = forceAttrs(current.env);
|
||||||
if (name in attrs) {
|
if (attrs.has(name)) {
|
||||||
return attrs[name];
|
return attrs.get(name) as NixValue;
|
||||||
}
|
}
|
||||||
current = current.last;
|
current = current.last;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import { isNixPath } from "./types";
|
|||||||
const canCoerceToString = (v: NixValue): boolean => {
|
const canCoerceToString = (v: NixValue): boolean => {
|
||||||
const forced = force(v);
|
const forced = force(v);
|
||||||
if (isNixString(forced)) return true;
|
if (isNixString(forced)) return true;
|
||||||
if (typeof forced === "object" && forced !== null && !Array.isArray(forced)) {
|
if (forced instanceof Map) {
|
||||||
if ("outPath" in forced || "__toString" in forced) return true;
|
if (forced.has("outPath") || forced.has("__toString")) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -219,27 +219,24 @@ export const op = {
|
|||||||
const attrsA = av as NixAttrs;
|
const attrsA = av as NixAttrs;
|
||||||
const attrsB = bv as NixAttrs;
|
const attrsB = bv as NixAttrs;
|
||||||
|
|
||||||
// Derivation comparison: compare outPaths only
|
if (attrsA.has("type") && attrsB.has("type")) {
|
||||||
// Safe to force 'type' because it's always a string literal, never a computed value
|
const typeValA = force(attrsA.get("type") as NixValue);
|
||||||
if ("type" in attrsA && "type" in attrsB) {
|
const typeValB = force(attrsB.get("type") as NixValue);
|
||||||
const typeValA = force(attrsA.type);
|
|
||||||
const typeValB = force(attrsB.type);
|
|
||||||
if (typeValA === "derivation" && typeValB === "derivation") {
|
if (typeValA === "derivation" && typeValB === "derivation") {
|
||||||
if ("outPath" in attrsA && "outPath" in attrsB) {
|
if (attrsA.has("outPath") && attrsB.has("outPath")) {
|
||||||
return op.eq(attrsA.outPath, attrsB.outPath);
|
return op.eq(attrsA.get("outPath") as NixValue, attrsB.get("outPath") as NixValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, compare attributes one by one
|
const keysA = Array.from(attrsA.keys()).sort();
|
||||||
const keysA = Object.keys(attrsA).sort();
|
const keysB = Array.from(attrsB.keys()).sort();
|
||||||
const keysB = Object.keys(attrsB).sort();
|
|
||||||
|
|
||||||
if (keysA.length !== keysB.length) return false;
|
if (keysA.length !== keysB.length) return false;
|
||||||
|
|
||||||
for (let i = 0; i < keysA.length; i++) {
|
for (let i = 0; i < keysA.length; i++) {
|
||||||
if (keysA[i] !== keysB[i]) return false;
|
if (keysA[i] !== keysB[i]) return false;
|
||||||
if (!op.eq(attrsA[keysA[i]], attrsB[keysB[i]])) return false;
|
if (!op.eq(attrsA.get(keysA[i]) as NixValue, attrsB.get(keysB[i]) as NixValue)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -270,5 +267,13 @@ export const op = {
|
|||||||
return forceList(a).concat(forceList(b));
|
return forceList(a).concat(forceList(b));
|
||||||
},
|
},
|
||||||
|
|
||||||
update: (a: NixValue, b: NixValue): NixAttrs => ({ ...forceAttrs(a), ...forceAttrs(b) }),
|
update: (a: NixValue, b: NixValue): NixAttrs => {
|
||||||
|
const mapA = forceAttrs(a);
|
||||||
|
const mapB = forceAttrs(b);
|
||||||
|
const result: NixAttrs = new Map(mapA);
|
||||||
|
for (const [k, v] of mapB) {
|
||||||
|
result.set(k, v);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,12 +14,11 @@ const canonicalizePath = (path: string): string => {
|
|||||||
const component = path.slice(i, j);
|
const component = path.slice(i, j);
|
||||||
i = j;
|
i = j;
|
||||||
|
|
||||||
if (component === ".") {
|
if (component === "..") {
|
||||||
} else if (component === "..") {
|
|
||||||
if (parts.length > 0) {
|
if (parts.length > 0) {
|
||||||
parts.pop();
|
parts.pop();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (component !== ".") {
|
||||||
parts.push(component);
|
parts.push(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { isAttrs, isList } from "./builtins/type-check";
|
import { isAttrs, isList } from "./builtins/type-check";
|
||||||
import { HAS_CONTEXT } from "./string-context";
|
import { HAS_CONTEXT } from "./string-context";
|
||||||
import type { NixStrictValue, NixThunkInterface, NixValue } from "./types";
|
import type { NixAttrs, NixStrictValue, NixThunkInterface, NixValue } from "./types";
|
||||||
import { IS_PATH } from "./types";
|
import { IS_PATH } from "./types";
|
||||||
|
|
||||||
export const IS_THUNK = Symbol("is_thunk");
|
export const IS_THUNK = Symbol("is_thunk");
|
||||||
@@ -117,7 +117,7 @@ export const createThunk = (func: () => NixValue, label?: string): NixThunkInter
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const IS_CYCLE = Symbol("is_cycle");
|
export const IS_CYCLE = Symbol("is_cycle");
|
||||||
export const CYCLE_MARKER = { [IS_CYCLE]: true };
|
export const CYCLE_MARKER = { [IS_CYCLE]: true as const };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deeply force a value, handling cycles by returning a special marker.
|
* Deeply force a value, handling cycles by returning a special marker.
|
||||||
@@ -150,10 +150,10 @@ export const forceDeep = (value: NixValue, seen: WeakSet<object> = new WeakSet()
|
|||||||
return forced.map((item) => forceDeep(item, seen));
|
return forced.map((item) => forceDeep(item, seen));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof forced === "object") {
|
if (forced instanceof Map) {
|
||||||
const result: Record<string, NixValue> = {};
|
const result: NixAttrs = new Map();
|
||||||
for (const [key, val] of Object.entries(forced)) {
|
for (const [key, val] of forced) {
|
||||||
result[key] = forceDeep(val, seen);
|
result.set(key, forceDeep(val, seen));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -180,10 +180,10 @@ export const forceShallow = (value: NixValue): NixStrictValue => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAttrs(forced)) {
|
if (isAttrs(forced)) {
|
||||||
const result: Record<string, NixValue> = {};
|
const result: NixAttrs = new Map();
|
||||||
for (const [key, val] of Object.entries(forced)) {
|
for (const [key, val] of forced) {
|
||||||
const forcedVal = force(val);
|
const forcedVal = force(val as NixValue);
|
||||||
result[key] = forcedVal === forced ? CYCLE_MARKER : forcedVal;
|
result.set(key, forcedVal === forced ? CYCLE_MARKER : forcedVal);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ export const forceFunction = (value: NixValue): NixFunction => {
|
|||||||
if (isFunction(forced)) {
|
if (isFunction(forced)) {
|
||||||
return forced;
|
return forced;
|
||||||
}
|
}
|
||||||
if (typeof forced === "object" && !Array.isArray(forced) && forced !== null && "__functor" in forced) {
|
if (forced instanceof Map && forced.has("__functor")) {
|
||||||
const functorSet = forced as NixAttrs;
|
const functorSet = forced as NixAttrs;
|
||||||
const functor = forceFunction(functorSet.__functor);
|
const functor = forceFunction(functorSet.get("__functor") as NixValue);
|
||||||
return (arg: NixValue) => forceFunction(functor(functorSet))(arg);
|
return (arg: NixValue) => forceFunction(functor(functorSet))(arg);
|
||||||
}
|
}
|
||||||
throw new TypeError(`Expected function, got ${typeOf(forced)}`);
|
throw new TypeError(`Expected function, got ${typeOf(forced)}`);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { HAS_CONTEXT, isStringWithContext, type StringWithContext } from "./string-context";
|
import { HAS_CONTEXT, isStringWithContext, type StringWithContext } from "./string-context";
|
||||||
import { force, IS_THUNK } from "./thunk";
|
import { type CYCLE_MARKER, force, IS_THUNK } from "./thunk";
|
||||||
import { forceAttrs, forceStringNoCtx } from "./type-assert";
|
import { forceAttrs, forceStringNoCtx } from "./type-assert";
|
||||||
export { HAS_CONTEXT, isStringWithContext };
|
export { HAS_CONTEXT, isStringWithContext };
|
||||||
export type { StringWithContext };
|
export type { StringWithContext };
|
||||||
@@ -22,9 +22,9 @@ export type NixBool = boolean;
|
|||||||
export type NixString = string | StringWithContext;
|
export type NixString = string | StringWithContext;
|
||||||
export type NixNull = null;
|
export type NixNull = null;
|
||||||
|
|
||||||
|
export const ATTR_POSITIONS = Symbol("attrPositions");
|
||||||
export type NixList = NixValue[];
|
export type NixList = NixValue[];
|
||||||
// FIXME: reject contextful string
|
export type NixAttrs = Map<string, NixValue> & { [ATTR_POSITIONS]?: Record<string, string> };
|
||||||
export type NixAttrs = { [key: string]: NixValue };
|
|
||||||
export type NixFunction = ((arg: NixValue) => NixValue) & { args?: NixArgs };
|
export type NixFunction = ((arg: NixValue) => NixValue) & { args?: NixArgs };
|
||||||
export class NixArgs {
|
export class NixArgs {
|
||||||
required: string[];
|
required: string[];
|
||||||
@@ -43,13 +43,13 @@ export class NixArgs {
|
|||||||
const attrs = forceAttrs(arg);
|
const attrs = forceAttrs(arg);
|
||||||
|
|
||||||
for (const key of this.required) {
|
for (const key of this.required) {
|
||||||
if (!Object.hasOwn(attrs, key)) {
|
if (!attrs.has(key)) {
|
||||||
throw new Error(`Function called without required argument '${key}'`);
|
throw new Error(`Function called without required argument '${key}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.ellipsis) {
|
if (!this.ellipsis) {
|
||||||
for (const key in attrs) {
|
for (const key of attrs.keys()) {
|
||||||
if (!this.allowed.has(key)) {
|
if (!this.allowed.has(key)) {
|
||||||
throw new Error(`Function called with unexpected argument '${key}'`);
|
throw new Error(`Function called with unexpected argument '${key}'`);
|
||||||
}
|
}
|
||||||
@@ -77,18 +77,18 @@ export const mkAttrs = (attrs: NixAttrs, keys: NixValue[], values: NixValue[]):
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const str = forceStringNoCtx(key);
|
const str = forceStringNoCtx(key);
|
||||||
attrs[str] = values[i];
|
attrs.set(str, values[i]);
|
||||||
}
|
}
|
||||||
return attrs;
|
return attrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ATTR_POSITIONS = Symbol("attrPositions");
|
|
||||||
|
|
||||||
export const mkAttrsWithPos = (
|
export const mkAttrsWithPos = (
|
||||||
attrs: NixAttrs,
|
obj: Record<string, NixValue>,
|
||||||
positions: Record<string, string>,
|
positions: Record<string, string>,
|
||||||
dyns?: { dynKeys: NixValue[]; dynVals: NixValue[]; dynSpans: string[] },
|
dyns?: { dynKeys: NixValue[]; dynVals: NixValue[]; dynSpans: string[] },
|
||||||
): NixAttrs => {
|
): NixAttrs => {
|
||||||
|
const attrs: NixAttrs = new Map(Object.entries(obj));
|
||||||
|
|
||||||
if (dyns) {
|
if (dyns) {
|
||||||
const len = dyns.dynKeys.length;
|
const len = dyns.dynKeys.length;
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
@@ -97,17 +97,13 @@ export const mkAttrsWithPos = (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const str = forceStringNoCtx(key);
|
const str = forceStringNoCtx(key);
|
||||||
attrs[str] = dyns.dynVals[i];
|
attrs.set(str, dyns.dynVals[i]);
|
||||||
positions[str] = dyns.dynSpans[i];
|
positions[str] = dyns.dynSpans[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(positions).length > 0) {
|
if (Object.keys(positions).length > 0) {
|
||||||
Object.defineProperty(attrs, ATTR_POSITIONS, {
|
attrs[ATTR_POSITIONS] = positions;
|
||||||
value: positions,
|
|
||||||
enumerable: false,
|
|
||||||
writable: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return attrs;
|
return attrs;
|
||||||
@@ -120,7 +116,14 @@ export interface NixThunkInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type NixPrimitive = NixNull | NixBool | NixInt | NixFloat | NixString;
|
export type NixPrimitive = NixNull | NixBool | NixInt | NixFloat | NixString;
|
||||||
export type NixValue = NixPrimitive | NixPath | NixList | NixAttrs | NixFunction | NixThunkInterface;
|
export type NixValue =
|
||||||
|
| NixPrimitive
|
||||||
|
| NixPath
|
||||||
|
| NixList
|
||||||
|
| NixAttrs
|
||||||
|
| NixFunction
|
||||||
|
| NixThunkInterface
|
||||||
|
| typeof CYCLE_MARKER;
|
||||||
export type NixStrictValue = Exclude<NixValue, NixThunkInterface>;
|
export type NixStrictValue = Exclude<NixValue, NixThunkInterface>;
|
||||||
|
|
||||||
export class CatchableError extends Error {}
|
export class CatchableError extends Error {}
|
||||||
|
|||||||
@@ -263,9 +263,9 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
|
|||||||
}
|
}
|
||||||
&Ir::Builtin(Builtin { inner: name, .. }) => {
|
&Ir::Builtin(Builtin { inner: name, .. }) => {
|
||||||
code!(buf, ctx;
|
code!(buf, ctx;
|
||||||
"Nix.builtins["
|
"Nix.builtins.get("
|
||||||
ctx.get_sym(name)
|
ctx.get_sym(name)
|
||||||
"]"
|
")"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ir::ConcatStrings(x) => x.compile(ctx, buf),
|
Ir::ConcatStrings(x) => x.compile(ctx, buf),
|
||||||
@@ -309,9 +309,9 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
|
|||||||
}
|
}
|
||||||
&Ir::ScopedImportBinding(ScopedImportBinding { inner: name, .. }) => {
|
&Ir::ScopedImportBinding(ScopedImportBinding { inner: name, .. }) => {
|
||||||
code!(buf, ctx;
|
code!(buf, ctx;
|
||||||
"__scope["
|
"__scope.get("
|
||||||
ctx.get_sym(name)
|
ctx.get_sym(name)
|
||||||
"]"
|
")"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ir::WithExpr(x) => x.compile(ctx, buf),
|
Ir::WithExpr(x) => x.compile(ctx, buf),
|
||||||
@@ -632,7 +632,7 @@ impl<Ctx: CodegenContext> Compile<Ctx> for AttrSet {
|
|||||||
"})"
|
"})"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
code!(buf, ctx; "{}");
|
code!(buf, ctx; "new Map()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ impl Context {
|
|||||||
let code = self.ctx.compile(source, None)?;
|
let code = self.ctx.compile(source, None)?;
|
||||||
self.runtime.eval(
|
self.runtime.eval(
|
||||||
format!(
|
format!(
|
||||||
"Nix.builtins.derivation = {};Nix.builtins.storeDir=\"{}\"",
|
"Nix.builtins.set('derivation',({}));Nix.builtins.set('storeDir','{}')",
|
||||||
code,
|
code,
|
||||||
self.get_store_dir()
|
self.get_store_dir()
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -364,6 +364,28 @@ fn to_value<'a>(
|
|||||||
Value::Func
|
Value::Func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ if val.is_map() => {
|
||||||
|
let val = val.try_cast::<v8::Map>().expect("infallible conversion");
|
||||||
|
let size = val.size() as u32;
|
||||||
|
let array = val.as_array(scope);
|
||||||
|
let attrs = (0..size)
|
||||||
|
.map(|i| {
|
||||||
|
let key = array.get_index(scope, i * 2).expect("infallible index operation");
|
||||||
|
let key = key.to_rust_string_lossy(scope);
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
(Symbol::new(Cow::Owned(key)), val)
|
||||||
|
}).collect();
|
||||||
|
Value::AttrSet(AttrSet::new(attrs))
|
||||||
|
}
|
||||||
_ if val.is_object() => {
|
_ if val.is_object() => {
|
||||||
if is_thunk(val, scope, is_thunk_symbol) {
|
if is_thunk(val, scope, is_thunk_symbol) {
|
||||||
return Value::Thunk;
|
return Value::Thunk;
|
||||||
|
|||||||
@@ -745,10 +745,10 @@ impl<'a> deno_core::convert::ToV8<'a> for NixJsonValue {
|
|||||||
scope: &mut v8::PinScope<'a, 'i>,
|
scope: &mut v8::PinScope<'a, 'i>,
|
||||||
) -> std::result::Result<v8::Local<'a, v8::Value>, Self::Error> {
|
) -> std::result::Result<v8::Local<'a, v8::Value>, Self::Error> {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::Null => v8::null(scope).into() ,
|
Self::Null => v8::null(scope).into(),
|
||||||
Self::Bool(b) => v8::Boolean::new(scope, b).into() ,
|
Self::Bool(b) => v8::Boolean::new(scope, b).into(),
|
||||||
Self::Int(i) => v8::BigInt::new_from_i64(scope, i).into() ,
|
Self::Int(i) => v8::BigInt::new_from_i64(scope, i).into(),
|
||||||
Self::Float(f) => v8::Number::new(scope, f).into() ,
|
Self::Float(f) => v8::Number::new(scope, f).into(),
|
||||||
Self::Str(s) => v8::String::new(scope, &s)
|
Self::Str(s) => v8::String::new(scope, &s)
|
||||||
.map(|s| s.into())
|
.map(|s| s.into())
|
||||||
.ok_or("failed to create v8 string")?,
|
.ok_or("failed to create v8 string")?,
|
||||||
@@ -757,18 +757,18 @@ impl<'a> deno_core::convert::ToV8<'a> for NixJsonValue {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| v.to_v8(scope))
|
.map(|v| v.to_v8(scope))
|
||||||
.collect::<std::result::Result<Vec<_>, _>>()?;
|
.collect::<std::result::Result<Vec<_>, _>>()?;
|
||||||
v8::Array::new_with_elements(scope, &elements).into()
|
v8::Array::new_with_elements(scope, &elements).into()
|
||||||
}
|
}
|
||||||
Self::Obj(entries) => {
|
Self::Obj(entries) => {
|
||||||
let obj = v8::Object::new(scope);
|
let map = v8::Map::new(scope);
|
||||||
for (k, v) in entries {
|
for (k, v) in entries {
|
||||||
let key: v8::Local<v8::Value> = v8::String::new(scope, &k)
|
let key: v8::Local<v8::Value> = v8::String::new(scope, &k)
|
||||||
.ok_or("failed to create v8 string")?
|
.ok_or("failed to create v8 string")?
|
||||||
.into();
|
.into();
|
||||||
let val = v.to_v8(scope)?;
|
let val = v.to_v8(scope)?;
|
||||||
obj.set(scope, key, val);
|
map.set(scope, key, val);
|
||||||
}
|
}
|
||||||
obj.into()
|
map.into()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1227,19 +1227,19 @@ impl<'s> XmlCtx<'s> {
|
|||||||
nix_obj: v8::Local<'s, v8::Object>,
|
nix_obj: v8::Local<'s, v8::Object>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let get_fn = |scope: &v8::PinScope<'s, 'i>, name: &str| {
|
let get_fn = |scope: &v8::PinScope<'s, 'i>, name: &str| {
|
||||||
let key = v8::String::new(scope, name).ok_or("v8 string" )?;
|
let key = v8::String::new(scope, name).ok_or("v8 string")?;
|
||||||
let val = nix_obj
|
let val = nix_obj
|
||||||
.get(scope, key.into())
|
.get(scope, key.into())
|
||||||
.ok_or_else(|| format!("no {name}") )?;
|
.ok_or_else(|| format!("no {name}"))?;
|
||||||
v8::Local::<v8::Function>::try_from(val)
|
v8::Local::<v8::Function>::try_from(val)
|
||||||
.map_err(|e| format!("{name} not function: {e}") )
|
.map_err(|e| format!("{name} not function: {e}"))
|
||||||
};
|
};
|
||||||
let get_sym = |scope: &v8::PinScope<'s, 'i>, name: &str| {
|
let get_sym = |scope: &v8::PinScope<'s, 'i>, name: &str| {
|
||||||
let key = v8::String::new(scope, name).ok_or("v8 string" )?;
|
let key = v8::String::new(scope, name).ok_or("v8 string")?;
|
||||||
let val = nix_obj
|
let val = nix_obj
|
||||||
.get(scope, key.into())
|
.get(scope, key.into())
|
||||||
.ok_or_else(|| format!("no {name}") )?;
|
.ok_or_else(|| format!("no {name}"))?;
|
||||||
v8::Local::<v8::Symbol>::try_from(val).map_err(|e| format!("{name} not symbol: {e}") )
|
v8::Local::<v8::Symbol>::try_from(val).map_err(|e| format!("{name} not symbol: {e}"))
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
force_fn: get_fn(scope, "force")?,
|
force_fn: get_fn(scope, "force")?,
|
||||||
@@ -1378,12 +1378,12 @@ impl XmlWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_derivation<'s>(obj: v8::Local<'s, v8::Object>, scope: &mut v8::PinScope<'s, '_>) -> bool {
|
fn is_derivation<'s>(map: v8::Local<'s, v8::Map>, scope: &mut v8::PinScope<'s, '_>) -> bool {
|
||||||
let key = match v8::String::new(scope, "type") {
|
let key = match v8::String::new(scope, "type") {
|
||||||
Some(k) => k,
|
Some(k) => k,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
match obj.get(scope, key.into()) {
|
match map.get(scope, key.into()) {
|
||||||
Some(v) if v.is_string() => v.to_rust_string_lossy(scope) == "derivation",
|
Some(v) if v.is_string() => v.to_rust_string_lossy(scope) == "derivation",
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -1414,7 +1414,7 @@ impl XmlWriter {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if val.is_big_int() {
|
if val.is_big_int() {
|
||||||
let bi = val.to_big_int(scope).ok_or("bigint" )?;
|
let bi = val.to_big_int(scope).ok_or("bigint")?;
|
||||||
let (i, _) = bi.i64_value();
|
let (i, _) = bi.i64_value();
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("<int value=\"");
|
self.buf.push_str("<int value=\"");
|
||||||
@@ -1423,7 +1423,7 @@ impl XmlWriter {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if val.is_number() {
|
if val.is_number() {
|
||||||
let n = val.number_value(scope).ok_or("number" )?;
|
let n = val.number_value(scope).ok_or("number")?;
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("<float value=\"");
|
self.buf.push_str("<float value=\"");
|
||||||
self.buf.push_str(&format!("{}", n));
|
self.buf.push_str(&format!("{}", n));
|
||||||
@@ -1439,11 +1439,11 @@ impl XmlWriter {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if val.is_array() {
|
if val.is_array() {
|
||||||
let arr = v8::Local::<v8::Array>::try_from(val).map_err(|e| e.to_string() )?;
|
let arr = v8::Local::<v8::Array>::try_from(val).map_err(|e| e.to_string())?;
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("<list>\n");
|
self.buf.push_str("<list>\n");
|
||||||
for i in 0..arr.length() {
|
for i in 0..arr.length() {
|
||||||
let elem = arr.get_index(scope, i).ok_or("array elem" )?;
|
let elem = arr.get_index(scope, i).ok_or("array elem")?;
|
||||||
self.write_value(elem, scope, ctx, depth + 1)?;
|
self.write_value(elem, scope, ctx, depth + 1)?;
|
||||||
}
|
}
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
@@ -1453,14 +1453,18 @@ impl XmlWriter {
|
|||||||
if val.is_function() {
|
if val.is_function() {
|
||||||
return self.write_function(val, scope, ctx, depth);
|
return self.write_function(val, scope, ctx, depth);
|
||||||
}
|
}
|
||||||
|
if val.is_map() {
|
||||||
|
let map = v8::Local::<v8::Map>::try_from(val).map_err(|e| e.to_string())?;
|
||||||
|
return self.write_attrs(map, scope, ctx, depth);
|
||||||
|
}
|
||||||
if val.is_object() {
|
if val.is_object() {
|
||||||
let obj = val.to_object(scope).ok_or("to_object" )?;
|
let obj = val.to_object(scope).ok_or("to_object")?;
|
||||||
|
|
||||||
if Self::has_sym(obj, scope, ctx.has_context) {
|
if Self::has_sym(obj, scope, ctx.has_context) {
|
||||||
let key = v8::String::new(scope, "value").ok_or("v8 str" )?;
|
let key = v8::String::new(scope, "value").ok_or("v8 str")?;
|
||||||
let s = obj
|
let s = obj
|
||||||
.get(scope, key.into())
|
.get(scope, key.into())
|
||||||
.ok_or("value" )?
|
.ok_or("value")?
|
||||||
.to_rust_string_lossy(scope);
|
.to_rust_string_lossy(scope);
|
||||||
self.collect_context(obj, scope);
|
self.collect_context(obj, scope);
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
@@ -1470,10 +1474,10 @@ impl XmlWriter {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if Self::has_sym(obj, scope, ctx.is_path) {
|
if Self::has_sym(obj, scope, ctx.is_path) {
|
||||||
let key = v8::String::new(scope, "value").ok_or("v8 str" )?;
|
let key = v8::String::new(scope, "value").ok_or("v8 str")?;
|
||||||
let s = obj
|
let s = obj
|
||||||
.get(scope, key.into())
|
.get(scope, key.into())
|
||||||
.ok_or("value" )?
|
.ok_or("value")?
|
||||||
.to_rust_string_lossy(scope);
|
.to_rust_string_lossy(scope);
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("<path value=\"");
|
self.buf.push_str("<path value=\"");
|
||||||
@@ -1486,8 +1490,6 @@ impl XmlWriter {
|
|||||||
self.buf.push_str("<unevaluated />\n");
|
self.buf.push_str("<unevaluated />\n");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.write_attrs(obj, scope, ctx, depth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
@@ -1497,31 +1499,39 @@ impl XmlWriter {
|
|||||||
|
|
||||||
fn write_attrs<'s>(
|
fn write_attrs<'s>(
|
||||||
&mut self,
|
&mut self,
|
||||||
obj: v8::Local<'s, v8::Object>,
|
map: v8::Local<'s, v8::Map>,
|
||||||
scope: &mut v8::PinScope<'s, '_>,
|
scope: &mut v8::PinScope<'s, '_>,
|
||||||
ctx: &XmlCtx<'s>,
|
ctx: &XmlCtx<'s>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if Self::is_derivation(obj, scope) {
|
if Self::is_derivation(map, scope) {
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("<derivation");
|
self.buf.push_str("<derivation");
|
||||||
|
|
||||||
let drv_path_key = v8::String::new(scope, "drvPath").ok_or("v8 str" )?;
|
let drv_path_key: v8::Local<v8::Value> =
|
||||||
let drv_str = if let Some(drv_val) = obj.get(scope, drv_path_key.into()) {
|
v8::String::new(scope, "drvPath").ok_or("v8 str")?.into();
|
||||||
let forced = self.force(drv_val, scope, ctx)?;
|
let drv_str = if let Some(drv_val) = map.get(scope, drv_path_key) {
|
||||||
let s = self.extract_str(forced, scope, ctx);
|
if drv_val.is_undefined() {
|
||||||
if let Some(ref s) = s {
|
None
|
||||||
self.buf.push_str(" drvPath=\"");
|
} else {
|
||||||
self.escape_attr(s);
|
let forced = self.force(drv_val, scope, ctx)?;
|
||||||
self.buf.push('"');
|
let s = self.extract_str(forced, scope, ctx);
|
||||||
|
if let Some(ref s) = s {
|
||||||
|
self.buf.push_str(" drvPath=\"");
|
||||||
|
self.escape_attr(s);
|
||||||
|
self.buf.push('"');
|
||||||
|
}
|
||||||
|
s
|
||||||
}
|
}
|
||||||
s
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let out_path_key = v8::String::new(scope, "outPath").ok_or("v8 str" )?;
|
let out_path_key: v8::Local<v8::Value> =
|
||||||
if let Some(out_val) = obj.get(scope, out_path_key.into()) {
|
v8::String::new(scope, "outPath").ok_or("v8 str")?.into();
|
||||||
|
if let Some(out_val) = map.get(scope, out_path_key)
|
||||||
|
&& !out_val.is_undefined()
|
||||||
|
{
|
||||||
let forced = self.force(out_val, scope, ctx)?;
|
let forced = self.force(out_val, scope, ctx)?;
|
||||||
if let Some(ref s) = self.extract_str(forced, scope, ctx) {
|
if let Some(ref s) = self.extract_str(forced, scope, ctx) {
|
||||||
self.buf.push_str(" outPath=\"");
|
self.buf.push_str(" outPath=\"");
|
||||||
@@ -1542,7 +1552,7 @@ impl XmlWriter {
|
|||||||
self.indent(depth + 1);
|
self.indent(depth + 1);
|
||||||
self.buf.push_str("<repeated />\n");
|
self.buf.push_str("<repeated />\n");
|
||||||
} else {
|
} else {
|
||||||
self.write_attrs_sorted(obj, scope, ctx, depth + 1)?;
|
self.write_attrs_sorted(map, scope, ctx, depth + 1)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
@@ -1550,7 +1560,7 @@ impl XmlWriter {
|
|||||||
} else {
|
} else {
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("<attrs>\n");
|
self.buf.push_str("<attrs>\n");
|
||||||
self.write_attrs_sorted(obj, scope, ctx, depth + 1)?;
|
self.write_attrs_sorted(map, scope, ctx, depth + 1)?;
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("</attrs>\n");
|
self.buf.push_str("</attrs>\n");
|
||||||
}
|
}
|
||||||
@@ -1559,34 +1569,32 @@ impl XmlWriter {
|
|||||||
|
|
||||||
fn write_attrs_sorted<'s>(
|
fn write_attrs_sorted<'s>(
|
||||||
&mut self,
|
&mut self,
|
||||||
obj: v8::Local<'s, v8::Object>,
|
map: v8::Local<'s, v8::Map>,
|
||||||
scope: &mut v8::PinScope<'s, '_>,
|
scope: &mut v8::PinScope<'s, '_>,
|
||||||
ctx: &XmlCtx<'s>,
|
ctx: &XmlCtx<'s>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let keys = obj
|
let arr = map.as_array(scope);
|
||||||
.get_own_property_names(scope, v8::GetPropertyNamesArgsBuilder::new().build())
|
let len = arr.length();
|
||||||
.ok_or("property names" )?;
|
|
||||||
|
|
||||||
let mut key_strings: Vec<String> = Vec::with_capacity(keys.length() as usize);
|
let mut entries: Vec<(String, v8::Local<'s, v8::Value>)> =
|
||||||
for i in 0..keys.length() {
|
Vec::with_capacity((len / 2) as usize);
|
||||||
let key = keys.get_index(scope, i).ok_or("key index" )?;
|
let mut i = 0;
|
||||||
key_strings.push(key.to_rust_string_lossy(scope));
|
while i < len {
|
||||||
|
let key = arr.get_index(scope, i).ok_or("map key")?;
|
||||||
|
let val = arr.get_index(scope, i + 1).ok_or("map value")?;
|
||||||
|
entries.push((key.to_rust_string_lossy(scope), val));
|
||||||
|
i += 2;
|
||||||
}
|
}
|
||||||
key_strings.sort();
|
entries.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
|
||||||
for key_str in &key_strings {
|
|
||||||
let v8_key = v8::String::new(scope, key_str).ok_or("v8 str" )?;
|
|
||||||
let val = obj
|
|
||||||
.get(scope, v8_key.into())
|
|
||||||
.ok_or("attr value" )?;
|
|
||||||
|
|
||||||
|
for (key_str, val) in &entries {
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("<attr name=\"");
|
self.buf.push_str("<attr name=\"");
|
||||||
self.escape_attr(key_str);
|
self.escape_attr(key_str);
|
||||||
self.buf.push_str("\">\n");
|
self.buf.push_str("\">\n");
|
||||||
|
|
||||||
self.write_value(val, scope, ctx, depth + 1)?;
|
self.write_value(*val, scope, ctx, depth + 1)?;
|
||||||
|
|
||||||
self.indent(depth);
|
self.indent(depth);
|
||||||
self.buf.push_str("</attr>\n");
|
self.buf.push_str("</attr>\n");
|
||||||
@@ -1601,7 +1609,7 @@ impl XmlWriter {
|
|||||||
ctx: &XmlCtx<'s>,
|
ctx: &XmlCtx<'s>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let obj = val.to_object(scope).ok_or("fn to_object" )?;
|
let obj = val.to_object(scope).ok_or("fn to_object")?;
|
||||||
|
|
||||||
if let Some(meta) = obj.get(scope, ctx.primop_meta.into())
|
if let Some(meta) = obj.get(scope, ctx.primop_meta.into())
|
||||||
&& meta.is_object()
|
&& meta.is_object()
|
||||||
@@ -1612,16 +1620,16 @@ impl XmlWriter {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let args_key = v8::String::new(scope, "args").ok_or("v8 str" )?;
|
let args_key = v8::String::new(scope, "args").ok_or("v8 str")?;
|
||||||
let args_val = obj.get(scope, args_key.into());
|
let args_val = obj.get(scope, args_key.into());
|
||||||
|
|
||||||
match args_val {
|
match args_val {
|
||||||
Some(args) if args.is_object() && !args.is_null_or_undefined() => {
|
Some(args) if args.is_object() && !args.is_null_or_undefined() => {
|
||||||
let args_obj = args.to_object(scope).ok_or("args to_object" )?;
|
let args_obj = args.to_object(scope).ok_or("args to_object")?;
|
||||||
|
|
||||||
let req_key = v8::String::new(scope, "required").ok_or("v8 str" )?;
|
let req_key = v8::String::new(scope, "required").ok_or("v8 str")?;
|
||||||
let opt_key = v8::String::new(scope, "optional").ok_or("v8 str" )?;
|
let opt_key = v8::String::new(scope, "optional").ok_or("v8 str")?;
|
||||||
let ellipsis_key = v8::String::new(scope, "ellipsis").ok_or("v8 str" )?;
|
let ellipsis_key = v8::String::new(scope, "ellipsis").ok_or("v8 str")?;
|
||||||
|
|
||||||
let mut all_formals: Vec<String> = Vec::new();
|
let mut all_formals: Vec<String> = Vec::new();
|
||||||
if let Some(req) = args_obj.get(scope, req_key.into())
|
if let Some(req) = args_obj.get(scope, req_key.into())
|
||||||
@@ -1721,12 +1729,12 @@ impl<'a> FromV8<'a> for ToXmlResult {
|
|||||||
value: v8::Local<'a, v8::Value>,
|
value: v8::Local<'a, v8::Value>,
|
||||||
) -> std::result::Result<Self, Self::Error> {
|
) -> std::result::Result<Self, Self::Error> {
|
||||||
let global = scope.get_current_context().global(scope);
|
let global = scope.get_current_context().global(scope);
|
||||||
let nix_key = v8::String::new(scope, "Nix").ok_or("v8 string" )?;
|
let nix_key = v8::String::new(scope, "Nix").ok_or("v8 string")?;
|
||||||
let nix_obj = global
|
let nix_obj = global
|
||||||
.get(scope, nix_key.into())
|
.get(scope, nix_key.into())
|
||||||
.ok_or("no Nix global" )?
|
.ok_or("no Nix global")?
|
||||||
.to_object(scope)
|
.to_object(scope)
|
||||||
.ok_or("Nix not object" )?;
|
.ok_or("Nix not object")?;
|
||||||
|
|
||||||
let ctx = XmlCtx::new(scope, nix_obj)?;
|
let ctx = XmlCtx::new(scope, nix_obj)?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user