diff --git a/packages/foam-vscode/src/core/model/workspace.test.ts b/packages/foam-vscode/src/core/model/workspace.test.ts index 852112da..86b3a8c6 100644 --- a/packages/foam-vscode/src/core/model/workspace.test.ts +++ b/packages/foam-vscode/src/core/model/workspace.test.ts @@ -183,4 +183,41 @@ describe('Identifier computation', () => { workspace.getIdentifier(noteABis.uri, [noteB.uri, noteA.uri]) ).toEqual('note-a'); }); + + it('should handle case-sensitive filenames correctly (#1303)', () => { + const workspace = new FoamWorkspace('.md'); + const noteUppercase = createTestNote({ uri: '/a/Note.md' }); + const noteLowercase = createTestNote({ uri: '/b/note.md' }); + + workspace.set(noteUppercase).set(noteLowercase); + + // Should find exact case matches + expect(workspace.listByIdentifier('Note').length).toEqual(1); + expect(workspace.listByIdentifier('Note')[0].uri.path).toEqual( + '/a/Note.md' + ); + + expect(workspace.listByIdentifier('note').length).toEqual(1); + expect(workspace.listByIdentifier('note')[0].uri.path).toEqual( + '/b/note.md' + ); + + // Should not treat them as the same identifier + expect(workspace.listByIdentifier('Note')[0]).not.toEqual( + workspace.listByIdentifier('note')[0] + ); + }); + + it('should generate correct identifiers for case-sensitive files', () => { + const workspace = new FoamWorkspace('.md'); + const noteUppercase = createTestNote({ uri: '/a/Note.md' }); + const noteLowercase = createTestNote({ uri: '/b/note.md' }); + + workspace.set(noteUppercase).set(noteLowercase); + + // Each should have a unique identifier without directory disambiguation + // since they differ by case, they are not considered conflicting + expect(workspace.getIdentifier(noteUppercase.uri)).toEqual('Note'); + expect(workspace.getIdentifier(noteLowercase.uri)).toEqual('note'); + }); }); diff --git a/packages/foam-vscode/src/core/model/workspace.ts b/packages/foam-vscode/src/core/model/workspace.ts index 49f84549..283a2eb9 100644 --- a/packages/foam-vscode/src/core/model/workspace.ts +++ b/packages/foam-vscode/src/core/model/workspace.ts @@ -89,13 +89,12 @@ export class FoamWorkspace implements IDisposable { public listByIdentifier(identifier: string): Resource[] { let needle = this.getTrieIdentifier(identifier); - const mdNeedle = getExtension(normalize(identifier)) !== this.defaultExtension ? this.getTrieIdentifier(identifier + this.defaultExtension) : undefined; - const resources: Resource[] = []; + let resources: Resource[] = []; this._resources.find(needle).forEach(elm => resources.push(elm[1])); @@ -103,6 +102,15 @@ export class FoamWorkspace implements IDisposable { this._resources.find(mdNeedle).forEach(elm => resources.push(elm[1])); } + // if multiple resources found, try to filter exact case matches + if (resources.length > 1) { + resources = resources.filter( + r => + r.uri.getBasename() === identifier || + r.uri.getBasename() === identifier + this.defaultExtension + ); + } + return resources.sort(Resource.sortByPath); } @@ -115,7 +123,7 @@ export class FoamWorkspace implements IDisposable { const amongst = []; const basename = forResource.getBasename(); - this.listByIdentifier(basename).map(res => { + this.listByIdentifier(basename).forEach(res => { // skip self if (res.uri.isEqual(forResource)) { return;