getProp.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import propName from './propName';
  2. const DEFAULT_OPTIONS = {
  3. ignoreCase: true,
  4. };
  5. /**
  6. * Returns the JSXAttribute itself or undefined, indicating the prop
  7. * is not present on the JSXOpeningElement.
  8. *
  9. */
  10. export default function getProp(props = [], prop = '', options = DEFAULT_OPTIONS) {
  11. function getName(name) { return options.ignoreCase ? name.toUpperCase() : name; }
  12. const propToFind = getName(prop);
  13. function isPropToFind(property) {
  14. return property.type === 'Property'
  15. && property.key.type === 'Identifier'
  16. && propToFind === getName(property.key.name);
  17. }
  18. const foundAttribute = props.find((attribute) => {
  19. // If the props contain a spread prop, try to find the property in the object expression.
  20. if (attribute.type === 'JSXSpreadAttribute') {
  21. return attribute.argument.type === 'ObjectExpression'
  22. && propToFind !== getName('key') // https://github.com/reactjs/rfcs/pull/107
  23. && attribute.argument.properties.some(isPropToFind);
  24. }
  25. return propToFind === getName(propName(attribute));
  26. });
  27. if (foundAttribute && foundAttribute.type === 'JSXSpreadAttribute') {
  28. return propertyToJSXAttribute(foundAttribute.argument.properties.find(isPropToFind));
  29. }
  30. return foundAttribute;
  31. }
  32. function propertyToJSXAttribute(node) {
  33. const { key, value } = node;
  34. return {
  35. type: 'JSXAttribute',
  36. name: { type: 'JSXIdentifier', name: key.name, ...getBaseProps(key) },
  37. value: value.type === 'Literal'
  38. ? adjustRangeOfNode(value)
  39. : { type: 'JSXExpressionContainer', expression: adjustExpressionRange(value), ...getBaseProps(value) },
  40. ...getBaseProps(node),
  41. };
  42. }
  43. function adjustRangeOfNode(node) {
  44. const [start, end] = node.range || [node.start, node.end];
  45. return {
  46. ...node,
  47. end: undefined,
  48. range: [start, end],
  49. start: undefined,
  50. };
  51. }
  52. function adjustExpressionRange({ expressions, quasis, ...expression }) {
  53. return {
  54. ...adjustRangeOfNode(expression),
  55. ...(expressions ? { expressions: expressions.map(adjustRangeOfNode) } : {}),
  56. ...(quasis ? { quasis: quasis.map(adjustRangeOfNode) } : {}),
  57. };
  58. }
  59. function getBaseProps({ loc, ...node }) {
  60. const { range } = adjustRangeOfNode(node);
  61. return {
  62. loc: getBaseLocation(loc),
  63. range,
  64. };
  65. }
  66. function getBaseLocation({
  67. start,
  68. end,
  69. source,
  70. filename,
  71. }) {
  72. return {
  73. start,
  74. end,
  75. ...(source !== undefined ? { source } : {}),
  76. ...(filename !== undefined ? { filename } : {}),
  77. };
  78. }