This commit is contained in:
Team3
2026-05-22 00:01:59 +02:00
commit b7759d6542
15 changed files with 2032 additions and 0 deletions

160
src/fs.ts Normal file
View File

@@ -0,0 +1,160 @@
import { App, TFile, TFolder, normalizePath } from "obsidian";
import { PROJECTS_ROOT, PROJECT_FILES } from "./const";
export function projectsPath(): string {
return PROJECTS_ROOT;
}
export function projectPath(name: string): string {
return normalizePath(`${PROJECTS_ROOT}/${name}`);
}
export function nodeMdPath(folderPath: string): string {
const p = normalizePath(folderPath);
const name = p.split("/").pop() ?? p;
return normalizePath(`${p}/${name}.md`);
}
export function isNode(app: App, folderPath: string): boolean {
const md = app.vault.getAbstractFileByPath(nodeMdPath(folderPath));
return md instanceof TFile;
}
export async function ensureFolder(app: App, path: string): Promise<void> {
if (!path) return;
const p = normalizePath(path);
const exists = app.vault.getAbstractFileByPath(p);
if (!exists) {
await app.vault.createFolder(p);
}
}
export async function ensureFile(app: App, path: string, content = ""): Promise<TFile> {
const p = normalizePath(path);
const existing = app.vault.getAbstractFileByPath(p);
if (existing instanceof TFile) return existing;
return await app.vault.create(p, content);
}
export function listFolders(app: App, path: string): TFolder[] {
const folder = path ? app.vault.getAbstractFileByPath(normalizePath(path)) : app.vault.getRoot();
if (!(folder instanceof TFolder)) return [];
return folder.children
.filter((c): c is TFolder => c instanceof TFolder)
.filter((c) => !c.name.startsWith("_") || c.name.startsWith("__"))
.sort((a, b) => a.name.localeCompare(b.name));
}
export function listMarkdownFiles(app: App, path: string, exclude: string[] = []): TFile[] {
const folder = path ? app.vault.getAbstractFileByPath(normalizePath(path)) : app.vault.getRoot();
if (!(folder instanceof TFolder)) return [];
return folder.children
.filter((c): c is TFile => c instanceof TFile && c.extension === "md")
.filter((f) => !exclude.includes(f.name))
.filter((f) => !f.basename.startsWith("_") || f.basename.startsWith("__"))
.sort((a, b) => a.basename.localeCompare(b.basename));
}
export async function readFile(app: App, path: string): Promise<string> {
const p = normalizePath(path);
const f = app.vault.getAbstractFileByPath(p);
if (!(f instanceof TFile)) return "";
return await app.vault.read(f);
}
export async function deleteRecursive(app: App, path: string): Promise<void> {
const p = normalizePath(path);
const f = app.vault.getAbstractFileByPath(p);
if (!f) return;
await app.vault.delete(f, true);
}
export async function rename(app: App, oldPath: string, newPath: string): Promise<void> {
const f = app.vault.getAbstractFileByPath(normalizePath(oldPath));
if (!f) return;
await app.fileManager.renameFile(f, normalizePath(newPath));
}
export async function createProject(app: App, name: string): Promise<void> {
const root = projectPath(name);
await ensureFolder(app, projectsPath());
await ensureFolder(app, root);
for (const file of PROJECT_FILES) {
await ensureFile(app, normalizePath(`${root}/${file}`), "");
}
}
export async function createNode(
app: App,
parentFolderPath: string,
name: string,
): Promise<TFile> {
const folder = normalizePath(`${parentFolderPath}/${name}`);
await ensureFolder(app, folder);
return await ensureFile(app, nodeMdPath(folder), "");
}
export async function renameNode(
app: App,
folderPath: string,
newName: string,
): Promise<void> {
const p = normalizePath(folderPath);
const parent = p.substring(0, p.lastIndexOf("/"));
const oldName = p.split("/").pop() ?? "";
if (oldName === newName) return;
const oldMd = nodeMdPath(p);
const newFolder = normalizePath(`${parent}/${newName}`);
const mdFile = app.vault.getAbstractFileByPath(oldMd);
if (mdFile instanceof TFile) {
const tmpMd = normalizePath(`${p}/${newName}.md`);
if (tmpMd !== oldMd) await rename(app, oldMd, tmpMd);
}
await rename(app, p, newFolder);
}
export async function moveNode(
app: App,
folderPath: string,
newParentFolderPath: string,
): Promise<void> {
const p = normalizePath(folderPath);
const name = p.split("/").pop() ?? "";
const target = normalizePath(`${newParentFolderPath}/${name}`);
if (p === target) return;
await rename(app, p, target);
}
export interface NodeTree {
name: string;
path: string;
children: NodeTree[];
}
export function buildNodeTree(app: App, projectName: string): NodeTree {
const root = projectPath(projectName);
const walk = (folderPath: string, name: string): NodeTree => {
const children = listFolders(app, folderPath).map((f) => walk(f.path, f.name));
return { name, path: folderPath, children };
};
return walk(root, projectName);
}
export interface ProjectFileLocation {
project: string;
path: string[];
}
export function parseProjectFilePath(path: string): ProjectFileLocation | null {
if (!path.endsWith(".md")) return null;
const parts = normalizePath(path).split("/");
let idx = 0;
if (PROJECTS_ROOT) {
if (parts[0] !== PROJECTS_ROOT) return null;
idx = 1;
}
if (parts.length < idx + 2) return null;
const project = parts[idx];
const rest = parts.slice(idx + 1);
return { project, path: rest };
}