feat(knowledge): add link resolution service
- Add resolveLinksFromContent() to parse wiki links from content and resolve them - Add getBacklinks() to find all entries that link to a target entry - Import parseWikiLinks from utils for content parsing - Export new types: ResolvedLink, Backlink - Add comprehensive tests for new functionality (27 tests total)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaService } from "../../prisma/prisma.service";
|
||||
import { parseWikiLinks, WikiLink } from "../utils/wiki-link-parser";
|
||||
|
||||
/**
|
||||
* Represents a knowledge entry that matches a link target
|
||||
@@ -9,6 +10,32 @@ export interface ResolvedEntry {
|
||||
title: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a resolved wiki link with entry information
|
||||
*/
|
||||
export interface ResolvedLink {
|
||||
/** The parsed wiki link */
|
||||
link: WikiLink;
|
||||
/** The resolved entry ID, or null if not found */
|
||||
entryId: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a backlink - an entry that links to a target entry
|
||||
*/
|
||||
export interface Backlink {
|
||||
/** The source entry ID */
|
||||
sourceId: string;
|
||||
/** The source entry title */
|
||||
sourceTitle: string;
|
||||
/** The source entry slug */
|
||||
sourceSlug: string;
|
||||
/** The link text used to reference the target */
|
||||
linkText: string;
|
||||
/** The display text shown for the link */
|
||||
displayText: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service for resolving wiki-style links to knowledge entries
|
||||
*
|
||||
@@ -165,4 +192,72 @@ export class LinkResolutionService {
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse wiki links from content and resolve them to knowledge entries
|
||||
*
|
||||
* @param content - The markdown content containing wiki links
|
||||
* @param workspaceId - The workspace scope for resolution
|
||||
* @returns Array of resolved links with entry IDs (or null if not found)
|
||||
*/
|
||||
async resolveLinksFromContent(
|
||||
content: string,
|
||||
workspaceId: string
|
||||
): Promise<ResolvedLink[]> {
|
||||
// Parse wiki links from content
|
||||
const parsedLinks = parseWikiLinks(content);
|
||||
|
||||
if (parsedLinks.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Resolve each link
|
||||
const resolvedLinks: ResolvedLink[] = [];
|
||||
|
||||
for (const link of parsedLinks) {
|
||||
const entryId = await this.resolveLink(workspaceId, link.target);
|
||||
resolvedLinks.push({
|
||||
link,
|
||||
entryId,
|
||||
});
|
||||
}
|
||||
|
||||
return resolvedLinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all entries that link TO a specific entry (backlinks)
|
||||
*
|
||||
* @param entryId - The target entry ID
|
||||
* @returns Array of backlinks with source entry information
|
||||
*/
|
||||
async getBacklinks(entryId: string): Promise<Backlink[]> {
|
||||
// Find all links where this entry is the target
|
||||
const links = await this.prisma.knowledgeLink.findMany({
|
||||
where: {
|
||||
targetId: entryId,
|
||||
resolved: true,
|
||||
},
|
||||
include: {
|
||||
source: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
|
||||
return links.map((link) => ({
|
||||
sourceId: link.source.id,
|
||||
sourceTitle: link.source.title,
|
||||
sourceSlug: link.source.slug,
|
||||
linkText: link.linkText,
|
||||
displayText: link.displayText,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user