/** * Markdown API 文档导入器:提取 curl 代码块(及可选 JSON 请求体示例)。 */ import type { Collection } from "../model"; import { createCollection, createFolder } from "../factory"; import type { ImportResult } from "../model"; import { importCurl } from "./curl"; export function looksLikeMarkdown(text: string): boolean { const t = text.trimStart(); if (!t.startsWith("#") && !t.includes("```")) return false; return /^#{1,6}\s/m.test(text) || /```/.test(text); } export function importMarkdown(text: string): ImportResult { const warnings: string[] = []; const blocks: { heading: string; code: string }[] = []; const lines = text.split(/\r?\n/); let heading = ""; let inBlock = false; let lang = ""; let buf: string[] = []; for (const line of lines) { const fence = line.match(/^\s*```(\w*)\s*$/); if (fence) { if (!inBlock) { inBlock = true; lang = fence[1].toLowerCase(); buf = []; } else { inBlock = false; const code = buf.join("\n"); if (["curl", "bash", "sh", "shell", ""].includes(lang) && code.trim().startsWith("curl")) { blocks.push({ heading: heading || `curl ${blocks.length + 1}`, code }); } } continue; } if (inBlock) { buf.push(line); continue; } const h = line.match(/^#{1,6}\s+(.*)$/); if (h) heading = h[1].trim(); } if (blocks.length === 0) { warnings.push("未在 Markdown 中找到 curl 代码块(也支持直接粘贴 cURL 导入)"); } const folders = new Map>(); const rootChildren = []; for (const block of blocks) { try { const temp = importCurl(block.code, "temp"); const node = temp.children[0]; if (!node) continue; // 一级标题做目录,二级及以下做请求名 const parts = block.heading.split(/[::]/); const folderName = parts[0]?.trim(); if (folderName && folders.has(folderName)) { folders.get(folderName)!.children.push(node); } else if (folderName) { const f = createFolder(folderName, [node]); folders.set(folderName, f); } else { rootChildren.push(node); } } catch (e) { warnings.push(`解析代码块失败:${e instanceof Error ? e.message : String(e)}`); } } const collection = createCollection( firstHeading(text) || "Markdown 导入", [...folders.values(), ...rootChildren], ); return { collections: [collection], environmentVariables: [], warnings }; } function firstHeading(text: string): string { const m = text.match(/^#\s+(.+)$/m); return m ? m[1].trim().slice(0, 60) : ""; }