import * as t from '@babel/types' import type { ClassNameObject } from '../types' type Builder = ( objects: ClassNameObject[], extras?: string ) => t.Expression | t.StringLiteral | null export const buildClassName: Builder = (objectsIn, extras = '') => { let objects = buildClassNameLogic(objectsIn) if (!objects) return null if (t.isStringLiteral(objects)) { // objects.value = objects.value objects.value = `${extras} ${objects.value}` } else { objects = t.binaryExpression('+', t.stringLiteral(extras), objects) } return objects } export const buildClassNameLogic: Builder = (objects) => { return objects.reduce((acc, val) => { if (acc == null) { if ( // pass conditional expressions through t.isConditionalExpression(val) || // pass non-null literals through t.isStringLiteral(val) || t.isNumericLiteral(val) ) { return val } return t.logicalExpression('||', val, t.stringLiteral('')) } let inner: t.Expression if (t.isStringLiteral(val)) { if (t.isStringLiteral(acc)) { // join adjacent string literals return t.stringLiteral(`${acc.value} ${val.value}`) } inner = t.stringLiteral(` ${val.value}`) } else if (t.isLiteral(val)) { inner = t.binaryExpression('+', t.stringLiteral(' '), val) } else if (t.isConditionalExpression(val) || t.isBinaryExpression(val)) { if (t.isStringLiteral(acc)) { return t.binaryExpression('+', t.stringLiteral(`${acc.value} `), val) } inner = t.binaryExpression('+', t.stringLiteral(' '), val) } else if (t.isIdentifier(val) || t.isMemberExpression(val)) { // identifiers and member expressions make for reasonable ternaries inner = t.conditionalExpression( val, t.binaryExpression('+', t.stringLiteral(' '), val), t.stringLiteral('') ) } else { if (t.isStringLiteral(acc)) { return t.binaryExpression( '+', t.stringLiteral(`${acc.value} `), t.logicalExpression('||', val, t.stringLiteral('')) ) } // use a logical expression for more complex prop values inner = t.binaryExpression( '+', t.stringLiteral(' '), t.logicalExpression('||', val, t.stringLiteral('')) ) } return t.binaryExpression('+', acc, inner) }, null) }