Node 5.10 spread operator not working - node.js

According to the docs, the latest node (Node 5+) should support the spread operator by default, like so:
const newObj = {
...oldObj,
newProperty: 1
}
And I have node 5.10.1 installed (e.g. that's what 'node -v' tells me). But I am still getting this error:
c:\[myprojectfolder]>node index.js
c:\[myprojectfolder]\index.js:21
...oldObj,
^^^
SyntaxError: Unexpected token ...
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:387:25)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:146:18)
at node.js:404:3
What am I missing?

The array spread syntax is supported, but the object spread syntax is not - this is most likely due to it not being finalized as part of the ECMAScript spec yet (it was originally planned for inclusion in ES7/ES2016, but it got bumped back, if I recall correctly).
Your options in the meantime are either to use a transpiler (such as Babel, with the transform-object-rest-spread plugin), or if that feels like overkill, you can use the new built-in Object.assign function. The object spread syntax is effectively just syntax sugar around Object.assign - the example in your question could be expressed like so:
const newObj = Object.assign({}, oldObj, {
newProperty: 1
});
Note the empty object as the first argument; the properties from the rest of the passed objects get merged into it, with those furthest to the right of the function call taking priority. It may seem more intuitive to simply have oldObj as the first argument, but this doesn't have quite the same effect - it would mutate the existing oldObj as well as returning it. Having an empty object as the target leaves oldObj unchanged.
Update: As of Node 8.6, object spread syntax is supported.
Update 2: Object spread syntax has finally made its way through the proposal process, and will be part of the ES2018 spec.

What you tried to use is called object spread and is not part of the es2015 specification. Node only supports the regular spread in function calls and array literals. Unfortunately not even array destructuring is supported yet, although they link to the MDN page which describes both structuring and destructuring use of ....
You can use Object.assign instead:
const newObj = Object.assign({}, oldObj, {
newProperty: 1
});

That's works in Node.js 8.5.0.
Example:
var oldObj = {
oldProperty: 0
}
var newObj = {
...oldObj,
newProperty: 1
}
console.log('Old Object: ' + JSON.stringify(oldObj, null, ' '))
console.log('New Object: ' + JSON.stringify(newObj, null, ' '))
Output:
Old Object: {
"oldProperty": 0
}
New Object: {
"oldProperty": 0,
"newProperty": 1
}
Screenshot from IDE Debug Console:

Related

How to query data from InfluxDB using Node.js

I am working on a project where I have an InfluxDB bucket that has a measurement of elapsedtime and a tag of service. I want to query Influx to be able to get all datapoints in the last 1 hour for foobar as the service. Ideally I will add a time measurement later on which I could use to base my 1 hour off since the system that gets the elapsed time and the system that writes it to Influx are different and have about 1-2 minutes of latency between them.
I have taken some example code from here and I have gotten this which is nearly identical since I am unsure of what needs to change and could not understand the documentation (head's cloudy?).
The end goal of this is to be able to have a graph that shows the elapsedtime for a service when I query my application - which queries Influx. I would like to be able to query based off a preset list of service and times but that is application side of things and I am giving here as context to what I'd like this to result in eventually.
...
variables that define bucket, url, org and token
...
const queryApi = new InfluxDB({url, token}).getQueryApi(org)
const fluxQuery =
`from(bucket:"${bucket}") |> range(start: 0) |> filter(fn: (r) => r._measurement == "elapsedTime")`
console.log('*** QUERY ROWS ***')
// Execute query and receive table metadata and rows.
// https://v2.docs.influxdata.com/v2.0/reference/syntax/annotated-csv/
queryApi.queryRows(fluxQuery, {
next(row: string[], tableMeta: FluxTableMetaData) {
const o = tableMeta.toObject(row)
console.log(
`${o._time} ${o._measurement} in '${o.location}' (${o.example}): ${o._field}=${o._value}`
)
},
error(error: Error) {
console.error(error)
},
complete() {
console.log('\nFinished SUCCESS')
},
})
When I run this I get an error about an extra value in there however I'd expect the example to have correct code so maybe I am missing something I need to update?
next(row: string[], tableMeta: FluxTableMetaData) {
^
SyntaxError: Unexpected token ':'
at wrapSafe (internal/modules/cjs/loader.js:992:16)
at Module._compile (internal/modules/cjs/loader.js:1040:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
at Module.load (internal/modules/cjs/loader.js:941:32)
at Function.Module._load (internal/modules/cjs/loader.js:782:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
at internal/main/run_main_module.js:17:47
The issue ended up being that the code I had copied was TypeScript which as you can imagine doesn't work in a JavaScript file. Silly mistake on my end

Reference a global JS function in another file, in NodeJS

What I'm actually doing is writing a VS Code Extension, but since I'm new to Node I'm struggling with referencing one JS file from another.
//main.js (compiled from TypeScript)
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("./Test.js");
console.log("hello");
t1();
and
//Test.js
function t1() {
console.log("t1");
}
They're both in the same folder. If I run it from VS Code, or from node directly, it doesn't work
PS E:\VSCodeTest> node src/main.js
hello
E:\VSCodeTest\src\main.js:5
t1();
^
ReferenceError: t1 is not defined
at Object.<anonymous> (E:\VSCodeTest\src\main.js:5:1)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:608:3
The VS Code project is actually TypeScript but I've distilled it down to the crux of the problem in the JS files.
I believe it should work based on
https://www.typescriptlang.org/docs/handbook/modules.html
Import a module for side-effects only Though not recommended practice,
some modules set up some global state that can be used by other
modules. These modules may not have any exports, or the consumer is
not interested in any of their exports. To import these modules, use:
import "./my-module.js";
How have I misunderstood that?
Change Test.js to this:
//Test.js
function t1() {
console.log("t1");
}
module.exports = t1;
And then do something more like this in main.js:
const t1 = require("./Test.js");
t1(); // prints "t1"
There's a lot of information about how modules work in the docs: https://nodejs.org/api/modules.html
Alternatively, if you want t1 to be a global, then assign it to global.t1 in Test.js:
//Test.js
global.t1 = function t1() {
console.log("t1");
};
I wouldn't recommend that if you can avoid it, though, for all the reasons people recommend avoiding globals when possible
Require doesn't work quite like that, but you're close -- if you want to use a function you've created to in another file, just add it to that file's exports.
/// test.js
exports.t1 = function() ...
// or
module.exports = {
t1: function() ...
}
Then you need to specifically save that off to use it
/// main.js
var t1 = require('./test.js').t1;
t1();
Global scoping doesn't work like it does in the browser, check out node's docs on it, or try a blog explaining it (I didn't write this and can't fully vouch)

How do I use and apply JavaScript decorators?

I am trying to understand how to use decorators in a very simple piece of code, so I can apply this concept to my bigger project. Taking cue from Addy Osmani's article here, I created a simple piece of code as below.
Say, I have a class called Cat, with a meow() method, I want to decorate it with some logging, as below.
class Cat {
#logger
meow() { console.log( ' Meeeoow! ') }
};
function logger(target, key, descriptor) {
console.log("Cat snarling...");
return descriptor;
}
const cat = new Cat();
cat.meow();
When I try to execute this against the Node.js interpreter (version 9.1.0), I get the following error.
/Users/ravindranath/projects/decorators/index.js:2 #logger ^
SyntaxError: Invalid or unexpected token
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:152:10)
at Module._compile (module.js:605:28)
at Object.Module._extensions..js (module.js:652:10)
at Module.load (module.js:560:32)
at tryModuleLoad (module.js:503:12)
at Function.Module._load (module.js:495:3)
at Function.Module.runMain (module.js:682:10)
at startup (bootstrap_node.js:191:16)
at bootstrap_node.js:613:3
So, my questions are:
Does Node.js 9.x support decorator syntax? Or is it coming up in some future version?
I see some express-js based decorators on GitHub, but I am unable to figure out how to create my own decorator. Can someone provide a simple basic example of creating a custom decorator with Node.js?
Decorators are not part of ECMAScript 2016 (aka 7). Decorators are currently in Stage 2 Draft out of the total 4 stages a feature goes through before being finalized and becoming part of the language. They'll probably be integrated into the language in the near future, but its features and specifics are subject to change. Because of this, you'll have to use a transpiler such as Babel to transform the decorators into code the Node runtime can understand (ECMAScript 2016) by installing the transform-decorators Babel plugin.
As for creating decorators, you've already done so. Each decorator is just a function that wraps another, that is provided with arguments based on the usecase, in your case target, key, and descriptor. Your logger function:
function logger(target, key, descriptor) {
console.log("Cat snarling...");
return descriptor;
}
Is already a decorator. For class properties and methods, target refers to the class of the property, key is the property name, and descriptor is the descriptor of the property. The decorator is then called and the property of the class is defined via Object.defineProperty once desugared. Your example can be boiled down to this:
class Cat { }
let meowDescriptor = {
type: 'method',
initializer: () => () => {
console.log(' Meeeoow! ');
},
enumerable: false,
configurable: true,
writable: true
}
function logger(target, key, descriptor) {
console.log("Cat snarling...");
return descriptor;
}
meowDescriptor = logger(Cat.prototype, 'meow', meowDescriptor);
Object.defineProperty(Cat.prototype, 'meow', {
...meowDescriptor,
value: meowDescriptor.initializer()
});
For classes themselves, decorators take one argument, target which describes the decorated class. I suggest reading some documentation on the subject to become acquainted with it.

unexpected strict mode reserved word -- yield? Node v0.11, harmony, es6

Trying to use a new ES6 based node.js ODM for Mongo (Robe http://hiddentao.github.io/robe/)
Getting "unexpected strict mode reserved word" error. Am I dong something wrong here?
test0.js
"use strict";
// Random ES6 (works)
{ let a = 'I am declared inside an anonymous block'; }
var Robe = require('robe');
// :(
var db1 = yield Robe.connect('127.0.0.1');
Run it:
C:\TestWS>node --version
v0.11.10
C:\TestWS>node --harmony test0.js
C:\TestWS\test0.js:12
var db1 = yield Robe.connect('127.0.0.1');
^^^^^
SyntaxError: Unexpected strict mode reserved word
at exports.runInThisContext (vm.js:69:16)
at Module._compile (module.js:432:25)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:349:32)
at Function.Module._load (module.js:305:12)
at Function.Module.runMain (module.js:490:10)
at startup (node.js:123:16)
at node.js:1031:3
If you want to use generators to do asynchronous operation in synchronous fashion you must do it like:
co(function*() {
"use strict";
{ let a = 'I am declared inside an anonymous block'; }
var Robe = require('robe');
var db1 = yield Robe.connect('127.0.0.1');
})();
where co realization you can find in:
co
Task.js
bluebird's Promise.coroutine
q's spawn
and so on.
In strict mode you cannot use yield outside of the generators. In non-strict mode outside of the generators yield will be considered as variable identifier - so in your case it'll throw an error anyway.
Also noteworthy... new versions of co return/use promises rather than thunks. So this is what worked with newer versions of co.
var co = require('co');
co(function*() {
"use strict";
{ let a = 'I am declared inside an anonymous block'; }
var Robe = require('robe');
var db1 = yield Robe.connect('127.0.0.1/swot');
console.log(db1)
return db1;
}).then(function (value) {
console.log(value);
}, function (err) {
console.error(err.stack);
});

mongodb with nodejs

this is th code I am using inserting a document to mongodb.
var client = new Db('test', new Server("127.0.0.1", 27017, {}), {w: 1}),
test = function (err, collection) {
collection.insert({a:2}, function(err, docs) {
collection.count(function(err, count) {
test.assertEquals(1, count);
});
// Locate all the entries using find
collection.find().toArray(function(err, results) {
test.assertEquals(1, results.length);
test.assertTrue(results[0].a === 2);
// Let's close the db
client.close();
});
});
};
client.open(function(err, p_client) {
client.collection('test_insert', test);
});
but while running I am getting error
xports, require, module, __filename, __dirname) { var client = new Db('test',
^
ReferenceError: Db is not defined
at Object. (C:\Users\Basic node\cheerio\mongonode.js:1:81
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
can you suggest me how to solve this problem
thanks in advance
Please import all the required modules, which you are using. Db is not defined points out that Db is defined in some other module or you have forgot to declare it.
You'll notice this exact code block posted in a number of different stackoverflow questions. The problem here is that this is a copy and pasted code block from mongodb's documentation, as is in fact the first example of a mongodb nodejs program.
https://npmjs.org/package/mongodb
You'll find this under "Introduction" as "A simple example of inserting a document."
It's clearly an incomplete example, but a lot of people are just trying it out to see if they've got everything installed correctly and immediately run into a wall.
Most people will have installed the mongodb driver, but will be missing something at the top like this:
var mongodb = require('mongodb');
var Db = mongodb.Db;
var Server = mongodb.Server;
I also fell into the copy-paste trap here and ran into another issue with the "assertEquals" method not existing. I've seen other people reference that function in other places on the web, but not really sure how it works.
In any case, to make it work for me, I required the assert module:
var assert = require('assert');
And then I replaced the assertEquals lines with something like this:
assert.equal(1, count, "Unexpected result");
Note that you're going to run into an issue if you've run this a couple of times; it's going to count the number of things in that table, and there is going to be more than one.
You'll have to figure out how to get into mongo's CLI and remove them to get it to run successfully.
Try to install mongodb native driver
npm install mongodb

Resources