This function's cyclomatic complexity is too high. (38) - javascript

I have a switch case statement for my filters.
But it throws me complexity issues of 39 can u help me solve it??
Below is my sample code. It includes some more cases.
angular.forEach(docsClone, function(doc) {
var added = false;
angular.forEach($scope.filterOptions, function(opt) {
if (!added) {
switch (opt.AttributeId) {
case 'documentStatus':
if ((doc.documentStatus !== undefined && doc.documentStatus !== null && doc.documentStatus.indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
case 'planStatus':
if ((doc.planStatus !== undefined && doc.planStatus.indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
case 'planFamily':
if ((doc.planProductFamily !== undefined && doc.planProductFamily !== null && doc.planProductFamily.indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
case 'planYear':
planYear(doc, opt.AttributeValue, filteredDocs, added);
break;
case 'documentType':
if ((doc.documentType !== undefined && doc.documentType !== null && doc.documentType.indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
case 'businessEntity':
if ((doc.businessEntity !== undefined && doc.businessEntity !== null && doc.businessEntity.indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
case 'productClass':
if ((doc.productClass !== undefined && doc.productClass !== null && doc.productClass !== null && doc.productClass.indexOf(opt.AttributeValue) !== -1) ||
(doc.planProductClass !== undefined && doc.planProductClass.indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
case 'productType':
if ((doc.productType !== undefined && doc.productType !== null && doc.productType.indexOf(opt.AttributeValue) !== -1) ||
(doc.planProductType !== undefined && doc.planProductType.indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
}

I see you have a lot of common conditions, why not break down into something common :
angular.forEach(docsClone, function(doc) {
var added = false;
angular.forEach($scope.filterOptions, function(opt) {
if (!added) {
switch (opt.AttributeId) {
case 'planStatus':
planYear(doc, opt.AttributeValue, filteredDocs, added);
break;
case 'documentType':
case 'documentStatus':
case 'planStatus':
case 'planFamily':
if ((doc[opt.AttributeId] !== undefined && doc[opt.AttributeId] !== null && doc[opt.AttributeId].indexOf(opt.AttributeValue) !== -1)) {
filteredDocs.push(doc);
added = true;
}
break;
}
}
});
}
You can generalise your case statements depending upon the comparisons / manipulations performed.

Related

Is there a better way to change button display in javascript/Vue?

After writing so many if else, I feel very tired. I'm using Vue. The following code are written in the script section of the vue file. I get a json from file, and then read the values in json, then set what button should be display based on employee level and on application status. Is there a better way to change the button display status in Vue?
if (
(this.GLOBAL2.jsonForGlobal.employeeLevel == "1" &&
(this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Checking" ||
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Pending" ||
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Approved")) ||
(this.GLOBAL2.jsonForGlobal.employeeLevel == "2" &&
(this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Pending" ||
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Approved")) ||
(this.GLOBAL2.jsonForGlobal.employeeLevel == "3" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Approved")
) {
this.pullDisplay = true;
} else {
this.pullDisplay = false;
};
if (
this.GLOBAL2.jsonForGlobal.employeeLevel == "1" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Revising"
) {
this.cancelDisplay = true;
} else {
this.cancelDisplay = false;
};
if (
(this.GLOBAL2.jsonForGlobal.employeeLevel == "1" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Revising") ||
(this.GLOBAL2.jsonForGlobal.employeeLevel == "2" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Checking") ||
(this.GLOBAL2.jsonForGlobal.employeeLevel == "3" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Pending")
) {
this.saveDisplay = true;
} else {
this.saveDisplay = false;
};
if (
this.GLOBAL2.jsonForGlobal.employeeLevel == "1" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Revising"
) {
this.reviseDisplay = true;
} else {
this.reviseDisplay = false;
};
if (
(this.GLOBAL2.jsonForGlobal.employeeLevel == "2" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Checking") ||
(this.GLOBAL2.jsonForGlobal.employeeLevel == "3" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Pending")
) {
this.sendDisplay = true;
} else {
this.sendDisplay = false;
};
if (
(this.GLOBAL2.jsonForGlobal.employeeLevel == "3" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Pending") ||
(this.GLOBAL2.jsonForGlobal.employeeLevel == "2" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus == "Checking")
) {
this.approvalDisplay = true;
} else {
this.approvalDisplay = false;
};
And also there are a few ones need three conditions:
if (
this.GLOBAL2.jsonForGlobal.employeeLevel == "3" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].requestCategory ==
"External Request" &&
this.GLOBAL2.jsonForGlobal.detail[this.detailId].currentStatus ==
"Pending"
) {
this.returnDisplay = true;
} else {
this.returnDisplay = false;
}
Going with a configuration based approach will make your code much more easy to edit and to read.
const levels = {
'1': {
pullDisplayStatus: ['Checking', 'Pending', 'Approved'],
cancelDisplayStatus: ['Revising'],
saveDisplayStatus: ['Revising'],
reviseDisplayStatus: ['Revising'],
sendDisplayStatus: [],
approvalDisplayStatus: [],
},
'2': {
pullDisplayStatus: ['Pending', 'Approved'],
cancelDisplayStatus: [],
saveDisplayStatus: ['Checking'],
reviseDisplayStatus: [],
sendDisplayStatus: ['Checking'],
approvalDisplayStatus: ['Checking'],
},
'3': {
pullDisplayStatus: ['Approved'],
cancelDisplayStatus: [],
saveDisplayStatus: ['Pending'],
reviseDisplayStatus: [],
sendDisplayStatus: ['Pending'],
approvalDisplayStatus: ['Pending'],
},
}
const jsonForGlobal = this.GLOBAL2.jsonForGlobal;
const currentStatus = jsonForGlobal.detail[this.detailId].currentStatus;
const level = levels[jsonForGlobal.employeeLevel];
this.pullDisplay = level.pullDisplayStatus.indexOf(currentStatus) > -1;
this.cancelDisplay = level.cancelDisplayStatus.indexOf(currentStatus) > -1;
this.saveDisplay = level.cancelDisplayStatus.indexOf(currentStatus) > -1;
this.reviseDisplay = level.reviseDisplayStatus.indexOf(currentStatus) > -1;
this.sendDisplay = level.reviseDisplayStatus.indexOf(currentStatus) > -1;
If you use a property often it makes sense to introduce a local variable for it to clean things up:
const { employeeLevel, detail: { [this.detailId]: { currentStatus }}} = his.GLOBAL2.jsonForGlobal;
Secondly you don't need the if / else, you can just assign the boolean:
this.pullDisplay = (
employeeLevel == "1" && ["Checking", "Pending", "Approved"].includes(currentStatus) ||
employeeLevel == "2" && ["Pending", "Approved"].includes(currentStatus) ||
employeeLevel == "3" && currentStatus == "Approved"
)

Adding conditions to filter() dynamically in Javascript

I want to add conditions in JavaScript filter() method dynamically.
I have the code below:
let condition = '';
let a = ['empEmail', 'employeeAction', 'transactionNo', 'deviceListName', 'projectName'];
if (this.selectedEmployeeAlias != undefined) {
condition += '&& a => a.empEmail === this.selectedEmployeeAlias';
}
if (this.employeeStatusList != undefined) {
condition += '&& a.employeeAction === this.employeeStatusList'
}
if (this.selectedTransactionNo != undefined) {
condition += '&& a.transactionNo === this.selectedTransactionNo';
}
if (this.selectedDeviceList != undefined) {
condition += ' && a.deviceListName == this.selectedDeviceList';
}
if (this.selectedProjectName != undefined) {
condition += '&& a.projectName == this.selectedProjectName';
}
var finalCondition = condition.substring(2, condition.length);
var fArray = arrayDetails.filter(finalCondition);
The code is returning an error as:
finalCondition is not a function.
Could you please let me know how can I add conditions to filter() dynamically.
You could take an array of functions with conditions. Then iterate with every.
var conditions = [];
if (this.selectedEmployeeAlias !== undefined) {
conditions.push(a => a.empEmail === this.selectedEmployeeAlias);
}
if (this.employeeStatusList !== undefined) {
conditions.push(a => a.employeeAction === this.employeeStatusList);
}
if (this.selectedTransactionNo !== undefined) {
conditions.push(a => a.transactionNo === this.selectedTransactionNo);
}
if (this.selectedDeviceList !== undefined) {
conditions.push(a => a.deviceListName == this.selectedDeviceList);
}
if (this.selectedProjectName !== undefined) {
conditions.push(a => a.projectName == this.selectedProjectName);
}
var fArray = arrayDetails.filter(o => conditions.every(c => c(o)));
As you got the nakes of the keys, just loop over them and check for undefineds:
const keys = ['empEmail', 'employeeAction', 'transactionNo', 'deviceListName', 'projectName'];
const result = arrayDetails.filter(el => {
for(const key of keys) {
if(this[key] === undefined) continue;
if(this[key] !== el[key]) return false;
}
return true;
});
eval to the Rescue!
While it's generally advised against, eval does exactly what you want here.
Just pass your condition variable to eval inside the .filter method and voila!
let condition='';
let a = ['empEmail', 'employeeAction', 'transactionNo', 'deviceListName', 'projectName'];
if (this.selectedEmployeeAlias != undefined) {
condition += '&& a => a.empEmail === this.selectedEmployeeAlias';
}
if (this.employeeStatusList != undefined) {
condition += '&& a.employeeAction === this.employeeStatusList'
}
if (this.selectedTransactionNo != undefined) {
condition += '&& a.transactionNo === this.selectedTransactionNo';
}
if (this.selectedDeviceList != undefined) {
condition += ' && a.deviceListName == this.selectedDeviceList';
}
if (this.selectedProjectName != undefined) {
condition += '&& a.projectName == this.selectedProjectName';
}
var finalCondition=condition.substring(2, condition.length);
var fArray=arrayDetails.filter(stuff => eval(finalCondition));

codefights isSubTress only one hide test case can not pass

Given two binary trees t1 and t2, determine whether the second tree is a subtree of the first tree. A subtree for vertex v in a binary tree t is a tree consisting of v and all its descendants in t. Determine whether or not there is a vertex v (possibly none) in tree t1 such that a subtree for vertex v (possibly empty) in t1 equals t2.
//
// Definition for binary tree:
// function Tree(x) {
// this.value = x;
// this.left = null;
// this.right = null;
// }
function isSubtree(t1, t2) {
function findroot(t1,t2){
if(t2==null){
return true;
}else if(t1==null){
if(t2==null){
return true;
}else{
return false;
}
}else if((
t1.value == t2.value && machedTree(t1,t2)) || findroot(t1.left,t2) || findroot(t1.right,t2)){
return true;
}else{
return false
}
}
function machedTree(t1,t2){
if((t1 == null && t2 == null)
&&(t1 == null && t2==null)){
return true;
}else if( t2 == null ||
((t1 != null && t2!=null)
&& machedTree(t1.left,t2.left)
&&t1.value == t2.value
&&machedTree(t1.right,t2.right))){
return true;
}else{
return false;
}
}
return findroot(t1,t2)
}
Has only one hide test case can not pass. do you have any idea where is wrong for the code
function isSubtree(t1, t2) {
function findroot(t1,t2){
if(t2==null){
return true;
}else if(t1==null){
return false;
}else if((
t1.value == t2.value && machedTree(t1,t2)) || findroot(t1.left,t2) || findroot(t1.right,t2)){
return true;
}else{
return false
}
}
function machedTree(t1,t2){
if(t1==null && t2 == null){
return true;
}
else if((t2 != null && t1 != null)
&& machedTree(t1.left,t2.left)
&& (t1.value === t2.value)
&&machedTree(t1.right,t2.right)){
return true;
}else{
return false;
}
}
return findroot(t1,t2)
}

JS | Why is the property of the Object truthy although it's empty?

So the value of the first object with the property "single" is empty, but still truthy, what did I wrong?
function every(collection, pre) {
var rtr = null;
for(var e in collection){
if(collection[e][pre] !== null &&
collection[e][pre] !== undefined &&
collection[e][pre] !== 0 &&
collection[e][pre] !== "" &&
collection[e][pre] !== false &&
collection[e][pre] !== NaN){
rtr = true;
}
else
rtr = false;
}
console.log(rtr);
}
every([{"single": ""}, {"single": "double"}], "single");
You console.log outside the loop. Try this (I also removed the stray `):
function every(collection, pre) {
var rtr = null;
for(var e in collection){
if(collection[e][pre] !== null &&
collection[e][pre] !== undefined &&
collection[e][pre] !== 0 &&
collection[e][pre] !== "" &&
collection[e][pre] !== false &&
collection[e][pre] !== NaN){
rtr = true;
}
else
rtr = false;
console.log(rtr);
}
}
every([{"single": ""}, {"single": "double"}], "single");
It logs
false
true

JavaScript: Parsing a string Boolean value? [duplicate]

This question already has answers here:
How can I convert a string to boolean in JavaScript?
(102 answers)
Closed 4 years ago.
JavaScript has parseInt() and parseFloat(), but there's no parseBool or parseBoolean method in the global scope, as far as I'm aware.
I need a method that takes strings with values like "true" or "false" and returns a JavaScript Boolean.
Here's my implementation:
function parseBool(value) {
return (typeof value === "undefined") ?
false :
// trim using jQuery.trim()'s source
value.replace(/^\s+|\s+$/g, "").toLowerCase() === "true";
}
Is this a good function? Please give me your feedback.
Thanks!
I would be inclined to do a one liner with a ternary if.
var bool_value = value == "true" ? true : false
Edit: Even quicker would be to simply avoid using the a logical statement and instead just use the expression itself:
var bool_value = value == 'true';
This works because value == 'true' is evaluated based on whether the value variable is a string of 'true'. If it is, that whole expression becomes true and if not, it becomes false, then that result gets assigned to bool_value after evaluation.
You can use JSON.parse for that:
JSON.parse("true"); //returns boolean true
It depends how you wish the function to work.
If all you wish to do is test for the word 'true' inside the string, and define any string (or nonstring) that doesn't have it as false, the easiest way is probably this:
function parseBoolean(str) {
return /true/i.test(str);
}
If you wish to assure that the entire string is the word true you could do this:
function parseBoolean(str) {
return /^true$/i.test(str);
}
You can try the following:
function parseBool(val)
{
if ((typeof val === 'string' && (val.toLowerCase() === 'true' || val.toLowerCase() === 'yes')) || val === 1)
return true;
else if ((typeof val === 'string' && (val.toLowerCase() === 'false' || val.toLowerCase() === 'no')) || val === 0)
return false;
return null;
}
If it's a valid value, it returns the equivalent bool value otherwise it returns null.
You can use JSON.parse or jQuery.parseJSON and see if it returns true using something like this:
function test (input) {
try {
return !!$.parseJSON(input.toLowerCase());
} catch (e) { }
}
last but not least, a simple and efficient way to do it with a default value :
ES5
function parseBool(value, defaultValue) {
return (value == 'true' || value == 'false' || value === true || value === false) && JSON.parse(value) || defaultValue;
}
ES6 , a shorter one liner
const parseBool = (value, defaultValue) => ['true', 'false', true, false].includes(value) && JSON.parse(value) || defaultValue
JSON.parse is efficient to parse booleans
Personally I think it's not good, that your function "hides" invalid values as false and - depending on your use cases - doesn't return true for "1".
Another problem could be that it barfs on anything that's not a string.
I would use something like this:
function parseBool(value) {
if (typeof value === "string") {
value = value.replace(/^\s+|\s+$/g, "").toLowerCase();
if (value === "true" || value === "false")
return value === "true";
}
return; // returns undefined
}
And depending on the use cases extend it to distinguish between "0" and "1".
(Maybe there is a way to compare only once against "true", but I couldn't think of something right now.)
Why not keep it simple?
var parseBool = function(str) {
if (typeof str === 'string' && str.toLowerCase() == 'true')
return true;
return (parseInt(str) > 0);
}
You can add this code:
function parseBool(str) {
if (str.length == null) {
return str == 1 ? true : false;
} else {
return str == "true" ? true : false;
}
}
Works like this:
parseBool(1) //true
parseBool(0) //false
parseBool("true") //true
parseBool("false") //false
Wood-eye be careful.
After looking at all this code, I feel obligated to post:
Let's start with the shortest, but very strict way:
var str = "true";
var mybool = JSON.parse(str);
And end with a proper, more tolerant way:
var parseBool = function(str)
{
// console.log(typeof str);
// strict: JSON.parse(str)
if(str == null)
return false;
if (typeof str === 'boolean')
{
if(str === true)
return true;
return false;
}
if(typeof str === 'string')
{
if(str == "")
return false;
str = str.replace(/^\s+|\s+$/g, '');
if(str.toLowerCase() == 'true' || str.toLowerCase() == 'yes')
return true;
str = str.replace(/,/g, '.');
str = str.replace(/^\s*\-\s*/g, '-');
}
// var isNum = string.match(/^[0-9]+$/) != null;
// var isNum = /^\d+$/.test(str);
if(!isNaN(str))
return (parseFloat(str) != 0);
return false;
}
Testing:
var array_1 = new Array(true, 1, "1",-1, "-1", " - 1", "true", "TrUe", " true ", " TrUe", 1/0, "1.5", "1,5", 1.5, 5, -3, -0.1, 0.1, " - 0.1", Infinity, "Infinity", -Infinity, "-Infinity"," - Infinity", " yEs");
var array_2 = new Array(null, "", false, "false", " false ", " f alse", "FaLsE", 0, "00", "1/0", 0.0, "0.0", "0,0", "100a", "1 00", " 0 ", 0.0, "0.0", -0.0, "-0.0", " -1a ", "abc");
for(var i =0; i < array_1.length;++i){ console.log("array_1["+i+"] ("+array_1[i]+"): " + parseBool(array_1[i]));}
for(var i =0; i < array_2.length;++i){ console.log("array_2["+i+"] ("+array_2[i]+"): " + parseBool(array_2[i]));}
for(var i =0; i < array_1.length;++i){ console.log(parseBool(array_1[i]));}
for(var i =0; i < array_2.length;++i){ console.log(parseBool(array_2[i]));}
I like the solution provided by RoToRa (try to parse given value, if it has any boolean meaning, otherwise - don't). Nevertheless I'd like to provide small modification, to have it working more or less like Boolean.TryParse in C#, which supports out params. In JavaScript it can be implemented in the following manner:
var BoolHelpers = {
tryParse: function (value) {
if (typeof value == 'boolean' || value instanceof Boolean)
return value;
if (typeof value == 'string' || value instanceof String) {
value = value.trim().toLowerCase();
if (value === 'true' || value === 'false')
return value === 'true';
}
return { error: true, msg: 'Parsing error. Given value has no boolean meaning.' }
}
}
The usage:
var result = BoolHelpers.tryParse("false");
if (result.error) alert(result.msg);
stringjs has a toBoolean() method:
http://stringjs.com/#methods/toboolean-tobool
S('true').toBoolean() //true
S('false').toBoolean() //false
S('hello').toBoolean() //false
S(true).toBoolean() //true
S('on').toBoolean() //true
S('yes').toBoolean() //true
S('TRUE').toBoolean() //true
S('TrUe').toBoolean() //true
S('YES').toBoolean() //true
S('ON').toBoolean() //true
S('').toBoolean() //false
S(undefined).toBoolean() //false
S('undefined').toBoolean() //false
S(null).toBoolean() //false
S(false).toBoolean() //false
S({}).toBoolean() //false
S(1).toBoolean() //true
S(-1).toBoolean() //false
S(0).toBoolean() //false
I shamelessly converted Apache Common's toBoolean to JavaScript:
JSFiddle: https://jsfiddle.net/m2efvxLm/1/
Code:
function toBoolean(str) {
if (str == "true") {
return true;
}
if (!str) {
return false;
}
switch (str.length) {
case 1: {
var ch0 = str.charAt(0);
if (ch0 == 'y' || ch0 == 'Y' ||
ch0 == 't' || ch0 == 'T' ||
ch0 == '1') {
return true;
}
if (ch0 == 'n' || ch0 == 'N' ||
ch0 == 'f' || ch0 == 'F' ||
ch0 == '0') {
return false;
}
break;
}
case 2: {
var ch0 = str.charAt(0);
var ch1 = str.charAt(1);
if ((ch0 == 'o' || ch0 == 'O') &&
(ch1 == 'n' || ch1 == 'N') ) {
return true;
}
if ((ch0 == 'n' || ch0 == 'N') &&
(ch1 == 'o' || ch1 == 'O') ) {
return false;
}
break;
}
case 3: {
var ch0 = str.charAt(0);
var ch1 = str.charAt(1);
var ch2 = str.charAt(2);
if ((ch0 == 'y' || ch0 == 'Y') &&
(ch1 == 'e' || ch1 == 'E') &&
(ch2 == 's' || ch2 == 'S') ) {
return true;
}
if ((ch0 == 'o' || ch0 == 'O') &&
(ch1 == 'f' || ch1 == 'F') &&
(ch2 == 'f' || ch2 == 'F') ) {
return false;
}
break;
}
case 4: {
var ch0 = str.charAt(0);
var ch1 = str.charAt(1);
var ch2 = str.charAt(2);
var ch3 = str.charAt(3);
if ((ch0 == 't' || ch0 == 'T') &&
(ch1 == 'r' || ch1 == 'R') &&
(ch2 == 'u' || ch2 == 'U') &&
(ch3 == 'e' || ch3 == 'E') ) {
return true;
}
break;
}
case 5: {
var ch0 = str.charAt(0);
var ch1 = str.charAt(1);
var ch2 = str.charAt(2);
var ch3 = str.charAt(3);
var ch4 = str.charAt(4);
if ((ch0 == 'f' || ch0 == 'F') &&
(ch1 == 'a' || ch1 == 'A') &&
(ch2 == 'l' || ch2 == 'L') &&
(ch3 == 's' || ch3 == 'S') &&
(ch4 == 'e' || ch4 == 'E') ) {
return false;
}
break;
}
default:
break;
}
return false;
}
console.log(toBoolean("yEs")); // true
console.log(toBoolean("yES")); // true
console.log(toBoolean("no")); // false
console.log(toBoolean("NO")); // false
console.log(toBoolean("on")); // true
console.log(toBoolean("oFf")); // false
Inspect this element, and view the console output.
Enough to using eval javascript function to convert string to boolean
eval('true')
eval('false')

Categories