@tapjs/reporter
Version:
Pretty test output reporters for tap
68 lines • 2.83 kB
JavaScript
// @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 from 'react';
import { stringify } from 'tap-yaml';
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) => !p || !(isAbsolute(p) || p.startsWith('node_modules'));
const removeRelativeGenerated = (c) => {
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, f) => {
if (!f ||
f === 'native' ||
f === '<anonymous>' ||
isAbsolute(f) ||
f.startsWith('..') ||
!s.includes(f)) {
return React.createElement(Text, null, chalk.dim(s));
}
const split = s.split(f);
const last = split[split.length - 1];
split.pop();
return (React.createElement(Text, null, split.map(s => `${chalk.dim(s)}${chalk.yellowBright(f)}`).join('') +
chalk.dim(last)));
};
const isUseful = (c) => !!c.lineNumber || !!c.columnNumber || !!c.fileName;
export const Stack = ({ stack }) => {
if (!stack?.trim())
return React.createElement(React.Fragment, null);
const p = parseStack(stack);
if (!p.length)
return React.createElement(React.Fragment, null);
const st = p
.map(c => String(c))
.join('\n')
.replace(/\n+$/, '')
.split('\n')
.map(l => {
const c = new CallSiteLike(null, l);
removeRelativeGenerated(c);
removeRelativeGenerated(c.evalOrigin);
if (!isUseful(c))
return undefined;
return c;
})
.filter(c => !!c)
.map(c => highlightFilename(String(c), c?.evalOrigin ? c?.evalOrigin.fileName : c?.fileName));
// if nothing useful was found, just show the string
const showRaw = !st.length && { stack };
return (React.createElement(Box, { flexDirection: "column" }, st.length ?
st.map((line, key) => (React.createElement(HangingIndent, { key: key }, line)))
: showRaw ?
React.createElement(Text, { dimColor: true }, stringify(showRaw).trimEnd())
: /* c8 ignore next - impossible */ React.createElement(React.Fragment, null)));
};
//# sourceMappingURL=stack.js.map