Disable duplicate declaration validation in Acorn - javascript

I'm using Acorn to parse some syntactically valid JavaScript code into an ESTree for further processing. It appears that Acorn does some semantic checks too - in particular it throws an error for duplicate declarations. For example, parsing the following code throws an error of Identifier 'f' has already been declared:
function f() { return 1; }
function f() { return 2; }
I do not want such semantic errors to be checked - I'm doing custom processing on the resultant ESTree, so the semantic validity of the source code does not matter to me.
I've looked though the Acorn options for the parse(input, options) function, but I could not find anything that sounds like what I want.
Is there a way to disable such semantic checking?

It seems like there is no proper way to disable semantic validation. I managed to get what I want with an ugly hack, by overriding the raiseRecoverable method.
This worked for me (note that I'm using TypeScript here, but it would of course be possible to do the same in plain JavaScript):
import { Parser } from "acorn";
class SyntacticParser extends Parser {
raiseRecoverable(pos: any, message: string) {
if (message.includes("Identifier ") && message.includes(" has already been declared")) return;
(Parser.prototype as any).raiseRecoverable.call(this, pos, message); // weird call syntax required because the TypeScript types for Parser doesn't contain the `raiseRecoverable` method
}
}
It's an ugly hack because I'm filtering out the duplicate declaration message based on the stringified error message. However, there does not appear to be a better way.

Related

Intercepting and interracting with a custom Error object in javascript

I am using a custom javascript modulue which has it's own Error objects. I would like to intercept those custom Error objects and take the appropriate path in my try{} catch{} block, distinguishing them from Javascript's built in Error objects such as ReferenceError, TypeError etc.
So a bit like this.
try {
// Some code that might produce a traditional javascript error
// or one of the errors raised by the module I am using.
}catch (error){
if(error instanceof ExchangeError){
// Handle this in a way.
}else{
// Probably one of the built in Javascript errors,
// So do this other thing.
}
}
So, in the example above, ExchangeError is a custom error belonging to that specific module, however, I am not able to run the instanceof on my error, despite the fact that when I do error.constructor.name I get ExchangeError.
My javascript scope simply does not know about that ExchangeError. So the question is, how can I intercept those kind of Error objects? I'm sure I can do it with string matching, but just wanted to check if there is a more elegant way.
One thing I tried, I have my own errors module, that has some custom errors in there, I tried to mimic the module's Error object:
class ExchangeError extends Error {
constructor (message) {
super (message);
this.constructor = ExchangeError;
this.__proto__ = ExchangeError.prototype;
this.message = message;
}
}
and import that through my errors module, but that did not work obviously.
By actually implementing my own ExchangeError I actually was doing something really really bad, I was blinding the instanceof check with my own ExchangeError, whereas the ExchangeError instance that was coming from the module, was NOT an instance of my own ExchangeError. That is why my if check was falling silent.
The solution is simply doing this:
const { ExchangeError } = require ('ccxt/js/base/errors');
Importing the error from within the module. Now the instanceof look up is working. I did not know that one can import bits and pieces from a module like that.
Thanks to #FrankerZ for pointing that out.

(<any>window).SomeLibrary.SomeMethod(arg1,arg2)?

What is (<any>window) when used in Angular2?
I found it while researching the Stripe payment library:
(<any>window).Stripe.card.createToken({
number: this.cardNumber,
exp_month: this.expiryMonth,
exp_year: this.expiryYear,
cvc: this.cvc
}, (status: number, response: any) => {
if (status === 200) {
this.message = `Success! Card token ${response.card.id}.`;
} else {
this.message = response.error.message;
}
});
http://blog.mgechev.com/2016/07/05/using-stripe-payment-with-angular-2/
Looks like it's something that lets you use global objects inside a controller, but I don't really understand the details. Can't seem to find other answers on this.
Sometimes you’ll end up in a situation where you’ll know more about a
value than TypeScript does. Usually this will happen when you know the
type of some entity could be more specific than its current type.
Type assertions are a way to tell the compiler “trust me, I know what I’m
doing.”
It might be in two forms:
(<any>window)
or
(window as any)
See also https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions
Another way to do the same thing is using Square bracket syntax
window['Stripe'].card...
In this case typescript compiler will work as well
<any> indicates a cast in TypeScript, so converting window to an any indicates that you are no longer bound by the compiler to what it thinks the window object is and what properties it has.
(<any>window) is preventing compile time type error checking from flagging the call as invalid.

JavaScript JSHint - 'close' is defined but never used

I don't know why but some words that I use as function names get a lint error of being defined but never used.
For instance, the code below returns error:
// I am using AngularJS
$scope.close = close;
function close() {
/* Code here */
}
But this does not:
// I am using AngularJS
$scope.close2 = close2;
function close2() {
/* Code here */
}
The error is on the line function close(). Why is this such a special name? How can I mute this error?
(Note: Answer has been heavily edited)
Summary
John Papa says to use latedef in JSHint and, at least implicitly, to ignore JSLint issues. (latedef defined here.)
I believe there's a plays-nicely solution (see below), however, that includes the advantages of Papa's suggested style with code that lints in JSHint and JSLint.
JSHint is "wrong" not to complain about close2. JSLint catches it exactly like you'd expect.
close but not close2 is a JSHint problem
For what it's worth, if you paste your code (jslint formatted Pasteee with both close & close2 here) into JSLint.com, both close and close2 cause errors. If you're not seeing an error for close2, I'm guessing it's JSHint's problem, but it'd be more useful to see exactly what you're linting through JSHint (in context) to know for sure.
So close is not a special name to JSLint. I would like to see your "actual" code in context to see if JSLint would say something similar
Just to be clear, this breaks on JSLint.com:
/*jslint sloppy:true, white:true */
/*global $scope */
$scope.close2 = close2;
function close2() {
return "something";
}
That will produce 'close2' was used before it was defined. $scope.close2 = close2;
If you want to know why JSHint is, I believe, breaking, we can go JSHint code spelunking, but to answer your JSLint tag (at least) the behavior you're seeing isn't happening.
How to fix
See this SO answer on exactly what you're discussing here, where John Papa says to use latedef in JSHint. One way around the linting issue is to ignore Papa and define the function first, but, as you mention in your comment, below, that's not ideal.
So here's the best compromise I could come up with...
Declare, but don't define, variables that will hold functions.
Insert your Angular directive
Define your functions from 1.
That definitely mutes the JSHint error, since the code that caused it isn't there any more. If I was doing Angular and needed to follow Papa-style, that's what I'd do to keep Crockford's blessing.
Example:
(function () {
'use strict';
// 1. Declare your function names. Minimally spammy!
var theController;
// 2. Directive
angular
.module('myApp')
.controller('myAppCtrl', theController);
// 3. *Define* the functions. No `latedef` needed, and JSLint compliant.
// Keeps "the list of calls at the top of the page" and allows you to
// "jump to each definition if you need more details". QED? ;^)
theController = function () {
return "so jslint doesn't complain about empty blocks";
};
}());

Find where a syntax error occurs when new Function() fails

To shortcut a long comment section on "don't use new Function" and/or "eval is evil", this question is about how to access, if possible, error information that is related to a new Function() constructor failing. It's mostly a question to discover a limit in what the browser will let me do when trying to exploit JavaScript to the extent that the spec and standard browser implementations allow. So with that disclaimer in place:
When evaluating code through a new Function() call, is there a way to find out where in the function's content a syntax error occurs, if illegal-syntax code is being evaluated? i.e.:
try {
var generator = new Function(input);
try {
generator();
}
catch (runtimeError) {
console.error("legal code; unforeseen result: ", runtimeError);
}
}
catch (syntaxError) {
console.error("illegal code; syntax errors: ", syntaxError);
}
When the building of the generator fails, is there a way to find out (from the browser, not using jslint or another external library) what the error was or where it occurred?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError/prototype mentions that a SyntaxError has a filename and linenumber property, but these are undefined for dynamic code evaluated through a new Function() constructor from what I can tell, so relying on the error object itself seems not to be an option. Are there alternative ways to introduce the code to the browser so that the code, once we know it has syntax errors from a failing new Function call, can be used to find out where the problem is according to the JS engine used?
(Of course, if the goal was to simply find syntax errors, jslint as a preprocess step would be the go-to solution, but I'm more interested in whether or not browsers can in some way be made to report this information, even if in limited form like "there is SOME error on line/char ...")
afaik impossible to find out where it occured. but you may want to see Exception.message to fetch information what the error was.
example: http://jsbin.com/IRoDiJIV/1/watch?js
Found a solution myself using a simiar method to setting breakpoints in evaled code
In chrome dev tools's sources panel, I put the following in a conditional breakpoint on the new Function line (since it's library code and I can't change it.)
(function(eval_js, load_js) {
try {
eval(eval_js);
} catch (e) {
(function addCode(js) {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = 'data:text/javascript;charset=utf-8,' + escape(js);
document.body.appendChild(e);
console.warn("Inserted Script for ", js);
})(load_js.replace(/;/g,";\n"));
handlerCode = "";
return false;
}
return false;
})("new Function('event', handlerCode)", handlerCode)

Catching "NullPointerExceptions" in JavaScript

I'm writing quite a bit of code in Prototype.js which returns null if a DOM-id wasn't found.
$("someId").show();
If someId doesn't exist, a method will be called on null, which halts the entire program, in effect disabling all JS effects after the error. I could just check for null before executing such a statement, but this is getting tiring.
I would like to catch an exception but I'm not sure which one its is. MDC lists the following ECMA Script error types, but on first glance none of them seem to be what I want:
* Error
* EvalError
* RangeError
* ReferenceError
* SyntaxError
* TypeError
* URIError
* DOMException
* EventException
* RangeException
Also, do browsers have a unified way of dealing with a method call on null?
I don't believe there's unity to be found. Chrome throws a TypeError, but IE throws an Error, so you would probably have to catch everything and make severe assumptions. Better to check for null first.
var element = $('someId');
if (element) {
element.show();
// whatever else...
}
If element.show() is the only thing you need it for, then it can obviously be written a lot shorter, but in most cases that would be appropriate.
The correct way to handle this is to check for null before doing something with an object. There are several shorthand ways to do this, the shortest is (as Alex K) wrote
$("someId") && $("someId").show();
but this seems to me to be harder to read.
To answer your question directly you can do
try { $('someId').show(); } catch (e) {}
but this seems amateurish. You should program explicitly because later on someone else won't know why you wrote that odd code. The first example is slightly opaque but at least contains the null test first, and doesn't hide errors in the show() method.
Incidentally, if you were using JQuery instead of Prototype, this code would work without error even if there is no object with id 'someId':
$('#someId').show()
That's because the $() function in JQuery returns a collection which may be empty but is never null.
If your going to chain .show() on $("someId") then check its result first.
if ($("someId"))
$("someId").show();
or
$("someId") && $("someId").show();
or
if (someVar = $("someId"))
someVar.show();
If for some reason you really need to identify them you could wrap $() and throw a custom exception:
function NullReferenceException(id) {this.id = id}
function $my(id) {
var el = $(id);
if (!el)
throw new NullReferenceException(id);
return el
}
try {
$my("iDontExistId").show();
} catch (e) {
if (e instanceof NullReferenceException)
alert(e.id + " doesn't exist");
}
Just ignore which exception it is...
try
{
null.hey()
}
catch(e)
{
//handle it here
}

Categories

Resources