@kimsungwhee/apple-docs-mcp
Version:
MCP server for Apple Developer Documentation - Search iOS/macOS/SwiftUI/UIKit docs, WWDC videos, Swift/Objective-C APIs & code examples in Claude, Cursor & AI assistants
199 lines • 6.82 kB
JavaScript
import { convertToJsonApiUrl } from '../utils/url-converter.js';
import { httpClient } from '../utils/http-client.js';
import { logger } from '../utils/logger.js';
/**
* 批量解析引用
*/
export async function handleResolveReferencesBatch(sourceUrl, maxReferences = 20, filterByType = 'all') {
try {
logger.info(`Resolving references from: ${sourceUrl}`);
// 将网页URL转换为JSON API URL
const jsonApiUrl = convertToJsonApiUrl(sourceUrl);
if (!jsonApiUrl) {
throw new Error('Invalid Apple Developer Documentation URL');
}
const data = await httpClient.getJson(jsonApiUrl);
if (!data.references || Object.keys(data.references).length === 0) {
return `No references found in: ${sourceUrl}`;
}
// 过滤和限制引用数量
const filteredReferences = filterReferences(data.references, filterByType);
const limitedReferences = Object.entries(filteredReferences).slice(0, maxReferences);
// 解析引用信息
const resolvedReferences = [];
for (const [identifier, refData] of limitedReferences) {
const resolved = await resolveReference(identifier, refData);
if (resolved) {
resolvedReferences.push(resolved);
}
}
// 格式化输出
return formatResolvedReferences(sourceUrl, resolvedReferences, data.metadata?.title);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return `Error: Failed to resolve references: ${errorMessage}`;
}
}
/**
* 过滤引用
*/
function filterReferences(references, filterByType) {
if (filterByType === 'all') {
return references;
}
const filtered = {};
for (const [identifier, refData] of Object.entries(references)) {
const matchesFilter = refData.role === filterByType ||
refData.kind === filterByType ||
refData.type === filterByType ||
refData.symbolKind === filterByType;
if (matchesFilter) {
filtered[identifier] = refData;
}
}
return filtered;
}
/**
* 解析单个引用
*/
async function resolveReference(identifier, refData) {
try {
// 基本信息
const resolved = {
identifier,
title: refData.title || 'Unknown',
url: refData.url ? `https://developer.apple.com${refData.url}` : '#',
type: refData.type || 'unknown',
role: refData.role || 'unknown',
kind: refData.kind,
symbolKind: refData.symbolKind,
};
// 处理摘要
if (refData.abstract && Array.isArray(refData.abstract)) {
resolved.abstract = refData.abstract
.map(item => item.text || '')
.join(' ')
.trim();
}
// 处理代码片段
if (refData.fragments && Array.isArray(refData.fragments)) {
resolved.fragments = refData.fragments.map(fragment => ({
kind: fragment.kind || 'text',
text: fragment.text || '',
}));
}
// 处理平台信息
if (refData.platforms && Array.isArray(refData.platforms)) {
resolved.platforms = refData.platforms.map(platform => ({
name: platform.name || 'Unknown',
introducedAt: platform.introducedAt,
beta: platform.beta || false,
deprecated: platform.deprecated || false,
}));
}
return resolved;
}
catch (error) {
logger.error(`Failed to resolve reference ${identifier}:`, error);
return null;
}
}
/**
* 格式化解析结果
*/
function formatResolvedReferences(sourceUrl, references, sourceTitle) {
if (references.length === 0) {
return `No references could be resolved from: ${sourceUrl}`;
}
const title = sourceTitle || new URL(sourceUrl).pathname.split('/').pop() || 'Document';
let content = `# References from ${title}\n\n`;
content += `**Source:** [${sourceUrl}](${sourceUrl})\n\n`;
content += `**Resolved ${references.length} references:**\n\n`;
// 按类型分组
const groupedReferences = groupReferencesByRole(references);
for (const [role, refs] of Object.entries(groupedReferences)) {
content += `## ${formatRoleTitle(role)} (${refs.length})\n\n`;
for (const ref of refs) {
content += formatSingleReference(ref);
}
}
content += `---\n\n*Total: ${references.length} references resolved*`;
return content;
}
/**
* 按角色分组引用
*/
function groupReferencesByRole(references) {
const groups = {};
for (const ref of references) {
const role = ref.role || 'unknown';
if (!groups[role]) {
groups[role] = [];
}
groups[role].push(ref);
}
return groups;
}
/**
* 格式化角色标题
*/
function formatRoleTitle(role) {
const roleTitles = {
'symbol': 'API Symbols',
'collection': 'Collections',
'article': 'Articles',
'sampleCode': 'Sample Code',
'overview': 'Overviews',
'collectionGroup': 'Collection Groups',
'unknown': 'Other References',
};
return roleTitles[role] || role.charAt(0).toUpperCase() + role.slice(1);
}
/**
* 格式化单个引用
*/
function formatSingleReference(ref) {
let content = `### [${ref.title}](${ref.url})\n`;
// 添加代码片段(如果是符号)
if (ref.fragments && ref.fragments.length > 0) {
const codeSignature = ref.fragments.map(f => f.text).join('');
if (codeSignature.trim()) {
content += `\`\`\`swift\n${codeSignature}\`\`\`\n\n`;
}
}
// 添加摘要
if (ref.abstract) {
content += `${ref.abstract}\n\n`;
}
// 添加元数据
const metadata = [];
if (ref.kind) {
metadata.push(`Kind: ${ref.kind}`);
}
if (ref.symbolKind) {
metadata.push(`Symbol: ${ref.symbolKind}`);
}
if (metadata.length > 0) {
content += `*${metadata.join(' | ')}*\n\n`;
}
// 添加平台信息
if (ref.platforms && ref.platforms.length > 0) {
const platformInfo = ref.platforms.map(p => {
let info = p.name;
if (p.introducedAt) {
info += ` ${p.introducedAt}+`;
}
if (p.beta) {
info += ' (Beta)';
}
if (p.deprecated) {
info += ' (Deprecated)';
}
return info;
}).join(', ');
content += `**Platforms:** ${platformInfo}\n\n`;
}
return content;
}
//# sourceMappingURL=resolve-references-batch.js.map