Skip to main content
Glama

Convex MCP server

Official
by get-convex
snippet.tsx5.37 kB
import React from "react"; import CodeBlock from "./theme/CodeBlock/CodeBlock"; // Otherwise file extension === language name const FILE_EXTENSION_TO_LANGUAGE = { rs: "rust", jsonl: "json", }; /** * Create a snippet from a given TSX program `source`. * * Snippet lines can either be * * // @snippet start <name> * * or * * // @snippet end <name> * * which start and end the named snippet, respectively. These snippets name a * span in the original source file. * * If `snippet` is not provided, this function returns the source file with all * snippet comment lines removed. Otherwise, it extracts the selected snippet. * * Other special comments: * // @skipNextLine */ export function Snippet({ title, titleSuffix, link, source, snippet, prefix, suffix, highlightPatterns, showLanguageSelector, replacements = [], }: { source: string; title?: string; titleSuffix?: string; link?: string; snippet?: string | string[]; prefix?: string; suffix?: string; highlightPatterns?: string[]; showLanguageSelector?: boolean; replacements?: [RegExp | string, string][]; }) { const lines = source.split("\n"); const allSpans = new Map<string, { start: number; end: number }>(); const openSpans = new Map<string, { start: number }>(); const nonSnippetLines = []; const linesOmittingSkipped = []; let lineIndex = 0; while (lineIndex < lines.length) { const line = lines[lineIndex]; const trimmed = line.trim(); if (trimmed.startsWith("// @skipNextLine")) { lineIndex += 2; continue; } else { linesOmittingSkipped.push(line); lineIndex += 1; } } for (const line of linesOmittingSkipped) { const trimmed = line.trim(); if ( trimmed.startsWith("// @snippet") || trimmed.startsWith("{/* @snippet") ) { const pieces = trimmed.split(" "); if (pieces.length < 4) { throw new Error(`Invalid snippet line: ${trimmed}`); } // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_comment, _snippet, command, name] = pieces; if (command === "start") { if (allSpans.has(name) || openSpans.has(name)) { throw new Error(`Duplicate span ${name}`); } openSpans.set(name, { start: nonSnippetLines.length }); } else if (command === "end") { if (!openSpans.has(name)) { throw new Error(`Invalid span close ${name}`); } const openSpan = openSpans.get(name); openSpans.delete(name); const span = { start: openSpan.start, end: nonSnippetLines.length }; allSpans.set(name, span); } else { throw new Error(`Invalid snippet command in ${trimmed}`); } } else { nonSnippetLines.push(line); } } if (openSpans.size > 0) { throw new Error(`Spans left open: ${Array.from(openSpans.keys())}`); } let finalSource; if (snippet) { const spans: [string, { start: number; end: number }][] = ( Array.isArray(snippet) ? snippet : [snippet] ).map((snippet) => [snippet, allSpans.get(snippet)]); const [invalidSnippet] = spans.find(([_snippet, span]) => span === undefined) ?? []; if (invalidSnippet !== undefined) { throw new Error(`Invalid snippet="${invalidSnippet}"`); } console.log( ...spans.map(([_, span]) => nonSnippetLines.slice(span.start, span.end)), ); finalSource = trimLeftWhitespace( (prefix?.split("\n") ?? []).concat( ...spans.map(([_, span]) => nonSnippetLines.slice(span.start, span.end), ), suffix?.split("\n") ?? [], ), ).join("\n"); } else { finalSource = nonSnippetLines.join("\n"); } for (const [pat, replace] of replacements) { finalSource = finalSource.replaceAll(pat, replace); } finalSource = highlightPatterns ? highlightLines(finalSource, highlightPatterns) : finalSource; const fileExtension = title?.match(/\.([^.]+)$/)?.[1]; const language = FILE_EXTENSION_TO_LANGUAGE[fileExtension] ?? fileExtension ?? "tsx"; const combinedTitle = title === undefined ? undefined : ( <> {link ? ( <a href={link} target="_blank"> {title} </a> ) : ( title )} {titleSuffix} </> ); return ( <CodeBlock className={"language-" + language} showLanguageSelector={showLanguageSelector === true} // CodeBlock is wrongly typed title={combinedTitle as unknown as string} > {finalSource} </CodeBlock> ); } function trimLeftWhitespace(lines: string[]): string[] { const nonEmptyLines = lines.filter((line) => line.trim().length > 0); const toTrim = Math.min( ...nonEmptyLines.map((line) => line.length - line.trimStart().length), ); return lines.map((line) => (line !== "" ? line.slice(toTrim) : "")); } function highlightLines(source: string, patterns: string[]): string { const linesToHighlight = new Set<number>(); const lines = source.split("\n"); for (const pattern of patterns) { lines.forEach((line, i) => { if (line.match(pattern)) { linesToHighlight.add(i); } }); } for (const i of Array.from(linesToHighlight).sort((a, b) => b - a)) { lines.splice(i, 0, "// highlight-next-line"); } return lines.join("\n"); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server