Files
zclaw_openfang/desktop/src/lib/json-utils.ts
iven f79560a911 refactor(desktop): split kernel_commands/pipeline_commands into modules, add SaaS client libs and gateway modules
Split monolithic kernel_commands.rs (2185 lines) and pipeline_commands.rs (1391 lines)
into focused sub-modules under kernel_commands/ and pipeline_commands/ directories.
Add gateway module (commands, config, io, runtime), health_check, and 15 new
TypeScript client libraries for SaaS relay, auth, admin, telemetry, and kernel
sub-systems (a2a, agent, chat, hands, skills, triggers).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 11:12:47 +08:00

174 lines
5.2 KiB
TypeScript

/**
* Safe JSON Parsing Utilities
*
* Provides try-catch protected JSON parsing with optional default values
* and context-aware error messages.
*
* Usage:
* - safeJsonParse: Returns result object with success/failure status
* - parseJsonOrDefault: Returns parsed value or default on failure
* - parseJsonOrThrow: Returns parsed value or throws friendly error
*/
export interface SafeJsonParseResult<T> {
success: boolean;
data?: T;
error?: string;
}
/**
* Safely parse a JSON string with error handling
*
* @param text - The JSON string to parse
* @param defaultValue - Optional default value to return on parse failure
* @returns Result object with success status, data, and optional error message
*
* @example
* const result = safeJsonParse<UserData>(jsonString);
* if (result.success) {
* console.log(result.data);
* } else {
* console.error(result.error);
* }
*/
export function safeJsonParse<T>(text: string, defaultValue?: T): SafeJsonParseResult<T> {
try {
const data = JSON.parse(text) as T;
return { success: true, data };
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown JSON parse error';
// Log truncated input for debugging
const truncatedInput = text.length > 100 ? `${text.substring(0, 100)}...` : text;
console.warn('[json-utils] Parse failed:', errorMessage, 'Input:', truncatedInput);
return {
success: false,
error: errorMessage,
data: defaultValue,
};
}
}
/**
* Safely parse JSON and return default value on failure
*
* Use this when you have a sensible default and don't need to know
* about parse failures.
*
* @param text - The JSON string to parse
* @param defaultValue - The value to return if parsing fails
* @returns The parsed data or the default value
*
* @example
* const config = parseJsonOrDefault(rawConfig, defaultConfig);
*/
export function parseJsonOrDefault<T>(text: string, defaultValue: T): T {
const result = safeJsonParse<T>(text, defaultValue);
return result.data!;
}
/**
* Safely parse JSON or throw a friendly error with context
*
* Use this when JSON parsing is required and failures should halt execution
* with a clear error message.
*
* @param text - The JSON string to parse
* @param context - Optional context for the error message (e.g., "loading config")
* @returns The parsed data
* @throws Error with context-aware message if parsing fails
*
* @example
* try {
* const data = parseJsonOrThrow<UserConfig>(rawJson, 'parsing user config');
* } catch (error) {
* showToast(error.message); // "JSON parse failed (parsing user config): Unexpected token..."
* }
*/
export function parseJsonOrThrow<T>(text: string, context?: string): T {
const result = safeJsonParse<T>(text);
if (!result.success) {
throw new Error(`JSON parse failed${context ? ` (${context})` : ''}: ${result.error}`);
}
return result.data!;
}
/**
* Type guard to check if a value is a valid JSON-compatible object
*
* @param value - The value to check
* @returns True if the value can be safely serialized to JSON
*/
export function isJsonSerializable(value: unknown): boolean {
try {
JSON.stringify(value);
return true;
} catch (_e) {
return false;
}
}
/**
* Safely stringify a value to JSON
*
* @param value - The value to stringify
* @param fallback - Fallback string if stringification fails
* @returns JSON string or fallback
*/
export function safeJsonStringify(value: unknown, fallback = '{}'): string {
try {
return JSON.stringify(value);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown stringify error';
console.warn('[json-utils] Stringify failed:', errorMessage);
return fallback;
}
}
/**
* Safely stringify with pretty formatting
*
* @param value - The value to stringify
* @param indent - Number of spaces for indentation (default: 2)
* @param fallback - Fallback string if stringification fails
* @returns Formatted JSON string or fallback
*/
export function safeJsonStringifyPretty(value: unknown, indent = 2, fallback = '{}'): string {
try {
return JSON.stringify(value, null, indent);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown stringify error';
console.warn('[json-utils] Pretty stringify failed:', errorMessage);
return fallback;
}
}
/**
* Deep clone an object using JSON serialization
*
* Note: This only works for JSON-serializable data (no functions, undefined, symbols, etc.)
*
* @param value - The value to clone
* @returns A deep clone of the value
* @throws Error if the value cannot be serialized
*/
export function deepClone<T>(value: T): T {
return JSON.parse(JSON.stringify(value)) as T;
}
/**
* Safely deep clone an object with fallback
*
* @param value - The value to clone
* @param fallback - Fallback value if cloning fails
* @returns A deep clone of the value or the fallback
*/
export function safeDeepClone<T>(value: T, fallback: T): T {
try {
return JSON.parse(JSON.stringify(value)) as T;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown clone error';
console.warn('[json-utils] Deep clone failed:', errorMessage);
return fallback;
}
}