UNPKG

babel-plugin-react-component-trace-data-attr

Version:

Adds data- attribute to html elements showing the trace of React components names that led to this element creation.

115 lines (92 loc) 4.39 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = function (babel) { var t = babel.types; return { visitor: { CallExpression: _styledComponents.CallExpression, TaggedTemplateExpression: _styledComponents.TaggedTemplateExpression, JSXOpeningElement: function JSXOpeningElement(path, state) { var options = (0, _options2.default)(state); handleOpeningElement(t, path, options); } } }; }; var _options = require('./options'); var _options2 = _interopRequireDefault(_options); var _styledComponents = require('./styled-components'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var findOrAddDataProperty = function findOrAddDataProperty(t, properties, identifier, attribute) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = properties[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var prop = _step.value; if (prop.key && prop.key.type === 'StringLiteral' && prop.key.value === attribute) { return prop.value; } } // It's better to unshift instead of push, because last property may be a RestElement (...restProps). } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } properties.unshift(t.objectProperty(t.stringLiteral(attribute), identifier, true, false)); return identifier; }; var getParentDataAttrExpression = function getParentDataAttrExpression(t, path, options, functionParent) { // It is safe to handle nodes with only one param, because probably it is props splitting if (functionParent.node.params.length !== 1) { return; } if (functionParent.node.params[0].type === 'ObjectPattern') { return findOrAddDataProperty(t, functionParent.node.params[0].properties, path.scope.generateUidIdentifier(), options.attribute); } else { var elementDataAttr = t.memberExpression(functionParent.node.params[0], t.stringLiteral(options.attribute), true); // functionParent.node.params[0] must be defined return t.logicalExpression("&&", functionParent.node.params[0], elementDataAttr); } }; var handleOpeningElement = function handleOpeningElement(t, path, options) { var functionParent = path.getFunctionParent(); var componentName = void 0; var parentDataAttrExpression = void 0; if (!functionParent) return; if (functionParent.type == "ClassMethod" || functionParent.parent.type == "ClassProperty") { // Class components componentName = functionParent.findParent(function (path) { return path.isClassExpression() || path.isClassDeclaration(); }).node.id.name; parentDataAttrExpression = t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('props')), t.stringLiteral(options.attribute), true); } else if (functionParent.parent.type === "VariableDeclarator") { // Function components without decorators componentName = functionParent.parent.id.name; parentDataAttrExpression = getParentDataAttrExpression(t, path, options, functionParent); } else if (functionParent.parent.type === "CallExpression" && (functionParent.parent.callee.name === 'memo' || functionParent.parent.callee.property && functionParent.parent.callee.property.name === 'memo')) { // Function components with memo var parentPath = functionParent.parentPath; // Looking for variable declaration. while (parentPath.parent.type !== 'VariableDeclarator') { parentPath = parentPath.parentPath; } componentName = parentPath.parent.id.name; parentDataAttrExpression = getParentDataAttrExpression(t, path, options, functionParent); } else { return; } path.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(options.attribute), t.jSXExpressionContainer(t.binaryExpression("+", parentDataAttrExpression ? t.logicalExpression("||", parentDataAttrExpression, t.stringLiteral("")) : t.stringLiteral(""), t.stringLiteral(options.separator + options.format(componentName)))))); };