qpp-measures-data
Advanced tools
Comparing version 1.0.0-alpha.15 to 1.0.0-alpha.16
12
index.js
// Libraries | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var YAML = require('yamljs'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const YAML = require('yamljs'); | ||
var yearRegEx = /^[0-9]{4}/; | ||
var benchmarkJsonFileRegEx = /^[0-9]{4}\.json$/; | ||
const yearRegEx = /^[0-9]{4}/; | ||
const benchmarkJsonFileRegEx = /^[0-9]{4}\.json$/; | ||
@@ -16,3 +16,3 @@ /** | ||
exports.getBenchmarksData = function() { | ||
var benchmarksByYear = {}; | ||
const benchmarksByYear = {}; | ||
@@ -19,0 +19,0 @@ fs.readdirSync(path.join(__dirname, 'benchmarks')).forEach(function(file) { |
{ | ||
"name": "qpp-measures-data", | ||
"version": "1.0.0-alpha.15", | ||
"version": "1.0.0-alpha.16", | ||
"description": "Quality Payment Program Measures Data Repository", | ||
@@ -27,5 +28,4 @@ "repository": { | ||
"eslint": "^4.2.0", | ||
"eslint-config-nava": "^1.0.0", | ||
"eslint-config-nava": "^2.0.0", | ||
"eslint-plugin-react": "^7.1.0", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"lodash": "^4.16.4", | ||
@@ -32,0 +32,0 @@ "mocha": "^3.2.0", |
// Utility functions for formatting the csv records | ||
// Libraries | ||
var keyBy = require('lodash/keyBy'); | ||
const keyBy = require('lodash/keyBy'); | ||
// Data | ||
var measures = require('../../measures/measures-data.json'); | ||
const measures = require('../../measures/measures-data.json'); | ||
// Constants | ||
@@ -12,3 +12,3 @@ /** | ||
*/ | ||
var SUBMISSION_METHOD_MAP = { | ||
const SUBMISSION_METHOD_MAP = { | ||
'claims': 'claims', | ||
@@ -25,3 +25,3 @@ 'registry': 'registry', | ||
*/ | ||
var MEASURE_ID_TO_MEASURE_MAP = keyBy(measures, function(measure) { | ||
const MEASURE_ID_TO_MEASURE_MAP = keyBy(measures, function(measure) { | ||
/** | ||
@@ -40,7 +40,7 @@ * NOTE: Quality measurements' measureIds are usually string integers. | ||
*/ | ||
var formatSubmissionMethod = function(submissionMethod) { | ||
const formatSubmissionMethod = function(submissionMethod) { | ||
return SUBMISSION_METHOD_MAP[submissionMethod.replace(/\s/g, '').toLowerCase()]; | ||
}; | ||
var isInverseBenchmarkRecord = require('../../util/benchmarks/is-inverse-benchmark-record'); | ||
var floatRegex = /([0-9]*[.]?[0-9]+)/g; | ||
const isInverseBenchmarkRecord = require('../../util/benchmarks/is-inverse-benchmark-record'); | ||
const floatRegex = /([0-9]*[.]?[0-9]+)/g; | ||
/** | ||
@@ -69,6 +69,6 @@ * Generator function to create a | ||
*/ | ||
var formatDecileGenerator = function(record) { | ||
var isInverseMeasure = isInverseBenchmarkRecord(record); | ||
var top = isInverseMeasure ? 0 : 100; | ||
var bottom = isInverseMeasure ? 100 : 0; | ||
const formatDecileGenerator = function(record) { | ||
const isInverseMeasure = isInverseBenchmarkRecord(record); | ||
const top = isInverseMeasure ? 0 : 100; | ||
const bottom = isInverseMeasure ? 100 : 0; | ||
@@ -83,7 +83,7 @@ /** | ||
return function(decileString, index, array) { | ||
var range = decileString ? decileString.match(floatRegex) : null; | ||
var nextIndex = index + 1; | ||
var prevIndex = index - 1; | ||
var definedPredecessor; | ||
var definedSuccessor; | ||
const range = decileString ? decileString.match(floatRegex) : null; | ||
let nextIndex = index + 1; | ||
let prevIndex = index - 1; | ||
let definedPredecessor; | ||
let definedSuccessor; | ||
@@ -168,3 +168,3 @@ // If decile is explicitly defined: | ||
*/ | ||
var formatBenchmarkRecord = function(record, options) { | ||
const formatBenchmarkRecord = function(record, options) { | ||
/** | ||
@@ -175,3 +175,3 @@ * NOTE: Some of the benchmarks don't correspond to | ||
*/ | ||
var measure = MEASURE_ID_TO_MEASURE_MAP[record.qualityId]; | ||
const measure = MEASURE_ID_TO_MEASURE_MAP[record.qualityId]; | ||
@@ -178,0 +178,0 @@ if (!measure) return; |
// Libraries | ||
var parse = require('csv-parse'); | ||
const parse = require('csv-parse'); | ||
// Constants | ||
var BENCHMARK_CSV_COLUMNS = [ | ||
const BENCHMARK_CSV_COLUMNS = [ | ||
'measureName', | ||
@@ -21,5 +21,5 @@ 'qualityId', | ||
// Utils | ||
var formatBenchmarkRecord = require('./format-benchmark-record'); | ||
const formatBenchmarkRecord = require('./format-benchmark-record'); | ||
// Data | ||
var benchmarksData = ''; | ||
let benchmarksData = ''; | ||
@@ -32,6 +32,6 @@ /** | ||
*/ | ||
var benchmarks = []; | ||
const benchmarks = []; | ||
// Commandline Arguments | ||
var benchmarkYear = process.argv[2]; | ||
var performanceYear = process.argv[3]; | ||
const benchmarkYear = process.argv[2]; | ||
const performanceYear = process.argv[3]; | ||
@@ -42,3 +42,3 @@ if (benchmarkYear && performanceYear) { | ||
process.stdin.on('readable', function() { | ||
var chunk = process.stdin.read(); | ||
const chunk = process.stdin.read(); | ||
if (chunk !== null) { | ||
@@ -55,3 +55,3 @@ benchmarksData += chunk; | ||
records.forEach(function(record) { | ||
var benchmark = formatBenchmarkRecord(record, {benchmarkYear: benchmarkYear, performanceYear: performanceYear}); | ||
const benchmark = formatBenchmarkRecord(record, {benchmarkYear: benchmarkYear, performanceYear: performanceYear}); | ||
@@ -58,0 +58,0 @@ if (benchmark) benchmarks.push(benchmark); |
@@ -20,14 +20,14 @@ /** | ||
*/ | ||
var fs = require('fs'); | ||
var _ = require('lodash'); | ||
var parse = require('csv-parse/lib/sync'); | ||
const fs = require('fs'); | ||
const _ = require('lodash'); | ||
const parse = require('csv-parse/lib/sync'); | ||
var MAX_SPECIALITY_SET_SIZE = 6; | ||
var SUPPORTED_PERFORMANCE_YEARS = [2017]; | ||
const MAX_SPECIALITY_SET_SIZE = 6; | ||
const SUPPORTED_PERFORMANCE_YEARS = [2017]; | ||
var measuresJson = ''; | ||
var claimsClusterFilePath = process.argv[2]; | ||
var registryClusterFilePath = process.argv[3]; | ||
let measuresJson = ''; | ||
const claimsClusterFilePath = process.argv[2]; | ||
const registryClusterFilePath = process.argv[3]; | ||
var specialClusterRelations = { | ||
const specialClusterRelations = { | ||
registry: [ | ||
@@ -92,7 +92,7 @@ {measureId: '047', optionals: []}, | ||
function populateClinicalClusters(clusterMap, measures, submissionMethod, filePath) { | ||
let contents = fs.readFileSync(filePath, 'utf8'); | ||
let rows = parse(contents, {columns: true}); | ||
const contents = fs.readFileSync(filePath, 'utf8'); | ||
const rows = parse(contents, {columns: true}); | ||
// group the measures by cluster | ||
let byClusterName = _.chain(rows) | ||
const byClusterName = _.chain(rows) | ||
.map(r => ({clusterName: _.camelCase(r['Title']), measureId: _.padStart(r['Quality ID'], 3, '0')})) | ||
@@ -106,4 +106,4 @@ .groupBy('clusterName') | ||
clinicalCluster.measureIds.forEach(measureId => { | ||
let measure = measures.find(m => m.measureId === measureId); | ||
let cluster = clusterMap.get(measureId) || { | ||
const measure = measures.find(m => m.measureId === measureId); | ||
const cluster = clusterMap.get(measureId) || { | ||
measureId: measureId, | ||
@@ -123,3 +123,3 @@ submissionMethod: submissionMethod, | ||
// group the measures of submissionMethod by specialty set | ||
let bySpecialty = _.chain(measures) | ||
const bySpecialty = _.chain(measures) | ||
.filter(m => m.category === 'quality') | ||
@@ -136,4 +136,4 @@ .filter(m => m.submissionMethods && m.submissionMethods.indexOf(submissionMethod) > -1) | ||
specialty.measureIds.forEach(measureId => { | ||
let measure = measures.find(m => m.measureId === measureId); | ||
let cluster = clusterMap.get(measureId) || { | ||
const measure = measures.find(m => m.measureId === measureId); | ||
const cluster = clusterMap.get(measureId) || { | ||
measureId: measureId, | ||
@@ -153,3 +153,3 @@ submissionMethod: submissionMethod, | ||
function generateEMAClusters(allMeasures) { | ||
let measures = allMeasures.filter(m => | ||
const measures = allMeasures.filter(m => | ||
(SUPPORTED_PERFORMANCE_YEARS.indexOf(m.firstPerformanceYear) > -1) && | ||
@@ -159,4 +159,4 @@ (m.lastPerformanceYear == null || SUPPORTED_PERFORMANCE_YEARS.indexOf(m.lastPerformanceYear) > -1) | ||
let claimsClusterMap = new Map(); | ||
let registryClusterMap = new Map(); | ||
const claimsClusterMap = new Map(); | ||
const registryClusterMap = new Map(); | ||
@@ -173,3 +173,3 @@ // set the claims and registry specialty set | ||
let emaClusters = []; | ||
const emaClusters = []; | ||
@@ -185,5 +185,5 @@ claimsClusterMap | ||
if (ema.clinicalClusters) { | ||
let clinicalClusters = []; | ||
const clinicalClusters = []; | ||
ema.clinicalClusters.forEach(cc => { | ||
let cluster = Object.assign({}, cc, {measureIds: cc.measureIds.concat([ema.measureId])}); | ||
const cluster = Object.assign({}, cc, {measureIds: cc.measureIds.concat([ema.measureId])}); | ||
clinicalClusters.push(cluster); | ||
@@ -202,3 +202,3 @@ cluster.measureIds = _.uniq(cluster.measureIds); | ||
process.stdin.on('readable', () => { | ||
var chunk = process.stdin.read(); | ||
const chunk = process.stdin.read(); | ||
if (chunk !== null) { | ||
@@ -205,0 +205,0 @@ measuresJson += chunk; |
@@ -9,7 +9,7 @@ /** | ||
var xml2js = require('xml2js'); | ||
const xml2js = require('xml2js'); | ||
var schemaType = 'measures'; | ||
const schemaType = 'measures'; | ||
var json = ''; | ||
let json = ''; | ||
/** | ||
@@ -32,4 +32,4 @@ * XML does not allow for multiple elements without a root element. So by | ||
function convertToXml(json) { | ||
var builder = new xml2js.Builder({rootName: schemaType}); | ||
var xml = builder.buildObject(JSON.parse(json, 'utf8')); | ||
const builder = new xml2js.Builder({rootName: schemaType}); | ||
const xml = builder.buildObject(JSON.parse(json, 'utf8')); | ||
process.stdout.write( | ||
@@ -47,3 +47,3 @@ xml | ||
process.stdin.on('readable', function() { | ||
var chunk = this.read(); | ||
const chunk = this.read(); | ||
if (chunk !== null) { | ||
@@ -50,0 +50,0 @@ json += chunk; |
@@ -16,3 +16,3 @@ #!/usr/bin/env node | ||
const additionalMeasuresFilepath = '../../util/measures/additional-measures.json'; | ||
var additionalMeasures = require(additionalMeasuresFilepath); | ||
let additionalMeasures = require(additionalMeasuresFilepath); | ||
@@ -53,3 +53,3 @@ // Some measures have an NqfId (NQF: National Quality Forum) of '0005' | ||
// Initialize a string to store the CSV data. | ||
var cahpsMeasuresData = ''; | ||
let cahpsMeasuresData = ''; | ||
@@ -59,3 +59,3 @@ process.stdin.setEncoding('utf8'); | ||
process.stdin.on('readable', function() { | ||
var chunk = process.stdin.read(); | ||
const chunk = process.stdin.read(); | ||
if (chunk !== null) { | ||
@@ -67,4 +67,4 @@ cahpsMeasuresData += chunk; | ||
function generateCahpsMeasure(record, idx) { | ||
var measureTitle = record['Measure Name']; | ||
var measureIdx = cahpsTitleToMeasureIdIndexMap[measureTitle]; | ||
const measureTitle = record['Measure Name']; | ||
const measureIdx = cahpsTitleToMeasureIdIndexMap[measureTitle]; | ||
@@ -108,3 +108,3 @@ if (measureIdx === undefined) { | ||
additionalMeasures = additionalMeasures.filter(function(measure) { | ||
var re = /CAHPS_\d+/i; | ||
const re = /CAHPS_\d+/i; | ||
return measure.measureId.match(re) === null; | ||
@@ -114,3 +114,3 @@ }); | ||
records.forEach(function(record, idx) { | ||
var measure = generateCahpsMeasure(record, idx); | ||
const measure = generateCahpsMeasure(record, idx); | ||
if (measure) additionalMeasures.push(measure); | ||
@@ -117,0 +117,0 @@ }); |
@@ -47,3 +47,3 @@ /** | ||
process.stdin.on('readable', () => { | ||
var chunk = process.stdin.read(); | ||
const chunk = process.stdin.read(); | ||
if (chunk !== null) { | ||
@@ -122,7 +122,7 @@ qpp += chunk; | ||
} | ||
var result = []; | ||
const result = []; | ||
for (var i = 0; i < measureList.length; i++) { | ||
var measure = measureList[i]; | ||
var obj = {}; | ||
for (let i = 0; i < measureList.length; i++) { | ||
const measure = measureList[i]; | ||
const obj = {}; | ||
obj.category = category; | ||
@@ -129,0 +129,0 @@ obj.firstPerformanceYear = new Date().getFullYear(); |
@@ -24,3 +24,3 @@ #!/usr/bin/env node | ||
process.stdin.on('readable', () => { | ||
var chunk = process.stdin.read(); | ||
const chunk = process.stdin.read(); | ||
if (chunk !== null) { | ||
@@ -27,0 +27,0 @@ measuresData += chunk; |
@@ -7,10 +7,10 @@ // running this will generate a file in util/measures/quality-performace-rates.json | ||
var _ = require('lodash'); | ||
var fs = require('fs'); | ||
var program = require('commander'); | ||
var pdfToText = require('pdf-to-text'); | ||
var p = require('path'); | ||
const _ = require('lodash'); | ||
const fs = require('fs'); | ||
const program = require('commander'); | ||
const pdfToText = require('pdf-to-text'); | ||
const p = require('path'); | ||
var folderPath = null; | ||
var performanceRateJson = []; | ||
let folderPath = null; | ||
const performanceRateJson = []; | ||
@@ -33,3 +33,3 @@ function setPath(path) { | ||
function cleanUpString(input) { | ||
var removeWords = ['OR', 'AND', 'Eligible clinicians should continue to report the measure as specified, with no additional steps needed to account for multiple performance rates.']; | ||
const removeWords = ['OR', 'AND', 'Eligible clinicians should continue to report the measure as specified, with no additional steps needed to account for multiple performance rates.']; | ||
@@ -49,5 +49,5 @@ removeWords.forEach(function(word) { | ||
var rateDescriptions = []; | ||
const rateDescriptions = []; | ||
var found = data.match(/This measure will be calculated with (\d) performance rates:/); | ||
let found = data.match(/This measure will be calculated with (\d) performance rates:/); | ||
@@ -59,6 +59,7 @@ if (!found) { | ||
let foundRate; | ||
if (!found) { | ||
// only a single performace rate | ||
let rateRegex = /DESCRIPTION:((.|\s)*?)INSTRUCTIONS:/; | ||
var foundRate = data.match(rateRegex); | ||
const rateRegex = /DESCRIPTION:((.|\s)*?)INSTRUCTIONS:/; | ||
foundRate = data.match(rateRegex); | ||
@@ -68,6 +69,6 @@ rateDescriptions.push(cleanUpString(foundRate[1])); | ||
// multi performance rate | ||
var numOfRates = found[1]; | ||
const numOfRates = found[1]; | ||
var reportingStart = /REPORTING CRITERIA FOR THIS MEASURE:/; | ||
var reportingFound = data.match(reportingStart); | ||
const reportingStart = /REPORTING CRITERIA FOR THIS MEASURE:/; | ||
let reportingFound = data.match(reportingStart); | ||
if (reportingFound == null) { | ||
@@ -77,8 +78,8 @@ reportingFound = found; | ||
var remainingFile = data.substring(reportingFound.index + reportingFound[0].length); | ||
const remainingFile = data.substring(reportingFound.index + reportingFound[0].length); | ||
// find the 1, see if a ) or a . comes after each performance rate number | ||
var firstPos = remainingFile.indexOf('1'); | ||
var delineationChar = remainingFile[firstPos + 1]; | ||
const firstPos = remainingFile.indexOf('1'); | ||
const delineationChar = remainingFile[firstPos + 1]; | ||
for (var i = 1; i <= numOfRates; i++) { | ||
for (let i = 1; i <= numOfRates; i++) { | ||
// look for the description between 1) and 2) | ||
@@ -89,3 +90,3 @@ let rateRegex = new RegExp(i + '\\' + delineationChar + '((.|\\s)*?)(' + (i + 1) + '\\' + delineationChar + '|Version 1\\.0)'); | ||
// if this is the last rate, look for the description between x) and the ending phrases | ||
var endingPhrases = '(REPORTING CRITERIA|Measure Reporting:|Version 1\\.0|DENOMINATOR \\(REPORTING|The eligible clinician should submit data)'; | ||
const endingPhrases = '(REPORTING CRITERIA|Measure Reporting:|Version 1\\.0|DENOMINATOR \\(REPORTING|The eligible clinician should submit data)'; | ||
rateRegex = new RegExp(i + '\\' + delineationChar + '((.|\\s)*?)' + endingPhrases); | ||
@@ -105,4 +106,4 @@ } | ||
// group the files by the qualityId. This way we don't have to look through the claims and registry files | ||
var groupedFiles = fs.readdirSync(folderPath).reduce(function(arr, current) { | ||
var qualityId = current.split('_')[2]; | ||
const groupedFiles = fs.readdirSync(folderPath).reduce(function(arr, current) { | ||
const qualityId = current.split('_')[2]; | ||
arr[qualityId] ? arr[qualityId].push(current) : arr[qualityId] = [current]; | ||
@@ -112,3 +113,3 @@ return arr; | ||
var qualityIds = Object.keys(groupedFiles); | ||
const qualityIds = Object.keys(groupedFiles); | ||
qualityIds.forEach(function(qualityId, i) { | ||
@@ -121,3 +122,3 @@ getRates(p.join(folderPath, groupedFiles[qualityId][0]), function(rateDescriptions) { | ||
// sort all performance rates | ||
var sortedRates = _.sortBy(performanceRateJson, ['qualityId']); | ||
const sortedRates = _.sortBy(performanceRateJson, ['qualityId']); | ||
// write file to tmp | ||
@@ -124,0 +125,0 @@ fs.writeFile(p.join(__dirname, '../../util/measures/quality-performance-rates.json'), JSON.stringify(sortedRates, null, 2)); |
@@ -14,3 +14,3 @@ // this script merges the util/measures/quality-performance-rates.json, | ||
process.stdin.on('readable', () => { | ||
var chunk = process.stdin.read(); | ||
const chunk = process.stdin.read(); | ||
if (chunk !== null) { | ||
@@ -27,12 +27,12 @@ qpp += chunk; | ||
// read in tmp/quality-performance-rates.json | ||
var performanceRatesJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../util/measures/quality-performance-rates.json'), 'utf8')); | ||
const performanceRatesJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../util/measures/quality-performance-rates.json'), 'utf8')); | ||
// read in measures/quality-measures-additional-info.json | ||
var performanceRateAdditionalJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../util/measures/quality-measures-strata-details.json'), 'utf8')); | ||
const performanceRateAdditionalJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../util/measures/quality-measures-strata-details.json'), 'utf8')); | ||
var measuresNotFound = []; | ||
const measuresNotFound = []; | ||
// iterate through all qppJson measures and find matching items from other json blobs | ||
qppJson.forEach(function(qppItem, index) { | ||
if (qppItem.category === 'quality') { | ||
var performanceRateDescription = _.find(performanceRatesJson, {'qualityId': qppItem.measureId}); | ||
var performanceRateInfo = _.find(performanceRateAdditionalJson, {'qualityId': qppItem.measureId}); | ||
const performanceRateDescription = _.find(performanceRatesJson, {'qualityId': qppItem.measureId}); | ||
const performanceRateInfo = _.find(performanceRateAdditionalJson, {'qualityId': qppItem.measureId}); | ||
@@ -43,3 +43,3 @@ if (!performanceRateDescription || !performanceRateInfo) { | ||
var strataDetails = []; | ||
const strataDetails = []; | ||
performanceRateDescription.descriptions.forEach(function(description, index) { | ||
@@ -140,3 +140,3 @@ strataDetails.push({description: description, name: performanceRateInfo.performanceRates[index]}); | ||
// find the relation and populate reporting category and substitutions | ||
var aciRelation = aciRelations[measure.measureId]; | ||
const aciRelation = aciRelations[measure.measureId]; | ||
if (aciRelation) { | ||
@@ -143,0 +143,0 @@ measure.reportingCategory = aciRelation.reportingCategory; |
@@ -35,3 +35,3 @@ const fs = require('fs'); | ||
// find the relation and populate reporting category and substitutions | ||
var aciRelation = aciRelations[measure.measureId]; | ||
const aciRelation = aciRelations[measure.measureId]; | ||
if (aciRelation) { | ||
@@ -53,3 +53,3 @@ measure.reportingCategory = aciRelation.reportingCategory; | ||
Object.keys(cpcPlusGroups).forEach((groupId) => { | ||
var match = cpcPlusGroups[groupId].find((id) => id === measure.eMeasureId); | ||
const match = cpcPlusGroups[groupId].find((id) => id === measure.eMeasureId); | ||
if (match !== undefined) { | ||
@@ -67,4 +67,4 @@ measure.cpcPlusGroup = groupId; | ||
function enrichAddMeasuresSpecification(measures) { | ||
var csv = parse(fs.readFileSync(path.join(__dirname, '../../util/measures/measurePDF-Specification.csv'), 'utf8')); | ||
var mappedLinks = csv.reduce(function(acc, [submissionMethod, measureId, link]) { | ||
const csv = parse(fs.readFileSync(path.join(__dirname, '../../util/measures/measurePDF-Specification.csv'), 'utf8')); | ||
const mappedLinks = csv.reduce(function(acc, [submissionMethod, measureId, link]) { | ||
acc[measureId] = acc[measureId] || {}; | ||
@@ -74,3 +74,3 @@ acc[measureId][submissionMethod] = link; | ||
}, {}); | ||
var measureData = measures.map(function(measure) { | ||
const measureData = measures.map(function(measure) { | ||
measure.measureSpecification = mappedLinks[measure.measureId]; | ||
@@ -87,3 +87,3 @@ return measure; | ||
function enrichInverseMeasures(measures) { | ||
let inverseMeasures = JSON.parse(fs.readFileSync(path.join(__dirname, '../../util/measures/inverse-measures.json'))); | ||
const inverseMeasures = JSON.parse(fs.readFileSync(path.join(__dirname, '../../util/measures/inverse-measures.json'))); | ||
measures.forEach(measure => { | ||
@@ -90,0 +90,0 @@ if (inverseMeasures.hasOwnProperty(measure.measureId)) { |
@@ -40,3 +40,3 @@ // running this will print out whether each measure is an inverse measure | ||
let found = data.match(/inverse measure/i); // ignore case | ||
const found = data.match(/inverse measure/i); // ignore case | ||
@@ -54,3 +54,3 @@ if (found) { | ||
const groupedFiles = fs.readdirSync(folderPath).reduce(function(arr, current) { | ||
let qualityId = current.split('_')[2]; | ||
const qualityId = current.split('_')[2]; | ||
arr[qualityId] ? arr[qualityId].push(current) : arr[qualityId] = [current]; | ||
@@ -57,0 +57,0 @@ return arr; |
@@ -30,7 +30,2 @@ const parse = require('csv-parse/lib/sync'); | ||
nqfId: null, | ||
strata: [ | ||
{ | ||
name: 'overall' | ||
} | ||
], | ||
measureSets: [], | ||
@@ -90,2 +85,55 @@ isRegistryMeasure: true | ||
const addMultiPerformanceRateDetails = function(newMeasure, record, qcdrStrataNamesDataPath) { | ||
// Parse the names for qcdr measures with multiple strata/performance rates | ||
// { measureId: [name of 1st performance rate, name of 2nd performance rate, etc.] } | ||
// | ||
// In the strata names file, note that the order of the array values matter. | ||
// Also, unlike the descriptions for each of the strata/performance rates, | ||
// the names do not come from a source outside of this codebase. They were | ||
// created by manually selecting distinct keywords from the associated | ||
// performance rate description and are used when submitting to the API. | ||
const strataNames = fs.readFileSync(path.join(__dirname, qcdrStrataNamesDataPath), 'utf8'); | ||
const qcdrStrataNames = JSON.parse(strataNames); | ||
newMeasure['metricType'] = 'multiPerformanceRate'; | ||
const overallPerformanceRate = _.lowerCase(_.trim(record[12])); | ||
const nthPerformanceRate = _.parseInt(overallPerformanceRate); | ||
if (_.isInteger(nthPerformanceRate)) { | ||
newMeasure['overallAlgorithm'] = 'overallStratumOnly'; | ||
} else if (overallPerformanceRate === 'sum numerators') { | ||
newMeasure['overallAlgorithm'] = 'sumNumerators'; | ||
} else if (overallPerformanceRate === 'weighted average') { | ||
newMeasure['overallAlgorithm'] = 'weightedAverage'; | ||
} | ||
// Add the names and descriptions of strata | ||
let strataName; | ||
const measureId = _.trim(record[2]); | ||
const measureDescription = _.trim(record[4]); | ||
// Measure description column contains performance rate description | ||
// Split '*summary* Rate 1: text Rate 2: text' into [text, text] | ||
const strata = _.split(measureDescription, /\s*[Rr]ate [0-9]+:\s*/); | ||
// Drop anything before 'Rate 1' (usually a description of the measure) | ||
strata.shift(); | ||
newMeasure['strata'] = []; | ||
_.each(strata, function(stratum, index) { | ||
strataName = qcdrStrataNames[measureId][index]; | ||
// i + 1 because Rates in the csv are numbered starting from 1 | ||
if (_.lowerCase(strataName) === 'overall' && | ||
index + 1 !== nthPerformanceRate) { | ||
throw TypeError('"Overall" strata for ' + measureId + ' in QCDR ' + | ||
'CSV doesn\'t match the name in the strata details file'); | ||
} | ||
newMeasure['strata'].push({ | ||
'name': strataName, | ||
'description': strata[index] | ||
}); | ||
}); | ||
return newMeasure; | ||
}; | ||
/** | ||
@@ -97,5 +145,7 @@ * [convertCsvToMeasures description] | ||
* | ||
* We trim all data sourced from CSVs because people sometimes unintentionally include spaces or linebreaks | ||
* Notes: | ||
* 1. The terms [performance rate] 'strata' and 'performance rates' are used interchangeably | ||
* 2. We trim all data sourced from CSVs because people sometimes unintentionally include spaces or linebreaks | ||
*/ | ||
const convertCsvToMeasures = function(records, config) { | ||
const convertCsvToMeasures = function(records, config, qcdrStrataNamesDataPath) { | ||
const sourcedFields = config.sourced_fields; | ||
@@ -105,3 +155,3 @@ const constantFields = config.constant_fields; | ||
const newMeasures = records.map(function(record) { | ||
var newMeasure = {}; | ||
const newMeasure = {}; | ||
Object.entries(sourcedFields).forEach(function([measureKey, columnObject]) { | ||
@@ -127,11 +177,15 @@ if (typeof columnObject === 'number') { | ||
// (continuous and ratio, cols 18 and 19) are N, metricType should be | ||
// 'singlePerformanceRate'. Otherwise it should be 'nonProportion' | ||
// | ||
// Note: if the 'proportion' column is Y *and* there are multiple | ||
// strata, then the metricType should be 'multiPerformanceRate' | ||
// TODO(kalvin): implement multiPerformanceRate; | ||
if (record[17] === 'Y' && | ||
record[18] === 'N' && | ||
record[19] === 'N') { | ||
newMeasure['metricType'] = 'singlePerformanceRate'; | ||
// 'singlePerformanceRate', or 'multiPerformanceRate' if there are multiple | ||
// strata/performance rates. Otherwise it should be 'nonProportion' | ||
const proportion = _.trim(record[17]); | ||
const continuous = _.trim(record[18]); | ||
const ratio = _.trim(record[19]); | ||
if (proportion === 'Y' && continuous === 'N' && ratio === 'N') { | ||
// returns an integer if passed string '3', NaN if passed 'N/A' | ||
const numPerformanceRates = _.parseInt(_.trim(record[11])); | ||
if (_.isInteger(numPerformanceRates) && numPerformanceRates > 1) { | ||
addMultiPerformanceRateDetails(newMeasure, record, qcdrStrataNamesDataPath); | ||
} else { | ||
newMeasure['metricType'] = 'singlePerformanceRate'; | ||
} | ||
} else { | ||
@@ -209,3 +263,3 @@ newMeasure['metricType'] = 'nonProportion'; | ||
function importMeasures(measuresDataPath, qcdrMeasuresDataPath, outputPath) { | ||
function importMeasures(measuresDataPath, qcdrMeasuresDataPath, qcdrStrataNamesDataPath, outputPath) { | ||
const qpp = fs.readFileSync(path.join(__dirname, measuresDataPath), 'utf8'); | ||
@@ -215,9 +269,10 @@ const allMeasures = JSON.parse(qpp); | ||
const csv = fs.readFileSync(path.join(__dirname, qcdrMeasuresDataPath), 'utf8'); | ||
const records = parse(csv, 'utf8'); | ||
const qcdrCsv = parse(csv, 'utf8'); | ||
// remove header | ||
records.shift(); | ||
qcdrCsv.shift(); | ||
// If there's more than one QCDR measure with the same measure, we can | ||
// arbitrarily pick one and ignore the others (they should all be | ||
// identical except for the QCDR Organization Name which we don't care about) | ||
const qcdrMeasures = _.uniqBy(convertCsvToMeasures(records, config), 'measureId'); | ||
const qcdrMeasures = _.uniqBy(convertCsvToMeasures(qcdrCsv, config, qcdrStrataNamesDataPath), 'measureId'); | ||
@@ -230,5 +285,6 @@ const mergedMeasures = mergeMeasures(allMeasures, qcdrMeasures, outputPath); | ||
const qcdrMeasuresDataPath = process.argv[3]; | ||
const outputPath = process.argv[4]; | ||
const qcdrStrataNamesDataPath = process.argv[4]; | ||
const outputPath = process.argv[5]; | ||
const newMeasures = importMeasures(measuresDataPath, qcdrMeasuresDataPath, outputPath); | ||
const newMeasures = importMeasures(measuresDataPath, qcdrMeasuresDataPath, qcdrStrataNamesDataPath, outputPath); | ||
fs.writeFileSync(path.join(__dirname, outputPath), newMeasures); |
@@ -13,13 +13,13 @@ /** | ||
var Ajv = require('ajv'); | ||
var path = require('path'); | ||
var YAML = require('yamljs'); | ||
const Ajv = require('ajv'); | ||
const path = require('path'); | ||
const YAML = require('yamljs'); | ||
var ajv = Ajv(); | ||
const ajv = Ajv(); | ||
var schemaType = process.argv[2]; | ||
const schemaType = process.argv[2]; | ||
var json = ''; | ||
let json = ''; | ||
function validate(json) { | ||
var valid = ajv.validate( | ||
const valid = ajv.validate( | ||
YAML.load(path.join(__dirname, '../' + schemaType, | ||
@@ -39,3 +39,3 @@ schemaType + '-schema.yaml')), | ||
process.stdin.on('readable', function() { | ||
var chunk = this.read(); | ||
const chunk = this.read(); | ||
if (chunk !== null) { | ||
@@ -42,0 +42,0 @@ json += chunk; |
@@ -6,3 +6,3 @@ /** | ||
*/ | ||
var isInverseBenchmarkRecord = function(record) { | ||
const isInverseBenchmarkRecord = function(record) { | ||
if (parseFloat(record.decile10) === 100) return false; | ||
@@ -13,3 +13,3 @@ if (parseFloat(record.decile10) === 0) return true; | ||
var deciles = [ | ||
const deciles = [ | ||
record.decile1, | ||
@@ -27,7 +27,7 @@ record.decile2, | ||
for (var i = 0; i < deciles.length; i++) { | ||
var decile = deciles[i]; | ||
for (let i = 0; i < deciles.length; i++) { | ||
const decile = deciles[i]; | ||
if (decile) { | ||
var range = decile.match(/(\d{0,3}\.?\d{2,})/g); | ||
const range = decile.match(/(\d{0,3}\.?\d{2,})/g); | ||
@@ -34,0 +34,0 @@ if (range) { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
8962875
14
100598
12
0
56