{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { originalPositionFor, TraceMap } from '@jridgewell/trace-mapping';\nimport type { ErrorPayload, ModuleGraph, Plugin, WebSocketClient } from 'vite';\n\nconst packageName = 'runtime-error-plugin';\n\nexport default function viteRuntimeErrorOverlayPlugin(options?: {\n  filter?: (error: Error) => boolean;\n}): Plugin {\n  return {\n    name: packageName,\n\n    apply(config, env) {\n      return env.command === 'serve' && !config.ssr;\n    },\n\n    transformIndexHtml() {\n      return [\n        {\n          tag: 'script',\n          attrs: { type: 'module' },\n          children: CLIENT_SCRIPT,\n        },\n      ];\n    },\n\n    configureServer(server) {\n      server.ws.on(MESSAGE_TYPE, (data: unknown, client: WebSocketClient) => {\n        const error = Object.assign(new Error(), data);\n        if (!error.stack) {\n          return;\n        }\n\n        if (options?.filter && !options.filter(error)) {\n          return;\n        }\n\n        const { stack, loc } = rewriteStacktrace(\n          error.stack,\n          server.moduleGraph,\n        );\n\n        const err: ErrorPayload['err'] = {\n          name: error.name,\n          message: error.message,\n          stack,\n          loc,\n          plugin: packageName,\n        };\n\n        if (loc?.file) {\n          err.id = loc?.file;\n          const source = readFileSync(loc.file, 'utf-8');\n          err.frame = generateCodeFrame(source, {\n            line: loc.line,\n            column: loc.column - 1,\n          });\n        }\n\n        client.send({\n          type: 'error',\n          err,\n        });\n      });\n    },\n  };\n}\n\nconst MESSAGE_TYPE = `${packageName}:error`;\nconst CLIENT_SCRIPT = `\nimport { createHotContext } from \"/@vite/client\";\nconst hot = createHotContext(\"/__dummy__${packageName}\");\n\nfunction sendError(error) {\n  if (!(error instanceof Error)) {\n    error = new Error(\"(unknown runtime error)\");\n  }\n  const serialized = {\n    message: error.message,\n    stack: error.stack,\n  };\n  hot.send(\"${MESSAGE_TYPE}\", serialized);\n}\n\nwindow.addEventListener(\"error\", (evt) => {\n  sendError(evt.error);\n});\n\nwindow.addEventListener(\"unhandledrejection\", (evt) => {\n  sendError(evt.reason);\n});\n`;\n\nfunction cleanStack(stack: string) {\n  return stack\n    .split(/\\n/g)\n    .filter((l) => /^\\s*at/.test(l))\n    .join('\\n');\n}\n\nfunction rewriteStacktrace(\n  stack: string,\n  moduleGraph: ModuleGraph,\n): {\n  stack: string;\n  loc?: Pos & { file: string };\n} {\n  let loc: (Pos & { file: string }) | undefined = undefined;\n  const rewrittenStack = cleanStack(stack)\n    .split('\\n')\n    .map((line) => {\n      return line.replace(\n        /^ {4}at (?:(\\S+?) )?\\(?(?:https|http):\\/\\/[^\\/]+(\\/[^\\s?]+).*:(\\d+):(\\d+)\\)?$/,\n        (input, varName, url, line, column) => {\n          if (!url) {\n            return input;\n          }\n\n          const module = moduleGraph.urlToModuleMap.get(url);\n          if (!module) {\n            return '';\n          }\n\n          const rawSourceMap = module?.transformResult?.map;\n\n          if (rawSourceMap) {\n            const traced = new TraceMap(rawSourceMap as any);\n            const pos = originalPositionFor(traced, {\n              line: Number(line),\n              // stacktrace's column is 1-indexed, but sourcemap's one is 0-indexed\n              column: Number(column) - 1,\n            });\n\n            if (pos.source && pos.line >= 0 && pos.column >= 0) {\n              line = pos.line;\n              column = pos.column + 1;\n            }\n          }\n\n          const trimmedVarName = varName?.trim();\n          const sourceFile = module.file;\n          const source = `${module.file}:${line}:${column}`;\n\n          if (sourceFile) {\n            loc ??= {\n              line: Number(line),\n              column: Number(column),\n              file: sourceFile,\n            };\n          }\n\n          if (!trimmedVarName || trimmedVarName === 'eval') {\n            return `    at ${source}`;\n          } else {\n            return `    at ${trimmedVarName} ${source}`;\n          }\n        },\n      );\n    })\n    .join('\\n');\n\n  return {\n    stack: rewrittenStack,\n    loc,\n  };\n}\n\ntype Pos = {\n  /** 1-based */\n  line: number;\n  /** 0-based */\n  column: number;\n};\n\nconst splitRE = /\\r?\\n/g;\nconst range: number = 2;\n\nfunction posToNumber(source: string, pos: number | Pos): number {\n  if (typeof pos === 'number') {\n    return pos;\n  }\n\n  const lines = source.split(splitRE);\n  const { line, column } = pos;\n  let start = 0;\n  for (let i = 0; i < line - 1 && i < lines.length; i++) {\n    start += lines[i].length + 1;\n  }\n\n  return start + column;\n}\n\nfunction generateCodeFrame(\n  source: string,\n  start: number | Pos = 0,\n  end?: number | Pos,\n): string {\n  start = Math.max(posToNumber(source, start), 0);\n  end = Math.min(\n    end !== undefined ? posToNumber(source, end) : start,\n    source.length,\n  );\n  const lines = source.split(splitRE);\n  let count = 0;\n  const res: Array<string> = [];\n  for (let i = 0; i < lines.length; i++) {\n    count += lines[i].length;\n    if (count >= start) {\n      for (let j = i - range; j <= i + range || end > count; j++) {\n        if (j < 0 || j >= lines.length) {\n          continue;\n        }\n\n        const line = j + 1;\n        res.push(\n          `${line}${' '.repeat(Math.max(3 - String(line).length, 0))}|  ${\n            lines[j]\n          }`,\n        );\n        const lineLength = lines[j].length;\n        if (j === i) {\n          const pad = Math.max(start - (count - lineLength), 0);\n          const length = Math.max(\n            1,\n            end > count ? lineLength - pad : end - start,\n          );\n          res.push(`   |  ` + ' '.repeat(pad) + '^'.repeat(length));\n        } else if (j > i) {\n          if (end > count) {\n            const length = Math.max(Math.min(end - count, lineLength), 1);\n            res.push(`   |  ` + '^'.repeat(length));\n          }\n\n          count += lineLength + 1;\n        }\n      }\n\n      break;\n    }\n\n    count++;\n  }\n\n  return res.join('\\n');\n}\n"],"mappings":"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","names":["line"]}