Skip to main content
Glama
Jpisnice
by Jpisnice
fetch-presets.ts4.39 kB
import axios from "axios"; import fs from "fs"; import path from "path"; /** * Fetches the raw tweakcn theme-presets.ts file from GitHub and attempts * to extract the exported object literal as a JavaScript object. */ export async function fetchPresetsFromGithub(url: string): Promise<Record<string, any>> { // Try network fetch first try { const res = await axios.get(url, { responseType: "text" }); const text: string = res.data; const parsed = extractExportedObject(text); if (parsed) return parsed; // fallthrough to local file } catch (err) { console.error("Network fetch failed:", err); // network failed — will try local fallback } // Fallback: try reading local tweakcn/theme-presets.ts try { const localPath = path.join(process.cwd(), "tweakcn", "theme-presets.ts"); if (fs.existsSync(localPath)) { const text = await fs.promises.readFile(localPath, "utf8"); const parsed = extractExportedObject(text); if (parsed) return parsed; } } catch (err) { console.error("Local read failed:", err); // ignore and throw below } throw new Error("Could not fetch or parse tweakcn presets from network or local file"); } function extractExportedObject(text: string): Record<string, any> | null { // User requested specific parsing logic: // 1. Remove everything till "export const defaultPresets: Record<string, ThemePreset> = {" // 2. Remove "};" from the end // 3. Wrap in "{ }" const startMarker = "export const defaultPresets: Record<string, ThemePreset> = {"; const startIndex = text.indexOf(startMarker); if (startIndex === -1) { // Fallback to regex if exact string not found (maybe type annotation is missing or different) // But user was specific, so let's try to be flexible but prefer their string. // Let's try a slightly more flexible regex that matches the user's intent. const regex = /export\s+const\s+defaultPresets\s*(?::\s*[^=]+)?\s*=\s*\{/; const match = text.match(regex); if (!match) return null; const matchIndex = match.index!; const matchLength = match[0].length; // We want to start AFTER the opening brace of the match // The regex ends with '{', so we slice after it. // But wait, the user said "remove everything till ... = {". // And "whatever is remaining put it in { }". // So if we have "prefix... = { content }; suffix", // Removing prefix gives " content }; suffix". // Removing "};" from end gives " content ". // Wrapping gives "{ content }". // Let's implement the logic based on the match end. const contentStart = matchIndex + matchLength; let content = text.slice(contentStart); // Remove suffix "};" (and potentially trailing whitespace/newlines) // We look for the last occurrence of "};" const lastSemiBrace = content.lastIndexOf("};"); if (lastSemiBrace !== -1) { content = content.slice(0, lastSemiBrace); } else { // Maybe just "}" if no semicolon? const lastBrace = content.lastIndexOf("}"); if (lastBrace !== -1) { content = content.slice(0, lastBrace); } } const finalString = `{${content}}`; try { const sanitized = finalString .replace(/`/g, "'") .replace(/:\s*undefined/g, ": null"); // eslint-disable-next-line no-new-func const obj = new Function(`return (${sanitized})`)(); if (typeof obj === "object") return obj as Record<string, any>; } catch (err) { console.error("Error parsing presets:", err); return null; } return null; } // If exact match found const contentStart = startIndex + startMarker.length; let content = text.slice(contentStart); const lastSemiBrace = content.lastIndexOf("};"); if (lastSemiBrace !== -1) { content = content.slice(0, lastSemiBrace); } const finalString = `{${content}}`; try { const sanitized = finalString .replace(/`/g, "'") .replace(/:\s*undefined/g, ": null"); // eslint-disable-next-line no-new-func const obj = new Function(`return (${sanitized})`)(); if (typeof obj === "object") return obj as Record<string, any>; } catch (err) { console.error("Error parsing presets:", err); return null; } return null; } export default fetchPresetsFromGithub;

Latest Blog Posts

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/Jpisnice/shadcn-ui-mcp-server'

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