Skip to content

Commit

Permalink
Integrate explicit type modifiers to wikilink syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
badsketch committed Sep 1, 2023
1 parent a9b9417 commit dfd01de
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 5 deletions.
76 changes: 76 additions & 0 deletions packages/foam-vscode/src/features/preview/wikilink-embed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,82 @@ This is the first subsection of note E`,
await deleteFile(note);
});

it('should allow a note embedding type to be overridden if a modifier is passed in', async () => {
const note = await createFile(
`
# Section 1
This is the first section of note E
# Section 2
This is the second section of note E
# Section 3
This is the third section of note E
`,
['note-e.md']
);
const parser = createMarkdownParser([]);
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);

await withModifiedFoamConfiguration(
CONFIG_EMBED_NOTE_TYPE,
'full-inline',
() => {
expect(
md.render(`This is the root node.
content![[note-e#Section 2]]
full![[note-e#Section 3]]`)
).toMatch(
`<p>This is the root node.</p>
<p><p>This is the second section of note E</p>
</p>
<p><h1>Section 3</h1>
<p>This is the third section of note E</p>
</p>
`
);
}
);

await deleteFile(note);
});

it('should allow a note embedding type to be overridden if two modifiers are passed in', async () => {
const note = await createFile(
`
# Section 1
This is the first section of note E
# Section 2
This is the second section of note E
`,
['note-e.md']
);
const parser = createMarkdownParser([]);
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);

await withModifiedFoamConfiguration(
CONFIG_EMBED_NOTE_TYPE,
'full-inline',
() => {
const res = md.render(`This is the root node.
content-card![[note-e#Section 2]]`);

expect(res).toContain('This is the root node');
expect(res).toContain('embed-container-note');
expect(res).toContain('This is the second section of note E');
expect(res).not.toContain('Section 2');
}
);

await deleteFile(note);
});

it('should fallback to the bare text when the note is not found', () => {
const md = markdownItWikilinkEmbed(
MarkdownIt(),
Expand Down
54 changes: 53 additions & 1 deletion packages/foam-vscode/src/features/preview/wikilink-embed.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,63 @@
import { retrieveNoteConfig } from './wikilink-embed';
import {
WIKILINK_EMBED_REGEX,
WIKILINK_EMBED_REGEX_GROUPS,
retrieveNoteConfig,
} from './wikilink-embed';
import * as config from '../../services/config';

describe('Wikilink Note Embedding', () => {
afterEach(() => {
jest.clearAllMocks();
});

describe('Wikilink Parsing', () => {
it('should match a wikilink item including a modifier and wikilink', () => {
// no configuration
expect('![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);

// one of the configurations
expect('full![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
expect('content![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
expect('inline![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
expect('card![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);

// any combination of configurations
expect('full-inline![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
expect('full-card![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
expect('content-inline![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
expect('content-card![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
});

it('should only match the wikilink if there are unrecognized keywords', () => {
const match1 = 'random-word![[note-a]]'.match(WIKILINK_EMBED_REGEX);
expect(match1[0]).toEqual('![[note-a]]');
expect(match1[1]).toEqual('![[note-a]]');

const match2 = 'foo![[note-a#section 1]]'.match(WIKILINK_EMBED_REGEX);
expect(match2[0]).toEqual('![[note-a#section 1]]');
expect(match2[1]).toEqual('![[note-a#section 1]]');
});

it('should group the wikilink into modifier and wikilink', () => {
const match1 = 'content![[note-a]]'.match(WIKILINK_EMBED_REGEX_GROUPS);
expect(match1[0]).toEqual('content![[note-a]]');
expect(match1[1]).toEqual('content');
expect(match1[2]).toEqual('note-a');

const match2 = 'full-inline![[note-a#section 1]]'.match(
WIKILINK_EMBED_REGEX_GROUPS
);
expect(match2[0]).toEqual('full-inline![[note-a#section 1]]');
expect(match2[1]).toEqual('full-inline');
expect(match2[2]).toEqual('note-a#section 1');

const match3 = '![[note-a#section 1]]'.match(WIKILINK_EMBED_REGEX_GROUPS);
expect(match3[0]).toEqual('![[note-a#section 1]]');
expect(match3[1]).toEqual(undefined);
expect(match3[2]).toEqual('note-a#section 1');
});
});

describe('Config Parsing', () => {
it('should use preview.embedNoteType if an explicit modifier is not passed in', () => {
jest
Expand Down
20 changes: 16 additions & 4 deletions packages/foam-vscode/src/features/preview/wikilink-embed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ import { MarkdownLink } from '../../core/services/markdown-link';
import { Position } from '../../core/model/position';
import { TextEdit } from '../../core/services/text-edit';

export const WIKILINK_EMBED_REGEX =
/((?:(?:full|content)-(?:inline|card)|full|content|inline|card)?!\[\[[^[\]]+?\]\])/;
// we need another regex because md.use(regex, replace) only permits capturing one group
// so we capture the entire possible wikilink item (ex. content-card![[note]]) using WIKILINK_EMBED_REGEX and then
// use WIKILINK_EMBED_REGEX_GROUPER to parse it into the modifier(content-card) and the wikilink(note)
export const WIKILINK_EMBED_REGEX_GROUPS =
/((?:\w+)|(?:(?:\w+)-(?:\w+)))?!\[\[([^[\]]+?)\]\]/;
export const CONFIG_EMBED_NOTE_TYPE = 'preview.embedNoteType';
const refsStack: string[] = [];

Expand All @@ -24,9 +31,13 @@ export const markdownItWikilinkEmbed = (
) => {
return md.use(markdownItRegex, {
name: 'embed-wikilinks',
regex: /!\[\[([^[\]]+?)\]\]/,
replace: (wikilink: string) => {
regex: WIKILINK_EMBED_REGEX,
replace: (wikilinkItem: string) => {
try {
const [_, noteEmbedModifier, wikilink] = wikilinkItem.match(
WIKILINK_EMBED_REGEX_GROUPS
);

const includedNote = workspace.find(wikilink);

if (!includedNote) {
Expand All @@ -49,7 +60,8 @@ export const markdownItWikilinkEmbed = (

switch (includedNote.type) {
case 'note': {
const { noteScope, noteStyle } = retrieveNoteConfig(undefined);
const { noteScope, noteStyle } =
retrieveNoteConfig(noteEmbedModifier);

const extractor: EmbedNoteExtractor =
noteScope === 'full'
Expand Down Expand Up @@ -88,7 +100,7 @@ Embed for attachments is not supported
return html;
} catch (e) {
Logger.error(
`Error while including [[${wikilink}]] into the current document of the Preview panel`,
`Error while including ${wikilinkItem} into the current document of the Preview panel`,
e
);
return '';
Expand Down

0 comments on commit dfd01de

Please sign in to comment.