Extract the assignment of from this expression with sonarQube - javascript

when I launch a sonar control I find myself with a smells code for the following function:
const changeMedia = (value: any, step: any) => {
step.definition?.steps
.filter((obj: any) => obj.media.includes(value))
.map((item: any) => {
if (value === 'EMAIL') {
return (item.media = 'LETTER');
} else if (value === 'LETTER') {
return (item.media = 'EMAIL');
}
return item;
});
};
I get the following sonar alert:
Extract the assignment of "item.media" from this expression.
What would be the solution to avoid this sonar message?

const changeMedia = (value, step) => {
step.definition?.steps
.filter((obj) => obj.media.includes(value))
.map((item) => {
if (value === 'EMAIL') {
item.media = 'LETTER'
return item; // returning item instead of (item.media = 'LETTER')
} else if (value === 'LETTER') {
item.media = 'EMAIL'
return item;
}
return item;
});
};

Related

react issue - Cannot assign to read only property '0' of object '[object Array]' ---

What causes the ff issue ? Cannot assign to read only property '0' of object '[object Array]' ?
Any idea would be appreacited. Thanks.
#ts code snippet
const [RegionalList, setRegionalList] = useState<IRegionalList[]>(RegionalListData);
const setEmailValue = (event: any, regionalId: number, index: number) => {
setRegionalList((prevState: IRegionalList[]) => {
const newState = prevState.map((prop: IRegionalList) => {
if (prop.id === regionalId) {
prop.emails[index] = { emailAddress: event.target.value, id: null };
return { ...prop };
}
return prop;
});
return newState;
});
}
here is the way that I suggest :
const [RegionalList, setRegionalList] = useState<IRegionalList[]>(RegionalListData);
const setEmailValue = (event: any, regionalId: number, index: number) => {
setRegionalList((prevState: IRegionalList[]) => {
const newState = prevState.map((prop: IRegionalList) => {
if (prop.id === regionalId) {
return { ...prop,emails:[...prop.emails.filter( (_,i)=>i !== index ),{ emailAddress: event.target.value, id: null }] }
}
return prop;
});
return newState;
});
}
and if you care about order of your list you can do this :
const setEmailValue = (event: any, regionalId: number, index: number) => {
setRegionalList((prevState: IRegionalList[]) => {
const newState = prevState.map((prop: IRegionalList) => {
if (prop.id === regionalId) {
let emails = prop.emails;
emails[index] = { emailAddress: event.target.value, id: null };
return { ...prop,emails }
}
return prop;
});
return newState;
});
}
please let me know if it fixed your problem

How to skip undefined/missing values in key-value pairs

I'm trying to build a citation generator from json in an API with data about images, stored in key-value pairs. I can get the data to return to the screen, but it always includes undefined in the citation. Sample manifest returns undefined as the creator since that isn't listed in this particular record. How can I keep any undefined value from being returned? I've tried changing the forEach to map, filtering at allMetadata by string length, using if !== undefined at insertCitation, and versions of those in different spots in the code.
EDIT: updated to provide full code, including print to page
(function () {
'use strict';
const buildCitation = {
buildMetadataObject: async function (collAlias, itemID) {
let response = await fetch('/iiif/info/' + collAlias + '/' + itemID + '/manifest.json');
let data = await response.json()
let allMetadata = data.metadata
let citationData = {};
allMetadata.forEach(function (kvpair) {
if (kvpair.value == undefined) {
return false;
} else if (kvpair.label === 'Title') {
citationData.itemTitle = kvpair.value;
} else if (kvpair.label === 'Creator') {
citationData.itemCreator = kvpair.value;
} else if (kvpair.label === 'Repository') {
citationData.itemRepository = kvpair.value;
} else if (kvpair.label === 'Collection Name') {
citationData.itemCollection = kvpair.value;
} else if (kvpair.label === 'Owning Institution') {
citationData.itemOwning = kvpair.value;
} else if (kvpair.label === 'Date') {
citationData.itemDate = kvpair.value;
} else if (kvpair.label === 'Storage Location') {
citationData.itemStorage = kvpair.value;
}
return true;
});
return citationData;
},
insertCitation: function (data) {
var testTitle = data.itemTitle;
console.log(testTitle);
const itemCite = `Citation: "${data.itemTitle}," ${data.itemDate}, ${data.itemCreator}, ${data.itemCollection}, ${data.itemOwning}, ${data.itemStorage}, ${data.itemRepository}.`;
const citationContainer = document.createElement('div');
citationContainer.id = 'citation';
citationContainer.innerHTML = itemCite;
// CHANGED to innerHTML instead of innerText because you may want to format it at some point as HTML code.
if (testTitle) {
document.querySelector('.ItemView-itemViewContainer').appendChild(citationContainer);
}
}
}
document.addEventListener('cdm-item-page:ready', async function (e) {
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
document.addEventListener('cdm-item-page:update', async function (e) {
document.getElementById('citation').remove();
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
})();
I've simplified your program. The undefined is coming from the fact that there is no item with label Date
const mappings = {
Date: 'itemDate',
Title: 'itemTitle',
Creator: 'itemCreator',
Repository: 'itemRepository',
'Storage Location': 'itemStorage',
'Owning Institution': 'itemOwning',
'Collection Name': 'itemCollection',
}
async function buildMetadataObject(collAlias, itemID) {
let response = await fetch('https://teva.contentdm.oclc.org/iiif/info/p15138coll25/1421/manifest.json');
let data = await response.json()
return data.metadata.reduce(
(acc, { label, value }) => ({ ...acc, [ mappings[label] ]: value }),
{}
)
}
function insertCitation(data) {
var testTitle = data.itemTitle;
const fieldBlackList = ['itemTitle'];
const itemCite = `Citation: "${data.itemTitle}," ${
Object.values(mappings).reduce((acc, cur) => {
if (fieldBlackList.includes(cur)) return acc;
const value = data[cur];
return value ? [...acc, value] : acc
}, []).join(', ')
}.`;
console.log(itemCite);
}
//MAIN PROGRAM
(async() => {
const citationData = await buildMetadataObject();
insertCitation(citationData);
})()

can't check if variable is undefined in typescript

I'm trying to solve compiler error " Object is possibly 'undefined' "
const destinationColumnIndex = (): number => {
if (typeof result.destination === 'undefined') {
return 0;
}
return boardData.findIndex(
(column) => column.id === Number(result.destination.droppableId)
);
};
but typescript compiler still tells me that "result.destination" may be undefined.
I have tried also:
if (result.destination === undefined) {
return 0;
}
and:
if (!result.destination) {
return 0;
}
and:
if (!result || typeof result.destination === 'undefined') {
return 0;
}
and nothing works. Even thought it may be some bug so i restarted VS Code but there are still the same error.
EDIT - MORE CODE:
const onDragEnd = async (result: DropResult) => {
if (!result.destination) {
return;
}
const sourceColumnIndex = (): number =>
boardData.findIndex(
(column) => column.id === Number(result.source.droppableId)
);
const destinationColumnIndex = (): number => {
if (typeof result === 'undefined' || result.destination === undefined) {
return 0;
}
return boardData.findIndex(
(column) => column.id === Number(result.destination.droppableId)
);
};
it's function inside of react component
You should just do:
if (result === undefined || result?.destination === undefined) {
return 0;
}
Checking typeof is not a good way to check for undefined.
or
if (!result || result?.destination === undefined) {
return 0;
}
UPDATE
try this:
const onDragEnd = (result: DropResult) => {
if (!result || !result.destination) {
return;
}
const sourceColumnIndex = (): number =>
boardData.findIndex(
(column) => column.id === Number(result.source?.droppableId)
);
const destinationColumnIndex = (): number => {
if (!result || !result.destination) {
return 0;
}
return boardData.findIndex(
(column) => column.id === Number(result.destination?.droppableId)
);
};
}

Error when I tried to apply filter in Typescript

I have a list of objects, and I wanted to filter it based on a specific string property.
openTasks: Task[]; //Initial list
inProgressTasks: Task[] = []; //Filtered list
getTasks(): void {
this.activatedRoute.paramMap.subscribe(params => {
this.projectId = +params.get('projectId');
if (this.projectId === 0) {
this.taskService.getTasks().subscribe(tasks => this.openTasks = tasks);
// HERE I ACQUIRE LIST OF OPEN TASKS
} else {
this.taskService.getTaskByProjectId(this.projectId).subscribe(tasks => this.openTasks = tasks);
// HERE I ACQUIRE LIST OF OPEN TASKS
}
// FILTER
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
});
}
I received this error:
ERROR TypeError: Cannot read property 'filter' of undefined
Could you, please, help me with this error?
Your probably having problems here because of the async nature with which you fetch openTasks.
Try waiting for it to definitely finish before trying to filter it.
getTasks(): void {
this.activatedRoute.paramMap.subscribe(params => {
this.projectId = +params.get('projectId');
if (this.projectId === 0) {
this.taskService.getTasks().subscribe(tasks =>
{this.openTasks = tasks},
error => {},
() => { this.filterTasks()}
);
}
});
}
filterTasks() {
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
}
The this.openTasks is not set yet. it is only set after the this.openTasks = tasks in subscribe. this should work.
this.activatedRoute.paramMap.subscribe(params => {
this.projectId = +params.get('projectId');
if (this.projectId === 0) {
this.taskService.getTasks()
.subscribe(tasks => {
this.openTasks = tasks;
// your code that requirest openTasks
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
});
} else {
this.taskService.getTaskByProjectId(this.projectId)
.subscribe(tasks => {
this.openTasks = tasks
// your code that requirest openTasks
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
});
}
});

javascript array filter very slow in REACT

I have a custom listbox, a div that contains a vertical list of other div children. And I have input for search something else in the list. It's working but in large data, it's working very slowly.
Also search criterion produce dynamically with column chooser. How can i increase search performance.
Firsly, prepare filter data for search and keeping state on the page load
prepareFilterData(allData) {
const filteredData = [];
let columnChooser = JSON.parse(getItemFromLocalStorage("ColumnData"));
allData.map(item => {
var data = "";
columnChooser.map(element => {
var newData = { value: item[element.value], format: element.format };
var filterItem = getFilterDataFormat(newData);
data += filterItem + " ";
});
filteredData.push(data);
});
this.setState({
filteredData: filteredData
});
}
Secondly, When user enter an char to textbox, i'm checking filteredData
filterList() {
const updatedList = this.state.allData.length > 0 ? this.state.allData : [];
var filteredData = [];
filteredData = updatedList.filter((item, index) => {
const data = this.state.filteredData[index];
return data.indexOf(this.state.searchInputValue) !== -1;
});
return filteredData;
}
This is input statement
<input
id="searchBox"
type="text"
className="filter-input empty"
placeholder="Search"
onChange={this.filterList}
value={this.props.state.searchInputValue}
style={{ width: "100%" }} />
Using a standard for loop can significantly increase the performance, especially in your case where you're using indexOf which is causing another iteration in your filter. The filter operation uses callbacks and it's often used because of the simpler syntax but it's these callback that make the operation to be slower especially on big data.
Read more here.
I found the solution.
SOLUTION:
I create a util.js in my project, and I called createFilter function.
import Fuse from "fuse.js";
import { toTrLowerCase } from "./process";
function flatten(array) {
return array.reduce((flat, toFlatten) => flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten), []);
}
export function getValuesForKey(key, item) {
const keys = key.split(".");
let results = [item];
keys.forEach(_key => {
const tmp = [];
results.forEach(result => {
if (result) {
if (result instanceof Array) {
const index = parseInt(_key, 10);
if (!isNaN(index)) {
return tmp.push(result[index]);
}
result.forEach(res => {
tmp.push(res[_key]);
});
} else if (result && typeof result.get === "function") {
tmp.push(result.get(_key));
} else {
tmp.push(result[_key]);
}
}
});
results = tmp;
});
// Support arrays and Immutable lists.
results = results.map(r => (r && r.push && r.toArray ? r.toArray() : r));
results = flatten(results);
return results.filter(r => typeof r === "string" || typeof r === "number");
}
export function searchStrings(strings, term, { caseSensitive, fuzzy, sortResults, exactMatch } = {}) {
strings = strings.map(e => e.toString());
try {
if (fuzzy) {
if (typeof strings.toJS === "function") {
strings = strings.toJS();
}
const fuse = new Fuse(
strings.map(s => {
return { id: s };
}),
{ keys: ["id"], id: "id", caseSensitive, shouldSort: sortResults }
);
return fuse.search(term).length;
}
return strings.some(value => {
try {
if (!caseSensitive) {
value = value.toLowerCase();
}
if (exactMatch) {
term = new RegExp("^" + term + "$", "i");
}
if (value && value.search(term) !== -1) {
return true;
}
return false;
} catch (e) {
return false;
}
});
} catch (e) {
return false;
}
}
export function createFilter(term, keys, options = { caseSensitive: false, fuzzy: false, sortResults: false, exactMatch: false }) {
debugger;
return item => {
if (term === "") {
return true;
}
if (!options.caseSensitive) {
term = term.toLowerCase();
}
const terms = term.split(" ");
if (!keys) {
return terms.every(term => searchStrings([item], term, options));
}
if (typeof keys === "string") {
keys = [keys];
}
return terms.every(term => {
// allow search in specific fields with the syntax `field:search`
let currentKeys;
if (term.indexOf(":") !== -1) {
const searchedField = term.split(":")[0];
term = term.split(":")[1];
currentKeys = keys.filter(key => key.toLowerCase().indexOf(searchedField) > -1);
} else {
currentKeys = keys;
}
return currentKeys.some(key => {
const values = getValuesForKey(key, item);
values[0] = toTrLowerCase(values[0]);
return searchStrings(values, term, options);
});
});
};
}
And then i added fuse.js to package.json.
"fuse.js": "^3.0.0"
I called createFilter function like that... term is searching value key
keysToFilter is which array column you wanna search.
this.state.allData.filter(createFilter(term, this.state.keysToFilter));
Link: https://github.com/enkidevs/react-search-input

Categories