File size: 6,637 Bytes
e706de2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
/**
* Solution 2: JSON Parser Runnable
*
* This solution demonstrates:
* - Graceful error handling with try-catch
* - Configuration through constructor options
* - Type checking input
* - Providing default values
*/
import { Runnable } from '../../../../src/index.js';
/**
* JsonParserRunnable - Safely parses JSON strings
*/
class JsonParserRunnable extends Runnable {
constructor(options = {}) {
super();
// Store configuration
this.defaultValue = options.defaultValue ?? null;
this.throwOnError = options.throwOnError ?? false;
}
async _call(input, config) {
// Ensure input is a string
if (typeof input !== 'string') {
if (this.throwOnError) {
throw new Error('Input must be a string');
}
return this.defaultValue;
}
// Handle empty strings
if (input.trim().length === 0) {
return this.defaultValue;
}
// Try to parse JSON
try {
return JSON.parse(input);
} catch (error) {
// If throwOnError is true, propagate the error
if (this.throwOnError) {
throw new Error(`Failed to parse JSON: ${error.message}`);
}
// Otherwise, return default value
return this.defaultValue;
}
}
toString() {
return `JsonParserRunnable()`;
}
}
// ============================================================================
// Tests
// ============================================================================
async function runTests() {
console.log('π§ͺ Testing JsonParserRunnable Solution...\n');
try {
// Test 1: Valid JSON object
console.log('Test 1: Valid JSON object');
const parser = new JsonParserRunnable();
const result1 = await parser.invoke('{"name":"Alice","age":30}');
console.assert(result1.name === 'Alice', 'Should parse name');
console.assert(result1.age === 30, 'Should parse age');
console.log('β
Parsed:', result1);
console.log();
// Test 2: Valid JSON array
console.log('Test 2: Valid JSON array');
const result2 = await parser.invoke('[1, 2, 3, 4, 5]');
console.assert(Array.isArray(result2), 'Should return array');
console.assert(result2.length === 5, 'Should have 5 elements');
console.log('β
Parsed:', result2);
console.log();
// Test 3: Invalid JSON returns null
console.log('Test 3: Invalid JSON returns null');
const result3 = await parser.invoke('this is not json');
console.assert(result3 === null, 'Should return null for invalid JSON');
console.log('β
Returns:', result3);
console.log();
// Test 4: Empty string returns null
console.log('Test 4: Empty string returns null');
const result4 = await parser.invoke('');
console.assert(result4 === null, 'Should return null for empty string');
console.log('β
Returns:', result4);
console.log();
// Test 5: With default value
console.log('Test 5: With default value');
const parserWithDefault = new JsonParserRunnable({
defaultValue: { error: 'Invalid JSON' }
});
const result5 = await parserWithDefault.invoke('bad json');
console.assert(result5.error === 'Invalid JSON', 'Should return default value');
console.log('β
Returns:', result5);
console.log();
// Test 6: Nested JSON
console.log('Test 6: Nested JSON');
const nested = '{"user":{"name":"Bob","address":{"city":"NYC"}}}';
const result6 = await parser.invoke(nested);
console.assert(result6.user.address.city === 'NYC', 'Should parse nested objects');
console.log('β
Parsed:', result6);
console.log();
// Test 7: Numbers and booleans
console.log('Test 7: Primitive values');
const result7a = await parser.invoke('42');
const result7b = await parser.invoke('true');
const result7c = await parser.invoke('"hello"');
console.assert(result7a === 42, 'Should parse number');
console.assert(result7b === true, 'Should parse boolean');
console.assert(result7c === 'hello', 'Should parse string');
console.log('β
Parsed primitives:', result7a, result7b, result7c);
console.log();
// Test 8: Batch processing
console.log('Test 8: Batch processing');
const inputs = [
'{"id":1}',
'{"id":2}',
'invalid',
'{"id":3}'
];
const results = await parser.batch(inputs);
console.log(' Inputs:', inputs);
console.log(' Results:', results);
console.assert(results[0].id === 1, 'First should parse');
console.assert(results[2] === null, 'Invalid should be null');
console.assert(results[3].id === 3, 'Last should parse');
console.log('β
Batch processing works');
console.log();
// Test 9: throwOnError mode
console.log('Test 9: throwOnError mode');
const strictParser = new JsonParserRunnable({ throwOnError: true });
try {
await strictParser.invoke('invalid json');
console.error('β Should have thrown error');
} catch (error) {
console.log('β
Throws error in strict mode:', error.message);
}
console.log();
// Test 10: Complex real-world JSON
console.log('Test 10: Complex real-world JSON');
const complexJson = `{
"users": [
{"id": 1, "name": "Alice", "active": true},
{"id": 2, "name": "Bob", "active": false}
],
"metadata": {
"total": 2,
"timestamp": "2024-01-01"
}
}`;
const result10 = await parser.invoke(complexJson);
console.assert(result10.users.length === 2, 'Should have 2 users');
console.assert(result10.metadata.total === 2, 'Should have metadata');
console.log('β
Parsed complex JSON');
console.log();
console.log('π All tests passed!');
} catch (error) {
console.error('β Test failed:', error.message);
console.error(error.stack);
}
}
// Run tests
if (import.meta.url === `file://${process.argv[1]}`) {
runTests();
}
export { JsonParserRunnable }; |