Skip to content

Commit bd9cf6c

Browse files
authored
Merge pull request #3195 from obsidian-tasks-group/explore-accessing-links
test: Add some example code to explore accessing links
2 parents 1e06f18 + e7a2cb8 commit bd9cf6c

File tree

10 files changed

+747
-1
lines changed

10 files changed

+747
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# link_in_task_html
2+
3+
- [ ] #task Task in 'link_in_task_html' - see the [Tasks Documentation](https://publish.obsidian.md/tasks/Introduction)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# link_in_task_markdown_link
2+
3+
- [ ] #task Task in 'link_in_task_markdown_link' [jason_properties](jason_properties) [multiple_headings](multiple_headings)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# link_in_task_wikilink
2+
3+
- [ ] #task Task in 'link_in_task_wikilink' [[link_in_task_wikilink]] [[multiple_headings]]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
link-in-frontmatter: "[[link_in_yaml]]"
3+
---
4+
# links_everywhere
5+
6+
A link in the file body: [[link_in_file_body]]
7+
8+
## A link in a [[link_in_heading]]
9+
10+
- [ ] #task Task in 'links_everywhere' - a link on the task: [[link_in_task_wikilink]]

tests/Obsidian/AllCacheSampleData.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ import jason_properties from './__test_data__/jason_properties.json';
3636
import link_in_file_body from './__test_data__/link_in_file_body.json';
3737
import link_in_file_body_with_custom_display_text from './__test_data__/link_in_file_body_with_custom_display_text.json';
3838
import link_in_heading from './__test_data__/link_in_heading.json';
39+
import link_in_task_html from './__test_data__/link_in_task_html.json';
40+
import link_in_task_markdown_link from './__test_data__/link_in_task_markdown_link.json';
41+
import link_in_task_wikilink from './__test_data__/link_in_task_wikilink.json';
3942
import link_in_yaml from './__test_data__/link_in_yaml.json';
4043
import link_is_broken from './__test_data__/link_is_broken.json';
44+
import links_everywhere from './__test_data__/links_everywhere.json';
4145
import list_statuses from './__test_data__/list_statuses.json';
4246
import list_styles from './__test_data__/list_styles.json';
4347
import multi_line_task_and_list_item from './__test_data__/multi_line_task_and_list_item.json';
@@ -101,8 +105,12 @@ export function allCacheSampleData() {
101105
link_in_file_body,
102106
link_in_file_body_with_custom_display_text,
103107
link_in_heading,
108+
link_in_task_html,
109+
link_in_task_markdown_link,
110+
link_in_task_wikilink,
104111
link_in_yaml,
105112
link_is_broken,
113+
links_everywhere,
106114
list_statuses,
107115
list_styles,
108116
multi_line_task_and_list_item,

tests/Obsidian/Cache.test.ts

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* @jest-environment jsdom
33
*/
44
import moment from 'moment/moment';
5+
import type { CachedMetadata } from 'obsidian';
56
import type { ListItem } from '../../src/Task/ListItem';
67
import { getTasksFileFromMockData, listPathAndData } from '../TestingTools/MockDataHelpers';
78
import inheritance_1parent1child from './__test_data__/inheritance_1parent1child.json';
@@ -29,8 +30,9 @@ import callout from './__test_data__/callout.json';
2930
import callout_labelled from './__test_data__/callout_labelled.json';
3031
import callout_custom from './__test_data__/callout_custom.json';
3132
import callouts_nested_issue_2890_unlabelled from './__test_data__/callouts_nested_issue_2890_unlabelled.json';
33+
import links_everywhere from './__test_data__/links_everywhere.json';
3234
import { allCacheSampleData } from './AllCacheSampleData';
33-
import { readTasksFromSimulatedFile } from './SimulatedFile';
35+
import { type SimulatedFile, readTasksFromSimulatedFile } from './SimulatedFile';
3436

3537
window.moment = moment;
3638

@@ -604,6 +606,130 @@ describe('cache', () => {
604606
});
605607
});
606608

609+
describe('accessing links in file', function () {
610+
describe('explore accessing links in file "links_everywhere.md"', () => {
611+
const data = links_everywhere as unknown as SimulatedFile;
612+
613+
const tasks = readTasksFromSimulatedFile(data);
614+
expect(tasks.length).toEqual(1);
615+
const task = tasks[0];
616+
617+
const cachedMetadata: CachedMetadata = task.file.cachedMetadata;
618+
619+
/**
620+
* I am thinking of the following, to evantually make links accessible to users.
621+
* 1. Provide a class or interface called Link, with fields:
622+
* - displayText, e.g. "link_in_yaml"
623+
* - link, e.g. "link_in_yaml"
624+
* - original, e.g. "[[link_in_yaml]]"
625+
* 2. Add some getters that construct the relevant Link objects from cached metadata on demand, such as:
626+
* - task.file.linksInBody
627+
* - task.file.linksInFrontMatter
628+
* - task.file.allLinks
629+
* - task.links
630+
* 3. Consider the vocabulary - some dataview users talk about inlines and outlinks.
631+
* The above are all outlinks - but do we want to name them as such, to prepare
632+
* for if or when inlinks are also supported?
633+
*/
634+
635+
it('see source', () => {
636+
expect(data.fileContents).toMatchInlineSnapshot(`
637+
"---
638+
link-in-frontmatter: "[[link_in_yaml]]"
639+
---
640+
# links_everywhere
641+
642+
A link in the file body: [[link_in_file_body]]
643+
644+
## A link in a [[link_in_heading]]
645+
646+
- [ ] #task Task in 'links_everywhere' - a link on the task: [[link_in_task_wikilink]]
647+
"
648+
`);
649+
});
650+
651+
it('should access links in frontmatter', () => {
652+
// Update to Obsidian API 1.4.0 to access cachedMetadata.frontmatterLinks
653+
// @ts-expect-error TS2551: Property frontmatterLinks does not exist on type CachedMetadata
654+
const frontMatterLinks = cachedMetadata['frontmatterLinks'];
655+
expect(frontMatterLinks).toBeDefined();
656+
657+
const firstFrontMatterLink = frontMatterLinks![0];
658+
expect(firstFrontMatterLink.original).toEqual('[[link_in_yaml]]');
659+
expect(firstFrontMatterLink).toMatchInlineSnapshot(`
660+
{
661+
"displayText": "link_in_yaml",
662+
"key": "link-in-frontmatter",
663+
"link": "link_in_yaml",
664+
"original": "[[link_in_yaml]]",
665+
}
666+
`);
667+
});
668+
669+
it('should access links in file body', () => {
670+
const fileBodyLinks = cachedMetadata.links;
671+
672+
const originalLinkText = fileBodyLinks?.map((link) => link.original).join('\n');
673+
expect(originalLinkText).toMatchInlineSnapshot(`
674+
"[[link_in_file_body]]
675+
[[link_in_heading]]
676+
[[link_in_task_wikilink]]"
677+
`);
678+
679+
const firstFileBodyLink = fileBodyLinks![0];
680+
expect(firstFileBodyLink).toMatchInlineSnapshot(`
681+
{
682+
"displayText": "link_in_file_body",
683+
"link": "link_in_file_body",
684+
"original": "[[link_in_file_body]]",
685+
"position": {
686+
"end": {
687+
"col": 46,
688+
"line": 5,
689+
"offset": 114,
690+
},
691+
"start": {
692+
"col": 25,
693+
"line": 5,
694+
"offset": 93,
695+
},
696+
},
697+
}
698+
`);
699+
});
700+
701+
it('should access links in task line', () => {
702+
const fileBodyLinks = cachedMetadata.links;
703+
const linksOnTask = fileBodyLinks?.filter((link) => link.position.start.line === task.lineNumber);
704+
705+
expect(linksOnTask).toBeDefined();
706+
expect(linksOnTask?.length).toEqual(1);
707+
708+
const firstLinkOnTask = linksOnTask![0];
709+
expect(firstLinkOnTask.original).toEqual('[[link_in_task_wikilink]]');
710+
expect(firstLinkOnTask).toMatchInlineSnapshot(`
711+
{
712+
"displayText": "link_in_task_wikilink",
713+
"link": "link_in_task_wikilink",
714+
"original": "[[link_in_task_wikilink]]",
715+
"position": {
716+
"end": {
717+
"col": 86,
718+
"line": 9,
719+
"offset": 238,
720+
},
721+
"start": {
722+
"col": 61,
723+
"line": 9,
724+
"offset": 213,
725+
},
726+
},
727+
}
728+
`);
729+
});
730+
});
731+
});
732+
607733
describe('all mock files', () => {
608734
const files: any = allCacheSampleData();
609735

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
{
2+
"cachedMetadata": {
3+
"headings": [
4+
{
5+
"heading": "link_in_task_html",
6+
"level": 1,
7+
"position": {
8+
"end": {
9+
"col": 19,
10+
"line": 0,
11+
"offset": 19
12+
},
13+
"start": {
14+
"col": 0,
15+
"line": 0,
16+
"offset": 0
17+
}
18+
}
19+
}
20+
],
21+
"listItems": [
22+
{
23+
"parent": -2,
24+
"position": {
25+
"end": {
26+
"col": 119,
27+
"line": 2,
28+
"offset": 140
29+
},
30+
"start": {
31+
"col": 0,
32+
"line": 2,
33+
"offset": 21
34+
}
35+
},
36+
"task": " "
37+
}
38+
],
39+
"sections": [
40+
{
41+
"position": {
42+
"end": {
43+
"col": 19,
44+
"line": 0,
45+
"offset": 19
46+
},
47+
"start": {
48+
"col": 0,
49+
"line": 0,
50+
"offset": 0
51+
}
52+
},
53+
"type": "heading"
54+
},
55+
{
56+
"position": {
57+
"end": {
58+
"col": 119,
59+
"line": 2,
60+
"offset": 140
61+
},
62+
"start": {
63+
"col": 0,
64+
"line": 2,
65+
"offset": 21
66+
}
67+
},
68+
"type": "list"
69+
}
70+
],
71+
"tags": [
72+
{
73+
"position": {
74+
"end": {
75+
"col": 11,
76+
"line": 2,
77+
"offset": 32
78+
},
79+
"start": {
80+
"col": 6,
81+
"line": 2,
82+
"offset": 27
83+
}
84+
},
85+
"tag": "#task"
86+
}
87+
]
88+
},
89+
"fileContents": "# link_in_task_html\n\n- [ ] #task Task in 'link_in_task_html' - see the [Tasks Documentation](https://publish.obsidian.md/tasks/Introduction)\n",
90+
"filePath": "Test Data/link_in_task_html.md",
91+
"getAllTags": [
92+
"#task"
93+
],
94+
"obsidianApiVersion": "1.7.7",
95+
"parseFrontMatterTags": null
96+
}

0 commit comments

Comments
 (0)