import type { Protocol, Type } from "../src/protocol/schema"; import { writeFileSync } from "node:fs"; import { spawnSync } from "node:child_process"; run().catch(console.error); async function run() { const cwd = new URL("../protocol/", import.meta.url); const runner = "Bun" in globalThis ? "bunx" : "npx"; const write = (name: string, data: string) => { const path = new URL(name, cwd); writeFileSync(path, data); spawnSync(runner, ["prettier", "--write", path.pathname], { cwd, stdio: "ignore" }); }; const schema: Protocol = await download( "https://microsoft.github.io/debug-adapter-protocol/debugAdapterProtocol.json", ); write("protocol.json", JSON.stringify(schema)); const types = formatProtocol(schema); write("index.d.ts", `// GENERATED - DO NOT EDIT\n${types}`); } function formatProtocol(protocol: Protocol, extraTs?: string): string { const { definitions } = protocol; const requestMap = new Map(); const responseMap = new Map(); const eventMap = new Map(); let body = `export namespace DAP {`; loop: for (const [key, definition] of Object.entries(definitions)) { if (/[a-z]+Request$/i.test(key)) { continue; } if (/[a-z]+Arguments$/i.test(key)) { const name = key.replace(/(Request)?Arguments$/, ""); const requestName = `${name}Request`; requestMap.set(toMethod(name), requestName); body += formatType(definition, requestName); continue; } if ("allOf" in definition) { const { allOf } = definition; for (const type of allOf) { if (type.type !== "object") { continue; } const { description, properties = {} } = type; if (/[a-z]+Event$/i.test(key)) { const { event, body: type = {} } = properties; if (!event || !("enum" in event)) { continue; } const [eventKey] = event.enum ?? []; eventMap.set(eventKey, key); const eventType: Type = { type: "object", description, ...type, }; body += formatType(eventType, key); continue loop; } if (/[a-z]+Response$/i.test(key)) { const { body: type = {} } = properties; const bodyType: Type = { type: "object", description, ...type, }; const name = key.replace(/Response$/, ""); responseMap.set(toMethod(name), key); body += formatType(bodyType, key); continue loop; } } } body += formatType(definition, key); } for (const [key, name] of responseMap) { if (requestMap.has(key)) { continue; } const requestName = `${name.replace(/Response$/, "")}Request`; requestMap.set(key, requestName); body += formatType({ type: "object", properties: {} }, requestName); } body += formatMapType("RequestMap", requestMap); body += formatMapType("ResponseMap", responseMap); body += formatMapType("EventMap", eventMap); if (extraTs) { body += extraTs; } return body + "};"; } function formatMapType(key: string, typeMap: Map): string { const type: Type = { type: "object", required: [...typeMap.keys()], properties: Object.fromEntries([...typeMap.entries()].map(([key, value]) => [key, { $ref: value }])), }; return formatType(type, key); } function formatType(type: Type, key?: string): string { const { description, type: kind } = type; let body = ""; if (key) { if (description) { body += `\n${toComment(description)}\n`; } body += `export type ${key}=`; } if (kind === "boolean") { body += "boolean"; } else if (kind === "number" || kind === "integer") { body += "number"; } else if (kind === "string") { const { enum: choices } = type; if (choices) { body += choices.map(value => `"${value}"`).join("|"); } else { body += "string"; } } else if (kind === "array") { const { items } = type; const itemType = items ? formatType(items) : "unknown"; body += `${itemType}[]`; } else if (kind === "object") { const { properties, required } = type; if (!properties || Object.keys(properties).length === 0) { body += "{}"; } else { body += "{"; for (const [key, { description, ...type }] of Object.entries(properties)) { if (description) { body += `\n${toComment(description)}`; } const delimit = required?.includes(key) ? ":" : "?:"; body += `\n${key}${delimit}${formatType(type)};`; } body += "}"; } } else if ("$ref" in type) { const { $ref: ref } = type; body += ref.split("/").pop() || "unknown"; } else if ("allOf" in type) { const { allOf } = type; body += allOf.map(type => formatType(type)).join("&"); } else { body += "unknown"; } if (key) { body += ";"; } return body; } function toMethod(name: string): string { return `${name.substring(0, 1).toLowerCase()}${name.substring(1)}`; } function toComment(description?: string): string { if (!description) { return ""; } const lines = ["/**", ...description.split("\n").map(line => ` * ${line.trim()}`), "*/"]; return lines.join("\n"); } async function download(url: string | URL): Promise { const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to download ${url}: ${response.statusText}`); } return response.json(); } /add-git'>jarred/add-git Unnamed repository; edit this file 'description' to name the repository.
aboutsummaryrefslogtreecommitdiff
AgeCommit message (Expand)AuthorFilesLines
2023-10-09fix(AbortSignal/fetch) fix AbortSignal.timeout, fetch lock behavior and fetch...Gravatar Ciro Spaciari 29-61/+303
2023-10-09Fix npm tag for canary bun-types, againGravatar Ashcon Partovi 2-56/+10
2023-10-09Add Fedora build instructions to development.md (#6359)Gravatar otterDeveloper 1-0/+10
2023-10-09added commands (#6314)Gravatar babar 1-1/+2
2023-10-09Update README.md (#6291)Gravatar TPLJ 1-1/+1
2023-10-09docs: fixing a couple typos (#6331)Gravatar Michael Di Prisco 2-2/+2
2023-10-09fix: support uint8 exit code range (#6303)Gravatar Liz 2-2/+11
2023-10-09Fix array variables preview in debugger (#6379)Gravatar 2hu 1-1/+4
2023-10-07feat(KeyObject) (#5940)Gravatar Ciro Spaciari 106-67/+9342
2023-10-07Exclude more filesGravatar Jarred Sumner 1-1/+1
2023-10-07Exclude more filesGravatar Jarred Sumner 1-1/+2
2023-10-07Update settings.jsonGravatar Jarred Sumner 1-1/+2
2023-10-07Update settings.jsonGravatar Jarred Sumner 1-2/+3
2023-10-06fix a couple install testsGravatar Dylan Conway 1-8/+8
2023-10-06formatGravatar Dylan Conway 1-1/+2
2023-10-06Fix memory leak in fetch() (#6350)Gravatar Jarred Sumner 1-2/+0
2023-10-06[types] allow onLoad plugin callbacks to return undefined (#6346)Gravatar Silver 1-1/+1
2023-10-06docs: `file.stream()` is not a promise (#6337)Gravatar Paul Nodet 1-1/+1