Skip to content

Commit 15be161

Browse files
authored
refactor: Minor refactoring of links code and tests (#3494)
* test: . Extract data and index variables * test: . Extract getLink() * test: . Inline data and index variables * test: . Inline return value * test: - Re-use getLink() * jsdoc: Tiny improvements to some function docs * refactor: . Make fields readonly - spotted and fixed by SonarQube * refactor: . Use string.startsWith() - spotted and fixed by SonarQube * refactor: . Reformat single-line if statement * refactor: . Rename 'filename' field to better convey its meaning * refactor: . Rename 'filename' parameter to better convey its meaning * refactor: . Specify return type explicitly
1 parent 7a67173 commit 15be161

File tree

3 files changed

+43
-60
lines changed

3 files changed

+43
-60
lines changed

src/Scripting/TasksFile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class TasksFile {
5151
}
5252

5353
/**
54-
* Return a array of Link in the body of the file.
54+
* Return an array of {@link Link} in the body of the file.
5555
*/
5656
get outLinks(): Link[] {
5757
return this.cachedMetadata?.links?.map((link) => new Link(link, this.filenameWithoutExtension)) ?? [];

src/Task/Link.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,37 @@
11
import type { LinkCache } from 'obsidian';
22

33
export class Link {
4-
private rawLink: LinkCache;
5-
private filename: string;
4+
private readonly rawLink: LinkCache;
5+
private readonly filenameContainingLink: string;
66

77
/**
88
* @param {LinkCache} rawLink - The raw link from Obsidian cache.
9-
* @param {string} filename - The name of the file where this link is located.
9+
* @param {string} filenameContainingLink - The name of the file where this link is located.
1010
*/
11-
constructor(rawLink: LinkCache, filename: string) {
11+
constructor(rawLink: LinkCache, filenameContainingLink: string) {
1212
this.rawLink = rawLink;
13-
this.filename = filename;
13+
this.filenameContainingLink = filenameContainingLink;
1414
}
1515

16-
public get originalMarkdown() {
16+
public get originalMarkdown(): string {
1717
return this.rawLink.original;
1818
}
1919

20-
public get destination() {
20+
public get destination(): string {
2121
return this.rawLink.link;
2222
}
2323

2424
/**
2525
* Returns the filename of the link destination without the path or alias
2626
* Removes the .md extension if present leaves other extensions intact.
27-
* No accomodation for empty links.
27+
* No accommodation for empty links.
2828
* @returns {string}
2929
*/
30-
public get destinationFilename() {
30+
public get destinationFilename(): string {
3131
// Handle internal links (starting with '#')
32-
if (this.destination[0] === '#') return this.filename;
32+
if (this.destination.startsWith('#')) {
33+
return this.filenameContainingLink;
34+
}
3335

3436
// Extract filename from path (handles both path and optional hash fragment)
3537
const pathPart = this.destination.split('#', 1)[0];
@@ -39,7 +41,7 @@ export class Link {
3941
return destFilename.endsWith('.md') ? destFilename.slice(0, -3) : destFilename;
4042
}
4143

42-
public get displayText() {
44+
public get displayText(): string | undefined {
4345
return this.rawLink.displayText;
4446
}
4547
}

tests/Task/Link.test.ts

Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ import internal_heading_links from '../Obsidian/__test_data__/internal_heading_l
66
import link_in_task_wikilink from '../Obsidian/__test_data__/link_in_task_wikilink.json';
77
import link_in_task_markdown_link from '../Obsidian/__test_data__/link_in_task_markdown_link.json';
88

9+
function getLink(data: any, index: number) {
10+
const rawLink = data.cachedMetadata.links[index];
11+
return new Link(rawLink, new TasksFile(data.filePath).filenameWithoutExtension);
12+
}
13+
914
describe('linkClass', () => {
1015
it('should construct a Link object', () => {
11-
const rawLink = links_everywhere.cachedMetadata.links[0];
12-
const link = new Link(rawLink, new TasksFile(links_everywhere.filePath).filenameWithoutExtension);
16+
const link = getLink(links_everywhere, 0);
1317

1418
expect(link).toBeDefined();
1519
expect(link.originalMarkdown).toEqual('[[link_in_file_body]]');
@@ -25,83 +29,73 @@ describe('linkClass', () => {
2529

2630
// Tests checking against __internal_heading_links__
2731
it('should return the filename of the containing note if the link is internal [[#heading]]', () => {
28-
const rawLink = internal_heading_links.cachedMetadata.links[0];
29-
const link = new Link(rawLink, new TasksFile(internal_heading_links.filePath).filenameWithoutExtension);
32+
const link = getLink(internal_heading_links, 0);
3033

3134
expect(link.originalMarkdown).toEqual('[[#Basic Internal Links]]');
3235
expect(link.destinationFilename).toEqual('internal_heading_links');
3336
});
3437

3538
it('should return the filename of the containing note if the link is internal and has an alias [[#heading|display text]]', () => {
36-
const rawLink = internal_heading_links.cachedMetadata.links[6];
37-
const link = new Link(rawLink, new TasksFile(internal_heading_links.filePath).filenameWithoutExtension);
39+
const link = getLink(internal_heading_links, 6);
3840

3941
expect(link.originalMarkdown).toEqual('[[#Header Links With File Reference]]');
4042
expect(link.destinationFilename).toEqual('internal_heading_links');
4143
});
4244

4345
// Tests checking against __link_in_task_wikilink__
4446
it('should return the filename if simple [[filename]]', () => {
45-
const rawLink = link_in_task_wikilink.cachedMetadata.links[0];
46-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
47+
const link = getLink(link_in_task_wikilink, 0);
4748

4849
expect(link.originalMarkdown).toEqual('[[link_in_task_wikilink]]');
4950
expect(link.destinationFilename).toEqual('link_in_task_wikilink');
5051
});
5152

5253
it('should return the filename if link has a path [[path/filename]]', () => {
53-
const rawLink = link_in_task_wikilink.cachedMetadata.links[2];
54-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
54+
const link = getLink(link_in_task_wikilink, 2);
5555

5656
expect(link.originalMarkdown).toEqual('[[path/link_in_task_wikilink]]');
5757
expect(link.destinationFilename).toEqual('link_in_task_wikilink');
5858
});
5959

6060
it('should return the filename if link has a path and a heading link [[path/filename#heading]]', () => {
61-
const rawLink = link_in_task_wikilink.cachedMetadata.links[3];
62-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
61+
const link = getLink(link_in_task_wikilink, 3);
6362

6463
expect(link.originalMarkdown).toEqual('[[path/link_in_task_wikilink#heading_link]]');
6564
expect(link.destinationFilename).toEqual('link_in_task_wikilink');
6665
});
6766

6867
it('should return the filename if link has an alias [[filename|alias]]', () => {
69-
const rawLink = link_in_task_wikilink.cachedMetadata.links[4];
70-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
68+
const link = getLink(link_in_task_wikilink, 4);
7169

7270
expect(link.originalMarkdown).toEqual('[[link_in_task_wikilink|alias]]');
7371
expect(link.destinationFilename).toEqual('link_in_task_wikilink');
7472
});
7573

7674
it('should return the filename if link has a path and an alias [[path/path/filename|alias]]', () => {
77-
const rawLink = link_in_task_wikilink.cachedMetadata.links[5];
78-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
75+
const link = getLink(link_in_task_wikilink, 5);
7976

8077
expect(link.originalMarkdown).toEqual('[[path/path/link_in_task_wikilink|alias]]');
8178
expect(link.destinationFilename).toEqual('link_in_task_wikilink');
8279
});
8380

8481
// # is a valid character in a filename or a path but Obsidian does not support it in links
8582
it('should return the filename if path contains a # [[pa#th/path/filename]]', () => {
86-
const rawLink = link_in_task_wikilink.cachedMetadata.links[6];
87-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
83+
const link = getLink(link_in_task_wikilink, 6);
8884

8985
expect(link.originalMarkdown).toEqual('[[pa#th/path/link_in_task_wikilink]]');
9086
expect(link.destinationFilename).toEqual('pa');
9187
});
9288

9389
// When grouping a Wikilink link expect [[file.md]] to be grouped with [[file]].
9490
it('should return a filename with no file extension if suffixed with .md [[link_in_task_wikilink.md]]', () => {
95-
const rawLink = link_in_task_wikilink.cachedMetadata.links[7];
96-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
91+
const link = getLink(link_in_task_wikilink, 7);
9792

9893
expect(link.originalMarkdown).toEqual('[[link_in_task_wikilink.md]]');
9994
expect(link.destinationFilename).toEqual('link_in_task_wikilink');
10095
});
10196

10297
it('should return a filename with corresponding file extension if not markdown [[a_pdf_file.pdf]]', () => {
103-
const rawLink = link_in_task_wikilink.cachedMetadata.links[8];
104-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
98+
const link = getLink(link_in_task_wikilink, 8);
10599

106100
expect(link.originalMarkdown).toEqual('[[a_pdf_file.pdf]]');
107101
expect(link.destinationFilename).toEqual('a_pdf_file.pdf');
@@ -111,24 +105,21 @@ describe('linkClass', () => {
111105
// [[]] is not detected by the obsidian parser as a link
112106

113107
it('should provide no special functionality for [[|]]; returns "|")', () => {
114-
const rawLink = link_in_task_wikilink.cachedMetadata.links[9];
115-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
108+
const link = getLink(link_in_task_wikilink, 9);
116109

117110
expect(link.originalMarkdown).toEqual('[[|]]');
118111
expect(link.destinationFilename).toEqual('|');
119112
});
120113

121114
it('should provide no special functionality for [[|alias]]; returns "|alias".)', () => {
122-
const rawLink = link_in_task_wikilink.cachedMetadata.links[10];
123-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
115+
const link = getLink(link_in_task_wikilink, 10);
124116

125117
expect(link.originalMarkdown).toEqual('[[|alias]]');
126118
expect(link.destinationFilename).toEqual('|alias');
127119
});
128120

129121
it('should provide no special functionality for [[|#alias]]; returns "|".)', () => {
130-
const rawLink = link_in_task_wikilink.cachedMetadata.links[11];
131-
const link = new Link(rawLink, new TasksFile(link_in_task_wikilink.filePath).filenameWithoutExtension);
122+
const link = getLink(link_in_task_wikilink, 11);
132123

133124
expect(link.originalMarkdown).toEqual('[[|#alias]]');
134125
expect(link.destinationFilename).toEqual('|');
@@ -141,57 +132,50 @@ describe('linkClass', () => {
141132
// Tests checking against __link_in_task_markdown_link__
142133

143134
it('should return the filename if the link is internal [display name](#heading)', () => {
144-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[8];
145-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
135+
const link = getLink(link_in_task_markdown_link, 8);
146136

147137
expect(link.originalMarkdown).toEqual('[heading](#heading)');
148138
expect(link.destinationFilename).toEqual('link_in_task_markdown_link');
149139
});
150140

151141
it('should return the filename when a simple markdown link [display name](filename)', () => {
152-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[2];
153-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
142+
const link = getLink(link_in_task_markdown_link, 2);
154143

155144
expect(link.originalMarkdown).toEqual('[link_in_task_markdown_link](link_in_task_markdown_link.md)');
156145
expect(link.destinationFilename).toEqual('link_in_task_markdown_link');
157146
});
158147

159148
it('should return the filename if link has a path [link_in_task_markdown_link](path/filename.md)', () => {
160-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[3];
161-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
149+
const link = getLink(link_in_task_markdown_link, 3);
162150

163151
expect(link.originalMarkdown).toEqual('[link_in_task_markdown_link](path/link_in_task_markdown_link.md)');
164152
expect(link.destinationFilename).toEqual('link_in_task_markdown_link');
165153
});
166154

167155
it('should return the filename if link has a path and a heading link [heading_link](path/filename.md#heading)', () => {
168-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[4];
169-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
156+
const link = getLink(link_in_task_markdown_link, 4);
170157

171158
expect(link.originalMarkdown).toEqual('[heading_link](path/link_in_task_markdown_link.md#heading_link)');
172159
expect(link.destinationFilename).toEqual('link_in_task_markdown_link');
173160
});
174161

175162
it('should return the filename if link has an alias [alias](filename.md)', () => {
176-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[5];
177-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
163+
const link = getLink(link_in_task_markdown_link, 5);
178164

179165
expect(link.originalMarkdown).toEqual('[alias](link_in_task_markdown_link.md)');
180166
expect(link.destinationFilename).toEqual('link_in_task_markdown_link');
181167
});
182168

183169
it('should return the filename if link has a path and an alias [alias](path/path/filename.md)', () => {
184-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[6];
185-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
170+
const link = getLink(link_in_task_markdown_link, 6);
186171

187172
expect(link.originalMarkdown).toEqual('[alias](path/path/link_in_task_markdown_link.md)');
188173
expect(link.destinationFilename).toEqual('link_in_task_markdown_link');
189174
});
190175

191176
// # is a valid character in a filename or a path but Obsidian does not support it in links
192177
it('should return the string before the # [link_in_task_markdown_link](pa#th/path/filename.md)', () => {
193-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[7];
194-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
178+
const link = getLink(link_in_task_markdown_link, 7);
195179

196180
expect(link.originalMarkdown).toEqual(
197181
'[link_in_task_markdown_link](pa#th/path/link_in_task_markdown_link.md)',
@@ -201,24 +185,21 @@ describe('linkClass', () => {
201185

202186
// When grouping a Wikilink link expect [[file.md]] to be grouped with [[file]].
203187
it('should return a filename when no .md extension if the .md exists in markdown link [alias](filename)', () => {
204-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[9];
205-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
188+
const link = getLink(link_in_task_markdown_link, 9);
206189

207190
expect(link.originalMarkdown).toEqual('[link_in_task_markdown_link](link_in_task_markdown_link)');
208191
expect(link.destinationFilename).toEqual('link_in_task_markdown_link');
209192
});
210193

211194
it('should return a filename with corresponding file extension if not markdown [a_pdf_file](a_pdf_file.pdf)', () => {
212-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[10];
213-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
195+
const link = getLink(link_in_task_markdown_link, 10);
214196

215197
expect(link.originalMarkdown).toEqual('[a_pdf_file](a_pdf_file.pdf)');
216198
expect(link.destinationFilename).toEqual('a_pdf_file.pdf');
217199
});
218200

219201
it('should handle spaces in the path, filename, and heading link [heading link](path/filename with spaces.md#heading link)', () => {
220-
const rawLink = link_in_task_markdown_link.cachedMetadata.links[11];
221-
const link = new Link(rawLink, new TasksFile(link_in_task_markdown_link.filePath).filenameWithoutExtension);
202+
const link = getLink(link_in_task_markdown_link, 11);
222203

223204
expect(link.originalMarkdown).toEqual(
224205
'[spaces everywhere](Test%20Data/spaced%20filename%20link.md#spaced%20heading)',

0 commit comments

Comments
 (0)