Skip to content

Commit 7a67173

Browse files
feat: Add ability to filter and group by linked note (#3466)
* feat: Add access to links in body of note Co-Authored-By: rhhub <[email protected]> * feat: Add task.links, to access links on task line Co-Authored-By: rhhub <[email protected]> * Added experimental Link class. * Added destination and displayText getters to Link class. * chore: add Test-TasksInLocalObsidian.bat * refactor: . moved Link class to own file * test: - Move link test to appropiate file. * refactor: - ListItem.links now returns Link object * refactor: . rename ListItem.links to .outLinks * feat: added TasksFile.outLinks * refactor: - change return type of get outLinks to Link * create script for running hot reload plugins * Renamed and added comments. * update to accept multiple target vaults, group repo settings, clean up comments * Fix splitting, add notes. * feat: Create destinationFilename getter. * test: ensure ListItem.outlinks return empty array when no links on line * feat: link.destinationFilename now handles internal heading links * test: add test for internal alias link * chore - Add .yarn to .gitignore * fix - ensure validation works correctly * feat: handle wikilink with path * perf: increased performande of destinationFilename() * test: test destinationFilename for wikilink with path and heading link * test: add case for alias in destinationFilename * test: add path/path and alias case for destinationFilename * feat: handle # in path * fix: don't handle # in path * test: add 2 more tests * chore: add link_in_task_wikilink for the prior tests * feat: remove .md from destinationFilename() and refactor * test: basic wikilink * feat: handle markdown links * test: add more test cases for markdown links * test: destinationFilename empty links and cleanup * refactor: headings * chore: clean up * refactor: use slice * refactor: clean up * chore: feat-access-links depends on generating these * refactor: clean up and comment * test: Push to test script on macbook. * Revert "test: Push to test script on macbook." This reverts commit 765aa4e. * temp to track * pull: untrack Untitled.md * pull: git rm --cached .\scripts\Test-TasksInLocalObsidianCrossPlatform.ps1 * pull: make more readable * test: add test to ensure no links from yaml section and rename test * pull: make first line level 1 heading * refactor: rename to rawLinksInFileBody --------- Co-authored-by: Clare Macrae <[email protected]>
1 parent 69d6bf8 commit 7a67173

File tree

12 files changed

+2564
-99
lines changed

12 files changed

+2564
-99
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
# npm
66
node_modules
7+
.yarn
78
yarn-error.log
89

910
# build
Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,51 @@
11
# link_in_task_markdown_link
22

3-
- [ ] #task Task in 'link_in_task_markdown_link' [jason_properties](jason_properties) [multiple_headings](multiple_headings)
3+
## Multiple Links
4+
5+
- [ ] #task Multiple Links [jason_properties](jason_properties.md) [multiple_headings](multiple_headings.md)
6+
7+
## Link with Simple Link
8+
9+
- [ ] #task Link with Markdown Extension [link_in_task_markdown_link](link_in_task_markdown_link.md)
10+
11+
## Link with Path
12+
13+
- [ ] #task Link with Path [link_in_task_markdown_link](path/link_in_task_markdown_link.md)
14+
15+
## Link with Path Heading Link
16+
17+
- [ ] #task Link with Heading Reference Link [heading_link](path/link_in_task_markdown_link.md#heading_link)
18+
19+
## Link with Alias
20+
21+
- [ ] #task Link with Alias [alias](link_in_task_markdown_link.md)
22+
23+
## Link with Nested Path and Alias
24+
25+
- [ ] #task Link with Nested Path and Alias [alias](path/path/link_in_task_markdown_link.md)
26+
27+
## Link with Hash in Path
28+
29+
- [ ] #task Heading Link with text that looks like a path [link_in_task_markdown_link](pa#th/path/link_in_task_markdown_link.md)
30+
31+
## Link with Internal Link
32+
33+
- [ ] #task Link with Internal Link [heading](#heading)
34+
35+
## Link with Markdown Link No Suffix
36+
37+
- [ ] #task Link with Markdown Link No Suffix [link_in_task_markdown_link](link_in_task_markdown_link)
38+
39+
## Link with PDF File
40+
41+
- [ ] #task Link with PDF File [a_pdf_file](a_pdf_file.pdf)
42+
43+
## Link with Spaces
44+
45+
- [ ] Link with spaces everywhere[spaces everywhere](Test%20Data/spaced%20filename%20link.md#spaced%20heading)
46+
47+
## Empty Links That Aren't Processed
48+
49+
- [ ] #task Link with empty link []()
50+
- [ ] #task Link with empty link [alias]()
51+
Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
11
# link_in_task_wikilink
22

3-
- [ ] #task Task in 'link_in_task_wikilink' [[link_in_task_wikilink]] [[multiple_headings]]
3+
## Multiple
4+
5+
- [ ] #task Link with Multiple Wikilinks [[link_in_task_wikilink]] [[multiple_headings]]
6+
7+
## Link with Simple Path
8+
9+
- [ ] #task Link with Simple Path [[path/link_in_task_wikilink]]
10+
11+
## Link with Heading Reference
12+
13+
- [ ] #task Link with Heading Reference [[path/link_in_task_wikilink#heading_link]]
14+
15+
## Link with Alias
16+
17+
- [ ] #task Link with Alias [[link_in_task_wikilink|alias]]
18+
19+
## Link with Nested Path and Alias
20+
21+
- [ ] #task Link with Nested Path and Alias [[path/path/link_in_task_wikilink|alias]]
22+
23+
## Link with Hash in Path
24+
25+
- [ ] #task Link with Hash in Path [[pa#th/path/link_in_task_wikilink]]
26+
27+
## Link with Markdown File Extension
28+
29+
- [ ] #task Link with Markdown File Extension [[link_in_task_wikilink.md]]
30+
31+
## Link with PDF File
32+
33+
- [ ] #task Link with PDF File [[a_pdf_file.pdf]]
34+
35+
## Empty Link That Obsidian Doesn't Parse
36+
37+
- [ ] #task Link with empty link [[]]
38+
39+
## Empty Links That Obsidian Parses
40+
41+
- [ ] #task Link with empty link [[|]]
42+
- [ ] #task Link with empty link [[|alias]]
43+
- [ ] #task Link with empty link [[|#alias]]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
rem Should be run from root of repository
2+
copy "main.js" "resources\sample_vaults\Tasks-Demo\.obsidian\plugins\obsidian-tasks-plugin\"
3+
copy "manifest.json" "resources\sample_vaults\Tasks-Demo\.obsidian\plugins\obsidian-tasks-plugin\"
4+
copy "styles.css" "resources\sample_vaults\Tasks-Demo\.obsidian\plugins\obsidian-tasks-plugin\"
5+

src/Scripting/TasksFile.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { type CachedMetadata, type FrontMatterCache, getAllTags, parseFrontMatterTags } from 'obsidian';
2+
import { Link } from '../Task/Link';
23

34
export type OptionalTasksFile = TasksFile | undefined;
45

@@ -49,6 +50,13 @@ export class TasksFile {
4950
return this._tags;
5051
}
5152

53+
/**
54+
* Return a array of Link in the body of the file.
55+
*/
56+
get outLinks(): Link[] {
57+
return this.cachedMetadata?.links?.map((link) => new Link(link, this.filenameWithoutExtension)) ?? [];
58+
}
59+
5260
/**
5361
* Return Obsidian's [CachedMetadata](https://docs.obsidian.md/Reference/TypeScript+API/CachedMetadata)
5462
* for this file, if available.

src/Task/Link.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { LinkCache } from 'obsidian';
2+
3+
export class Link {
4+
private rawLink: LinkCache;
5+
private filename: string;
6+
7+
/**
8+
* @param {LinkCache} rawLink - The raw link from Obsidian cache.
9+
* @param {string} filename - The name of the file where this link is located.
10+
*/
11+
constructor(rawLink: LinkCache, filename: string) {
12+
this.rawLink = rawLink;
13+
this.filename = filename;
14+
}
15+
16+
public get originalMarkdown() {
17+
return this.rawLink.original;
18+
}
19+
20+
public get destination() {
21+
return this.rawLink.link;
22+
}
23+
24+
/**
25+
* Returns the filename of the link destination without the path or alias
26+
* Removes the .md extension if present leaves other extensions intact.
27+
* No accomodation for empty links.
28+
* @returns {string}
29+
*/
30+
public get destinationFilename() {
31+
// Handle internal links (starting with '#')
32+
if (this.destination[0] === '#') return this.filename;
33+
34+
// Extract filename from path (handles both path and optional hash fragment)
35+
const pathPart = this.destination.split('#', 1)[0];
36+
const destFilename = pathPart.substring(pathPart.lastIndexOf('/') + 1);
37+
38+
// Remove.md extension if present
39+
return destFilename.endsWith('.md') ? destFilename.slice(0, -3) : destFilename;
40+
}
41+
42+
public get displayText() {
43+
return this.rawLink.displayText;
44+
}
45+
}

src/Task/ListItem.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LinkCache } from 'obsidian';
12
import type { TasksFile } from '../Scripting/TasksFile';
23
import type { Task } from './Task';
34
import type { TaskLocation } from './TaskLocation';
45
import { TaskRegularExpressions } from './TaskRegularExpressions';
6+
import { Link } from './Link';
57

68
export class ListItem {
79
// The original line read from file.
@@ -191,6 +193,26 @@ export class ListItem {
191193
return this.taskLocation.tasksFile;
192194
}
193195

196+
/**
197+
* Return a list of links in the body of the file containing
198+
* the task or list item.
199+
*
200+
* The data contest is documented here:
201+
* https://docs.obsidian.md/Reference/TypeScript+API/LinkCache
202+
*/
203+
get rawLinksInFileBody(): LinkCache[] {
204+
return this.file.cachedMetadata?.links ?? [];
205+
}
206+
207+
/**
208+
* Return a list of links in the task or list item's line.
209+
*/
210+
public get outLinks(): Link[] {
211+
return this.rawLinksInFileBody
212+
.filter((link) => link.position.start.line === this.lineNumber)
213+
.map((link) => new Link(link, this.file.filenameWithoutExtension));
214+
}
215+
194216
/**
195217
* Return the name of the file containing this object, with the .md extension removed.
196218
*/

0 commit comments

Comments
 (0)