refactor: consume Commonlib as a package

This commit is contained in:
vorotamoroz
2026-07-17 11:13:16 +00:00
parent 6475d32769
commit a721d3b602
665 changed files with 3438 additions and 31592 deletions
@@ -1,7 +1,7 @@
import type { FilePath, UXFileInfoStub, UXFolderInfo } from "@lib/common/types";
import type { IConversionAdapter } from "@lib/serviceModules/adapters";
import type { FilePath, UXFileInfoStub, UXFolderInfo } from "@vrtmrz/livesync-commonlib/compat/common/types";
import type { IConversionAdapter } from "@vrtmrz/livesync-commonlib/compat/serviceModules/adapters";
import type { NodeFile, NodeFolder } from "./NodeTypes";
import { path } from "@/apps/cli/node-compat";
import { path } from "@vrtmrz/livesync-commonlib/node";
/**
* Conversion adapter implementation for Node.js
@@ -1,12 +1,12 @@
import type { FilePath, UXStat } from "@lib/common/types";
import type { IFileSystemAdapter } from "@lib/serviceModules/adapters";
import type { FilePath, UXStat } from "@vrtmrz/livesync-commonlib/compat/common/types";
import type { IFileSystemAdapter } from "@vrtmrz/livesync-commonlib/compat/serviceModules/adapters";
import { NodePathAdapter } from "./NodePathAdapter";
import { NodeTypeGuardAdapter } from "./NodeTypeGuardAdapter";
import { NodeConversionAdapter } from "./NodeConversionAdapter";
import { NodeStorageAdapter } from "./NodeStorageAdapter";
import { NodeStorageAdapter } from "@vrtmrz/livesync-commonlib/node";
import { NodeVaultAdapter } from "./NodeVaultAdapter";
import type { NodeFile, NodeFolder, NodeStat } from "./NodeTypes";
import { fsPromises as fs, path } from "@/apps/cli/node-compat";
import { fsPromises as fs, path } from "@vrtmrz/livesync-commonlib/node";
/**
* Complete file system adapter implementation for Node.js
+3 -3
View File
@@ -1,7 +1,7 @@
import type { FilePath } from "@lib/common/types";
import type { IPathAdapter } from "@lib/serviceModules/adapters";
import type { FilePath } from "@vrtmrz/livesync-commonlib/compat/common/types";
import type { IPathAdapter } from "@vrtmrz/livesync-commonlib/compat/serviceModules/adapters";
import type { NodeFile } from "./NodeTypes";
import { path } from "@/apps/cli/node-compat";
import { path } from "@vrtmrz/livesync-commonlib/node";
/**
* Path adapter implementation for Node.js
-127
View File
@@ -1,127 +0,0 @@
import type { UXDataWriteOptions } from "@lib/common/types";
import type { IStorageAdapter } from "@lib/serviceModules/adapters";
import type { NodeStat } from "./NodeTypes";
import { fsPromises as fs, path } from "@/apps/cli/node-compat";
import { validateStoragePath } from "@/apps/storagePath";
/**
* Storage adapter implementation for Node.js
*/
export class NodeStorageAdapter implements IStorageAdapter<NodeStat> {
constructor(private readonly basePath: string) {}
private resolvePath(p: string, allowRoot: boolean = true): string {
return path.join(this.basePath, validateStoragePath(p, allowRoot));
}
async exists(p: string): Promise<boolean> {
const fullPath = this.resolvePath(p);
try {
await fs.access(fullPath);
return true;
} catch {
return false;
}
}
async trystat(p: string): Promise<NodeStat | null> {
const fullPath = this.resolvePath(p);
try {
const stat = await fs.stat(fullPath);
return {
size: stat.size,
mtime: Math.floor(stat.mtimeMs),
ctime: Math.floor(stat.ctimeMs),
type: stat.isDirectory() ? "folder" : "file",
};
} catch {
return null;
}
}
async stat(p: string): Promise<NodeStat | null> {
return await this.trystat(p);
}
async mkdir(p: string): Promise<void> {
await fs.mkdir(this.resolvePath(p), { recursive: true });
}
async remove(p: string): Promise<void> {
const fullPath = this.resolvePath(p, false);
const stat = await fs.stat(fullPath);
if (stat.isDirectory()) {
await fs.rm(fullPath, { recursive: true, force: true });
} else {
await fs.unlink(fullPath);
}
}
async read(p: string): Promise<string> {
return await fs.readFile(this.resolvePath(p, false), "utf-8");
}
async readBinary(p: string): Promise<ArrayBuffer> {
const buffer = await fs.readFile(this.resolvePath(p, false));
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- required in environments where Buffer.buffer is ArrayBufferLike
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer;
}
async write(p: string, data: string, options?: UXDataWriteOptions): Promise<void> {
const fullPath = this.resolvePath(p, false);
await fs.mkdir(path.dirname(fullPath), { recursive: true });
await fs.writeFile(fullPath, data, "utf-8");
if (options?.mtime || options?.ctime) {
const atime = options.mtime ? new Date(options.mtime) : new Date();
const mtime = options.mtime ? new Date(options.mtime) : new Date();
await fs.utimes(fullPath, atime, mtime);
}
}
async writeBinary(p: string, data: ArrayBuffer, options?: UXDataWriteOptions): Promise<void> {
const fullPath = this.resolvePath(p, false);
await fs.mkdir(path.dirname(fullPath), { recursive: true });
await fs.writeFile(fullPath, new Uint8Array(data));
if (options?.mtime || options?.ctime) {
const atime = options.mtime ? new Date(options.mtime) : new Date();
const mtime = options.mtime ? new Date(options.mtime) : new Date();
await fs.utimes(fullPath, atime, mtime);
}
}
async append(p: string, data: string, options?: UXDataWriteOptions): Promise<void> {
const fullPath = this.resolvePath(p, false);
await fs.mkdir(path.dirname(fullPath), { recursive: true });
await fs.appendFile(fullPath, data, "utf-8");
if (options?.mtime || options?.ctime) {
const atime = options.mtime ? new Date(options.mtime) : new Date();
const mtime = options.mtime ? new Date(options.mtime) : new Date();
await fs.utimes(fullPath, atime, mtime);
}
}
async list(basePath: string): Promise<{ files: string[]; folders: string[] }> {
const fullPath = this.resolvePath(basePath);
try {
const entries = await fs.readdir(fullPath, { withFileTypes: true });
const files: string[] = [];
const folders: string[] = [];
for (const entry of entries) {
const entryPath = path.join(basePath, entry.name).replace(/\\/g, "/");
if (entry.isDirectory()) {
folders.push(entryPath);
} else if (entry.isFile()) {
files.push(entryPath);
}
}
return { files, folders };
} catch {
return { files: [], folders: [] };
}
}
}
@@ -1,9 +1,6 @@
import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { storageAdapterContractCases } from "@/apps/_test/storageAdapterContract";
import { NodeStorageAdapter } from "./NodeStorageAdapter";
import { fsPromises as fs, os, path, NodeStorageAdapter } from "@vrtmrz/livesync-commonlib/node";
describe("NodeStorageAdapter", () => {
const tempDirs: string[] = [];
@@ -1,4 +1,4 @@
import type { ITypeGuardAdapter } from "@lib/serviceModules/adapters";
import type { ITypeGuardAdapter } from "@vrtmrz/livesync-commonlib/compat/serviceModules/adapters";
import type { NodeFile, NodeFolder } from "./NodeTypes";
/**
+1 -1
View File
@@ -1,4 +1,4 @@
import type { FilePath, UXStat } from "@lib/common/types";
import type { FilePath, UXStat } from "@vrtmrz/livesync-commonlib/compat/common/types";
/**
* Node.js file representation
+3 -3
View File
@@ -1,7 +1,7 @@
import type { FilePath, UXDataWriteOptions } from "@lib/common/types";
import type { IVaultAdapter } from "@lib/serviceModules/adapters";
import type { FilePath, UXDataWriteOptions } from "@vrtmrz/livesync-commonlib/compat/common/types";
import type { IVaultAdapter } from "@vrtmrz/livesync-commonlib/compat/serviceModules/adapters";
import type { NodeFile, NodeFolder } from "./NodeTypes";
import { fsPromises as fs, path } from "@/apps/cli/node-compat";
import { fsPromises as fs, path } from "@vrtmrz/livesync-commonlib/node";
/**
* Vault adapter implementation for Node.js
@@ -1,16 +1,14 @@
import { mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { fsPromises, os, path } from "@vrtmrz/livesync-commonlib/node";
import { describe, expect, it } from "vitest";
import type { FilePath } from "@lib/common/types";
import type { FilePath } from "@vrtmrz/livesync-commonlib/compat/common/types";
import { NodeFileSystemAdapter } from "./NodeFileSystemAdapter";
import { NodeVaultAdapter } from "./NodeVaultAdapter";
describe("NodeVaultAdapter.rename", () => {
it("changes the directory entry case without changing the content", async () => {
const directory = await mkdtemp(join(tmpdir(), "livesync-case-rename-"));
const directory = await fsPromises.mkdtemp(path.join(os.tmpdir(), "livesync-case-rename-"));
try {
await writeFile(join(directory, "Calculus.md"), "content", "utf8");
await fsPromises.writeFile(path.join(directory, "Calculus.md"), "content", "utf8");
const adapter = new NodeVaultAdapter(directory);
const file = {
path: "Calculus.md" as FilePath,
@@ -19,20 +17,20 @@ describe("NodeVaultAdapter.rename", () => {
await adapter.rename(file, "calculus.md");
expect(await readdir(directory)).toEqual(["calculus.md"]);
expect(await readFile(join(directory, "calculus.md"), "utf8")).toBe("content");
expect(await fsPromises.readdir(directory)).toEqual(["calculus.md"]);
expect(await fsPromises.readFile(path.join(directory, "calculus.md"), "utf8")).toBe("content");
expect(file.path).toBe("calculus.md");
} finally {
await rm(directory, { recursive: true, force: true });
await fsPromises.rm(directory, { recursive: true, force: true });
}
});
});
describe("NodeFileSystemAdapter path case", () => {
it("finds the stored case and refreshes the cache after a case-only rename", async () => {
const directory = await mkdtemp(join(tmpdir(), "livesync-case-cache-"));
const directory = await fsPromises.mkdtemp(path.join(os.tmpdir(), "livesync-case-cache-"));
try {
await writeFile(join(directory, "Calculus.md"), "content", "utf8");
await fsPromises.writeFile(path.join(directory, "Calculus.md"), "content", "utf8");
const adapter = new NodeFileSystemAdapter(directory);
await expect(adapter.getAbstractFileByPath("calculus.md")).resolves.toBeNull();
@@ -43,9 +41,9 @@ describe("NodeFileSystemAdapter path case", () => {
expect(renamedFile.path).toBe("calculus.md");
expect((await adapter.getFiles()).map((file) => file.path)).toEqual(["calculus.md"]);
expect(await readdir(directory)).toEqual(["calculus.md"]);
expect(await fsPromises.readdir(directory)).toEqual(["calculus.md"]);
} finally {
await rm(directory, { recursive: true, force: true });
await fsPromises.rm(directory, { recursive: true, force: true });
}
});
});