json-parser-yaml-converter
Version:
Enhanced JSON Parser with verbose error messages and JSON to YAML conversion
66 lines (60 loc) • 1.92 kB
JavaScript
/**
* This module contains the function jsonParse that parses a JSON file.
*
* @module parser
*/
;
import { readFileSync } from 'fs';
import { YELLOW, RESET, BOLD, UNDERLINE } from './colors.js';
import nearley from 'nearley';
import grammar from './grammar.js';
/**
* Parses a JSON file.
* @param {string} jsonFile JSON file to parse.
* @param {boolean} ast If true, returns the AST instead of the object.
* @returns {Object} The parsed JSON file.
* @throws {Error} If the JSON file could not be parsed.
*/
function jsonParse(jsonFile, ast = false) {
const INPUT = readFileSync(jsonFile, 'utf-8');
const PARSER = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
try {
const RESULT = PARSER.feed(INPUT);
return ast ? RESULT.results[0] : astToObject(RESULT.results[0]);
} catch (error) {
const TOKEN = error.token;
const EXPECTED = error.message.match(/(?<=A ).*(?= based on:)/g).map(s => s.replace(/\s+token/i, ''));
if (INPUT.length === 0) {
TOKEN.line = 0;
TOKEN.col = 0;
}
const FINAL_ERROR = {
token: TOKEN.value,
line: TOKEN.line,
col: TOKEN.col,
expected: [...new Set(EXPECTED)]
}
throw FINAL_ERROR;
}
}
/**
* Converts an AST to an object.
* @param {Object} ast AST to convert.
* @returns {Object} The object.
*/
function astToObject(ast) {
if (ast.type === 'object') {
return ast.properties.reduce((acc, property) => {
if (property.key in acc) {
console.warn(YELLOW + 'Warning: Duplicate key ' + RESET + BOLD + UNDERLINE + property.key + RESET + YELLOW + ' found!' + RESET);
}
acc[property.key] = astToObject(property.value);
return acc;
}, {});
}
if (ast.type === 'array') {
return ast.elements.map(astToObject);
}
return ast.value;
}
export { jsonParse, astToObject };