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