Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/data-index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,15 +276,41 @@ export class PrefixIndex extends Component {

/**
* Use the in-memory prefix index to convert a relative path to an absolute one.
* - Absolute paths start with "/" and are resolved from the vault root (the leading "/" is stripped).
* - Relative paths starting with "./" or "../" are resolved relative to the origin file's parent folder.
* - Other paths are treated as absolute (from vault root) for backward compatibility.
*/
public resolveRelative(path: string, origin?: string): string {
if (!origin) return path;
else if (path.startsWith("/")) return path.substring(1);

// Only resolve as relative if the path explicitly starts with "./" or "../".
// This preserves backward compatibility for absolute paths like "projects/folder".

let relativePath = getParentFolder(origin) + "/" + path;
if (path.startsWith("./") || path.startsWith("../")) {
// Normalize the path by resolving ".." and "." segments.
relativePath = this.normalizePath(relativePath);
}

if (this.pathExists(relativePath)) return relativePath;
else return path;
}

/** Normalize a path by resolving ".." and "." segments. */
private normalizePath(path: string): string {
let parts = path.split("/").filter(p => p.length > 0);
let stack: string[] = [];
for (let part of parts) {
if (part === ".") continue;
else if (part === "..") {
if (stack.length > 0) stack.pop();
} else {
stack.push(part);
}
}
return stack.join("/");
}
}

/** Simple path filters which filter file types. */
Expand Down
14 changes: 9 additions & 5 deletions src/data-index/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ export function matchingSourcePaths(
case "csv":
return Result.success(new Set<string>([index.prefix.resolveRelative(source.path, originFile)]));
case "folder":
// Resolve relative/absolute paths: paths starting with "/" are absolute (from vault root),
// paths containing ".." or starting with "./" are relative to the origin file.
let resolvedFolder = index.prefix.resolveRelative(source.folder, originFile);

// Prefer loading from the folder at the given path.
if (index.prefix.nodeExists(source.folder))
return Result.success(index.prefix.get(source.folder, PathFilters.markdown));
if (index.prefix.nodeExists(resolvedFolder))
return Result.success(index.prefix.get(resolvedFolder, PathFilters.markdown));

// But allow for loading individual files if they exist.
if (index.prefix.pathExists(source.folder)) return Result.success(new Set([source.folder]));
else if (index.prefix.pathExists(source.folder + ".md"))
return Result.success(new Set([source.folder + ".md"]));
if (index.prefix.pathExists(resolvedFolder)) return Result.success(new Set([resolvedFolder]));
else if (index.prefix.pathExists(resolvedFolder + ".md"))
return Result.success(new Set([resolvedFolder + ".md"]));

// For backwards-compat, return an empty result even if the folder does not exist.
return Result.success(new Set());
Expand Down