All files / src/utils getPropType.js

88.33% Statements 53/60
81.08% Branches 30/37
100% Functions 10/10
88.33% Lines 53/60
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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165                                              2x     2x 4x               2x 2x       2x   2x       2x 2x       2x   2x       1x 1x   1x       1x   1x       5x 5x 1x     5x 5x 5x   8x 8x 8x 2x   8x 8x   5x     5x       1x           2x                         2x                                   60x 65x   65x   65x 65x   65x 65x 27x 27x 38x 1x 1x       60x 32x 32x   18x 14x     10x   4x     60x    
/*
 * Copyright (c) 2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 *
 */
 
/*eslint no-use-before-define: 0*/
 
 
import {getDocblock} from '../utils/docblock';
import getMembers from './getMembers';
import getPropertyName from './getPropertyName';
import isRequiredPropType from '../utils/isRequiredPropType';
import printValue from './printValue';
import recast from 'recast';
import resolveToValue from './resolveToValue';
 
var {types: {namedTypes: types}} = recast;
 
function getEnumValues(path) {
  return path.get('elements').map(function(elementPath) {
    return {
      value: printValue(elementPath),
      computed: !types.Literal.check(elementPath.node),
    };
  });
}
 
function getPropTypeOneOf(argumentPath) {
  var type: PropTypeDescriptor = {name: 'enum'};
  Iif (!types.ArrayExpression.check(argumentPath.node)) {
    type.computed = true;
    type.value = printValue(argumentPath);
  } else {
    type.value = getEnumValues(argumentPath);
  }
  return type;
}
 
function getPropTypeOneOfType(argumentPath) {
  var type: PropTypeDescriptor = {name: 'union'};
  Iif (!types.ArrayExpression.check(argumentPath.node)) {
    type.computed = true;
    type.value = printValue(argumentPath);
  } else {
    type.value = argumentPath.get('elements').map(getPropType);
  }
  return type;
}
 
function getPropTypeArrayOf(argumentPath) {
  var type: PropTypeDescriptor = {name: 'arrayOf'};
  var subType = getPropType(argumentPath);
 
  Iif (subType.name === 'unknown') {
    type.value = printValue(argumentPath);
    type.computed = true;
  } else {
    type.value = subType;
  }
  return type;
}
 
function getPropTypeShape(argumentPath) {
  var type: PropTypeDescriptor = {name: 'shape', value: 'unknown'};
  if (!types.ObjectExpression.check(argumentPath.node)) {
    argumentPath = resolveToValue(argumentPath);
  }
 
  Eif (types.ObjectExpression.check(argumentPath.node)) {
    var value = {};
    argumentPath.get('properties').each(function(propertyPath) {
      var descriptor: PropDescriptor | PropTypeDescriptor =
        getPropType(propertyPath.get('value'));
      var docs = getDocblock(propertyPath);
      if (docs) {
        descriptor.description = docs;
      }
      descriptor.required = isRequiredPropType(propertyPath.get('value'));
      value[getPropertyName(propertyPath)] = descriptor;
    });
    type.value = value;
  }
 
  return type;
}
 
function getPropTypeInstanceOf(argumentPath) {
  return {
    name: 'instanceOf',
    value: printValue(argumentPath),
  };
}
 
var simplePropTypes = {
  array: 1,
  bool: 1,
  func: 1,
  number: 1,
  object: 1,
  string: 1,
  any: 1,
  element: 1,
  node: 1,
  symbol: 1,
};
 
var propTypes = {
  oneOf: getPropTypeOneOf,
  oneOfType: getPropTypeOneOfType,
  instanceOf: getPropTypeInstanceOf,
  arrayOf: getPropTypeArrayOf,
  shape: getPropTypeShape,
};
 
/**
 * Tries to identify the prop type by inspecting the path for known
 * prop type names. This method doesn't check whether the found type is actually
 * from React.PropTypes. It simply assumes that a match has the same meaning
 * as the React.PropTypes one.
 *
 * If there is no match, "custom" is returned.
 */
export default function getPropType(path: NodePath): PropTypeDescriptor {
  var descriptor;
  getMembers(path, true).some(member => {
    var node = member.path.node;
    var name;
    Iif (types.Literal.check(node)) {
      name = node.value;
    } else Eif (types.Identifier.check(node) && !member.computed) {
      name = node.name;
    }
    Eif (name) {
      if (simplePropTypes.hasOwnProperty(name)) {
        descriptor = {name};
        return true;
      } else if (propTypes.hasOwnProperty(name) && member.argumentsPath) {
        descriptor = propTypes[name](member.argumentsPath.get(0));
        return true;
      }
    }
  });
  if (!descriptor) {
    var node = path.node;
    if (types.Identifier.check(node) &&
        simplePropTypes.hasOwnProperty(node.name)) {
      descriptor = {name: node.name};
    } else if (types.CallExpression.check(node) &&
        types.Identifier.check(node.callee) &&
        propTypes.hasOwnProperty(node.callee.name)) {
      descriptor = propTypes[node.callee.name](path.get('arguments', 0));
    } else {
      descriptor = {name: 'custom', raw: printValue(path)};
    }
  }
  return descriptor;
}