8

How can i read this file 'file.json':

# Comment01
# Comment02
{
   "name": "MyName"
}

and retrieve the json without comments?

I'm using this code:

var fs = require('fs');
var obj;
fs.readFile('./file.json', 'utf8', function (err, data) { 
  if (err) throw err;
  obj = JSON.parse(data);
});

it returns this error:

SyntaxError: Unexpected token # in JSON at position 0

Have npm some package to solve this question?

peteb
  • 18,552
  • 9
  • 50
  • 62
Hemã Vidal
  • 1,742
  • 2
  • 17
  • 28

6 Answers6

10

The perfect package for this problem is https://www.npmjs.com/package/hjson

hjsonText input:


{
  # hash style comments
  # (because it's just one character)

  // line style comments
  // (because it's like C/JavaScript/...)

  /* block style comments because
     it allows you to comment out a block */

  # Everything you do in comments,
  # stays in comments ;-}
}

Usage:

var Hjson = require('hjson');

var obj = Hjson.parse(hjsonText);
var text2 = Hjson.stringify(obj);
Hemã Vidal
  • 1,742
  • 2
  • 17
  • 28
4

There is alternative package on NPM: json-easy-strip The main idea is to use just one-liner RegExp to strip all type of JS-style comments. And yes, it's simple and very possible! Package is more advanced, with some file caching etc, but still simple. Here is the core:

sweet.json

{
    /*
     * Sweet section
     */
    "fruit": "Watermelon", // Yes, watermelons is sweet!
    "dessert": /* Yummy! */ "Cheesecake",
    // And finally
    "drink": "Milkshake - /* strawberry */ or // chocolate!" // Mmm...
}

index.js

const fs = require('fs');
const data = (fs.readFileSync('./sweet.json')).toString();

// Striper core intelligent RegExp.
// The idea is to match data in quotes and
// group JS-type comments, which is not in
// quotes. Then return nothing if there is
// a group, else return matched data.
const json = JSON.parse(data.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) => g ? "" : m));

console.log(json);

//  {
//    fruit: 'Watermelon',
//    dessert: 'Cheesecake',
//    drink: 'Milkshake - /* strawberry */ or // chocolate!'
//  }

So now because you was asking about ShellScripting-style comments

#
# comments
#

We can extend our RegExp by adding \#.* at the end of it:

const json = JSON.parse(data.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/|\#.*)/g, (m, g) => g ? "" : m));

Or, if you don't want JS-style comments at all:

const json = JSON.parse(data.replace(/\\"|"(?:\\"|[^"])*"|(\#.*)/g, (m, g) => g ? "" : m));
tarkh
  • 2,424
  • 1
  • 9
  • 12
3

You can use your own RegExp pretty easily to match the comments beginning with a #

const matchHashComment = new RegExp(/(#.*)/, 'gi');
const fs = require('fs');

fs.readFile('./file.json', (err, data) => {
    // replaces all hash comments & trim the resulting string
    let json = data.toString('utf8').replace(matchHashComment, '').trim();  
    json = JSON.parse(json);
    console.log(json);
});
peteb
  • 18,552
  • 9
  • 50
  • 62
2

The package you are looking for is called strip-json-comments - https://github.com/sindresorhus/strip-json-comments

const json = '{/*rainbows*/"unicorn":"cake"}';

JSON.parse(stripJsonComments(json)); //=> {unicorn: 'cake'}
Kalman
  • 8,001
  • 1
  • 27
  • 45
  • But in this package i can define my custom comment as #? – Hemã Vidal Nov 18 '16 at 20:35
  • Take a look at how that package deals with regular comments and it should give you an idea for dealing with custom comments – Kalman Nov 18 '16 at 20:46
  • I'd submitted an issue! https://github.com/sindresorhus/strip-json-comments/issues/31 to creator fix this solution in plugin. – Hemã Vidal Nov 18 '16 at 20:59
  • 1
    The author rejected my issue request, but suggested this package that works with "#" char as comment. https://www.npmjs.com/package/hjson – Hemã Vidal Nov 18 '16 at 22:00
2
let json = require('json5')
let fs = require('fs-extra')

let a = json.parse(fs.readFileSync("./tsconfig.json"))
console.log(a)

you can use json5 module

PDHide
  • 18,113
  • 2
  • 31
  • 46
-3

Javascript has a comment remover built-in, no need for an extra package. I wouldn't do this for user input though.

eval(
  'var myjsonfile=' +
    require('fs')
      .readFileSync('./myjsonfile.json')
      .toString(),
);
console.log(myjsonfile);