Merge pull request #1058 from vrtmrz/issue-1056-preserve-utf8-bom

Preserve UTF-8 BOMs during Vault ingestion
This commit is contained in:
vorotamoroz
2026-07-31 13:39:27 +09:00
committed by GitHub
2 changed files with 39 additions and 1 deletions
@@ -10,7 +10,8 @@ export class ObsidianVaultAdapter implements IVaultAdapter<TFile, TFolder> {
constructor(private app: App) {}
async read(file: TFile): Promise<string> {
return await this.app.vault.read(file);
// Vault.read strips a leading UTF-8 BOM, leaving the content size inconsistent with TFile.stat.
return await this.app.vault.adapter.read(file.path);
}
async cachedRead(file: TFile): Promise<string> {
@@ -0,0 +1,37 @@
import { describe, expect, it, vi } from "vitest";
import type { App, TFile } from "obsidian";
import { ObsidianVaultAdapter } from "./ObsidianVaultAdapter";
describe("ObsidianVaultAdapter.read", () => {
it("preserves a UTF-8 BOM so the content size matches the file stat", async () => {
const path = "Transcripts/字幕.md";
const contentWithoutBom = "字幕の検証行です。\n";
const contentWithBom = `\ufeff${contentWithoutBom}`;
const read = vi.fn().mockResolvedValue(contentWithoutBom);
const adapterRead = vi.fn().mockResolvedValue(contentWithBom);
const app = {
vault: {
read,
adapter: {
read: adapterRead,
},
},
} as unknown as App;
const file = {
path,
stat: {
ctime: 1,
mtime: 2,
size: new Blob([contentWithBom]).size,
},
} as TFile;
const adapter = new ObsidianVaultAdapter(app);
const result = await adapter.read(file);
expect(new Blob([result]).size).toBe(file.stat.size);
expect(result.charCodeAt(0)).toBe(0xfeff);
expect(adapterRead).toHaveBeenCalledWith(path);
expect(read).not.toHaveBeenCalled();
});
});