Parse JSON with more helpful errors and visual code frames for debugging
npx @tessl/cli install tessl/npm-parse-json@8.3.0Parse JSON is a JavaScript library that enhances the standard JSON.parse() functionality with more helpful error messages and visual code frames for debugging. It generates user-friendly error messages with code frames that highlight the exact location of JSON syntax errors, making it particularly valuable for development tools, configuration parsers, CLI applications, and any system that needs to provide clear feedback about JSON parsing failures.
npm install parse-jsonimport parseJson, { JSONError } from "parse-json";For CommonJS:
const parseJson = require("parse-json");
const { JSONError } = require("parse-json");Parse JSON is built around two main components:
import parseJson, { JSONError } from "parse-json";
const invalidJson = '{\n\t"foo": true,\n}';
try {
// Standard JSON.parse would throw a less helpful error
const result = parseJson(invalidJson);
} catch (error) {
if (error instanceof JSONError) {
console.log(error.message);
// Output:
// Expected double-quoted property name in JSON at position 16 (line 3 column 1)
//
// 1 | {
// 2 | "foo": true,
// > 3 | }
// | ^
}
}
// Include filename for better debugging context
try {
const result = parseJson(invalidJson, 'config.json');
} catch (error) {
console.log(error.message);
// Output includes filename: "... in config.json"
}The main parsing function that provides enhanced error messages with visual code frames.
/**
* Parse JSON with more helpful errors
* @param {string} string - A valid JSON string to parse
* @param {Reviver} [reviver] - Optional reviver function (same as JSON.parse)
* @param {string} [filename] - Optional filename for error context
* @returns {JsonObject} Parsed JSON object
* @throws {JSONError} When there is a parsing error
*/
function parseJson(string: string, reviver?: Reviver, filename?: string): JsonObject;
/**
* Parse JSON with filename as second parameter (overload)
* @param {string} string - A valid JSON string to parse
* @param {string} [filename] - Optional filename for error context
* @returns {JsonObject} Parsed JSON object
* @throws {JSONError} When there is a parsing error
*/
function parseJson(string: string, filename?: string): JsonObject;Usage Examples:
import parseJson from "parse-json";
// Basic parsing
const data = parseJson('{"name": "Alice", "age": 30}');
// With reviver function
const dataWithReviver = parseJson('{"date": "2023-01-01"}', (key, value) => {
if (key === 'date') return new Date(value);
return value;
});
// With filename for better error context
const config = parseJson(configString, 'app-config.json');
// Filename as second parameter (alternative syntax)
const userdata = parseJson(jsonString, 'users.json');Custom error class with detailed error information and visual code frames.
/**
* Custom error class for JSON parsing errors
* Exposed for instanceof checking and error handling
*/
class JSONError extends Error {
/**
* The error name, always "JSONError"
*/
name: "JSONError";
/**
* The filename displayed in the error message, if provided
*/
fileName?: string;
/**
* Enhanced error message including code frame and filename context
* Supports both getter and setter behavior
*/
message: string;
/**
* The printable section of JSON with syntax highlighting that shows the error
* @readonly
*/
readonly codeFrame?: string;
/**
* The raw version of codeFrame without ANSI color codes
* @readonly
*/
readonly rawCodeFrame?: string;
/**
* The original JSON.parse() SyntaxError that caused this error
*/
cause?: SyntaxError;
/**
* Constructor for JSONError
* @param messageOrOptions - Either a string message (legacy) or options object
*/
constructor(messageOrOptions: string | JSONErrorOptions);
}
/**
* Options for creating a JSONError with enhanced features
*/
interface JSONErrorOptions {
/** The original JSON.parse() error */
jsonParseError: SyntaxError;
/** Optional filename for error context */
fileName?: string;
/** The input JSON string that caused the error */
input: string;
}Usage Examples:
import parseJson, { JSONError } from "parse-json";
try {
parseJson('{"invalid": json}');
} catch (error) {
if (error instanceof JSONError) {
// Access error properties
console.log('Error name:', error.name); // "JSONError"
console.log('Filename:', error.fileName); // undefined or specified filename
console.log('Enhanced message:', error.message); // Full message with code frame
console.log('Code frame:', error.codeFrame); // Highlighted code frame
console.log('Raw code frame:', error.rawCodeFrame); // Code frame without colors
console.log('Original error:', error.cause); // Original SyntaxError
// You can modify the filename after catching
error.fileName = 'my-config.json';
console.log(error.message); // Now includes filename
// You can also modify the message
error.message = 'Custom error message';
console.log(error.message); // Custom message with filename and code frame
}
}
// Legacy constructor pattern (for backwards compatibility)
const legacyError = new JSONError('Custom error message');
legacyError.fileName = 'config.json';
console.log(legacyError.message); // "Custom error message in config.json"
// Modern constructor pattern (used internally by parseJson)
const modernError = new JSONError({
jsonParseError: new SyntaxError('Invalid JSON'),
fileName: 'data.json',
input: '{"invalid": json}'
});
console.log(modernError.cause); // Original SyntaxError
console.log(modernError.codeFrame); // Generated code frame/**
* Type alias for the reviver parameter, matches JSON.parse signature
*/
type Reviver = Parameters<typeof JSON['parse']>[1];
/**
* Return type for parsed JSON, using JsonObject from type-fest
*/
type JsonObject = import('type-fest').JsonObject;
/**
* Options for creating a JSONError with enhanced features
*/
interface JSONErrorOptions {
/** The original JSON.parse() error */
jsonParseError: SyntaxError;
/** Optional filename for error context */
fileName?: string;
/** The input JSON string that caused the error */
input: string;
}The library provides several patterns for handling JSON parsing errors:
Basic Error Handling:
try {
const data = parseJson(jsonString);
// Process data
} catch (error) {
if (error instanceof JSONError) {
console.error('JSON parsing failed:', error.message);
}
}Filename Context:
// Set filename during parsing
try {
const config = parseJson(configString, 'app.config.json');
} catch (error) {
// Error message will include filename
}
// Or set filename after catching
try {
const data = parseJson(jsonString);
} catch (error) {
if (error instanceof JSONError) {
error.fileName = 'user-data.json';
throw error; // Re-throw with filename context
}
}Accessing Code Frames:
try {
parseJson(invalidJson);
} catch (error) {
if (error instanceof JSONError) {
// For display in terminals (with colors)
console.log(error.codeFrame);
// For logging or plain text display (without colors)
console.log(error.rawCodeFrame);
}
}Edge Cases:
// Empty string handling
try {
parseJson('');
} catch (error) {
console.log(error.message); // "Unexpected end of JSON input while parsing empty string"
console.log(error.rawCodeFrame); // undefined (no code frame for empty input)
}
// Incomplete JSON
try {
parseJson('{');
} catch (error) {
console.log(error.rawCodeFrame); // Shows code frame pointing to the problematic character
}
// Invalid tokens with Unicode representation
try {
parseJson('a');
} catch (error) {
console.log(error.message); // 'Unexpected token "a"(\u{61}), "a" is not valid JSON'
}"type": "module")