1

I have a JS file, in whcih I have lots of objects; I want to read this file in Node.Js and loop through the objects. The JS file looks like:

User = {
    fields: {
        name: {
            type: "STRING"
        },
        id: {
            type: "integer"
        },
        password: {
            type: "STRING"
        }
    }
};

car = {
    fields: {
        model: {
            type: "STRING"
        },
        color: {
            type: "STRING"
        }

    }
};

I tried the following but it does not work:

var Model = fs.readFileSync("Model.js");
data_test = JSON.stringify(Model);
response.send(data_test);
  • Change the file ext to .json and change the objects to valid JSON. – Jake Sellers Jul 29 '14 at 22:38
  • Your example is definitely *not* valid JSON therefore `JSON.stringify` is not going to work. – James Jul 29 '14 at 22:38
  • No it is a JS file; I dont know how I can iterate through the objects from my JS file; I tried to convert it to JSON, which I think is not a right approach! –  Jul 29 '14 at 22:39
  • 1
    Do you have control over this file? It sounds to me like you really just want to make `Model.js` a module and load it via `require`... – James Jul 29 '14 at 22:41
  • @JakeSellers but this file is from a third part I cannot change it; I have to use it as is; any way to include it in my node.js project and loop through the objects? –  Jul 29 '14 at 22:42
  • 1
    Then you need to talk to whoever is providing this file and ask them either make it valid JSON(fits your situation best, imo) or do as James mentions and export it as a module. – Jake Sellers Jul 29 '14 at 22:45
  • @James you are absolutely right; I don't know why I was making it complicated; if you like, please feel free to add it as an answer and I'll accept it ; thanks for your help :-) –  Jul 29 '14 at 22:51
  • `readFile` does already yield a string. Why are you trying to `JSON.stringify` it? – Bergi Jul 29 '14 at 23:32

2 Answers2

0

Clearly the file is JS, not JSON, therefore JSON.stringify isn't going to work. If you have absolutely no control over the file then you could technically get this to work with some hacking

function requireFromString(src, filename) {
    var Module = module.constructor;
    var m = new Module();
    m._compile(src, filename);
    return m.exports;
}
var moduleStr = fs.readFileSync("Model.js");
moduleStr = 'module.exports = {' + moduleStr + '}';
response.send(requireFromString(moduleStr));

On-the-fly module compilation code example stolen borrowed from this answer.


The idea behind the above example was to attempt to export Model.js as a single object because I assumed you didn't know what type of objects resided in there. However, looking back at it I can see that it's not going to work because

module.exports = { 
     User = { ... };
     car = { ... };
}

Is not valid JS. If you do know which objects you want to export then you can of course just modify the moduleStr to do that

moduleStr = moduleStr + '\nmodule.exports = { User: User, Car: car }';
Community
  • 1
  • 1
James
  • 80,725
  • 18
  • 167
  • 237
  • Sorry I didn't understand this approach! I just simply added module.exports.User = User; in my JS file and used it in my app.js; but I wonder should I export it for each single object like this? Also, your approach gave me the following error: "SyntaxError: Unexpected token = at Module._compile (module.js:439:25) at requireFromString" –  Jul 29 '14 at 23:03
  • 1
    @user3421904 the idea behind this approach is that you don't know how many objects are residing in `Model.js` therefore you can't know which ones to export. However, I just realised that `User = ` / `car =` which is why this approach wouldn't work... If you know which objects you want to export then you can obviously do that directly, I will update my answer accordingly. – James Jul 30 '14 at 09:28
0

Also, your approach gave me the following error: "SyntaxError: Unexpected token = at Module._compile (module.js:439:25) at requireFromString"

A slight tweak to @James' answer should do the trick:

function requireFromString(src, filename) {
    var Module = module.constructor;
    var m = new Module();
    m._compile(src, filename);
    return m.exports;
}
var moduleStr = fs.readFileSync("Model.js");
//moduleStr = 'module.exports = {' + moduleStr + '}';
moduleStr = moduleStr + '\nmodule.exports = { User: User, car: car };';
response.send(requireFromString(moduleStr));

Explanation:

As others have commented, valid JSON !== valid Javascript; and if a file loads in the browser, that means that it is valid Javascript, but not necessarily valid JSON.

Essentially what you are trying to do is load a Javascript file in NodeJs. Unfrotunately NodeJs uses a different system when loading different files and managing the dependencies between them. In the browser, it is based on a first-come-first-served basis. Essentially the variables are created in the order that files are loaded.

In NodeJs OTOH, you specify qa single Javascript file as the entry point, and that file should 'require()' any other Javascript files that it needs. Whatever each file exports is what the require-ing file sees.

tl;dr Browsers and NodeJs load Javascript files in incompatible ways.

So, how do you solve you problem? Well James' solution provides a way to compile a NodeJs module manually, by compiling a string.

This is great, except that way that string is modified to export what you have in your file simply will not yield valid Javascript:

module.exports = { foo = 'bar'; }

What my solution does instead is this, which yields valid Javascript:

foo = 'bar';
module.exports = { foo: foo };
bguiz
  • 27,371
  • 47
  • 154
  • 243
  • 2
    it was pretty late when I answered this question, *completely* overlooked the fact that `User =` and not `User:`. – James Jul 30 '14 at 09:34
  • No worries. GO TEAM! ... I would totally not have solved this without your answer. I feel that I should share half my check mark with you! – bguiz Jul 30 '14 at 23:38