UNPKG

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