Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save satya164/dc45a17b7bc74a144f57e1ea12509f59 to your computer and use it in GitHub Desktop.
Save satya164/dc45a17b7bc74a144f57e1ea12509f59 to your computer and use it in GitHub Desktop.
aphrodite to styled-components codemod
const dashify = text => text.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
const unitless = {
animationIterationCount: true,
borderImageOutset: true,
borderImageSlice: true,
borderImageWidth: true,
boxFlex: true,
boxFlexGroup: true,
boxOrdinalGroup: true,
columnCount: true,
columns: true,
flex: true,
flexGrow: true,
flexPositive: true,
flexShrink: true,
flexNegative: true,
flexOrder: true,
gridRow: true,
gridRowEnd: true,
gridRowSpan: true,
gridRowStart: true,
gridColumn: true,
gridColumnEnd: true,
gridColumnSpan: true,
gridColumnStart: true,
fontWeight: true,
lineClamp: true,
lineHeight: true,
opacity: true,
order: true,
orphans: true,
tabSize: true,
widows: true,
zIndex: true,
zoom: true,
// SVG-related properties
fillOpacity: true,
floodOpacity: true,
stopOpacity: true,
strokeDasharray: true,
strokeDashoffset: true,
strokeMiterlimit: true,
strokeOpacity: true,
strokeWidth: true,
};
export default function(babel) {
const { types: t } = babel;
return {
visitor: {
Program: {
enter(path, state) {
state.components = {};
state.styled = {};
},
exit(path, state) {
Object.keys(state.styled).forEach(key => {
const name = Object.keys(state.components).find(k => {
const { classes } = state.components[k];
return classes && classes.includes(key);
});
if (name) {
const tag = state.components[name].id;
const node = t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(name),
t.taggedTemplateExpression(
/^[a-z0-9]+$/.test(tag)
? t.memberExpression(t.identifier('styled'), t.identifier(tag))
: t.callExpression(t.identifier('styled'), [t.identifier(tag)]),
state.styled[key]
)
),
]);
path.node.body.push(node);
}
});
},
},
JSXOpeningElement(path, state) {
let name;
let classes;
path.traverse({
JSXExpressionContainer(p) {
if (t.isCallExpression(p.node.expression) && p.node.expression.callee.name === 'css') {
if (name) {
throw new Error(`Found duplicate css calls in component ${path.node.name.name}`);
}
name = p.node.expression.arguments
.map(a => a.property.name.charAt(0).toUpperCase() + a.property.name.substr(1))
.join('');
classes = p.node.expression.arguments.map(a => a.property.name);
p.parentPath.remove();
}
},
});
if (name) {
state.components[name] = {
id: path.node.name.name,
classes,
};
path.node.name.name = name;
if (path.parentPath.node.closingElement) {
path.parentPath.node.closingElement.name.name = name;
}
}
},
MemberExpression(path, state) {
if (path.node.object.name === 'StyleSheet' && path.node.property.name === 'create') {
path.parentPath.parentPath.node.init.arguments[0].properties.forEach(p => {
const quasis = [];
const expressions = [];
let text = '';
const indentation = ' ';
const finalize = (expr, str) => {
quasis.push(t.templateElement({ raw: text }));
expressions.push(expr);
text = str;
};
const serialize = (styles, level = 1) => {
const indent = indentation.repeat(level);
styles.forEach((prop, i) => {
if (t.isObjectExpression(prop.value)) {
if (i !== 0) {
text += '\n';
}
if (prop.computed) {
text += `\n${indent}`;
finalize(prop.key, ' {');
} else {
let key;
if (t.isIdentifier(prop.key)) {
key = prop.key.name;
} else {
key = prop.key.value;
}
text += `\n${indent}${key} {`;
}
serialize(prop.value.properties, level + 1);
text += `\n${indent}}`;
return;
}
let key;
if (prop.computed) {
text += `\n${indent}`;
finalize(prop.key, ': ');
} else {
if (t.isIdentifier(prop.key)) {
key = prop.key.name;
} else {
key = prop.key.value;
}
text += `\n${indent}${dashify(key)}: `;
}
if (t.isStringLiteral(prop.value) || t.isNumericLiteral(prop.value)) {
let value = prop.value.value;
if (t.isNumericLiteral(prop.value) && key && !unitless[key]) {
value += 'px';
}
text += `${value};`;
} else {
finalize(prop.value, ';');
}
});
};
serialize(p.value.properties);
quasis.push(t.templateElement({ raw: `${text}\n` }));
state.styled[p.key.name] = t.templateLiteral(quasis, expressions);
});
path.parentPath.parentPath.remove();
}
},
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment