UNPKG

@cnbcool/mcp-server

Version:

CNB MCP Server. A comprehensive MCP server that provides seamless integration to the CNB's API(https://cnb.cool), offering a wide range of tools for repository management, pipelines operations and collaboration features

102 lines (101 loc) 3.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = convertLink; function trimTrailingSlash(val) { return val.replace(/\/+$/, ''); } function normaliseLink(link, repoSlug, branchOrSha) { const endpoint = trimTrailingSlash(process.env.CNB_WEB_ENDPOINT || 'https://cnb.cool'); const baseURL = `${endpoint}/${repoSlug}`; if (!link) return link; if (/^([a-z][a-z0-9+.-]*:)?\/\//i.test(link) || /^[a-z][a-z0-9+.-]*:/i.test(link) || link.startsWith('#')) { return link; } if (link.startsWith('/-/')) { return `${baseURL}${link}`; } if (!branchOrSha) { return link; } if (link.startsWith('../')) { return `${baseURL}/-/git/raw/${branchOrSha}/${link}`; } if (link.startsWith('./')) { return `${baseURL}/-/git/raw/${branchOrSha}${link.substring(1)}`; } if (link.startsWith('/') && !link.startsWith('//')) { return `${baseURL}/-/git/raw/${branchOrSha}${link}`; } return link; } function convertLink(text, repoSlug, branchOrSha) { if (!text || !repoSlug) return text; let codeBlockPositions = []; let index = 0; while (index !== -1) { const nextIndex = text.indexOf('```', index); if (nextIndex === -1) break; codeBlockPositions.push(nextIndex); index = nextIndex + 3; } if (codeBlockPositions.length % 2 !== 0) { codeBlockPositions = codeBlockPositions.slice(0, codeBlockPositions.length - 1); } let inlineCodeBlockPositions = []; index = 0; while (index < text.length) { const nextIndex = text.indexOf('`', index); if (nextIndex === -1) break; if ((nextIndex === 0 || text.charAt(nextIndex - 1) !== '`') && (nextIndex === text.length - 1 || text.charAt(nextIndex + 1) !== '`')) { inlineCodeBlockPositions.push(nextIndex); } index = nextIndex + 1; } if (inlineCodeBlockPositions.length % 2 !== 0) { inlineCodeBlockPositions = inlineCodeBlockPositions.slice(0, inlineCodeBlockPositions.length - 1); } const excludedRanges = [...codeBlockPositions, ...inlineCodeBlockPositions].reduce((result, item, idx) => { if (idx % 2 === 0) { return result.concat([[item]]); } result[result.length - 1].push(item); return result; }, []); const isInExcludedRange = (pos) => excludedRanges.some(([start, end]) => pos >= start && pos < end); const replacements = []; let match; const markdownLinkRegex = /!?\[([^\]]+)\]\(([^)]+)\)/g; while ((match = markdownLinkRegex.exec(text)) !== null) { if (isInExcludedRange(match.index)) continue; const prefixLength = (match[0].startsWith('!') ? 1 : 0) + 1 + match[1].length + 2; const urlStart = match.index + prefixLength; const urlEnd = urlStart + match[2].length; const newUrl = normaliseLink(match[2], repoSlug, branchOrSha); if (newUrl !== match[2]) { replacements.push({ start: urlStart, end: urlEnd, newUrl }); } } const htmlTagRegex = /\s(src|href)=["']([^"']+)["']/gi; while ((match = htmlTagRegex.exec(text)) !== null) { if (isInExcludedRange(match.index)) continue; const urlStart = match.index + match[0].indexOf(match[2]); const urlEnd = urlStart + match[2].length; const newUrl = normaliseLink(match[2], repoSlug, branchOrSha); if (newUrl !== match[2]) { replacements.push({ start: urlStart, end: urlEnd, newUrl }); } } replacements.sort((a, b) => b.start - a.start); let result = text; for (const { start, end, newUrl } of replacements) { result = result.substring(0, start) + newUrl + result.substring(end); } return result; }