mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-11-06 16:28:18 +00:00
(src/serviceModules/FileSystemAdapters/pathAliasGuard.ts) - Require every existing, unindexed path component to use a name listed by its parent directory. - Accept case-only and Unicode-normalisation differences while caching positive directory listings briefly. (src/serviceModules/FileSystemAdapters/ObsidianStorageAdapter.ts, src/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.ts) - Apply the alias boundary before text, binary, append, directory, removal, create, modify, rename, delete, and trash operations. - Check both the source and destination of vault renames before calling the host API. (src/serviceModules/FileSystemAdapters/pathAliasGuard.unit.spec.ts) - Cover directory and file aliases across every mutating adapter route with synthetic host behaviour. - Exercise real host filesystem aliases where the platform exposes them, including new files and directories below an aliased folder. - Preserve listed names, case-only differences, indexed paths, and new-file behaviour. (src/serviceModules/FileSystemAdapters/ObsidianStorageAdapter.unit.spec.ts, src/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.unit.spec.ts) - Extend existing adapter fixtures with the vault-index contract used by the guard.
68 lines
2.6 KiB
TypeScript
68 lines
2.6 KiB
TypeScript
import type { UXDataWriteOptions } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
|
import type { IStorageAdapter } from "@vrtmrz/livesync-commonlib/compat/serviceModules/adapters";
|
|
import { toArrayBuffer } from "@vrtmrz/livesync-commonlib/compat/serviceModules/FileAccessBase";
|
|
import type { Stat, App } from "obsidian";
|
|
import { toIntegerTimestamps } from "./sanitizeWriteOptions";
|
|
import { createPathAliasGuard, type PathAliasGuard } from "./pathAliasGuard";
|
|
|
|
/**
|
|
* Storage adapter implementation for Obsidian
|
|
*/
|
|
|
|
export class ObsidianStorageAdapter implements IStorageAdapter<Stat> {
|
|
constructor(
|
|
private app: App,
|
|
private readonly aliasGuard: PathAliasGuard = createPathAliasGuard(app)
|
|
) {}
|
|
|
|
async exists(path: string): Promise<boolean> {
|
|
return await this.app.vault.adapter.exists(path);
|
|
}
|
|
|
|
async trystat(path: string): Promise<Stat | null> {
|
|
if (!(await this.app.vault.adapter.exists(path))) return null;
|
|
return await this.app.vault.adapter.stat(path);
|
|
}
|
|
|
|
async stat(path: string): Promise<Stat | null> {
|
|
return await this.app.vault.adapter.stat(path);
|
|
}
|
|
|
|
async mkdir(path: string): Promise<void> {
|
|
await this.aliasGuard.assertNoAlias(path);
|
|
await this.app.vault.adapter.mkdir(path);
|
|
}
|
|
|
|
async remove(path: string): Promise<void> {
|
|
await this.aliasGuard.assertNoAlias(path);
|
|
await this.app.vault.adapter.remove(path);
|
|
}
|
|
|
|
async read(path: string): Promise<string> {
|
|
return await this.app.vault.adapter.read(path);
|
|
}
|
|
|
|
async readBinary(path: string): Promise<ArrayBuffer> {
|
|
return await this.app.vault.adapter.readBinary(path);
|
|
}
|
|
|
|
async write(path: string, data: string, options?: UXDataWriteOptions): Promise<void> {
|
|
await this.aliasGuard.assertNoAlias(path);
|
|
return await this.app.vault.adapter.write(path, data, toIntegerTimestamps(options));
|
|
}
|
|
|
|
async writeBinary(path: string, data: ArrayBuffer, options?: UXDataWriteOptions): Promise<void> {
|
|
await this.aliasGuard.assertNoAlias(path);
|
|
return await this.app.vault.adapter.writeBinary(path, toArrayBuffer(data), toIntegerTimestamps(options));
|
|
}
|
|
|
|
async append(path: string, data: string, options?: UXDataWriteOptions): Promise<void> {
|
|
await this.aliasGuard.assertNoAlias(path);
|
|
return await this.app.vault.adapter.append(path, data, toIntegerTimestamps(options));
|
|
}
|
|
|
|
list(basePath: string): Promise<{ files: string[]; folders: string[] }> {
|
|
return Promise.resolve(this.app.vault.adapter.list(basePath));
|
|
}
|
|
}
|