Search code examples
javascriptnode.jsunderscore.jshoisting

Chaining underscore.js in node.js throws 'Invalid REPL keyword'


I'm a n00b at using underscore/node and am trying to understand the concept of chaining functions. However, I cannot elicit proper outputs when trying to chain functions in node. Grabbing the example snipp from underscore's chaining section produces 'Invalid REPL keyword':

var __ = require("underscore"); //for underscore use in node

var lyrics = [
  {line: 1, words: "I'm a lumberjack and I'm okay"},
  {line: 2, words: "I sleep all night and I work all day"},
  {line: 3, words: "He's a lumberjack and he's okay"},
  {line: 4, words: "He sleeps all night and he works all day"}
];

__.chain(lyrics) //in the console chain appears to run and return correctly, but then
  .map(function(line) { return line.words.split(' '); }) //Invalid REPL keyword
  .flatten()                                             //Invalid REPL keyword
  .reduce(function(counts, word) { 
    counts[word] = (counts[word] || 0) + 1;
    return counts;
  }, {})                                                 //Invalid REPL keyword
  .value();                                              //Invalid REPL keyword

Am I a victim of ASI in this case? If so where is the ';' trying to be inserted? I am confused since plugging this snippet into JSHint produces no errors. Can one of you please help me identify the error?

Thanks!


Solution

  • I guess in a way you are running into ASI in that generally semicolons are inserted to separate expressions. In a more general sense though, what you are doing is typing into Node's REPL (what you get when you run node with no args), and in a REPL environment, if a line can be executed on its own, it will and its result will be printed out.

    This is different from a standard JS environment, which will fully process an entire function/file before executing it.

    The error you are getting, Invalid REPL keyword, is because Node's REPL has a set of commands that all begin with ., such as .clear (the full list is here), and .map and such are JS functions, not REPL commands.

    So for example if I take your example and reorder the .s to the end of the line (so that each line can't be processed on its own), it will work in the REPL:

    var __ = require("underscore"); //for underscore use in node
    
    var lyrics = [
      {line: 1, words: "I'm a lumberjack and I'm okay"},
      {line: 2, words: "I sleep all night and I work all day"},
      {line: 3, words: "He's a lumberjack and he's okay"},
      {line: 4, words: "He sleeps all night and he works all day"}
    ];
    
    __.chain(lyrics).
      map(function(line) {
        return line.words.split(' ');
      }).
      flatten().
      reduce(function(counts, word) { 
        counts[word] = (counts[word] || 0) + 1;
        return counts;
      }, {}).
      value();
    

    Really though, the only time you should be using the REPL is for quick tests, where the single-line behavior is usually helpful. When doing normal development, you should work in a file and run node <filename> to test your code.