Is there an ESLint rule to detect if the code can be detected when it's not using guard clauses?
This is related to this post- https://elliotekj.com/2016/12/02/guard-clauses-in-javascript/
for example, this should HAVE a warning:
function doSomething(obj) {
if(obj) {
console.log('I did something');
}
return null;
}
This should have NO warning
function doSomething(obj) {
if(!obj) {
return null;
}
console.log('I did something');
}
I would prefer the latter. Please don't comment on the 'opinionated' aspect of this question. I just want to know if there is an ESLint specific rule or something similar that I can work with.
Or is ESLint even the right tool to detect/correct this kind of code style enforcement?
Thank you.
PS. I did do some research and did not found any rules that related to this my specific need on ESLint Rules. Now, I'm just a newcomer JS developer and would like to know if I miss anything that I should have checked before I go any deeper into writing my own rule.
There is no ESLint rule that will catch that (up to v5.8.0). You provided the source yourself :)
I'm all in for guard clauses but I don't think this is a feature coming anytime soon because it's very context dependent and difficult to correctly identify it on all cases.
A sidenote from looking at your snippet, if you want to follow ESLint best practices, you should be returning a undefined/void instead of null in cases you don't expect a value to be returned (check https://eslint.org/docs/rules/consistent-return#require-return-statements-to-either-always-or-never-specify-values-consistent-return)
Related
I was trying to tsc ts file to js file.I want to input some numbers in texture, and then calculate the mean of those numbers. But here is an error: TypeScriptLab.ts(23,28): error TS1005: ',' expected.
I attached my ts code. Anyone can help please? Thank you so much.
import $ from "jquery";
class average{
constructor(){
$("#btn").on("click",()=>{
this.getaverage();
});
}
getaverage():void{
let list:Array<number> = $("textarea").val() as Array<number>;
let i:number = 0;
let aver:number =0;
let sum:number = 0;
while(i++){
if (isNaN(list[i])) {
sum+=list[i];
aver=sum/(i+1);
}
else
break;
}
$("span").html(aver:number);
}
}
Here: $("span").html(aver:number); Remove the :number. You don't have to apply the type syntax when passing variables into other functions.
A bit out of the way, but I was getting this error where I should not be getting the error. Even updating the version of TS did nothing. But I had other errors in Lint, so I went through all my code and cleaned it all up and found linting issues upstream from the area that was giving this error. Once I fixed those - unrelated - issues, these just cleared up.
It appears that Lint is darn good, but not perfect in every way. As expected. It is just another tool to be used, at times in context with a little extra troubleshooting. But I can't complain about this idiosyncrasy because it helped me catch a few errors that would have been extremely difficult to troubleshoot.
The errors I caught were not coming up in Lint, but because Lint triggered near the errors, in relation to the errors, I was able to catch them. In other words, Lint basically was not able to point directly at my errors, but was able to say "I don't exactly know what's wrong here, but there is something wrong near here."
I don't know if this can help you out in you specific case since in your case it appears to be limited to that small amount of specific code, but I would definitely address any other Lint issues that you are seeing first, then come back to this if you have not already solved it.
If this info does not help you, hopefully it helps someone else Googling the issue months from now. Good luck.
how can i turn the following alert into an acceptable alert for ESLint?
svg.onerror = function() {
alert("File cannot be loaded");
};
My build fails because apparently i cant use "alert". I want to call this alert when there is an issue loading something. This code works successfully but it does not comply with ESLint.
http://eslint.org/docs/rules/no-alert
how can i modify my code to make it build successfully?
thanks in advance :)
If you think you have a good reason for not observing an eslint setting, then you can disable that specific rule for that specific line by specifying eslint-disable-line in a comment on the offending line, like so:
svg.onerror = function() {
alert("File cannot be loaded"); // eslint-disable-line no-alert
};
A better solution might be to implement a modal or show an error to the user in another less-intrusive way (eg: toggle visibility of an error element, or use something like Bootstrap's modal).
Some ESLint rules don't make sense to include in every project, and no-alert is definitely one of them. While critics might say alert is obtrusive, that fails to account for the fact that obtrusive can be good!
To disable this rule, disable it in your ESLint configuration file by setting it to "off."
...
"rules": {
...
"no-alert": "off",
...
}
ESlint: Turning off a specific rule across a project
I met this Breeze error
[Illegal construction - use 'or' to combine checks]
on Chrome when loading the edit page of an entity. When I refresh the page, the error message no longer appears. This error happens randomly, irregularly on my site. I could not reproduce it using a specified scenario, just met it by random.
I see this error message inside Breeze code
if (curContext.prevContext === null) {
curContext.prevContext = context;
// just update the prevContext but don't change the curContext.
return that;
} else if (context.prevContext === null) {
context.prevContext = that._context;
} else {
throw new Error("Illegal construction - use 'or' to combine checks");
}
Could you please tell me: based on above block of code, in which cases this error is thrown?
Thanks a lot.
My team has been having this problem too. It started happening about a month ago, but has really increased in frequency over the past 1-2 weeks. Possibly the recent chrome release to blame.
Here is what I know, all commentary relative to breeze 1.4.1:
-The behavior is intermittent, and seemingly occurs at random. To me, this indicates a timing issue.
-The primary browser generating this error is chrome. We also support firefox and IE and have no concrete evidence that any browser but chrome is throwing this error. Perhaps the recent release of chrome has a different performance profile that exacerbates a pre-existing issue (again, timing?)
-For us, turning off bundling and minification seems to eliminate the problem. I don't believe there is an issue with our minified code (Microsoft Web Optimizations) as everything works on other browsers regardless. This to me again indicates a timing issue.
-Finally, I was just able to reproduce it in my dev environment with the chrome developer tools open. Using a q promise stack, and painfully navigating the minified code I was able to narrow it down to this: At my app start, I call fetchMetadata. Within the fetchMetadata success handler, I make a call to metadataStore.getEntityType('some_entity') and it is within this breeze method that the error is being generated in my scenario. Something with the metadata store isn't consistently initialized or setup at this early stage in the pages app lifecycle.
EDIT: From the comments, this appears to be a chrome 33 bug where null !== null at random times. For unknown reasons, the minifying of the breeze.debug.js file seems to be related (most/all reports of the problem are happening on a minified version of breeze). For me, changing the following code in breeze.debug.js:
} else if (context.prevContext === null) {
context.prevContext = that._context;
} else {
throw new Error("Illegal construction - use 'or' to combine checks");
}
to:
} else if (context.prevContext == null) {
context.prevContext = that._context;
} else {
throw new Error("Illegal construction - use 'or' to combine checks");
}
(change === to == on first line) seems to have resolved the issue as a workaround. All other aspects of breeze are working fine for me after this change.
One other thing I have noticed is that the minified version of the function has an argument with the same name of the function (t). This still doesn't explain the results of the "Aaarg" test.
function t(n, t) {
if (n._context) {
for (var i = n._context; i.prevContext != null; )
i = i.prevContext;
if (i.prevContext === null)
return i.prevContext = t, n;
if (t.prevContext == null)
t.prevContext = n._context;
else
throw new Error("Illegal construction - use 'or' to combine checks");
}
return b(n, t)
}
We're kind of stumped because no one can pin down when this happens.
Would you all do us a favor and modify your breeze.debug.js to capture more information about the state of affairs when it throws?
Maybe you can add this:
} else {
console.log("** Aaargh! 'curContext.prevContext': " + curContext.prevContext +
" 'context.prevContext': " + context.prevContext);
throw new Error("Illegal construction - use 'or' to combine checks");
}
Grasping at straws. All info helps.
Update 26 Feb 2014
AHA! Thank you #steve, #matthias, and others!
As I privately suspected, something, somewhere, has decide to set prevContext to undeclared instead of null. I was going to recommend that we switch to "==" anyway ... which would handle both cases. Falsiness is good enough IMO. We'll get back to you when we do it (assuming no one inside the Breeze team objects to applying a fix that we can't test).
Update 27 Feb 2014
I'm running my DocCode tests with breeze.min.js in Chrome v33 and they all pass. Frustrating. Jay will run his tests with breeze.min.js in Chrome v33 too ... and we will see if any of them fail for him. I am not hopeful.
I get the expected behavior for sensible (including illegal) variations of parm (undefined, null, true, false, a string) on the line from getEntityType that #Matthias mentioned
assertParam(parm, "okIfNotFound").isBoolean().isOptional().check(false);
My static analysis of the code (who trusts that?) tells me that the first comparison operator must remain === whereas the comparison operator in the second clause can be either == or ===. The code author worked hard to make sure that the left operand was never undefined in practice; my static analysis shows that it could become undefined ... although I am unable to arrange the world so that it happens. Maybe a failure of imagination.
My static analysis of the minified code says it is correct although my minified version is different from yours, perhaps because mine is minified against an evolving copy of breeze.debug.js (somewhere closer to what v.1.4.9 will be).
// Reformatted w/ spaces and new lines for readability.
// Observe that the minifier reversed the direction of the second null test!
// That is smart and does no harm
// I can assure you the pre-minified code is the same as what you folks are reporting.
function m(a,b) {
if(a._context){
for(var c=a._context; null!=c.prevContext;) c=c.prevContext;
if(null === c.prevContext) return c.prevContext=b, a;
if(null !== b.prevContext)
throw new Error("Illegal construction - use 'or' to combine checks");
b.prevContext=a._context
}
return n(a,b)
}
Under these trying circumstances, unless we can find a failing test, we'll make a leap of faith, slaughter a chicken, rattle some bones, and change the code to this:
if (curContext.prevContext === null) {
curContext.prevContext = context;
// just update the prevContext but don't change the curContext.
return that;
} else if (context.prevContext == null) { // CHANGED TO "if null or undefined"
context.prevContext = that._context;
} else {
throw new Error("Illegal construction - use 'or' to combine checks");
}
If you can make the time, please try this in your apps and confirm that all is well.
We're shipping v.1.4.9 tomorrow (28 Feb) so please try this pronto!
This started occurring when Chrome updated to version 33. It did not happen in Chrome 32.
I downgraded Breeze from version 1.4.8 to version 1.4.7, and this fixed the problem made the problem happen less often.
(The only breaking change listed in the changelog is that contains queries must be escaped in version 1.4.7. So do a word = word.replace(/'/g, "''"); before doing .where("yourColumn", "contains", word))
Edit:
Nope, changing to 1.4.7 did NOT fix this, it just made the problem occur much less often.
Ok, we just released Breeze 1.4.9 with Mathias999us's suggested fix. Please let us know whether this fixes the issue ... or not. Thanks Mathias ;)
Looking at the code, Breeze is expecting either 'curContext.prevContext' or 'context.prevContext' to be 'null'. One of them has to be 'null' in this check.
The error is thrown when both curContext.prevContext and context.prevContext already are set to a value.
For our application, switching to the non-minified (debug) version of breeze 1.4.8 eliminated the error. I cannot say with confidence that this will fix the problem for everyone since I don't know the root cause of the problem or how minification causes the error. Maybe the error can still happen with the non-minified version, but it doesn't in our application.
FWIW: Based on our experience and what I've read from others, the error is characterized in that it:
only occurs in the latest version of Chrome (33) -- windows and mac!
does not always happen.
seems to have a timing aspect. For us it only happens in first few breeze queries after starting the application -- although not necessarily the first query.
occurs for every query after the first query that fails.
I'm running JSLint on a project and I'm hitting this error:
Expected exactly one space between } and else
On this block of code:
// Check for the existance of the file created by firstrun.js
if (runOnce.exists) {
window.location = 'app:/core/firstrun.html';
}
// Check for version info
else if (!versionInfo.exists) {
window.location = 'app:/core/createVersion.html';
}
The // Check for version info line is obviously causing the problem; but where would Crockford have me put this comment?
I could obviously change the else if to an if since the first if contains a redirect; but I have other commented if/else if/else's not containing redirects.
I know this sounds odd, but you may try and put it inline with the else
Like this:
else if (!versionInfo.exists) { // Check for version info
window.location = 'app:/core/createVersion.html';
}
JSHint from JsFiddle said that this piece of js is syntactically valid :/
It looks a little weird, but I use this style.
if (runOnce.exists) {
// Check for the existance of the file created by firstrun.js
window.location = 'app:/core/firstrun.html';
} else if (!versionInfo.exists) {
// Check for version info
window.location = 'app:/core/createVersion.html';
}
Honestly, though, just forget about JSLint, for this case.
Those are just suggestions, not rules. I think readability is more important here.
Set the JSLint option to allow messy whitespace, otherwise it tries to enforce its own whitespace style rules, which are silly (IMO):
/*jslint white: true */
I'm looking into different ways to minify my JavaScript code including the regular JSMin, Packer, and YUI solutions. I'm really interested in the new Google Closure Compiler, as it looks exceptionally powerful.
I noticed that Dean Edwards packer has a feature to exclude lines of code that start with three semicolons. This is handy to exclude debug code. For instance:
;;; console.log("Starting process");
I'm spending some time cleaning up my codebase and would like to add hints like this to easily exclude debug code. In preparation for this, I'd like to figure out if this is the best solution, or if there are other techniques.
Because I haven't chosen how to minify yet, I'd like to clean the code in a way that is compatible with whatever minifier I end up going with. So my questions are these:
Is using the semicolons a standard technique, or are there other ways to do it?
Is Packer the only solution that provides this feature?
Can the other solutions be adapted to work this way as well, or do they have alternative ways of accomplishing this?
I will probably start using Closure Compiler eventually. Is there anything I should do now that would prepare for it?
here's the (ultimate) answer for closure compiler :
/** #const */
var LOG = false;
...
LOG && log('hello world !'); // compiler will remove this line
...
this will even work with SIMPLE_OPTIMIZATIONS and no --define= is necessary !
Here's what I use with Closure Compiler. First, you need to define a DEBUG variable like this:
/** #define {boolean} */
var DEBUG = true;
It's using the JS annotation for closure, which you can read about in the documentation.
Now, whenever you want some debug-only code, just wrap it in an if statement, like so:
if (DEBUG) {
console.log("Running in DEBUG mode");
}
When compiling your code for release, add the following your compilation command: --define='DEBUG=false' -- any code within the debug statement will be completely left out of the compiled file.
A good solution in this case might be js-build-tools which supports 'conditional compilation'.
In short you can use comments such as
// #ifdef debug
var trace = debug.getTracer("easyXDM.Rpc");
trace("constructor");
// #endif
where you define a pragma such as debug.
Then when building it (it has an ant-task)
//this file will not have the debug code
<preprocess infile="work/easyXDM.combined.js" outfile="work/easyXDM.js"/>
//this file will
<preprocess infile="work/easyXDM.combined.js" outfile="work/easyXDM.debug.js" defines="debug"/>
Adding logic to every place in your code where you are logging to the console makes it harder to debug and maintain.
If you are already going to add a build step for your production code, you could always add another file at the top that turns your console methods into noop's.
Something like:
console.log = console.debug = console.info = function(){};
Ideally, you'd just strip out any console methods, but if you are keeping them in anyway but not using them, this is probably the easiest to work with.
If you use the Closure Compiler in Advanced mode, you can do something like:
if (DEBUG) console.log = function() {}
Then the compiler will remove all your console.log calls. Of course you need to --define the variable DEBUG in the command line.
However, this is only for Advanced mode. If you are using Simple mode, you'll need to run a preprocessor on your source file.
Why not consider the Dojo Toolkit? It has built-in comment-based pragma's to include/exclude sections of code based on a build. Plus, it is compatible with the Closure Compiler in Advanced mode (see link below)!
http://dojo-toolkit.33424.n3.nabble.com/file/n2636749/Using_the_Dojo_Toolkit_with_the_Closure_Compiler.pdf?by-user=t
Even though its an old question. I stumbled upon the same issue today and found that it can be achieved using CompilerOptions.
I followed this thread.
We run the compiler, from Java, on our server before sending the code to the client. This worked for us in Simple mode.
private String compressWithClosureCompiler(final String code) {
final Compiler compiler = new Compiler();
final CompilerOptions options = new CompilerOptions();
Logger.getLogger("com.google.javascript.jscomp").setLevel(Level.OFF);
if (compressRemovesLogging) {
options.stripNamePrefixes = ImmutableSet.of("logger");
options.stripNameSuffixes = ImmutableSet.of("debug", "dev", "info", "error",
"warn", "startClock", "stopClock", "dir");
}
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
final JSSourceFile extern = JSSourceFile.fromCode("externs.js", "");
final JSSourceFile input = JSSourceFile.fromCode("input.js", code);
compiler.compile(extern, input, options);
return compiler.toSource();
}
It will remove all the calls to logger.debug, logger.dev...etc.etc
If you're using UglifyJS2, you can use the drop_console argument to remove console.* functions.
I use this in my React apps:
if (process.env.REACT_APP_STAGE === 'PROD')
console.log = function no_console() {};
In other words, console.log will return nothing on prod enviroment.
I am with #marcel-korpel. Isn't perfect but works. Replace the debug instructions before minification. The regular expression works in many places. Watch out unenclosed lines.
/console\.[^;]*/gm
Works on:
;;; console.log("Starting process");
console.log("Starting process");
console.dir("Starting process");;;;;
console.log("Starting "+(1+2)+" processes"); iamok('good');
console.log('Message ' +
'with new line'
);
console.group("a");
console.groupEnd();
swtich(input){
case 1 : alert('ok'); break;
default: console.warn("Fatal error"); break;
}
Don't works:
console.log("instruction without semicolon")
console.log("semicolon in ; string");
I haven't looked into minification so far, but this behaviour could be accomplished using a simple regular expression:
s/;;;.*//g
This replaces everything in a line after (and including) three semicolons with nothing, so it's discarded before minifying. You can run sed (or a similar tool) before running your minification tool, like this:
sed 's/;;;.*//g' < infile.js > outfile.js
BTW, if you're wondering whether the packed version or the minified version will be 'better', read this comparison of JavaScript compression methods.
I've used following self-made stuf:
// Uncomment to enable debug messages
// var debug = true;
function ShowDebugMessage(message) {
if (debug) {
alert(message);
}
}
So when you've declared variable debug which is set to true - all ShowDebugMessage() calls would call alert() as well. So just use it in a code and forget about in place conditions like ifdef or manual commenting of the debug output lines.
I was searching for a built-in option to do this. I have not found that yet, but my favorite answer also does not require any changes to existing source code. Here's an example with basic usage.
Assume HTML file test.html with:
<html>
<script src="hallo.js"></script>
</html>
And hallo.js with:
sayhi();
function sayhi()
{
console.log("hallo, world!");
}
We'll use a separate file, say noconsole.js, having this from the linked answer:
console.log = console.debug = console.info = function(){};
Then we can compile it as follows, bearing in mind that order matters, noconsole.js must be placed first in the arguments:
google-closure-compiler --js noconsole.js hallo.js --js_output_file hallo.out.js
If you cat hallo.out.js you'd see:
console.log=console.debug=console.info=function(){};sayhi();function sayhi(){console.log("hallo, world!")};
And if I test with mv hallo.out.js hallo.js and reload the page, I can see that the console is now empty.
Hope this clarifies it. Note that I have not yet tested this in the ideal mode of compiling all the source code with ADVANCED optimizations, but I'd expect it to also work.