diff --git a/apps/scorecard/.eslintrc.json b/apps/scorecard/.eslintrc.json index c248c52f7d..4c1bfbc4b2 100644 --- a/apps/scorecard/.eslintrc.json +++ b/apps/scorecard/.eslintrc.json @@ -28,28 +28,11 @@ "space-before-function-paren": "off", // for Meteor API's that rely on `this` context, e.g. Template.onCreated and publications "func-names": "off", - "prefer-arrow-callback": "off", + "prefer-arrow-callback": "off" // Vx Team modifications - Warn on rules that would require refactoring to implement. // We want to be able to turn these back into "error"'s at some point. However, for // our first pass, we'll only consider the checks that ESLint can auto-fix as errors. // https://eslint.org/docs/latest/use/configure/rules#rule-severities - "no-undef": "warn", - "no-plusplus": "warn", - "vars-on-top": "warn", - "no-var": "warn", - "block-scoped-var": "warn", - "no-loop-func": "warn", - "no-unused-vars": "warn", - "prefer-destructuring": "warn", - "no-param-reassign": "warn", - "camelcase": "warn", - "no-redeclare": "warn", - "no-shadow": "warn", - "no-useless-escape": "warn", - "global-require": "warn", - "default-case": "warn", - "no-unused-expressions": "warn", - "no-sequences": "warn" } } diff --git a/apps/scorecard/client/main.js b/apps/scorecard/client/main.js index a87407a1f4..ecd922b6a2 100644 --- a/apps/scorecard/client/main.js +++ b/apps/scorecard/client/main.js @@ -2,6 +2,7 @@ * Copyright (c) 2021 Colorado State University and Regents of the University of Colorado. All rights reserved. */ +// eslint-disable-next-line no-unused-vars import { matsTypes, matsCollections, methods } from "meteor/randyp:mats-common"; import "@fortawesome/fontawesome-free"; import "@fortawesome/fontawesome-free/css/all.css"; diff --git a/apps/scorecard/server/dataFunctions/processScorecard.js b/apps/scorecard/server/dataFunctions/processScorecard.js index dc3c2f3a1c..84ae4e140a 100644 --- a/apps/scorecard/server/dataFunctions/processScorecard.js +++ b/apps/scorecard/server/dataFunctions/processScorecard.js @@ -5,8 +5,8 @@ import { matsTypes, matsParamUtils, matsCollections } from "meteor/randyp:mats-c /** A function to sanitize JSON keys by replacing the "." character with "__DOT__" */ const sanitizeKeys = function (str) { - str = str.replace(/\./g, "__DOT__"); - return str; + const newStr = str.replace(/\./g, "__DOT__"); + return newStr; }; const dealWithUATables = function ( @@ -182,10 +182,13 @@ processScorecard = function (plotParams, plotFunction) { // get the union of the fcst-length arrays of all the curves const fcstLengthsSet = new Set(); plotParams.curves.forEach(function (curve) { - if (!curve["forecast-length"]) curve["forecast-length"] = ["0"]; - curve["forecast-length"].forEach(function (fcl) { - fcstLengthsSet.add(fcl); - }); + if (!curve["forecast-length"]) { + fcstLengthsSet.add("0"); + } else { + curve["forecast-length"].forEach(function (fcl) { + fcstLengthsSet.add(fcl); + }); + } }); const fcstLengths = Array.from(fcstLengthsSet); @@ -383,6 +386,10 @@ processScorecard = function (plotParams, plotFunction) { // create the empty object for this block const { label } = curve; + + // duplicate the curve so we're not modifying a function parameter, which the linter doesn't like + const scorecardCurve = curve; + scorecardDocument.results.blocks[label] = {}; scorecardDocument.queryMap.blocks[label] = {}; // add the top level elements. @@ -395,76 +402,73 @@ processScorecard = function (plotParams, plotFunction) { return !notIncludedParams.includes(paramName); }); - scorecardDocument.results.blocks[curve.label].blockTitle = { + scorecardDocument.results.blocks[label].blockTitle = { label, - dataSource: curve["data-source"], - controlDataSource: curve["control-data-source"], + dataSource: scorecardCurve["data-source"], + controlDataSource: scorecardCurve["control-data-source"], }; const appName = Meteor.settings.public.app; const appUrl = `${Meteor.settings.public.home}/${appName}`; - scorecardDocument.results.blocks[curve.label].blockApplication = appUrl; - scorecardDocument.results.blocks[curve.label].blockParameters = blockParameters; - scorecardDocument.results.blocks[curve.label].regions = regions; - scorecardDocument.results.blocks[curve.label].fcstlens = fcstLengths; - scorecardDocument.results.blocks[curve.label].data = {}; - scorecardDocument.queryMap.blocks[curve.label].data = {}; - curve.threshold = - curve.threshold === undefined ? ["threshold_NA"] : curve.threshold; - curve.level = curve.level === undefined ? ["level_NA"] : curve.level; + scorecardDocument.results.blocks[label].blockApplication = appUrl; + scorecardDocument.results.blocks[label].blockParameters = blockParameters; + scorecardDocument.results.blocks[label].regions = regions; + scorecardDocument.results.blocks[label].fcstlens = fcstLengths; + scorecardDocument.results.blocks[label].data = {}; + scorecardDocument.queryMap.blocks[label].data = {}; + scorecardCurve.threshold = + scorecardCurve.threshold === undefined + ? ["threshold_NA"] + : scorecardCurve.threshold; + scorecardCurve.level = + scorecardCurve.level === undefined ? ["level_NA"] : scorecardCurve.level; regions.forEach(function (regionText) { const region = sanitizeKeys(regionText); - if (scorecardDocument.results.blocks[curve.label].data[region] === undefined) { - scorecardDocument.results.blocks[curve.label].data[region] = {}; - scorecardDocument.queryMap.blocks[curve.label].data[region] = {}; + if (scorecardDocument.results.blocks[label].data[region] === undefined) { + scorecardDocument.results.blocks[label].data[region] = {}; + scorecardDocument.queryMap.blocks[label].data[region] = {}; } - curve.statistic.forEach(function (statText) { + scorecardCurve.statistic.forEach(function (statText) { const stat = sanitizeKeys(statText); - if ( - scorecardDocument.results.blocks[curve.label].data[region][stat] === undefined - ) { - scorecardDocument.results.blocks[curve.label].data[region][stat] = {}; - scorecardDocument.queryMap.blocks[curve.label].data[region][stat] = {}; + if (scorecardDocument.results.blocks[label].data[region][stat] === undefined) { + scorecardDocument.results.blocks[label].data[region][stat] = {}; + scorecardDocument.queryMap.blocks[label].data[region][stat] = {}; } - curve.variable.forEach(function (variableText) { + scorecardCurve.variable.forEach(function (variableText) { const variable = sanitizeKeys(variableText); if ( - scorecardDocument.results.blocks[curve.label].data[region][stat][ - variable - ] === undefined + scorecardDocument.results.blocks[label].data[region][stat][variable] === + undefined ) { - scorecardDocument.results.blocks[curve.label].data[region][stat][variable] = - {}; - scorecardDocument.queryMap.blocks[curve.label].data[region][stat][ - variable - ] = {}; + scorecardDocument.results.blocks[label].data[region][stat][variable] = {}; + scorecardDocument.queryMap.blocks[label].data[region][stat][variable] = {}; } - curve.threshold.forEach(function (thresholdText) { + scorecardCurve.threshold.forEach(function (thresholdText) { const threshold = sanitizeKeys(thresholdText); if ( - scorecardDocument.results.blocks[curve.label].data[region][stat][ - variable - ][threshold] === undefined + scorecardDocument.results.blocks[label].data[region][stat][variable][ + threshold + ] === undefined ) { - scorecardDocument.results.blocks[curve.label].data[region][stat][ - variable - ][threshold] = {}; - scorecardDocument.queryMap.blocks[curve.label].data[region][stat][ - variable - ][threshold] = {}; + scorecardDocument.results.blocks[label].data[region][stat][variable][ + threshold + ] = {}; + scorecardDocument.queryMap.blocks[label].data[region][stat][variable][ + threshold + ] = {}; } - curve.level.forEach(function (levelText) { + scorecardCurve.level.forEach(function (levelText) { const level = sanitizeKeys(levelText); if ( - scorecardDocument.results.blocks[curve.label].data[region][stat][ - variable - ][threshold][level] === undefined + scorecardDocument.results.blocks[label].data[region][stat][variable][ + threshold + ][level] === undefined ) { - scorecardDocument.results.blocks[curve.label].data[region][stat][ - variable - ][threshold][level] = {}; - scorecardDocument.queryMap.blocks[curve.label].data[region][stat][ - variable - ][threshold][level] = {}; + scorecardDocument.results.blocks[label].data[region][stat][variable][ + threshold + ][level] = {}; + scorecardDocument.queryMap.blocks[label].data[region][stat][variable][ + threshold + ][level] = {}; } fcstLengths.forEach(function (fcstlenText) { const fcstlen = sanitizeKeys(fcstlenText); @@ -527,7 +531,7 @@ processScorecard = function (plotParams, plotFunction) { // populate variable in query template -- partial sums if (localQueryTemplate.includes("{{variable0}}")) { const variableArray = variableMap[variableText]; - for (let vidx = 0; vidx < variableArray.length; vidx++) { + for (let vidx = 0; vidx < variableArray.length; vidx += 1) { const replaceString = `{{variable${vidx.toString()}}}`; const regex = new RegExp(replaceString, "g"); localQueryTemplate = localQueryTemplate.replace( @@ -545,7 +549,7 @@ processScorecard = function (plotParams, plotFunction) { if (application === "upperair") { // the upper air tables are unfortuately really inconsistent and need some handling localQueryTemplate = dealWithUATables( - curve, + scorecardCurve, regionValue, databaseValue, localQueryTemplate @@ -558,22 +562,23 @@ processScorecard = function (plotParams, plotFunction) { } // populate experimental model in query template - const experimentalModelValue = modelMap[curve["data-source"]]; + const experimentalModelValue = modelMap[scorecardCurve["data-source"]]; const experimentalQueryTemplate = localQueryTemplate.replace( /\{\{model\}\}/g, experimentalModelValue ); // populate control model in query template - const controlModelValue = modelMap[curve["control-data-source"]]; + const controlModelValue = + modelMap[scorecardCurve["control-data-source"]]; const controlQueryTemplate = localQueryTemplate.replace( /\{\{model\}\}/g, controlModelValue ); - scorecardDocument.queryMap.blocks[curve.label].data[region][stat][ - variable - ][threshold][level][fcstlen] = { + scorecardDocument.queryMap.blocks[label].data[region][stat][variable][ + threshold + ][level][fcstlen] = { experimentalQueryTemplate, controlQueryTemplate, }; @@ -583,18 +588,16 @@ processScorecard = function (plotParams, plotFunction) { const sval = -9999; if ( - scorecardDocument.results.blocks[curve.label].fcstlens.includes( - fcstlen - ) + scorecardDocument.results.blocks[label].fcstlens.includes(fcstlen) ) { - scorecardDocument.results.blocks[curve.label].data[region][stat][ - variable - ][threshold][level][fcstlen] = sval; + scorecardDocument.results.blocks[label].data[region][stat][variable][ + threshold + ][level][fcstlen] = sval; } else { // mark this undefined - scorecardDocument.results.blocks[curve.label].data[region][stat][ - variable - ][threshold][level][fcstlen] = "undefined"; + scorecardDocument.results.blocks[label].data[region][stat][variable][ + threshold + ][level][fcstlen] = "undefined"; } }); }); @@ -640,10 +643,11 @@ processScorecard = function (plotParams, plotFunction) { // to be in the public section of the scorecard settings file // NOTE: For now we do not have scheduled jobs. When we do we will need to change this. const notifyDataProcessorURL = `${Meteor.settings.public.vxdataProcessorUrl}`; - const sDocument = `\{"docid": "${id}"\}`; + const sDocument = `{"docid": "${id}"}`; HTTP.post( notifyDataProcessorURL, { content: `${sDocument}` }, + // eslint-disable-next-line no-unused-vars function (error, response) { if (error) { console.log(error); diff --git a/apps/scorecard/server/main.js b/apps/scorecard/server/main.js index 77b1da5ffa..faed40c55d 100644 --- a/apps/scorecard/server/main.js +++ b/apps/scorecard/server/main.js @@ -3,10 +3,13 @@ */ import { Meteor } from "meteor/meteor"; +import { moment } from "meteor/momentjs:moment"; import { + matsMethods, matsTypes, matsCollections, matsDataUtils, + matsParamUtils, matsCouchbaseUtils, } from "meteor/randyp:mats-common"; @@ -619,7 +622,7 @@ const doCurveParams = function () { const params = matsCollections.CurveParamsInfo.find({ curve_params: { $exists: true }, }).fetch()[0].curve_params; - for (let cp = 0; cp < params.length; cp++) { + for (let cp = 0; cp < params.length; cp += 1) { matsCollections[params[cp]].remove({}); } } @@ -657,8 +660,8 @@ const doCurveParams = function () { let currentURL; let queryURL; let expectedApps = []; - for (let aidx = 0; aidx < appsToScore.length; aidx++) { - currentApp = Object.keys(appsToScore[aidx])[0]; + for (let aidx = 0; aidx < appsToScore.length; aidx += 1) { + [currentApp] = Object.keys(appsToScore[aidx]); currentURL = appsToScore[aidx][currentApp]; // clean up URL if users left a trailing slash or didn't include https:// @@ -677,7 +680,7 @@ const doCurveParams = function () { ); // store the URL that was used to get each of these apps - for (let eaidx = 0; eaidx < expectedApps.length; eaidx++) { + for (let eaidx = 0; eaidx < expectedApps.length; eaidx += 1) { const thisApp = expectedApps[eaidx]; applicationSourceMap[thisApp] = currentApp; } @@ -910,10 +913,10 @@ const doCurveParams = function () { // remove excluded stats from the scorecard // we need to do this after the main metadata loop // is finished or we don't have the full list of apps - for (let aidx = 0; aidx < applicationOptions.length; aidx++) { + for (let aidx = 0; aidx < applicationOptions.length; aidx += 1) { // loop through all the applications found inside the app list in the settings const thisApp = applicationOptions[aidx]; - for (let sidx = statisticOptionsMap[thisApp].length - 1; sidx >= 0; sidx--) { + for (let sidx = statisticOptionsMap[thisApp].length - 1; sidx >= 0; sidx -= 1) { // loop backwards through the statistics for this app const thisStat = statisticOptionsMap[thisApp][sidx]; if (matsDataUtils.excludeStatFromScorecard(thisStat)) { @@ -924,7 +927,7 @@ const doCurveParams = function () { } } } catch (err) { - console.log(err.message); + throw new Error(err.message); } if (matsCollections.label.findOne({ name: "label" }) === undefined) { @@ -979,7 +982,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.application.findOne({ name: "application" }); + const currentParam = matsCollections.application.findOne({ name: "application" }); if (!matsDataUtils.areObjectsEqual(currentParam.dates, dateOptionsMap)) { // have to reload application data matsCollections.application.update( @@ -1023,7 +1026,9 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections["data-source"].findOne({ name: "data-source" }); + const currentParam = matsCollections["data-source"].findOne({ + name: "data-source", + }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, modelOptionsMap)) { // have to reload model data matsCollections["data-source"].update( @@ -1069,7 +1074,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections["control-data-source"].findOne({ + const currentParam = matsCollections["control-data-source"].findOne({ name: "control-data-source", }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, modelOptionsMap)) { @@ -1115,7 +1120,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.region.findOne({ name: "region" }); + const currentParam = matsCollections.region.findOne({ name: "region" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, regionOptionsMap)) { // have to reload region data matsCollections.region.update( @@ -1159,7 +1164,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.statistic.findOne({ name: "statistic" }); + const currentParam = matsCollections.statistic.findOne({ name: "statistic" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, statisticOptionsMap)) { // have to reload statistic data matsCollections.statistic.update( @@ -1196,7 +1201,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.variable.findOne({ name: "variable" }); + const currentParam = matsCollections.variable.findOne({ name: "variable" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, variableOptionsMap)) { // have to reload variable data matsCollections.variable.update( @@ -1244,7 +1249,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.threshold.findOne({ name: "threshold" }); + const currentParam = matsCollections.threshold.findOne({ name: "threshold" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, thresholdOptionsMap)) { // have to reload threshold data matsCollections.threshold.update( @@ -1297,7 +1302,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.scale.findOne({ name: "scale" }); + const currentParam = matsCollections.scale.findOne({ name: "scale" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, scaleOptionsMap)) { // have to reload scale data matsCollections.scale.update( @@ -1350,7 +1355,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.truth.findOne({ name: "truth" }); + const currentParam = matsCollections.truth.findOne({ name: "truth" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, truthOptionsMap)) { // have to reload truth data matsCollections.truth.update( @@ -1403,7 +1408,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections["forecast-length"].findOne({ + const currentParam = matsCollections["forecast-length"].findOne({ name: "forecast-length", }); if ( @@ -1459,7 +1464,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections["forecast-type"].findOne({ + const currentParam = matsCollections["forecast-type"].findOne({ name: "forecast-type", }); if ( @@ -1511,7 +1516,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections["valid-time"].findOne({ name: "valid-time" }); + const currentParam = matsCollections["valid-time"].findOne({ name: "valid-time" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, validTimeOptionsMap)) { // have to reload valid time data matsCollections["valid-time"].update( @@ -1556,7 +1561,7 @@ const doCurveParams = function () { }); } else { // it is defined but check for necessary update - var currentParam = matsCollections.level.findOne({ name: "level" }); + const currentParam = matsCollections.level.findOne({ name: "level" }); if (!matsDataUtils.areObjectsEqual(currentParam.optionsMap, levelOptionsMap)) { // have to reload level data matsCollections.level.update( @@ -1674,7 +1679,8 @@ const doPlotGraph = function () { Meteor.startup(function () { matsCollections.Databases.remove({}); if (matsCollections.Databases.find({}).count() < 0) { - console.log( + // eslint-disable-next-line no-console + console.warn( "main startup: corrupted Databases collection: dropping Databases collection" ); matsCollections.Databases.drop(); @@ -1691,7 +1697,7 @@ Meteor.startup(function () { databases = Meteor.settings.private.databases; } if (databases !== null && databases !== undefined && Array.isArray(databases)) { - for (let di = 0; di < databases.length; di++) { + for (let di = 0; di < databases.length; di += 1) { matsCollections.Databases.insert(databases[di]); } } @@ -1723,6 +1729,7 @@ Meteor.startup(function () { cbConnections.forEach(function (cbConnection) { if (cbConnection.collection === "METAR") { // global cbPool + // eslint-disable-next-line no-undef cbPool = new matsCouchbaseUtils.CBUtilities( cbConnection.host, cbConnection.bucket, @@ -1735,6 +1742,7 @@ Meteor.startup(function () { } if (cbConnection.collection === "SCORECARD") { // global cbScorecardPool + // eslint-disable-next-line no-undef cbScorecardPool = new matsCouchbaseUtils.CBUtilities( cbConnection.host, cbConnection.bucket, @@ -1750,6 +1758,7 @@ Meteor.startup(function () { } if (cbConnection.collection === "SCORECARD_SETTINGS") { // global cbScorecardSettingsPool + // eslint-disable-next-line no-undef cbScorecardSettingsPool = new matsCouchbaseUtils.CBUtilities( cbConnection.host, cbConnection.bucket, @@ -1776,7 +1785,7 @@ Meteor.startup(function () { dbType: matsTypes.DbTypes.couchbase, }); } catch (error) { - console.log(error.message); + throw new Error(error.message); } }); @@ -1784,6 +1793,7 @@ Meteor.startup(function () { // These are application specific mongo data - like curve params // The appSpecificResetRoutines object is a special name, // as is doCurveParams. The refreshMetaData mechanism depends on them being named that way. +// eslint-disable-next-line no-undef appSpecificResetRoutines = [ doCurveParams, doPlotGraph,