test(server/note_map): backlinks with excerpts

This commit is contained in:
Elian Doran 2025-09-28 17:12:01 +03:00
parent 614a8f177c
commit 151a2c284d
No known key found for this signature in database
3 changed files with 192 additions and 1 deletions

View File

@ -0,0 +1,99 @@
import { trimIndentation } from "@triliumnext/commons";
import { buildNote, buildNotes } from "../../test/becca_easy_mocking";
import note_map from "./note_map";
describe("Note map service", () => {
it("correctly identifies backlinks", () => {
const note = buildNote({ id: "dUtgloZIckax", title: "Backlink text" });
buildNotes([
{
title: "First",
id: "first",
"~internalLink": "dUtgloZIckax",
content: trimIndentation`\
<p>
The quick brownie
</p>
<p>
<a class="reference-link" href="#root/dUtgloZIckax">
Backlink text
</a>
</p>
<figure class="image">
<img style="aspect-ratio:960/1280;" src="api/attachments/llY9IHS3ZSqE/image/5877566469045340078_121.jpg" width="960" height="1280">
</figure>
`
},
{
title: "Second",
id: "second",
"~internalLink": "dUtgloZIckax",
content: trimIndentation`\
<p>
<a class="reference-link" href="#root/dUtgloZIckax">
Backlink text
</a>
</p>
<p>
<a class="reference-link" href="#root/dUtgloZIckax/wsq5D7wgKWrg">
First
</a>
</p>
<p>
<a class="reference-link" href="#root/dUtgloZIckax/TvyONGWYgV7N">
Second
</a>
</p>
`
}
]);
const backlinksResponse = note_map.getBacklinks({
params: {
noteId: note.noteId
}
} as any);
expect(backlinksResponse).toMatchObject([
{
excerpts: [
trimIndentation`\
<div class="ck-content backlink-excerpt"><head></head><body><p>
The quick brownie
</p>
<p>
<a class="reference-link backlink-link" href="#root/dUtgloZIckax">
Backlink text
</a>
</p>
<figure class="image">
${" "}
</figure>
</body></div>`
],
noteId: "first",
},
{
excerpts: [
trimIndentation`\
<div class="ck-content backlink-excerpt"><head></head><body><p>
<a class="reference-link backlink-link" href="#root/dUtgloZIckax">
Backlink text
</a>
</p>
<p>
<a class="reference-link" href="#root/dUtgloZIckax/wsq5D7wgKWrg">
First
</a>
</p>
<p>
<a class="reference-link" href="#root/dUtgloZIckax/TvyONGWYgV7N">
Second
</a>
</p>
</body></div>`
],
noteId: "second"
}
]);
});
});

View File

@ -251,7 +251,7 @@ function removeImages(document: Document) {
const EXCERPT_CHAR_LIMIT = 200; const EXCERPT_CHAR_LIMIT = 200;
type ElementOrText = Element | Text; type ElementOrText = Element | Text;
function findExcerpts(sourceNote: BNote, referencedNoteId: string) { export function findExcerpts(sourceNote: BNote, referencedNoteId: string) {
const html = sourceNote.getContent(); const html = sourceNote.getContent();
const document = new JSDOM(html).window.document; const document = new JSDOM(html).window.document;

View File

@ -0,0 +1,92 @@
import utils from "../services/utils.js";
import BNote from "../becca/entities/bnote.js";
import BAttribute from "../becca/entities/battribute.js";
type AttributeDefinitions = { [key in `#${string}`]: string; };
type RelationDefinitions = { [key in `~${string}`]: string; };
interface NoteDefinition extends AttributeDefinitions, RelationDefinitions {
id?: string | undefined;
title: string;
content?: string;
}
/**
* Creates the given notes with the given title and optionally one or more attributes.
*
* For a label to be created, simply pass on a key prefixed with `#` and any desired value.
*
* The notes and attributes will be injected in the froca.
*
* @param notes
* @returns an array containing the IDs of the created notes.
* @example
* buildNotes([
* { title: "A", "#startDate": "2025-05-05" },
* { title: "B", "#startDate": "2025-05-07" }
* ]);
*/
export function buildNotes(notes: NoteDefinition[]) {
const ids: string[] = [];
for (const noteDef of notes) {
ids.push(buildNote(noteDef).noteId);
}
return ids;
}
export function buildNote(noteDef: NoteDefinition) {
const note = new BNote({
noteId: noteDef.id ?? utils.randomString(12),
title: noteDef.title,
type: "text",
mime: "text/html",
isProtected: false,
blobId: ""
});
// Handle content.
if (noteDef.content) {
note.getContent = () => noteDef.content!;
}
// Handle labels and relations.
let position = 0;
for (const [ key, value ] of Object.entries(noteDef)) {
const attributeId = utils.randomString(12);
const name = key.substring(1);
let attribute: BAttribute | null = null;
if (key.startsWith("#")) {
attribute = new BAttribute({
noteId: note.noteId,
attributeId,
type: "label",
name,
value,
position,
isInheritable: false
});
}
if (key.startsWith("~")) {
attribute = new BAttribute({
noteId: note.noteId,
attributeId,
type: "relation",
name,
value,
position,
isInheritable: false
});
}
if (!attribute) {
continue;
}
position++;
}
return note;
}