UNPKG

react-native-xenon

Version:

A powerful in-app debugging tool for React Native.

185 lines (150 loc) 5.21 kB
import { URL } from 'react-native-url-polyfill'; import { NetworkType, type HttpRequest, type LogMessage, type WebSocketRequest } from '../types'; import colors from '../theme/colors'; import { Share } from 'react-native'; import refs, { DebuggerVisibility } from './refs'; let isSharing = false; export const shareText = async (text: string) => { if (isSharing) return; try { isSharing = true; refs.debugger.current?.setCurrentIndex(DebuggerVisibility.Bubble); await Share.share({ message: text.trim(), }); } catch (error) { // Handle error } finally { refs.debugger.current?.setCurrentIndex(DebuggerVisibility.Panel); isSharing = false; } }; export const getNetworkUtils = (data?: HttpRequest | WebSocketRequest) => { if (!data || !data.url) return {}; const isWS = data?.type === NetworkType.WS; const requestUrl = new URL(data.url); const overviewShown = !!data.url; const httpHeadersShown = !isWS && (!!data.requestHeaders?.size || !!data.responseHeaders?.size); const websocketHeadersShown = isWS && !!Object.keys(data.options?.headers ?? {}).length; const headersShown = httpHeadersShown || websocketHeadersShown; const requestShown = !isWS && (!!requestUrl.search || !!data.body); const responseShown = !isWS && !!data.response; const messagesShown = isWS && !!data.messages; return { isWS, requestUrl, overviewShown, headersShown, requestShown, responseShown, messagesShown, }; }; const hexToHexAlpha = (hex: string, opacity: number) => `${hex}${`${(Math.min(Math.max(opacity, 0), 1) * 255).toString(16)}0`.slice(0, 2)}`; export const getConsoleTypeColor = (type: LogMessage['type']) => { let color: string; switch (type) { case 'log': color = colors.white; break; case 'info': color = colors.blue; break; case 'warn': case 'debug': case 'trace': color = colors.yellow; break; case 'error': color = colors.red; break; default: color = colors.white; } return hexToHexAlpha(color, 0.25); }; //#region metrics export const getVerticalSafeMargin = (screenHeight: number) => screenHeight / 8; export const clamp = (min: number, max: number, value: number) => Math.max(min, Math.min(max, value)); export const getHttpInterceptorId = () => { const timestamp = Date.now().toString(36); const randomNum = Math.random().toString(36).substring(2, 10); return timestamp + randomNum; }; //#endregion //#region formatters export const showNewLine = (when: boolean) => (when ? '\n' : ''); const limitChar = (value: any, limit = 100000) => { const stringValue = typeof value === 'string' ? value : JSON.stringify(value ?? ''); return stringValue.length > limit ? `${stringValue.slice(0, limit)}\n---LIMITED TO ${limit} CHARACTERS---` : stringValue; }; export const keyValueToString = ( key: string, value: any, newLine: 'leading' | 'trailing' | null = 'trailing', ): string => `${newLine === 'leading' ? '\n' : ''}${key}: ${limitChar(value)}${showNewLine(newLine === 'trailing')}`; export const formatRequestMethod = (method?: string) => method ?? 'GET'; export const formatRequestDuration = (startTime?: number, endTime?: number) => { if (typeof startTime !== 'number' || typeof endTime !== 'number') return 'pending'; return `${endTime - startTime}ms`; }; export const formatRequestStatusCode = (statusCode?: number) => `${statusCode ?? 'pending'}`; export const formatLogMessage = (values: any[]) => { return values.reduce((pre, cur, index) => pre + (!index ? '' : ', ') + limitChar(cur), ''); }; export const beautify = (data: any, beautified: boolean) => { if (!data) return ''; try { const res = typeof data === 'string' ? JSON.parse(data) : data; return beautified ? JSON.stringify(res, null, 4) : limitChar(res); } catch (error) { return limitChar(data); } }; export const convertToCurl = ( method: HttpRequest['method'], url: HttpRequest['url'], headers: HttpRequest['requestHeaders'], body: HttpRequest['body'], ) => { let curlCommand = `curl -X ${method.toUpperCase()} "${url}"`; if (headers) { for (const [key, value] of headers.entries()) { curlCommand += ` -H "${key}: ${value}"`; } } if (body) { const bodyString = typeof body === 'string' ? body : JSON.stringify(body); curlCommand += ` -d '${bodyString}'`; } return curlCommand; }; export const formatCount = (count: number) => { if (count < 1000) return count.toString(); if (count < 1000000) return `${(count / 1000).toFixed(1)}K`; return `${(count / 1000000).toFixed(1)}M`; }; //#endregion //#region decorators export function frozen(_target: Object) { const descriptor: PropertyDescriptor = arguments[2]; descriptor.configurable = false; descriptor.writable = false; } export function singleton<T extends { new (...args: any[]): {} }>(constructor: T) { class Singleton extends constructor { static #instance: Singleton; constructor(...args: any[]) { if (Singleton.#instance) return Singleton.#instance; super(...args); Singleton.#instance = this; } } return Singleton; } //#endregion