All files parser.js

100% Statements 65/65
100% Branches 14/14
100% Functions 2/2
100% Lines 65/65

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 662x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 40x 40x 40x 40x 40x 40x 40x 9x 9x 9x 1x 1x 1x 9x 9x 9x 9x 9x 9x 9x 9x 40x 40x 2x 2x 2x 2x 2x 2x 30643x 5401x 14931x 2x 2x 14931x 14931x 5401x 5401x 25242x 5421x 5421x 19821x 19821x 30643x 2x  
/**
 * This module contains the function jsonParse that parses a JSON file.
 *
 * @module parser
 */
 
'use strict';
 
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 };