Creating JS library Warning instead of Error - javascript

I am creating my own JS library with NPM. I want to give the users of my library a warning but not an error, however, I want my users to have a stacktrace of the warning that I log inside my library. So to get the stacktrace, I use new Error().stack. The problem with this is (1) the word 'Error' appears in the stacktrace by default and (2) the stack trace is the same for Node and Chrome but different for Mozilla.
So my question is - what is the best way to create a warning message that has a stacktrace, but that doesn't look like an error? Chrome and Node.js are aligned and I could simply remove the first element of the stack array before calling toString() on it. But the problem is that this wouldn't work for Mozilla.
Anyway, this is what I currently do in my library when there should be a warning emitted:
var err = new Error('looks like you have called IdempotentJSON.parse on an object that was already parsed');
console.error(err.message.concat('\n'),err.stack);
this "logs a warning" that looks like this
in Chrome
looks like you have called IdempotentJSON.parse on an object that was already parsed
Error: looks like you have called IdempotentJSON.parse on an object that was already parsed
at IdempotentJSON.parse (http://localhost:3000/static/vendor/idempotent-json.js:11:23)
at Backbone.Model.extend.persistModel.save.success (http://localhost:3000/static/app/js/models/userModel.js:88:56)
at Object._.extend.save.options.success (http://localhost:3000/static/vendor/backbone.js:620:30)
at jQuery.Callbacks.fire (http://localhost:3000/static/vendor/jquery.js:3099:30)
at Object.jQuery.Callbacks.self.fireWith [as resolveWith] (http://localhost:3000/static/vendor/jquery.js:3211:7)
at done (http://localhost:3000/static/vendor/jquery.js:8264:14)
at XMLHttpRequest.jQuery.ajaxTransport.send.callback (http://localhost:3000/static/vendor/jquery.js:8605:9)
in Mozilla Firefox:
"looks like you have called IdempotentJSON.parse on an object that was already parsed
" "IdempotentJSON.prototype.parse#http://localhost:3000/static/vendor/idempotent-json.js:11:23
#http://localhost:3000/static/app/js/app.js:157:30
Backbone.batchSyncCollection/<#http://localhost:3000/static/app/js/app.js:141:16
jQuery.Callbacks/fire#http://localhost:3000/static/vendor/jquery.js:3099:10
jQuery.Callbacks/self.fireWith#http://localhost:3000/static/vendor/jquery.js:3211:7
done#http://localhost:3000/static/vendor/jquery.js:8264:5
.send/callback/<#http://localhost:3000/static/vendor/jquery.js:8605:1
in Node.js
looks like you have called IdempotentJSON.parse on an object that was already parsed
Error: looks like you have called IdempotentJSON.parse on an object that was already parsed
at IdempotentJSON.parse (/Users/amills001c/WebstormProjects/first_comcast/node_modules/idempotent-json/index.js:9:19)
at Object.<anonymous> (/Users/amills001c/WebstormProjects/first_comcast/IJSONexp/ijson.js:8:15)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
one quick solution that would work for Node.js and Chrome would be to remove the first line of the stack trace that says "Error:...".
But this call is not valid:
err.stack.shift(); //error
apparently the stack is not an Array in JS?
And this wouldn't work for Mozilla anyway.
Is my best bet another library that checks which environment/browser that it's in? Like this:
http://www.eriwen.com/javascript/js-stack-trace/
it's 2015! By the way Mozilla, Chrome and Node have it right with the stack trace, I can click on the stack trace in Chrome and Node and it takes me to the files involved, doesn't seem like I can do this in Firefox.
What I want is something that looks like this:
Warning: looks like you have called IdempotentJSON.parse on an object that was already parsed
at IdempotentJSON.parse (http://localhost:3000/static/vendor/idempotent-json.js:11:23)
at Backbone.Model.extend.persistModel.save.success (http://localhost:3000/static/app/js/models/userModel.js:88:56)
at Object._.extend.save.options.success (http://localhost:3000/static/vendor/backbone.js:620:30)
at jQuery.Callbacks.fire (http://localhost:3000/static/vendor/jquery.js:3099:30)
at Object.jQuery.Callbacks.self.fireWith [as resolveWith] (http://localhost:3000/static/vendor/jquery.js:3211:7)
at done (http://localhost:3000/static/vendor/jquery.js:8264:14)
at XMLHttpRequest.jQuery.ajaxTransport.send.callback (http://localhost:3000/static/vendor/jquery.js:8605:9)

Looking into the source of console.trace you can try this for chrome & node.js:
function warning(message) {
var err = new Error;
err.name = 'Warning';
err.message = message; //or use util.format in nodejs
Error.captureStackTrace(err, warning); // this is to prevent `warning` function being included in the stack.
return err;
};
console.log(warning('message').stack);
In nodejs, this outputs:
Warning: message
at Object.<anonymous> (/home/ubuntu/workspace/warning.js:9:13)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
Unfortunately firefox doesn't have captureStackTrace method. So you have to call the above directly without wrapping it in a function.

Related

JS Script using DOM running on pm2 server

I have read that serverside, you cant use DOM. I've created a web application using DOM and I wonder what needs to be done to reproduce this code to make it work on a server, so the people on the internet can work with it. Here is a little peak of a code:
// Listen for export button click
document.getElementById('exportForm').addEventListener('submit', function (e) {
setTimeout(exportData, 20);
e.preventDefault();
});
// Export data function
function exportData(e) {
console.log("Exporting...");
// device details and time range details
const devId = (document.getElementById('deviceInput')).value;
var dateFrom = (document.getElementById('dateFromInput')).value;
var dateTo = (document.getElementById('dateToInput')).value;
var timeFrom = (document.getElementById('timeFromInput')).value;
var timeTo = (document.getElementById('timeToInput')).value;
const limit = (document.getElementById('limitInput')).value;
const key = (document.getElementById('keysInput')).value;
When I try to run it on server using pm2 start app.js, it returns this error:
ReferenceError: document is not defined
at Object.<anonymous> (/home/cloud/sites/App/app.js:6:1)
at Module._compile (internal/modules/cjs/loader.js:999:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
at Object.<anonymous> (/usr/lib/node_modules/pm2/lib/ProcessContainerFork.js:33:23)
at Module._compile (internal/modules/cjs/loader.js:999:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
I've heard about JSDom, but I think there needs to be html included in a string and then I have no idea how to connect the css in there and so on. Is there a better way for me to make this work?
Document object is a browser feature hence you cant use it inside server, Instead you have other features like the FS (File System)
Anyhow using JSDom may be possible, you have to rewrite using inline styles https://www.codecademy.com/article/html-inline-styles which is not a good practice and you should avoid it

is there a problem with this expression {item_1.name: req.body.item } or alternatively with this {[item_1.name]: req.body.item }?

I'm trying to run this piece of code:
router.put('/restaurants/:id', async (req, res) => {
try {
const response = await Restaurant.findByIdAndUpdate(req.params.id, {name: req.body.name,
item_1.name: req.body.item,
item_2.name: req.body.item_2,
item_3.name: req.body.item_3,
item_4.name: req.body.item_4
})
res.send(response)
}
catch (error) {
res.send(error)
}
})
where the scenario is I have items (i.e item_1 etc) saved as objects in database, items got two properties name and rating, when admin wants to edit an item it should only be able to just edit the name property of an item not the rating, so for implementing this what i'm trying to do is, upon edit request as shown here, I want to set only the name property of an item as same to what has been sent in the request.
but it gives me a typescript error (though I don't have typescript installed) saying:
',' expected.ts(1005)
and it happens before running this code, actually vs code is showing this error.
and upon running it is showing something like this:
E:\xord\second_assignment\node\routes\restaurants.js:50
item_1.name: req.body.item,
^
SyntaxError: Unexpected token '.'
at wrapSafe (internal/modules/cjs/loader.js:1054:16)
at Module._compile (internal/modules/cjs/loader.js:1102:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Module.require (internal/modules/cjs/loader.js:1026:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object.<anonymous> (E:\xord\second_assignment\node\index.js:8:21)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47
[nodemon] app crashed - waiting for file changes before starting...
same thing happens with a different error when i try to access the object property with bracket notation.
I apologise for the very long query but I'm wondering; is the syntax I've used in this code for setting the value of an object's key inside another object, incorrect? if so then why? also what would be the alternative way to do this?
thanks God! in mongoose v5.10.19 documentation I saw almost the same instance where they use a property of an object as a key of another object here:
Parent.update({}, { 'child.name': 'Luke Skywalker' }, (error) => {
// Error because parentSchema has `strict: throw`, even though
// `childSchema` has `strict: false`
});
by which I learnt that in such cases one should wrap the key in quotes as they did in "child.name". and that resolved the issue i was facing.

Backticks in node.js

I am attempting to use the following code as a file test2.js with node.js version 12.0.
let apiKey = '117fa18eaf7312fa52f593c6d52fc48d';
let id = '6094817';
let xu1 = `http://api.openweathermap.org/data/2.5.weather?id=$(id)&APPID=$(apiKey)`;
console.log('xul is: ', xul);
I get the following results and I am unable to understand why.
jgossage#jgossage-XPS-8700:/LinuxData/Projects/node-weather$ node test2.js
/LinuxData/Projects/node-weather/test2.js:4
console.log('value is: ', xul);
^
ReferenceError: xul is not defined
at Object.<anonymous> (/LinuxData/Projects/node-weather/test2.js:4:27)
at Module._compile (internal/modules/cjs/loader.js:936:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:947:10)
at Module.load (internal/modules/cjs/loader.js:790:32)
at Function.Module._load (internal/modules/cjs/loader.js:703:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:999:10)
at internal/main/run_main_module.js:17:11
The only thing I can see is that possibly the template string is not being handled properly, resulting in the variable xul being not defined.
As #Andreas mentioned you have a typo it should be
console.log('value is: ', xu1);
but also even if you run that you get
xu1 is: http://api.openweathermap.org/data/2.5.weather?id=$(id)&APPID=$(apiKey)
That is because you have to use ${} instead of $().
So the final fix is
let xu1 = `http://api.openweathermap.org/data/2.5.weather?id=${id}&APPID=${apiKey}`;

Node.js https.createServer throws TypeError: listener must be a function

I've read posts all over concerning this and I know it must be something silly, but I can't figure out why the following code is throwing "TypeError: listener must be a function"
Assume options
var server = https.createServer(options, function(request,response){
if (request.url==='/') request.url='/home/altronic/Opti-Cal/web/arimonitor.htm';
console.log("Request: " + request.url);
fs.readFile("public"+request.url,function(error,data){
if (error) {
response.writeHead(404, {"Content-type":"text/plain"});
response.end ("Sorry the page you requested was not found.");
} else {
response.writeHead(200,{"Content-type":mime.lookup('public'+request.url)});
response.end (data);
}
})
}).listen(port);
Console output:
events.js:130
throw TypeError('listener must be a function');
^
TypeError: listener must be a function
at TypeError (<anonymous>)
at Server.EventEmitter.addListener (events.js:130:11)
at new Server (http.js:1816:10)
at Object.exports.createServer (http.js:1846:10)
at Object.<anonymous> (/home/altronic/Opti-Cal/src/Opti-Cal_HTTPS_Server.js:42:20)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
Can anyone help me figure this out?
Where do you assign https? It looks like you’re probably requiring http, not https. http.createServer doesn’t accept options like https.createServer.
You may hit this error when using a node version < 9.6
See the docs and history. I was very confused that the docs said I could use an options object on http.createServer and got this error until I realized I hadn't updated node in a while.
https://nodejs.org/api/http.html#http_http_createserver_options_requestlistener
I had the same error message:
throw TypeError('listener must be a function');
I have two separate files server.js and handler.js.
My problem was whilst I was requiring ( require(./handler.js) )my handler file in server.js I was not exporting it from handler.js file. You must have: module.exports =handler; at the bottom of your handler file
This is mostly coming from a version mismatch. Latest versions of nodejs's http.createServer() do take options in parameters like https does.

Node.js: console.log message doesn't show up if method throws exception... why?

In Node.js, if I have a method that throws an exception, console.log statements from that method don't fire. I recognize that in the simple test case below that I should catch the exception from the readFileSync call, or otherwise be defensive about it. Just curious if someone could explain the behavior to me.
Simple test case:
var fs = require('fs');
function readAFileThatDoesntExist(filename) {
console.log(filename);
fs.readFileSync(filename);
}
console.log("We're about to read a file that doesn't exist!");
readAFileThatDoesntExist("afile");
Output:
$ node test.js
We're about to read a file that doesn't exist!
fs.js:338
return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
^
Error: ENOENT, no such file or directory 'C:\blog\projects\bloggen\scripts\afile'
at Object.fs.openSync (fs.js:338:18)
at Object.fs.readFileSync (fs.js:182:15)
at readAFileThatDoesntExist (C:\blog\projects\bloggen\scripts\test.js:5:8)
at Object.<anonymous> (C:\blog\projects\bloggen\scripts\test.js:9:1)
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)
Ah, figured it out.
It seems that console.log isn't finishing before the process exits... If I use console.warn, the message does show up.
This post explains it: is node.js' console.log asynchronous?
Also, I'm on an older version (0.8.15), so this may no longer be relevant.

Categories

Resources