0

I am working on a Sails.js project that requires me to use this NPM package. I created a new Sails.js service to invoke this package after npm install-ing it like this:

// Require and initialize the rules engine
var jsonRulesEngine = require('json-rules-engine'),
    rulesEngine = new jsonRulesEngine();

When I run this script, I get the following error:

/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/async.js:61
        fn = function () { throw arg; };
                           ^

TypeError: jsonRulesEngine is not a constructor
    at Object.verify (/Users/Nag/Code/learn-nodejs/server/api/services/RulesService.js:21:27)
    at Object.wrapper [as verify] (/Users/Nag/Code/learn-nodejs/server/node_modules/@sailshq/lodash/lib/index.js:3250:19)
    at /Users/Nag/Code/learn-nodejs/server/api/controllers/UtilsController.js:113:43
    at /Users/Nag/Code/learn-nodejs/server/api/services/RedisService.js:55:13
    at tryCatcher (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/util.js:16:23)
    at Promise.successAdapter [as _fulfillmentHandler0] (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/nodeify.js:23:30)
    at Promise._settlePromise (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/promise.js:566:21)
    at Promise._settlePromise0 (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/promise.js:693:18)
    at Async._drainQueue (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues (/Users/Nag/Code/learn-nodejs/server/node_modules/bluebird/js/release/async.js:17:14)
    at Immediate.<anonymous> (/Users/Nag/Code/learn-nodejs/server/node_modules/async-listener/glue.js:188:31)
    at runCallback (timers.js:666:20)
    at tryOnImmediate (timers.js:639:5)
    at processImmediate [as _immediateCallback] (timers.js:611:5)
[nodemon] app crashed - waiting for file changes before starting...

Any clue why I might get that error? In the examples section of the package, the owner of the package imports the package using ES6 format whereas I am requiring it. Does that make a difference?

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
JackH
  • 4,613
  • 4
  • 36
  • 61
  • @AndrewLi Tried your suggestion but now it says `TypeError: Cannot call a class as a function`. – JackH May 06 '17 at 02:04
  • @AndrewLi I made a mistake by calling it like var Engine = require('json-rules-engine').Engine();`. Your original comment was correct. Happy to mark it as an answer if you add it as is. – JackH May 06 '17 at 02:11
  • I was wrong, the `Engine` *is* exported by default. I've edited the answer to reflect the real reason. – Andrew Li May 06 '17 at 02:28

1 Answers1

4

When you require an NPM package, depending on your module system1, the default export will not automatically be imported when you do this:

var jsonRulesEngine = require('json-rules-engine');

So when you require like you did, it will return the module object, not necessarily the default export as expected. In the package json-rules-package the Engine is exported by default but your require doesn't require the default. If you log the returned module object it will look like this:

{
  Engine: function(...) { ... },
  Fact: function(...) { ... },
  Operator: function(...) { ... },
  Rule: function(...) { ... },
  default: function(...) { ... }
}

The engine is under the property default and Engine. You could do:

var jsonRulesEngine = require('json-rules-engine').default();

Or:

var jsonRulesEngine = require('json-rules-engine').Engine;

The first will explicitly import the default export. Then you can create an instance of the class like so:

var rulesEngine = new jsonRulesEngine();

1 Yes, using ES2015 import will affect the outcome. If you were to use import syntax from ES2015, this problem would not be encountered. To know why see this answer. In short, Babel transpiles ES2015 code so that default is explicitly accessed when requiring thus importing the default export.

Community
  • 1
  • 1
Andrew Li
  • 55,805
  • 14
  • 125
  • 143