feat(knowledge): add markdown rendering (KNOW-004)
- Install marked, marked-highlight, marked-gfm-heading-id, sanitize-html - Create markdown utility with GFM support (tables, task lists, strikethrough) - Add code syntax highlighting with highlight.js - Implement XSS sanitization for security - Update knowledge service to use markdown renderer - Add comprehensive test suite (34 tests, all passing) - Generate IDs for headers for deep linking - Cache rendered HTML in database for performance
This commit is contained in:
@@ -4,7 +4,6 @@ import {
|
||||
ConflictException,
|
||||
} from "@nestjs/common";
|
||||
import { EntryStatus } from "@prisma/client";
|
||||
import { marked } from "marked";
|
||||
import slugify from "slugify";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
import type { CreateEntryDto, UpdateEntryDto, EntryQueryDto } from "./dto";
|
||||
@@ -12,20 +11,15 @@ import type {
|
||||
KnowledgeEntryWithTags,
|
||||
PaginatedEntries,
|
||||
} from "./entities/knowledge-entry.entity";
|
||||
import { renderMarkdown } from "./utils/markdown";
|
||||
|
||||
/**
|
||||
* Service for managing knowledge entries
|
||||
*/
|
||||
@Injectable()
|
||||
export class KnowledgeService {
|
||||
constructor(private readonly prisma: PrismaService) {
|
||||
// Configure marked for security and consistency
|
||||
marked.setOptions({
|
||||
gfm: true, // GitHub Flavored Markdown
|
||||
breaks: false,
|
||||
pedantic: false,
|
||||
});
|
||||
}
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
|
||||
/**
|
||||
* Get all entries for a workspace (paginated and filterable)
|
||||
@@ -175,8 +169,8 @@ export class KnowledgeService {
|
||||
const baseSlug = this.generateSlug(createDto.title);
|
||||
const slug = await this.ensureUniqueSlug(workspaceId, baseSlug);
|
||||
|
||||
// Render markdown to HTML
|
||||
const contentHtml = await marked.parse(createDto.content);
|
||||
// Render markdown to HTML with sanitization
|
||||
const contentHtml = await renderMarkdown(createDto.content);
|
||||
|
||||
// Use transaction to ensure atomicity
|
||||
const result = await this.prisma.$transaction(async (tx) => {
|
||||
@@ -299,7 +293,7 @@ export class KnowledgeService {
|
||||
// Render markdown if content is updated
|
||||
let contentHtml = existing.contentHtml;
|
||||
if (updateDto.content) {
|
||||
contentHtml = await marked.parse(updateDto.content);
|
||||
contentHtml = await renderMarkdown(updateDto.content);
|
||||
}
|
||||
|
||||
// Build update data object conditionally
|
||||
|
||||
Reference in New Issue
Block a user