@neabyte/stackz
Version:
Beautiful stack trace formatter with source code context for JavaScript
6 lines (5 loc) • 3 kB
JavaScript
class h{static getRuntimeType(){return typeof Deno<"u"&&Deno?.version?.deno?"deno":typeof globalThis<"u"&&"Bun"in globalThis&&globalThis.Bun?.version?"bun":typeof globalThis<"u"&&"process"in globalThis&&globalThis.process?.versions?.node?"nodejs":typeof window<"u"&&typeof document<"u"?"browser":"unknown"}static async readFile(t){const n=this.getRuntimeType();switch(n){case"deno":return await Deno.readTextFile(t);case"nodejs":return await(await import("node:fs/promises")).readFile(t,"utf-8");case"bun":{const r=globalThis;if(!r.Bun)throw new Error("Bun runtime detected but Bun API not available");return await r.Bun.file(t).text()}case"browser":throw new Error("File reading not supported in browser environment");default:throw new Error(`Unsupported runtime: ${n}`)}}}function g(e){const t=w(),n=[d(e,t).trim()];return e.frames.forEach(r=>{n.push($(r,t,"compact"))}),n.join(`
`)}async function y(e){const t=w(),n=[d(e,t).trim(),""];if(e.frames.length>0){const r=e.frames[0];if(r){n.push(`Path: ${r.file}:${r.line}:${r.column}`);const s=await b(r,t);n.push(...s),s.length>0&&n.push("")}n.push("Call Stack:"),e.frames.forEach(s=>{n.push($(s,t,"detailed"))})}return n.join(`
`)}function d(e,t){return`${t.redBg} ${t.white}${e.type} ${t.reset} ${e.message}`}function $(e,t,n){const r=B(e.file),s=`${r}:${e.line}:${e.column}`;return n==="compact"?e.function==="anonymous"||e.function===r?`${t.dim} \u2192 ${s}${t.reset}`:`${t.dim} \u2192 ${e.function} @ ${s}${t.reset}`:`${t.dim} \u2022 ${e.function} \u2192 ${s}${t.reset}`}function w(){const e=h.getRuntimeType(),t=e==="browser"||e==="unknown";return{dim:t?"":"\x1B[2m",red:t?"":"\x1B[91m",redBg:t?"":"\x1B[41m",reset:t?"":"\x1B[0m",white:t?"":"\x1B[97m"}}async function b(e,t){const n=[];try{const r=(await h.readFile(e.file)).split(`
`),s=Math.max(0,e.line-4),p=Math.min(r.length,e.line+1);for(let i=s;i<p;i++){const a=String(i+1).padStart(2," "),u=r[i]||"";if(i===e.line-1){n.push(`${t.redBg}${t.white} ${a} ${t.reset} ${t.red}${u}${t.reset}`);const o=Math.max(0,e.column-1),c=`${" ".repeat(o)}${"^".repeat(Math.max(1,u.length-o))}`;n.push(`${t.dim} ${t.red}${c}${t.reset}`)}else n.push(`${t.dim} ${a} | ${u}${t.reset}`)}}catch{}return n}function B(e){return e.split("/").pop()||e}class x{static format(t,n){const r=this.parseError(t);if(n==="compact")return g(r);if(n==="detailed")return y(r);throw new Error(`Unknown format style: ${n}`)}static parseError(t){const n=(t.stack||"").split(`
`).filter(a=>a.trim()),r=(n[0]||"").match(/^(\w+):\s*(.*)/),s=r?.[1]||"Error",p=r?.[2]||t.message,i=[];for(let a=1;a<n.length;a++){const u=n[a]?.trim();if(!u)continue;const o=u.match(/at\s+(?:async\s+)?(.+?)\s+\((.+?):(\d+):(\d+)\)|at\s+(.+?):(\d+):(\d+)/);if(o){let c,l,m,f;o[1]?(c=o[1]||"anonymous",l=o[2]||"",m=o[3]||"0",f=o[4]||"0"):(c="anonymous",l=o[5]||"",m=o[6]||"0",f=o[7]||"0"),l&&m&&f&&i.push({function:c,file:l.replace(/^file:\/\//,""),line:parseInt(m),column:parseInt(f)})}}return{type:s,message:p,frames:i}}}export{x as default};