123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- import {isValidElement} from 'react';
- import styled from '@emotion/styled';
- import isArray from 'lodash/isArray';
- import isNumber from 'lodash/isNumber';
- import isString from 'lodash/isString';
- import {AnnotatedText} from 'sentry/components/events/meta/annotatedText';
- import ExternalLink from 'sentry/components/links/externalLink';
- import {IconOpen} from 'sentry/icons';
- import {t} from 'sentry/locale';
- import {isUrl} from 'sentry/utils';
- import Toggle from './toggle';
- import {analyzeStringForRepr, naturalCaseInsensitiveSort} from './utils';
- type Props = React.HTMLAttributes<HTMLPreElement> & {
- data?: React.ReactNode;
- jsonConsts?: boolean;
- maxDefaultDepth?: number;
- meta?: Record<any, any>;
- preserveQuotes?: boolean;
- withAnnotatedText?: boolean;
- };
- function walk({
- depth,
- value = null,
- maxDefaultDepth: maxDepth = 2,
- preserveQuotes,
- withAnnotatedText,
- jsonConsts,
- meta,
- }: {
- depth: number;
- value?: React.ReactNode;
- } & Pick<
- Props,
- 'withAnnotatedText' | 'preserveQuotes' | 'jsonConsts' | 'meta' | 'maxDefaultDepth'
- >) {
- let i = 0;
- const children: React.ReactNode[] = [];
- if (value === null) {
- return (
- <span className="val-null">
- <AnnotatedText value={jsonConsts ? 'null' : 'None'} meta={meta?.[''] ?? meta} />
- </span>
- );
- }
- if (value === true || value === false) {
- return (
- <span className="val-bool">
- <AnnotatedText
- value={jsonConsts ? (value ? 'true' : 'false') : value ? 'True' : 'False'}
- meta={meta?.[''] ?? meta}
- />
- </span>
- );
- }
- if (isString(value)) {
- const valueInfo = analyzeStringForRepr(value);
- const valueToBeReturned = withAnnotatedText ? (
- <AnnotatedText value={valueInfo.repr} meta={meta?.[''] ?? meta} />
- ) : (
- valueInfo.repr
- );
- const out = [
- <span
- key="value"
- className={
- (valueInfo.isString ? 'val-string' : '') +
- (valueInfo.isStripped ? ' val-stripped' : '') +
- (valueInfo.isMultiLine ? ' val-string-multiline' : '')
- }
- >
- {preserveQuotes ? `"${valueToBeReturned}"` : valueToBeReturned}
- </span>,
- ];
- if (valueInfo.isString && isUrl(value)) {
- out.push(
- <ExternalLink key="external" href={value} className="external-icon">
- <StyledIconOpen size="xs" aria-label={t('Open link')} />
- </ExternalLink>
- );
- }
- return out;
- }
- if (isNumber(value)) {
- const valueToBeReturned =
- withAnnotatedText && meta ? (
- <AnnotatedText value={value} meta={meta?.[''] ?? meta} />
- ) : (
- value
- );
- return <span>{valueToBeReturned}</span>;
- }
- if (isArray(value)) {
- for (i = 0; i < value.length; i++) {
- children.push(
- <span className="val-array-item" key={i}>
- {walk({
- value: value[i],
- depth: depth + 1,
- preserveQuotes,
- withAnnotatedText,
- jsonConsts,
- meta: meta?.[i]?.[''] ?? meta?.[i] ?? meta?.[''] ?? meta,
- })}
- {i < value.length - 1 ? <span className="val-array-sep">{', '}</span> : null}
- </span>
- );
- }
- return (
- <span className="val-array">
- <span className="val-array-marker">{'['}</span>
- <Toggle highUp={depth <= maxDepth} wrapClassName="val-array-items">
- {children}
- </Toggle>
- <span className="val-array-marker">{']'}</span>
- </span>
- );
- }
- if (isValidElement(value)) {
- return value;
- }
- const keys = Object.keys(value);
- keys.sort(naturalCaseInsensitiveSort);
- for (i = 0; i < keys.length; i++) {
- const key = keys[i];
- children.push(
- <span className="val-dict-pair" key={key}>
- <span className="val-dict-key">
- <span className="val-string">{preserveQuotes ? `"${key}"` : key}</span>
- </span>
- <span className="val-dict-col">{': '}</span>
- <span className="val-dict-value">
- {walk({
- value: value[key],
- depth: depth + 1,
- preserveQuotes,
- withAnnotatedText,
- jsonConsts,
- meta: meta?.[key]?.[''] ?? meta?.[key] ?? meta?.[''] ?? meta,
- })}
- {i < keys.length - 1 ? <span className="val-dict-sep">{', '}</span> : null}
- </span>
- </span>
- );
- }
- return (
- <span className="val-dict">
- <span className="val-dict-marker">{'{'}</span>
- <Toggle highUp={depth <= maxDepth - 1} wrapClassName="val-dict-items">
- {children}
- </Toggle>
- <span className="val-dict-marker">{'}'}</span>
- </span>
- );
- }
- function ContextData({
- children,
- meta,
- jsonConsts,
- maxDefaultDepth,
- data = null,
- preserveQuotes = false,
- withAnnotatedText = false,
- ...props
- }: Props) {
- return (
- <pre {...props}>
- {walk({
- value: data,
- depth: 0,
- maxDefaultDepth,
- meta,
- jsonConsts,
- withAnnotatedText,
- preserveQuotes,
- })}
- {children}
- </pre>
- );
- }
- export default ContextData;
- const StyledIconOpen = styled(IconOpen)`
- position: relative;
- top: 1px;
- `;
|