-
-
Notifications
You must be signed in to change notification settings - Fork 269
/
stack.tsx
73 lines (67 loc) · 2.11 KB
/
stack.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// @tapjs/stack makes stack traces a bit nicer, but we can do even better
// with some colors and highlighting.
import { CallSiteLike, parseStack } from '@tapjs/stack'
import chalk from 'chalk'
import { Box, Text } from 'ink'
import { isAbsolute } from 'path'
import React, { FC } from 'react'
import { HangingIndent } from './hanging-indent.js'
// only show generated callsite info if it's not ours
// it's useful to know where to start throwing console.logs, but
// if it's our own code, it's just noise.
// Treat ./node_modules as "absolute" for this purpose, since deps
// aren't "local" in the same sense, even though they live in cwd.
const relativeOrMissing = (p?: string | null) =>
!p || !(isAbsolute(p) || p.startsWith('node_modules'))
const removeRelativeGenerated = (c?: CallSiteLike | null) => {
if (c && relativeOrMissing(c.fileName)) c.generated = undefined
}
// Only highlight *our* filenames, not those from deps or outside paths.
// We use chalk.dim() directly here, because neighboring Text nodes get
// squashed together.
const highlightFilename = (s: string, f?: string | null) => {
if (
!f ||
f === 'native' ||
f === '<anonymous>' ||
isAbsolute(f) ||
f.startsWith('..') ||
!s.includes(f)
) {
return <Text>{chalk.dim(s)}</Text>
}
const split = s.split(f)
const last = split[split.length - 1]
split.pop()
return (
<Text>
{split
.map(s => `${chalk.dim(s)}${chalk.yellowBright(f)}`)
.join('') + chalk.dim(last)}
</Text>
)
}
export const Stack: FC<{ stack?: string }> = ({ stack }) => {
if (!stack?.trim()) return <></>
const st = parseStack(stack)
.map(c => String(c))
.join('\n')
.replace(/\n+$/, '')
.split('\n')
.map(l => {
const c = new CallSiteLike(null, l)
removeRelativeGenerated(c)
removeRelativeGenerated(c.evalOrigin)
return highlightFilename(
c.toString(),
c.evalOrigin ? c.evalOrigin.fileName : c.fileName
)
})
return (
<Box flexDirection="column">
{st.map((line, key) => (
<HangingIndent key={key}>{line}</HangingIndent>
))}
</Box>
)
}