Skip to content

Commit

Permalink
Improved path handling for imports
Browse files Browse the repository at this point in the history
Slightly improved path handling for the import builtin, non-absolute string handling will be fixed in the future.
  • Loading branch information
arduano@localhost authored and arduano committed May 20, 2024
1 parent c4d2acd commit 631a2b5
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 33 deletions.
27 changes: 22 additions & 5 deletions nixjs-rt/src/builtins.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { err, errType, errTypes } from "./errors";
import { err, errType, errTypes, highlighted } from "./errors";
import { abortError } from "./errors/abort";
import { otherError } from "./errors/other";
import { typeMismatchError } from "./errors/typeError";
Expand All @@ -18,6 +18,7 @@ import {
Path,
TRUE,
} from "./lib";
import { dirOf, isAbsolutePath, normalizePath } from "./utils";

type BuiltinsRecord = Record<string, (param: NixType) => NixType>;

Expand Down Expand Up @@ -354,12 +355,28 @@ export function getBuiltins() {
throw builtinBasicTypeMismatchError("import", pathStrict, expected);
}

const pathValue = pathStrict.toJs();
let pathValue = "";
if (pathStrict instanceof NixString) {
pathValue = normalizePath(pathStrict.toJs());
} else if (pathStrict instanceof Path) {
pathValue = pathStrict.toJs();
}

debugLog(JSON.stringify(pathValue));
debugLog(JSON.stringify(pathStrict instanceof NixString));

// Check if it's an absolute path. Relative paths are not allowed.
// Path data types are always automatically absolute.
if (isAbsolutePath(pathValue)) {
throw otherError(
`string ${highlighted(JSON.stringify(pathValue))} doesn't represent an absolute path. Only absolute paths are allowed for imports.`,
);
}

const resultingFn: (ctx: EvalCtx) => NixType = importNixModule(pathValue);
const resultingFn = importNixModule(pathValue);

const ctx = new EvalCtx(pathValue);
return resultingFn(ctx);
const newCtx = new EvalCtx(dirOf(pathValue));
return resultingFn(newCtx);
},

intersectAttrs: (arg) => {
Expand Down
29 changes: 1 addition & 28 deletions nixjs-rt/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
couldntFindVariableError,
} from "./errors/variable";
import { NixAbortError } from "./errors/abort";
import { isAbsolutePath, joinPaths, normalizePath } from "./utils";

// Error re-exports
export { NixError } from "./errors";
Expand Down Expand Up @@ -1291,34 +1292,6 @@ export function recursiveStrictAttrset(theAttrset: Attrset): Attrset {
return theAttrset;
}

function isAbsolutePath(path: string): boolean {
return path.startsWith("/");
}

function joinPaths(abs_base: string, path: string): string {
return `${abs_base}/${path}`;
}

function normalizePath(path: string): string {
let segments = path.split("/");
let normalizedSegments = new Array();
for (const segment of segments) {
switch (segment) {
case "":
break;
case ".":
break;
case "..":
normalizedSegments.pop();
break;
default:
normalizedSegments.push(segment);
break;
}
}
return (isAbsolutePath(path) ? "/" : "") + normalizedSegments.join("/");
}

/**
* If given an attrset entry like `a = value`, then this function returns just the given value.
* If the attrset has multiple segments (e.g. `a.b.c = value`), then this function returns
Expand Down
33 changes: 33 additions & 0 deletions nixjs-rt/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export function isAbsolutePath(path: string): boolean {
return path.startsWith("/");
}

export function joinPaths(abs_base: string, path: string): string {
return `${abs_base}/${path}`;
}

export function normalizePath(path: string): string {
let segments = path.split("/");
let normalizedSegments: string[] = [];
for (const segment of segments) {
switch (segment) {
case "":
break;
case ".":
break;
case "..":
normalizedSegments.pop();
break;
default:
normalizedSegments.push(segment);
break;
}
}
return (isAbsolutePath(path) ? "/" : "") + normalizedSegments.join("/");
}

export function dirOf(path: string) {
// Return everything before the final slash
const lastSlash = path.lastIndexOf("/");
return path.substring(0, lastSlash);
}

0 comments on commit 631a2b5

Please sign in to comment.