import { YuqueDoc, YuqueDocListItem, YuqueTocItem } from "./types.js";
/**
* 从语雀 URL 中提取命名空间和文档 slug
* 支持的格式:
* - https://www.yuque.com/username/repo/doc-slug
* - https://www.yuque.com/username/repo/doc-slug?view=doc_embed
*/
export function extractDocInfoFromUrl(url: string): {
namespace: string;
slug: string;
} | null {
try {
const urlObj = new URL(url);
const pathParts = urlObj.pathname.split("/").filter((p) => p);
// 期望格式: ['username', 'repo', 'doc-slug']
if (pathParts.length >= 3) {
const username = pathParts[0];
const repo = pathParts[1];
const slug = pathParts[2];
return {
namespace: `${username}/${repo}`,
slug: slug,
};
}
return null;
} catch (error) {
return null;
}
}
/**
* 验证命名空间格式
* 格式: username/repo
*/
export function isValidNamespace(namespace: string): boolean {
const parts = namespace.split("/");
return parts.length === 2 && parts[0].length > 0 && parts[1].length > 0;
}
/**
* 格式化语雀文档为可读文本
*/
export function formatYuqueDoc(doc: YuqueDoc): string {
let output = `# ${doc.title}\n\n`;
output += `---\n\n`;
output += `**文档信息**:\n\n`;
output += `- **文档 ID**: ${doc.id}\n`;
output += `- **Slug**: ${doc.slug}\n`;
output += `- **知识库**: ${doc.book.name} (${doc.book.namespace})\n`;
output += `- **作者**: ${doc.user.name} (@${doc.user.login})\n`;
output += `- **格式**: ${doc.format}\n`;
output += `- **字数**: ${doc.word_count}\n`;
output += `- **创建时间**: ${new Date(doc.created_at).toLocaleString("zh-CN")}\n`;
output += `- **更新时间**: ${new Date(doc.updated_at).toLocaleString("zh-CN")}\n`;
output += `- **浏览量**: ${doc.hits}\n`;
output += `- **点赞数**: ${doc.likes_count}\n`;
output += `- **评论数**: ${doc.comments_count}\n`;
if (doc.description) {
output += `- **描述**: ${doc.description}\n`;
}
output += `\n---\n\n`;
output += `**文档链接**: https://www.yuque.com/${doc.book.namespace}/${doc.slug}\n\n`;
output += `---\n\n`;
output += `## 文档内容\n\n`;
// 根据格式选择输出内容
if (doc.format === "markdown" && doc.body) {
output += doc.body;
} else if (doc.body_html) {
// 如果是其他格式,使用 HTML 内容
output += `> 注意: 此文档使用 ${doc.format} 格式,以下是 HTML 版本\n\n`;
output += doc.body_html;
} else if (doc.body) {
output += doc.body;
} else {
output += `(内容不可用)`;
}
return output;
}
/**
* 格式化文档列表项
*/
export function formatDocListItem(doc: YuqueDocListItem, index?: number): string {
let output = "";
if (index !== undefined) {
output += `## ${index}. `;
}
output += `${doc.title}\n\n`;
output += `- **Slug**: ${doc.slug}\n`;
output += `- **格式**: ${doc.format}\n`;
output += `- **字数**: ${doc.word_count}\n`;
output += `- **更新时间**: ${new Date(doc.updated_at).toLocaleString("zh-CN")}\n`;
output += `- **浏览量**: ${doc.hits}\n`;
if (doc.description) {
output += `- **描述**: ${doc.description}\n`;
}
output += `\n`;
return output;
}
/**
* 格式化目录树
*/
export function formatTocTree(toc: YuqueTocItem[]): string {
let output = `# 知识库目录\n\n`;
const buildTree = (items: YuqueTocItem[], parentUuid: string = "", depth: number = 0): string => {
let result = "";
const children = items.filter((item) => (item.parent_uuid || "") === parentUuid);
children.forEach((item) => {
const indent = " ".repeat(depth);
const prefix = depth === 0 ? "#".repeat(Math.min(depth + 2, 6)) + " " : "- ";
if (item.type === "TITLE") {
result += `${indent}${prefix}**${item.title}**\n`;
} else if (item.type === "DOC") {
result += `${indent}${prefix}${item.title} \`[${item.slug}]\`\n`;
} else if (item.type === "LINK") {
result += `${indent}${prefix}[${item.title}](${item.url})\n`;
}
// 递归处理子节点
if (item.uuid) {
result += buildTree(items, item.uuid, depth + 1);
}
});
return result;
};
output += buildTree(toc);
return output;
}
/**
* 清理 HTML 标签(简单实现)
*/
export function stripHtmlTags(html: string): string {
return html.replace(/<[^>]*>/g, "").trim();
}