All files / style9/src/helpers mutate-ast.js

100% Statements 31/31
100% Branches 12/12
100% Functions 10/10
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 798x 8x 8x 8x     98x 69x 69x   69x 69x   69x     98x       61x       37x 49x 65x                 14x   6x   6x       1x     6x               6x       37x 45x   14x               61x 37x 37x   37x       8x  
const t = require('@babel/types');
const { mapObjectValues } = require('../utils/helpers');
const flattenStyles = require('./flatten-styles');
const generateExpression = require('./generate-expression');
 
function objectToAST(object) {
  const properties = Object.entries(object).map(([name, value]) => {
    const isObject = typeof value === 'object';
    const isIdentifier = t.isValidIdentifier(name, false);
 
    const astValue = isObject ? objectToAST(value) : t.stringLiteral(value);
    const key = isIdentifier ? t.identifier(name) : t.stringLiteral(name);
 
    return t.objectProperty(key, astValue);
  });
 
  return t.objectExpression(properties);
}
 
function replaceCreateCall(callExpr, minifiedDefinitions) {
  callExpr.replaceWith(objectToAST(minifiedDefinitions));
}
 
function flattenClasses(classes) {
  return mapObjectValues(classes, value => {
    return Object.fromEntries(
      flattenStyles(value).map(({ value, ...rest }) => [
        JSON.stringify(rest),
        value
      ])
    );
  });
}
 
function extractNode(path, node) {
  if (t.isIdentifier(node)) return node;
 
  const name = path.scope.generateUidBasedOnNode(node);
 
  if (
    path.scope.path.type !== 'Program' &&
    !Array.isArray(path.scope.path.get('body'))
  ) {
    path.scope.path.ensureBlock();
  }
 
  path
    .getStatementParent()
    .insertBefore(
      t.variableDeclaration('const', [
        t.variableDeclarator(t.identifier(name), node)
      ])
    );
 
  return t.identifier(name);
}
 
function extractArgumentIdentifiers(parentPath, args) {
  return args.map(arg => {
    if (typeof arg === 'string') return arg;
 
    return {
      value: arg.value,
      test: extractNode(parentPath, arg.test)
    };
  });
}
 
function replaceFunctionCalls(normalizedFuncCalls, styleClasses) {
  for (const [callExpr, args] of normalizedFuncCalls) {
    const flatClasses = flattenClasses(styleClasses);
    const replacedArguments = extractArgumentIdentifiers(callExpr, args);
 
    callExpr.replaceWith(generateExpression(replacedArguments, flatClasses));
  }
}
 
module.exports = { replaceCreateCall, replaceFunctionCalls };