From cc6aec6775d833f9220d34bf3506af1add05dc13 Mon Sep 17 00:00:00 2001 From: Christian Bager Bach Houmann Date: Sun, 1 Feb 2026 15:05:34 +0100 Subject: [PATCH] fix: handle alias frontmatter case and commas --- src/gui/suggesters/FileIndex.test.ts | 73 ++++++++++++++++++++++++++++ src/gui/suggesters/FileIndex.ts | 39 +++++++++++---- 2 files changed, 103 insertions(+), 9 deletions(-) diff --git a/src/gui/suggesters/FileIndex.test.ts b/src/gui/suggesters/FileIndex.test.ts index 6bb0fefe..f316dc89 100644 --- a/src/gui/suggesters/FileIndex.test.ts +++ b/src/gui/suggesters/FileIndex.test.ts @@ -298,6 +298,79 @@ describe('FileIndex', () => { }); }); + describe('alias extraction', () => { + it('should split comma-separated alias strings', async () => { + const files = [ + { + path: 'test.md', + basename: 'test', + extension: 'md', + parent: { path: '' }, + stat: { mtime: Date.now() } + } + ] as TFile[]; + + (mockApp.vault.getMarkdownFiles as any).mockReturnValue(files); + mockApp.metadataCache.getFileCache = vi.fn(() => ({ + frontmatter: { aliases: 'hello, world' } + })); + + await fileIndex.ensureIndexed(); + + const helloResults = fileIndex.search('hello', {}, 10); + const worldResults = fileIndex.search('world', {}, 10); + + expect(helloResults.some(result => + result.matchType === 'alias' && result.displayText === 'hello' + )).toBe(true); + expect(worldResults.some(result => + result.matchType === 'alias' && result.displayText === 'world' + )).toBe(true); + }); + + it('should read aliases from case-insensitive keys', async () => { + const files = [ + { + path: 'upper.md', + basename: 'upper', + extension: 'md', + parent: { path: '' }, + stat: { mtime: Date.now() } + }, + { + path: 'note.md', + basename: 'note', + extension: 'md', + parent: { path: '' }, + stat: { mtime: Date.now() } + } + ] as TFile[]; + + (mockApp.vault.getMarkdownFiles as any).mockReturnValue(files); + mockApp.metadataCache.getFileCache = vi.fn((file) => { + if (file.path === 'upper.md') { + return { frontmatter: { Aliases: ['Caps'] } }; + } + if (file.path === 'note.md') { + return { frontmatter: { aLiAs: 'Mixed' } }; + } + return { frontmatter: {} }; + }); + + await fileIndex.ensureIndexed(); + + const capsResults = fileIndex.search('caps', {}, 10); + const mixedResults = fileIndex.search('mixed', {}, 10); + + expect(capsResults.some(result => + result.matchType === 'alias' && result.displayText === 'Caps' + )).toBe(true); + expect(mixedResults.some(result => + result.matchType === 'alias' && result.displayText === 'Mixed' + )).toBe(true); + }); + }); + describe('heading search', () => { it.skip('should support global heading search with #', async () => { // Create files with headings diff --git a/src/gui/suggesters/FileIndex.ts b/src/gui/suggesters/FileIndex.ts index 0a85f402..053a344c 100644 --- a/src/gui/suggesters/FileIndex.ts +++ b/src/gui/suggesters/FileIndex.ts @@ -283,18 +283,39 @@ export class FileIndex { this.updateUnresolvedLinks(); } + private extractAliases(frontmatter?: Record): string[] { + if (!frontmatter) return []; + + const aliases: string[] = []; + for (const [key, value] of Object.entries(frontmatter)) { + const lowerKey = key.toLowerCase(); + if (lowerKey !== 'alias' && lowerKey !== 'aliases') continue; + + if (typeof value === 'string') { + const splitAliases = value + .split(',') + .map((alias) => alias.trim()) + .filter((alias) => alias.length > 0); + aliases.push(...splitAliases); + } else if (Array.isArray(value)) { + aliases.push( + ...value + .filter((alias) => typeof alias === 'string') + .map((alias) => alias.trim()) + .filter((alias) => alias.length > 0) + ); + } + } + + return aliases; + } + private createIndexedFile(file: TFile): IndexedFile { const fileCache = this.app.metadataCache.getFileCache(file); const frontmatter = fileCache?.frontmatter; - - // Extract aliases - const aliases: string[] = []; - const aliasData = frontmatter?.alias ?? frontmatter?.aliases; - if (typeof aliasData === 'string') { - aliases.push(aliasData); - } else if (Array.isArray(aliasData)) { - aliases.push(...aliasData.filter(a => typeof a === 'string')); - } + + // Extract aliases (case-insensitive keys, handle comma-separated strings) + const aliases = this.extractAliases(frontmatter as Record | undefined); const aliasesNormalized = aliases.map((alias) => normalizeForSearch(alias)); // Extract and sanitize headings at index time