export type DeploymentRuntime = "bun" | "node" | "edge" | "worker" | "service-worker" | "browser"; export type RuntimeCapability = "filesystem" | "tcp" | "process" | "websocket" | "crypto" | "streams" | "background-tasks"; const CAPABILITIES: Record> = { bun: new Set([ "filesystem", "tcp", "process", "websocket", "crypto", "streams", "background-tasks", ]), node: new Set([ "filesystem", "tcp", "process", "websocket", "crypto", "streams", "background-tasks", ]), edge: new Set(["websocket", "crypto", "streams", "background-tasks"]), worker: new Set(["websocket", "crypto", "streams", "background-tasks"]), "service-worker": new Set(["crypto", "streams", "background-tasks"]), browser: new Set(["websocket", "crypto", "streams"]), }; const MODULE_CAPABILITIES: Array<[RegExp, RuntimeCapability]> = [ [/^(?:node:)?(?:fs|path|os)(?:\/|$)/, "filesystem"], [/^(?:node:)?(?:net|tls|dgram|http2)(?:\/|$)/, "tcp"], [/^(?:node:)?(?:child_process|cluster|worker_threads)(?:\/|$)/, "process"], ]; export interface RuntimeCapabilityDiagnostic { code: "WRN-RUNTIME-CAPABILITY"; runtime: DeploymentRuntime; module: string; capability: RuntimeCapability; message: string; } export function runtimeCapabilities(runtime: DeploymentRuntime): ReadonlySet { return CAPABILITIES[runtime]; } export function analyzeRuntimeImports( source: string, runtime: DeploymentRuntime, ): RuntimeCapabilityDiagnostic[] { const modules = [ ...source.matchAll(/\b(?:import\s+(?:[\s\S]*?\s+from\s+)?|require\s*\()\s*["']([^"']+)["']/g), ].map((match) => match[1]!); const available = runtimeCapabilities(runtime); return modules.flatMap((module) => { const requirement = MODULE_CAPABILITIES.find(([pattern]) => pattern.test(module)); if (!requirement || available.has(requirement[1])) return []; return [ { code: "WRN-RUNTIME-CAPABILITY" as const, runtime, module, capability: requirement[1], message: `Module '${module}' requires ${requirement[1]}, which is unavailable in the ${runtime} runtime.`, }, ]; }); }