'use strict';
const _ = require('lodash');
const Assert = require('assert');
/**
* Receives an object containing an array property and substitutes it by a new property with the length of that array
* @param {Object} object Object containing publications, cites, etc., and other properties
* @param {String} property Name of the property that needs to be sumed
* @return {Object} Same object passed in, but without `property` (array) and with `property+Count` (length of the array)
*/
function sumPropertyLength(object, property) {
Assert(typeof (object) === 'object', "The object parameter must be an object");
Assert(typeof (property) === 'string', "The property parameter must be a string");
Assert(property in object, "The property passed must be present in the object passed");
let changedObject = _.clone(object);
changedObject[property + 'Count'] = changedObject[property].length;
delete changedObject[property];
return changedObject;
}
/**
* Receives an object containing an array property and substitutes it by a new property with the sum of the elements in the array
* @param {Object} object Object containing publications, cites, etc., and other properties
* @param {String} property Name of the property that needs to be sumed
* @return {Object} Same object passed in, but without `property` (array) and with `property+Count` (sum of the elements in the array)
*/
function sumProperties(object, property) {
Assert(typeof (object) === 'object', "The object parameter must be an object");
Assert(typeof (property) === 'string', "The property parameter must be a string");
Assert(property in object, "The property passed must be present in the object passed");
let changedObject = _.clone(object);
changedObject[property + 'Count'] = _.sum(changedObject[property]);
delete changedObject[property];
return changedObject;
}
/**
* Receives an array of objects and a property name and returns the sum of the values of the property for every array element
* @param {Object[]} array Array of objects with several properties each
* @param {String} property Name of the property to be sumed
* @return {Number} Sum of all the values called `property` in the passed array
*/
function sumTotal(array, property) {
Assert(typeof (array) === 'object', "The array parameter must be an array");
Assert(typeof (property) === 'string', "The property parameter must be a string");
array.forEach(element => {
Assert(property in element, "The property passed must be present in every element of the array passed");
});
return _.sumBy(array, property);
}
/**
* Calculates the average of a given property in an object
* @param {Object} object Object containing `property` property and others
* @param {String} property Name of the property to be averaged
* @return {Object} Same object passed in, but without `property` (array) and with `property+Average` (number)
*/
function averageProperty(object, property) {
Assert(typeof (object) === 'object', "The object parameter must be an object");
Assert(typeof (property) === 'string', "The property parameter must be a string");
Assert(property in object, "The property passed must be present in the object passed");
let changedObject = _.clone(object);
changedObject[property + 'Average'] = _.mean(changedObject.cites);
// If there are no cites, _.mean returns NaN, so we need to convert it to null
if (isNaN(changedObject[property + 'Average'])) {
changedObject[property + 'Average'] = null;
}
delete changedObject[property];
return changedObject;
}
/**
* Given an object, which contains an array, computes the percentage of elements over the total
* @param {Object} object Object with several properties, including the array
* @param {String} property Name of the property where to calculate percentage
* @param {Number} totalCount Total number of elements, counting all objects in the array passed
* @return {Object} Same object passed in, but substituting the array by the percentage of its elements over the total
*/
function percentOverTotal(object, property, totalCount) {
Assert(typeof (object) === 'object', "The object parameter must be an object");
Assert(typeof (property) === 'string', "The property parameter must be a string");
Assert(typeof (totalCount) === 'number', "The totalCount parameter must be a number");
Assert(property in object, "The property passed must be present in the object passed");
let changedObject = _.clone(object);
if (totalCount === 0) { // If the author has no publications at all
changedObject[property + 'PercentOverTotal'] = null;
} else {
changedObject[property + 'PercentOverTotal'] = changedObject[property].length / totalCount;
}
delete changedObject[property];
return changedObject;
}
/**
* Returns the number of publications that are above the required percentile number
* @param {Object[]} publications Array with all the publications' best percentiles, grouped by year
* returned by {@link bestPercentiles}
* @see {@link bestPercentiles}
* @param {Number} percentile The number over which the publications percentile have to be above
* @returns {Number} The number of publications that are above `percentile`
*/
function publicationsOverPercentile(publications, percentile) {
Assert(publications !== undefined, "No publications object received");
Assert(percentile !== undefined, "No percentile received");
Assert(publications.constructor === Array, "The publications object must be an array");
Assert(!isNaN(parseInt(percentile)), "Percentile must be a number");
percentile = parseInt(percentile);
Assert(percentile >= 0 && percentile <= 100, "Percentile must be between 0 and 100");
const publicationsUngrouped = [].concat.apply([], publications.map(group => group.publications));
const publicationsNumber = publicationsUngrouped.reduce((acc, currPublication) => {
if (currPublication.percentile >= percentile) {
acc++;
}
return acc;
}, 0);
return publicationsNumber;
}
/**
*
* @param {Object[]} publications Array with all the publications' best percentiles, grouped by year
* returned by {@link bestPercentiles}
* @param {Number} qNumber The Q you want to know how many publications have. Has to be a number
* between 1 and 4
* @return {Number} The number of publications in the Q you asked for
*/
function publicationsInQn(publications, qNumber) {
Assert(publications !== undefined, "No publications object received");
Assert(qNumber !== undefined, "No Q number received");
Assert(publications.constructor === Array, "The publications object must be an array");
Assert(!isNaN(parseInt(qNumber)), "Q number must be a number");
qNumber = parseInt(qNumber);
Assert(qNumber >= 1 && qNumber <= 4, "Q number must be between 1 and 4");
const publicationsUngrouped = [].concat.apply([], publications.map(group => group.publications));
const publicationsNumber = publicationsUngrouped.reduce((acc, currPublication) => {
const lowestPercentile = 100 - (25 * qNumber);
// This makes all the publications with percentile 0 not to
// be counted as Q4
if (currPublication.percentile > lowestPercentile &&
currPublication.percentile <= lowestPercentile + 25) {
acc++;
}
return acc;
}, 0);
return publicationsNumber;
}
/**
* Return the best percentile of each publication and the area in which the publication has that percentile.
* If more than one area is found, returns the one with lowest world average cites. If a publication does
* not have cite score data for its publication year, or if the area code with best percentile cannot be converted
* to an area name, `null` is returned in `percentile` and `area`.
* @param {Array} areasArray Array with the possible areas of the publications. It is used for converting area
* code to area name
* @param {Object} publicationsGrouped A JSON with a property year and a property publications with the ones from that year
* @param {Object} worldAverageCitesByArea JSON object containing all subject areas as keys, each of them with a number of
* years as keys too, whose values are the average number of cites in that year
* @returns {Object} Object with the same structure as the one passed as parameter but with an array of each publication's best percentile.
* If a publication has no percentile or area for its year, `null` is returned in the corresponding field. Example:
* ```
* {
* year: Number,
* publications: [...
* {
* publicationID: string,
* percentile: Number?,
* area: string?
* }
* ]
* }
* ```
*/
function bestPercentiles(areasArray, publicationsGrouped, worldAverageCitesByArea) {
Assert(typeof (publicationsGrouped) === 'object', 'The publicationsGrouped object must be an array');
Assert('year' in publicationsGrouped, 'Object has not the required format ({year: Number, publications: Array})');
Assert('publications' in publicationsGrouped, 'Object has not the required format ({year: Number, publications: Array})');
Assert(!isNaN(parseInt(publicationsGrouped.year)), 'Object has not the required format ({year: Number, publications: Array})');
Assert(publicationsGrouped.publications.constructor === Array, 'Object has not the required format ({year: Number, publications: Array})');
Assert(typeof (worldAverageCitesByArea) === 'object', "The worldAverageCitesByArea parameter must be an object");
Assert(areasArray.constructor === Array, 'areasArray is not an array');
let bestPercentilesObject = {
year: parseInt(publicationsGrouped.year),
publications: []
};
// Fixes the year in the range we have world average cites data. If the year
// lower than 2006, it fixes it to 2006. If it's greater than 2016, fixes
// it to 2016. Else, leaves the year untouched.
const worldAverageCitesYear = __fixYear(bestPercentilesObject.year);
let areasMapping = {};
areasArray.forEach((area) => {
areasMapping[area['@code']] = {
name: __fixSubjectArea(area['$']),
abbrev: area['@abbrev']
};
});
publicationsGrouped.publications.forEach((publication) => {
const publicationID = publication["dc:identifier"];
let citeScores;
let result = {
publicationID: publicationID,
percentile: null,
area: null
};
if (_.has(publication, 'publisherStats.citeScoreYearInfoList.citeScoreYearInfo')) {
citeScores = publication['publisherStats']['citeScoreYearInfoList']['citeScoreYearInfo']
.find(citeScore => {
return citeScore['@year'] === String(bestPercentilesObject.year);
});
if (citeScores) {
let bestAreas = [];
let bestPercentile = 0;
citeScores['citeScoreInformationList'][0]['citeScoreInfo'][0]['citeScoreSubjectRank'].forEach((area) => {
if (parseInt(area.percentile) === bestPercentile) {
bestAreas.push(area);
} else if (parseInt(area.percentile) > bestPercentile) {
bestAreas = [area];
bestPercentile = parseInt(area.percentile);
}
});
// Add the current publication areas to the areas mapping object
// to complete it. There are cases in which the author doesn't have
// all the areas in which he or she has published
publication['publisherStats']['subject-area'].forEach((area) => {
if (!(area['@code'] in areasMapping)) {
areasMapping[area['@code']] = {
name: __fixSubjectArea(area['$']),
abbrev: area['@abbrev']
};
}
});
// If we can resolve every area code into an area name, do the normal process
if (bestAreas.every((area) => {
return area['subjectCode'] in areasMapping;
})) {
let bestArea;
if (bestAreas.length === 1) {
bestArea = bestAreas[0];
} else {
bestArea = _.minBy(bestAreas, (area) => {
const areaName = areasMapping[area['subjectCode']].name;
return __checkWorldAverageCites(areaName, worldAverageCitesYear, worldAverageCitesByArea);
});
}
result = {
publicationID: publicationID,
percentile: bestPercentile,
area: areasMapping[bestArea['subjectCode']].name
};
}
// Else, skip the publication
}
}
bestPercentilesObject.publications.push(result);
});
return bestPercentilesObject;
}
/**
* Given an array of publications, it computes the Q1 publications percent by looking at the property
* ``percentile${qualitySource}`` placed at first level in every publication object
* @param {Array} publications Array with all publication objects
* @param {String} qualitySource Quality source (JCR, SCIE, etc.) used to compute percentile of a publication
* @returns {Number} Percent of Q1 publications out of the total number of publications
*/
function q1PublicationsPercent(publications, qualitySource) {
Assert(publications !== undefined, 'publications parameter is mandatory');
Assert(qualitySource !== undefined, 'qualitySource parameter is mandatory');
Assert(publications.constructor === Array, 'publications is not an array');
Assert(typeof (qualitySource) === 'string', 'qualitySource is not a string');
publications.forEach(publication => {
Assert(typeof (publication) === 'object');
});
return publications.filter(publication => { return Number(publication[`percentile${qualitySource.toUpperCase()}`]) >= 75; }).length / publications.length * 100;
}
/**
* Receives an object containing a year and a set of publications, and computes the area in which most publications are.
* If there is more than one mostPublishedArea, the one whose worldAverageCites is the lowest is chosen. In case the
* year associated to that subject-area is not between 2006 & 2016 (inclusive) these values are respectively taken to
* choose the mostPublishedArea
* @param {Object} publicationsOfYear Object containing year and array of publications
* @param {Object} worldAverageCitesByArea JSON object containing all subject areas as keys, each of them with a number of
* years as keys too, whose values are the average number of cites in that year
* @return {Object} Same object passed in, but without publications and with two new properties, `optimalMostPublishedArea` and
* `mostPublishedAreas`
*/
function mostPublishedArea(publicationsOfYear, worldAverageCitesByArea) {
Assert(typeof (publicationsOfYear) === 'object', "The publicationsOfYear parameter must be an object");
Assert('publications' in publicationsOfYear, "The property 'publications' must be present in 'publicationsOfYear'");
Assert(typeof (publicationsOfYear.publications) === 'object', "The publications property of publicationsOfYear must be an array");
Assert('year' in publicationsOfYear, "The property 'year' must be present in 'publicationsOfYear'");
Assert(typeof (publicationsOfYear.year) === 'number', "The year property of publicationsOfYear must be a number");
Assert(!isNaN(publicationsOfYear.year));
Assert(typeof (worldAverageCitesByArea) === 'object', "The worldAverageCitesByArea parameter must be an object");
publicationsOfYear.publications.forEach(publication => {
Assert('publisherStats' in publication, "The property 'publisherStats' must be present in every element of the array 'publicationsOfYear.publications'");
// Assert('subject-area' in publication.publisherStats, "The property 'subject-area' must be present in 'publicationsOfYear.publications.publisherStats'");
// publication.publisherStats["subject-area"].forEach(subjectAreaElement => {
// Assert('$' in subjectAreaElement, "The property '$' must be present in 'publicationsOfYear.publications.publisherStats[subject-area]'");
// });
});
// If publication year doesn't exist in Elsevier JSON file, choose the nearest one
const worldAverageCitesYear = __fixYear(publicationsOfYear.year);
let areaIndex;
let areasArray = []; // Contains all areas that come up at least once
let areasWithHighestCount = []; // Contains the areas that come up more times (same number of times)
let mostPublishedArea;
publicationsOfYear.publications.forEach(publication => {
if (_.has(publication, 'publisherStats[subject-area]')) { // Sometimes, 'publisherStats' is 'No indexed'
publication.publisherStats["subject-area"].forEach(subject => {
if (_.has(subject, '$')) {
subject["$"] = __fixSubjectArea(subject["$"]); // FIXES ALL SUBJECT-AREAS THAT ARE AREAS, NOT CATEGORIES
if ((areaIndex = _.findIndex(areasArray, ['area', subject["$"]])) < 0) {
areasArray.push({
area: subject["$"],
count: 1
});
} else {
areasArray[areaIndex].count++;
}
}
});
}
});
if (areasArray.length > 0) {
const highestCount = _.maxBy(areasArray, 'count').count;
areasArray.forEach(areaElement => {
if (areaElement.count === highestCount) {
areasWithHighestCount.push({
area: areaElement.area,
count: areaElement.count,
worldAverageCites: __checkWorldAverageCites(areaElement.area, worldAverageCitesYear, worldAverageCitesByArea)
});
}
});
if (areasWithHighestCount.length === 1) {
mostPublishedArea = areasWithHighestCount[0].area;
} else { // If there are multiple areas with the same count, choose the one whose worldAverageCites is the lowest
mostPublishedArea = _.minBy(areasWithHighestCount, 'worldAverageCites');
if (mostPublishedArea) {
mostPublishedArea = mostPublishedArea.area;
} else { // This happens when all areasWithHighestCount contain null worldAverageCites
// Return the first one, it's not possible to make a decision since we have no worldAverageCites figures for any area
mostPublishedArea = areasWithHighestCount[0].area;
}
}
} else {
mostPublishedArea = null;
}
return {
year: publicationsOfYear.year,
optimalMostPublishedArea: mostPublishedArea,
mostPublishedAreas: areasWithHighestCount.map(area => area.area)
};
}
/**
* Computes the normalized impact per year
* @param {Object} publicationsOfYear Object containing a year and an array of publications
* @param {Number} averageCites Number of average cites for the year passed in publicationsOfYear
* @param {String} mostPublishedArea Area in which most publications are
* @param {Object} worldAverageCitesByArea JSON object containing all subject areas as keys, each of them with a number of
* years as keys too, whose values are the average number of cites in that year
* @return {Object} New object containing the year and the normalized impact
*/
function normalizedImpact(year, averageCites, mostPublishedArea, worldAverageCitesByArea) {
Assert(typeof (year) === 'number', "The year parameter must be a number");
Assert(typeof (averageCites) === 'number' || averageCites === null, "The averageCites parameter must be a number or null");
Assert(typeof (mostPublishedArea) === 'string' || mostPublishedArea === null, "The mostPublishedArea parameter must be a string or null");
Assert(typeof (worldAverageCitesByArea) === 'object', "The worldAverageCitesByArea parameter must be an object");
// Don't assert the following, because this could happen and shouldn't return an error
// Assert(mostPublishedArea in worldAverageCitesByArea, "The mostPublishedArea passed property must be present in the JSON file worldAverageCitesByArea");
// If publication year doesn't exist in Elsevier JSON file, choose the nearest one
const worldAverageCitesYear = __fixYear(year);
const worldAverageCitesOfYear = __checkWorldAverageCites(mostPublishedArea, worldAverageCitesYear, worldAverageCitesByArea);
// Compute the value only if the properties passed are not null and year for that subject-area exists in the JSON file
const normalizedImpact = worldAverageCitesOfYear && __iT(averageCites) && mostPublishedArea ? averageCites / worldAverageCitesOfYear : null;
return {
year: year,
normalizedImpact: normalizedImpact
};
}
/**
* Computes an array with the weighted impact per year
* @param {Object[]} normalizedImpactPerYear Array of objects containing year and normalizedImpact
* @param {Object[]} publicationsPercentPerYear Array of objects containing year and percentOfPublications per year over the total
* @return {Object[]} Array containing year and weighted impact per year
*/
function weightedImpact(normalizedImpactPerYear, publicationsPercentPerYear) {
Assert(normalizedImpactPerYear !== undefined, "The function must be called with two parameters");
Assert(publicationsPercentPerYear !== undefined, "The function must be called with two parameters");
Assert(normalizedImpactPerYear.constructor === Array, "The normalizedImpactPerYear parameter must be an array");
Assert(publicationsPercentPerYear.constructor === Array, "The publicationsPercentPerYear parameter must be an array");
Assert(normalizedImpactPerYear.length === publicationsPercentPerYear.length, "Both arrays must have the same length");
const normalizedImpactYears = normalizedImpactPerYear.map(normalizedImpactElement => {
Assert('year' in normalizedImpactElement, "The property 'year' must be present in every element of the array normalizedImpactPerYear");
Assert(typeof (normalizedImpactElement.year) === 'number', "The year property of normalizedImpactElement must be a number");
Assert('normalizedImpact' in normalizedImpactElement, "The property 'normalizedImpact' must be present in every element of the array normalizedImpactPerYear");
Assert(typeof (normalizedImpactElement.normalizedImpact) === 'number' || normalizedImpactElement.normalizedImpact === null, "The normalizedImpact property of normalizedImpactElement must be a number or null");
return normalizedImpactElement.year;
});
const publicationsPercentYears = publicationsPercentPerYear.map(publicationsPercentElement => {
Assert('year' in publicationsPercentElement, "The property 'year' must be present in every element of the array publicationsPercentPerYear");
Assert(typeof (publicationsPercentElement.year) === 'number', "The year property of publicationsPercentElement must be a number");
Assert('publicationsPercentOverTotal' in publicationsPercentElement, "The property 'publicationsPercentOverTotal' must be present in every element of the array publicationsPercentPerYear");
Assert(typeof (publicationsPercentElement.publicationsPercentOverTotal) === 'number' || publicationsPercentElement.publicationsPercentOverTotal === null, "The publicationsPercentOverTotal property of publicationsPercentElement must be a number or null");
return publicationsPercentElement.year;
});
Assert(_.difference(normalizedImpactYears, publicationsPercentYears).length === 0, "Both arrays must contain the same years");
let weightedImpact;
const weightedImpactPerYear = normalizedImpactPerYear.map(normalizedImpactElement => {
let publicationsPercentElement = _.find(publicationsPercentPerYear, ['year', normalizedImpactElement.year]);
weightedImpact = __iT(normalizedImpactElement.normalizedImpact) && __iT(publicationsPercentElement.publicationsPercentOverTotal) ? normalizedImpactElement.normalizedImpact * publicationsPercentElement.publicationsPercentOverTotal : null; // If normalizedImpact or publicationsPercentOverTotal is null, weightedImpact will be null too
return {
year: normalizedImpactElement.year,
weightedImpact: weightedImpact
};
});
return weightedImpactPerYear;
}
/**
* Returns the world average cites for an area, a year.
* @param {Object} publicationsGrouped A JSON with a property year and an array of publications from that year
* @param {Object} worldAverageCitesByArea JSON containing the world average cites of each area
* @returns {Object[]} An object with the same year as the passed in, the area with most publications that year in the publications
* array of `publicationsGrouped` and the world average citation for that area. Example:
* ```
* {
* year: Number,
* area: String,
* worldAverageCites: Number
* }
* ```
*/
function worldAverageCites(publicationsGrouped, worldAverageCitesByArea) {
Assert(publicationsGrouped !== undefined, "No publications object received");
Assert(typeof (publicationsGrouped) === 'object', 'The publicationsGrouped object must be an array');
Assert(worldAverageCitesByArea !== undefined, "No world average cites object received");
Assert(typeof (worldAverageCitesByArea) === 'object', 'The worldAverageCitesByArea object must be an array');
Assert('year' in publicationsGrouped, 'Object has not the required format ({year: Number, publications: Array})');
Assert('publications' in publicationsGrouped, 'Object has not the required format ({year: Number, publications: Array})');
Assert(!isNaN(parseInt(publicationsGrouped.year)), 'Object has not the required format ({year: Number, publications: Array})');
Assert(publicationsGrouped.publications.constructor === Array, 'Object has not the required format ({year: Number, publications: Array})');
const area = mostPublishedArea(publicationsGrouped, worldAverageCitesByArea).optimalMostPublishedArea;
const year = publicationsGrouped.year;
const averageCites = areaWorldAverageCitesAtYear(area, year, worldAverageCitesByArea);
return {
year: year,
area: area,
worldAverageCites: averageCites
};
}
/**
* Returns the world average cites for the requested year and area
* @param {String} area The area to look for in the world average cites object
* @param {Number} year The year to look for citations in the world average cites object
* @param {Object} worldAverageCitesByArea The object with all the world average cite information
* @returns {Number?} The world average cites or null if the area or year are not in the world
* average cites object
*/
function areaWorldAverageCitesAtYear(area, year, worldAverageCitesByArea) {
Assert(area !== undefined, "No area received");
Assert(typeof (area) === 'string' || area === null, 'The area must be a string or null');
Assert(year !== undefined, "No year received");
Assert(typeof (year) === 'number', 'The year must be a number');
Assert(worldAverageCitesByArea !== undefined, "No world average cites object received");
Assert(typeof (worldAverageCitesByArea) === 'object', 'The worldAverageCitesByArea object must be an array');
// Don't assert the following, because this could happen and shouldn't return an error
// Assert(area in worldAverageCitesByArea, "The area doesn't exists in the world average cites by area object");
// If publication year doesn't exist in Elsevier JSON file, choose the nearest one
const worldAverageCitesYear = __fixYear(year);
const worldAverageCites = __checkWorldAverageCites(area, worldAverageCitesYear, worldAverageCitesByArea);
return worldAverageCites;
}
/**
* Returns an array with the name, abbreviature and code of each area in which the author has published. The result has the
* following format:
* <pre>
* [...{
* @abbrev: String,
* @code: String,
* $: String
* }]
* </pre>
* @param {Object} authorData Raw data of the author
* @return {Array?} An array with each area and its name, abbreviature and code or null if there are no subject areas fot that author
*/
function areasPublished(authorData) {
Assert(typeof (authorData) === 'object', "AuthorData has to be an object");
if (_.has(authorData, 'subject-areas.subject-area')) {
return authorData['subject-areas']['subject-area'];
} else {
return null;
}
}
/**
* This function receives an array of areas and return an array with unique areas
* @param {Array} areasArray The array with duplicates areas
* @returns {Array} Array containing only unique areas
*/
function removeDuplicatesSubjectAreas(areasArray) {
Assert(areasArray !== undefined, "No array of areas received");
Assert(areasArray.constructor === Array, 'areasArray has to be an array');
return _.uniqBy(areasArray, '@code');
}
/**
* Fixes all those areas where the subject-area field is not a category, but a general area, that
* does not have a corresponding average number of cites per year. The fix is done replacing the areas
* called XXXX (all) with General XXXX
* @param {String} subjectArea The area to fix
* @return {String} The fixed area or the original one if there's no need to fix it
* @private
*/
function __fixSubjectArea(subjectArea) {
if (/^.*\(all\)$/.test(subjectArea)) {
return "General " + subjectArea.split(" (all)")[0];
} else {
return subjectArea;
}
}
/**
* This function fixes a year that need to be used to find the worldAverageCites of a subject-area. If the year
* is not in the 2006-2016 range, it needs to be fixed to the nearest year in the range.
* @param {Number} year The year to fix
* @return {Number} The fixed year or the original year if it's in the correct range
* @private
*/
function __fixYear(year) {
return year > 2016 ? 2016 : year < 2006 ? 2006 : year;
}
// This function is used to check if the subject-area and year passed are present in the Elsevier JSON file. If so,
// returns the associated worldAverageCites; if not, returns null
/**
*
* @param {String} area The subject-area to check
* @param {Number} year The year to check for the subject-area
* @param {Object} worldAverageCitesByArea The JSON file with all the subjec-areas in which to do the checking
* @return {Number?} Returns the worldAverageCite of the subject-area passed in or null if its not present
* @private
*/
function __checkWorldAverageCites(area, year, worldAverageCitesByArea) {
return worldAverageCitesByArea[area] ? worldAverageCitesByArea[area][year] : null;
}
/**
* Short for "isTrue". This functions tests validity of a variable. We need to use it since 0 returns false
* in tests, which could happen with vars like citesAverage, citesCount, etc. and we need to return true in
* these cases
* @param {any} variable Variable to test
* @return {boolean} `true` if the variable is valid and `false` in other cases
* @private
*/
function __iT(variable) {
if (variable === null || variable === undefined) {
return false;
} else {
return true;
}
}
module.exports = {
sumProperties,
sumPropertyLength,
sumTotal,
averageProperty,
percentOverTotal,
mostPublishedArea,
worldAverageCites,
areaWorldAverageCitesAtYear,
normalizedImpact,
weightedImpact,
publicationsOverPercentile,
bestPercentiles,
q1PublicationsPercent,
areasPublished,
removeDuplicatesSubjectAreas,
publicationsInQn
};