transpileCssProp.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _helperModuleImports = require("@babel/helper-module-imports");
  7. var _detectors = require("../utils/detectors");
  8. var _options = require("../utils/options");
  9. // Most of this code was taken from @satya164's babel-plugin-css-prop
  10. // @see https://github.com/satya164/babel-plugin-css-prop
  11. var TAG_NAME_REGEXP = /^[a-z][a-z\d]*(\-[a-z][a-z\d]*)?$/;
  12. var getName = function getName(node, t) {
  13. if (typeof node.name === 'string') return node.name;
  14. if (t.isJSXMemberExpression(node)) {
  15. return `${getName(node.object, t)}.${node.property.name}`;
  16. }
  17. throw path.buildCodeFrameError(`Cannot infer name from node with type "${node.type}". Please submit an issue at github.com/styled-components/babel-plugin-styled-components with your code so we can take a look at your use case!`);
  18. };
  19. var _default = function _default(t) {
  20. return function (path, state) {
  21. if (!(0, _options.useCssProp)(state)) return;
  22. if (path.node.name.name !== 'css') return;
  23. var program = state.file.path; // state.customImportName is passed through from styled-components/macro if it's used
  24. // since the macro also inserts the import
  25. var importName = state.customImportName || (0, _detectors.importLocalName)('default', state);
  26. var bindings = program.scope.bindings; // Insert import if it doesn't exist yet
  27. if (!importName || !bindings[importName.name] || !bindings[importName]) {
  28. (0, _helperModuleImports.addDefault)(path, 'styled-components', {
  29. nameHint: 'styled'
  30. });
  31. importName = t.identifier((0, _detectors.importLocalName)('default', state, true));
  32. }
  33. if (!t.isIdentifier(importName)) importName = t.identifier(importName);
  34. var elem = path.parentPath;
  35. var name = getName(elem.node.name, t);
  36. var id = path.scope.generateUidIdentifier('Styled' + name.replace(/^([a-z])/, function (match, p1) {
  37. return p1.toUpperCase();
  38. }));
  39. var styled;
  40. var injector;
  41. if (TAG_NAME_REGEXP.test(name)) {
  42. styled = t.callExpression(importName, [t.stringLiteral(name)]);
  43. } else {
  44. styled = t.callExpression(importName, [t.identifier(name)]);
  45. if (bindings[name] && !t.isImportDeclaration(bindings[name].path.parent)) {
  46. injector = function injector(nodeToInsert) {
  47. return (t.isVariableDeclaration(bindings[name].path.parent) ? bindings[name].path.parentPath : bindings[name].path).insertAfter(nodeToInsert);
  48. };
  49. }
  50. }
  51. var css;
  52. if (t.isStringLiteral(path.node.value)) {
  53. css = t.templateLiteral([t.templateElement({
  54. raw: path.node.value.value,
  55. cooked: path.node.value.value
  56. }, true)], []);
  57. } else if (t.isJSXExpressionContainer(path.node.value)) {
  58. if (t.isTemplateLiteral(path.node.value.expression)) {
  59. css = path.node.value.expression;
  60. } else if (t.isTaggedTemplateExpression(path.node.value.expression) && path.node.value.expression.tag.name === 'css') {
  61. css = path.node.value.expression.quasi;
  62. } else if (t.isObjectExpression(path.node.value.expression)) {
  63. css = path.node.value.expression;
  64. } else {
  65. css = t.templateLiteral([t.templateElement({
  66. raw: '',
  67. cooked: ''
  68. }, false), t.templateElement({
  69. raw: '',
  70. cooked: ''
  71. }, true)], [path.node.value.expression]);
  72. }
  73. }
  74. if (!css) return;
  75. elem.node.attributes = elem.node.attributes.filter(function (attr) {
  76. return attr !== path.node;
  77. });
  78. elem.node.name = t.jSXIdentifier(id.name);
  79. if (elem.parentPath.node.closingElement) {
  80. elem.parentPath.node.closingElement.name = t.jSXIdentifier(id.name);
  81. } // object syntax
  82. if (t.isObjectExpression(css)) {
  83. /**
  84. * for objects as CSS props, we have to recurse through the object and replace any
  85. * object value scope references with generated props similar to how the template
  86. * literal transform above creates dynamic interpolations
  87. */
  88. var p = t.identifier('p');
  89. var replaceObjectWithPropFunction = false;
  90. css.properties = css.properties.reduce(function propertiesReducer(acc, property) {
  91. if (t.isObjectExpression(property.value)) {
  92. // recurse for objects within objects (e.g. {'::before': { content: x }})
  93. property.value.properties = property.value.properties.reduce(propertiesReducer, []);
  94. acc.push(property);
  95. } else if ( // if a non-primitive value we have to interpolate it
  96. [t.isBigIntLiteral, t.isBooleanLiteral, t.isNullLiteral, t.isNumericLiteral, t.isStringLiteral].filter(Boolean) // older versions of babel might not have bigint support baked in
  97. .every(function (x) {
  98. return !x(property.value);
  99. })) {
  100. replaceObjectWithPropFunction = true;
  101. var _name = path.scope.generateUidIdentifier('css');
  102. elem.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(_name.name), t.jSXExpressionContainer(property.value)));
  103. acc.push(t.objectProperty(property.key, t.memberExpression(p, _name)));
  104. } else {
  105. // some sort of primitive which is safe to pass through as-is
  106. acc.push(property);
  107. }
  108. return acc;
  109. }, []);
  110. if (replaceObjectWithPropFunction) {
  111. css = t.arrowFunctionExpression([p], css);
  112. }
  113. } else {
  114. // tagged template literal
  115. css.expressions = css.expressions.reduce(function (acc, ex) {
  116. if (Object.keys(bindings).some(function (key) {
  117. return bindings[key].referencePaths.find(function (p) {
  118. return p.node === ex;
  119. });
  120. }) || t.isFunctionExpression(ex) || t.isArrowFunctionExpression(ex)) {
  121. acc.push(ex);
  122. } else {
  123. var _name2 = path.scope.generateUidIdentifier('css');
  124. var _p = t.identifier('p');
  125. elem.node.attributes.push(t.jSXAttribute(t.jSXIdentifier(_name2.name), t.jSXExpressionContainer(ex)));
  126. acc.push(t.arrowFunctionExpression([_p], t.memberExpression(_p, _name2)));
  127. }
  128. return acc;
  129. }, []);
  130. }
  131. if (!injector) {
  132. var parent = elem;
  133. while (!t.isProgram(parent.parentPath)) {
  134. parent = parent.parentPath;
  135. }
  136. injector = function injector(nodeToInsert) {
  137. return parent.insertBefore(nodeToInsert);
  138. };
  139. }
  140. injector(t.variableDeclaration('var', [t.variableDeclarator(id, t.isObjectExpression(css) || t.isArrowFunctionExpression(css) ? t.callExpression(styled, [css]) : t.taggedTemplateExpression(styled, css))]));
  141. };
  142. };
  143. exports.default = _default;