Submatter/packages/database/src/markdown-backlog/paths.ts

68 lines
2.2 KiB
TypeScript
Raw Normal View History

import { sep } from "node:path";
/** POSIX-style path relative to repository root (e.g. `plans/Plan-a/Task-b.md`). */
export function toRepoPathPosix(relativeFromRepoRoot: string): string {
return relativeFromRepoRoot.split(sep).join("/");
}
/**
* Whether this repo-relative path should be imported as backlog markdown.
* Expects POSIX `plans/...` paths.
*/
export function isTrackedBacklogMarkdown(repoPathPosix: string): boolean {
if (!repoPathPosix.startsWith("plans/")) return false;
if (repoPathPosix === "plans/README.md") return false;
const base = repoPathPosix.split("/").pop() ?? "";
return (
base.startsWith("Plan-") || base.startsWith("Epic-") || base.startsWith("Task-")
);
}
/**
* Parent document path for hierarchy links, or `null` for plan roots.
*/
export function parentRepoPath(repoPathPosix: string): string | null {
const parts = repoPathPosix.split("/").filter(Boolean);
if (parts.length < 3 || parts[0] !== "plans") return null;
const planDir = parts[1];
if (!planDir.startsWith("Plan-")) return null;
if (parts.length === 3) {
const file = parts[2];
if (file.startsWith("Plan-") && file.endsWith(".md")) return null;
}
if (parts.length === 4) {
const file = parts[3];
if (file.startsWith("Epic-") && file.endsWith(".md")) {
return `plans/${planDir}/${planDir}.md`;
}
}
if (parts.length === 5) {
const epicDir = parts[2];
const file = parts[4];
if (epicDir.startsWith("Epic-") && file.startsWith("Task-") && file.endsWith(".md")) {
return `plans/${planDir}/${epicDir}/${epicDir}.md`;
}
}
return null;
}
export function planSlugFromPath(repoPathPosix: string): string | null {
const parts = repoPathPosix.split("/").filter(Boolean);
if (parts.length < 2 || parts[0] !== "plans") return null;
const planDir = parts[1];
return planDir.startsWith("Plan-") ? planDir.replace(/^Plan-/, "") : null;
}
export function epicFolderFromPath(repoPathPosix: string): string | null {
const parts = repoPathPosix.split("/").filter(Boolean);
if (parts.length < 3 || parts[0] !== "plans") return null;
const epicDir = parts[2];
if (parts.length >= 4 && epicDir.startsWith("Epic-")) return epicDir.replace(/^Epic-/, "");
return null;
}