LCOV - code coverage report
Current view: top level - dashql-app/src/ui/json - json_literal.tsx Coverage Total Hit
Test: DashQL 915828b Lines: 74.4 % 133 99
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as React from 'react';
       2              : import * as styles from './json_view.module.css';
       3              : 
       4              : import { useJsonViewerState } from './json_view_state.js';
       5              : 
       6            1 : export function isFloat(n: number) { return (Number(n) === n && n % 1 !== 0) || isNaN(n); }
       7              : 
       8              : interface ValueProps {
       9              :     value: unknown;
      10              : }
      11              : 
      12            1 : export function JsonLiteral(props: ValueProps) {
      13            1 :     const { value } = props;
      14            1 :     if (value instanceof URL) {
      15            0 :         return <UrlLiteral>{value}</UrlLiteral>;
      16              :     }
      17            1 :     if (typeof value === 'string') {
      18            1 :         return <StringLiteral>{value}</StringLiteral>;
      19              :     }
      20            1 :     if (value === true) {
      21            1 :         return <TrueLiteral />;
      22              :     }
      23            1 :     if (value === false) {
      24            1 :         return <FalseLiteral />;
      25              :     }
      26            1 :     if (value === null) {
      27            1 :         return <NullLiteral />;
      28              :     }
      29            1 :     if (value === undefined) {
      30            1 :         return <UndefinedLiteral />;
      31              :     }
      32            1 :     if (value instanceof Date) {
      33            0 :         return <DateLiteral>{value}</DateLiteral>;
      34              :     }
      35              : 
      36            1 :     if (typeof value === 'number' && isNaN(value)) {
      37            0 :         return <NanLiteral />;
      38            1 :     } else if (typeof value === 'number' && isFloat(value)) {
      39            0 :         return <FloatLiteral>{value}</FloatLiteral>;
      40            1 :     } else if (typeof value === 'bigint') {
      41            1 :         return <BigintLiteral>{value}</BigintLiteral>;
      42            1 :     } else if (typeof value === 'number') {
      43            1 :         return <IntLiteral>{value}</IntLiteral>;
      44              :     }
      45              : 
      46            0 :     return null;
      47            1 : };
      48              : 
      49            1 : export function bigIntToString(bi?: BigInt | string) {
      50            1 :     if (bi === undefined) {
      51            0 :         return '0n';
      52            1 :     } else if (typeof bi === 'string') {
      53            1 :         try {
      54            1 :             bi = BigInt(bi);
      55            1 :         } catch (e) {
      56            0 :             return '0n';
      57            0 :         }
      58              :     }
      59            1 :     return bi ? bi.toString() + 'n' : '0n';
      60            1 : };
      61              : 
      62            1 : function StringLiteral(props: { children: string }) {
      63            1 :     const { variant, shortenTextAfterLength: length = 30, stringEllipsis = '...' } = useJsonViewerState();
      64            1 :     const childrenStr = props.children as string;
      65            1 :     const [shorten, setShorten] = React.useState(length && childrenStr.length > length);
      66            1 :     React.useEffect(() => setShorten(length && childrenStr.length > length), [length]);
      67              : 
      68            1 :     const style: React.CSSProperties = length > 0 ? {
      69            1 :         cursor: childrenStr.length <= length ? 'initial' : 'pointer',
      70            1 :     } : {};
      71              : 
      72            1 :     const onClick = length > 0 && childrenStr.length > length ? () => setShorten(!shorten) : undefined;
      73            1 :     const text = shorten ? `${childrenStr.slice(0, length)}${stringEllipsis}` : childrenStr;
      74            1 :     const cls = shorten ? styles.literal_string_short : styles.literal_string;
      75              : 
      76              :     // The explorer shows strings without quotes, so an empty string needs a placeholder
      77            1 :     if (variant === 'explorer') {
      78            1 :         if (childrenStr.length === 0) {
      79            1 :             return <span className={styles.explorer_placeholder}>empty</span>;
      80              :         }
      81            1 :         return (
      82            1 :             <span className={cls} style={style} onClick={onClick}>
      83            1 :                 {text}
      84            1 :             </span>
      85              :         );
      86            1 :     }
      87            1 :     return (
      88            1 :         <React.Fragment>
      89            1 :             <LiteralQuotes />
      90            1 :             <span className={cls} style={style} onClick={onClick}>
      91            1 :                 {text}
      92            1 :             </span>
      93            1 :             <LiteralQuotes />
      94            1 :         </React.Fragment>
      95              :     );
      96            1 : };
      97              : 
      98            1 : function LiteralQuotes() {
      99            1 :     const { variant } = useJsonViewerState();
     100            1 :     if (variant === 'explorer') return null;
     101            1 :     return (
     102            1 :         <span className={styles.literal_quotes}>
     103              :             "
     104            1 :         </span>
     105              :     );
     106            1 : };
     107              : 
     108            1 : function TrueLiteral() {
     109            1 :     return (
     110            1 :         <span className={styles.literal_true}>
     111            1 :             {true.toString()}
     112            1 :         </span>
     113              :     );
     114            1 : };
     115              : 
     116            1 : function FalseLiteral() {
     117            1 :     return (
     118            1 :         <span className={styles.literal_false}>
     119            1 :             {false.toString()}
     120            1 :         </span>
     121              :     );
     122            1 : };
     123              : 
     124            0 : function FloatLiteral(props: { children: number }) {
     125            0 :     return (
     126            0 :         <span className={styles.literal_float}>
     127            0 :             {props.children.toString()}
     128            0 :         </span>
     129              :     );
     130            0 : };
     131              : 
     132            1 : function IntLiteral(props: { children: number }) {
     133            1 :     return (
     134            1 :         <span className={styles.literal_int}>
     135            1 :             {props.children.toString()}
     136            1 :         </span>
     137              :     );
     138            1 : };
     139              : 
     140            1 : function BigintLiteral(props: { children: bigint }) {
     141            1 :     return (
     142            1 :         <span className={styles.literal_bigint}>
     143            1 :             {bigIntToString(props.children.toString())}
     144            1 :         </span>
     145              :     );
     146            1 : };
     147              : 
     148            0 : function UrlLiteral(props: { children: URL }) {
     149            0 :     return (
     150            0 :         <a className={styles.literal_url} href={props.children?.href} target="_blank" rel="noopener noreferrer">
     151            0 :             <LiteralQuotes />
     152            0 :             {props.children?.href}
     153            0 :             <LiteralQuotes />
     154            0 :         </a>
     155              :     );
     156            0 : };
     157              : 
     158            0 : function DateLiteral(props: { children?: Date }) {
     159            0 :     const childStr = props.children instanceof Date ? props.children.toLocaleString() : props.children;
     160            0 :     return (
     161            0 :         <span className={styles.literal_date}>
     162            0 :             {childStr}
     163            0 :         </span>
     164              :     );
     165            0 : };
     166              : 
     167            1 : function UndefinedLiteral() {
     168            1 :     return (
     169            1 :         <span className={styles.literal_undefined}>
     170              :             undefined
     171            1 :         </span>
     172              :     );
     173            1 : };
     174              : 
     175            1 : function NullLiteral() {
     176            1 :     return (
     177            1 :         <span className={styles.literal_null}>
     178              :             null
     179            1 :         </span>
     180              :     );
     181            1 : };
     182              : 
     183            0 : function NanLiteral() {
     184            0 :     return (
     185            0 :         <span className={styles.literal_nan}>
     186              :             nan
     187            0 :         </span>
     188              :     );
     189            0 : };
        

Generated by: LCOV version 2.0-1