All files / src/cli-validator/utils addPathsToComponents.js

94.74% Statements 36/38
94.44% Branches 17/18
100% Functions 7/7
94.59% Lines 35/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 10113x 13x                                   13x 9x 37x 32x                                 32x 101x 101x 101x 101x 81x       81x           101x 36x           182x 182x 182x 182x 182x 953x 953x   22x 22x       931x 87x 81x 81x 6x         2x   87x   866x   182x               81x 81x    
const { each } = require('lodash');
const getPathAsArray = require('./getPathAsArray');
 
// takes validator results dictionary in the format:
//   {
//     errors: {
//       validator-name: [
//         {
//           path: [path, to, error],
//           message: 'error message',
//           rule: rule_name
//         },
//       ],
//     },
//     warnings: ...
//   }
//
// adds path to the originating component if it exists
// modifies the given results object
module.exports = function(originalResults, unresolvedSpec) {
  each(originalResults, function(validatorsDict) {
    each(validatorsDict, function(errors) {
      pointToComponents(errors, unresolvedSpec);
    });
  });
};
 
// takes an array of validator errors:
//   [
//     {
//       path: [path, to, error],
//       message: 'error message',
//       rule: rule_name
//     },
//   ]
//
// adds componentPath field to existing errors
// modifies existing errors in place
function pointToComponents(errors, unresolvedSpec) {
  each(errors, function(err) {
    const pathArray = getPathAsArray(err.path);
    let componentPath = null;
    let refObj = findRef(pathArray, unresolvedSpec);
    while (refObj.refString !== null) {
      componentPath = [
        ...parseRefString(refObj.refString),
        ...refObj.remainingPath
      ];
      refObj = findRef(componentPath, unresolvedSpec);
    }
    // only add the componentPath if the componentPath exists
    // and it is the result of a valid path.
    // protects against invalid $refs from the user and against
    // bugs in the path to the error.
    if (componentPath && refObj.validPath) {
      err.componentPath = componentPath;
    }
  });
}
 
function findRef(pathArray, unresolvedSpec) {
  let ref = null;
  let indexOfRef = 0;
  let currentObj = unresolvedSpec;
  let validPath = true;
  for (let i = 0; i < pathArray.length && currentObj; ++i) {
    let nextKey = pathArray[i];
    if (Array.isArray(currentObj)) {
      // convert the key to an index
      nextKey = Number(nextKey);
      Iif (!(nextKey >= 0 && nextKey < currentObj.length)) {
        validPath = false;
        break;
      }
    } else if (!(nextKey in currentObj)) {
      if ('$ref' in currentObj) {
        ref = currentObj['$ref'];
        indexOfRef = i;
      } else if (i != pathArray.length - 1) {
        // nextKey is not in the object
        // no $ref in the object
        // nextKey is not the last element of the path
        // hence, the given path is invalid
        validPath = false;
      }
      break;
    }
    currentObj = currentObj[nextKey];
  }
  return {
    refString: ref,
    remainingPath: pathArray.slice(indexOfRef, pathArray.length),
    validPath: validPath
  };
}
 
function parseRefString(refString) {
  const refArray = refString.split('/');
  return refArray.slice(refArray.indexOf('#') + 1, refArray.length);
}