All files / src/helpers validate.js

97.22% Statements 35/36
95.45% Branches 21/22
100% Functions 8/8
100% Lines 31/31

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 79 80 81 82 83 84 85 86 87 88 89 90 91 928x 8x 8x         8x     1x                             70x 62x 62x 17x 15x           1x                   130x 130x 1x     129x 30x     99x       117x   130x   130x   27x   2x 2x 25x 24x 24x   1x                       74x 93x 93x       8x  
const assert = require('assert');
const testASTShape = require('../utils/test-ast-shape');
const { evaluateNodePath } = require('../utils/ast');
const {
  isAtRuleObject,
  isAtRule,
  isPseudoSelector
} = require('../utils/styles');
 
function isHMR(identifier) {
  return testASTShape(identifier.parentPath, {
    type: 'CallExpression',
    callee: {
      type: 'MemberExpression',
      object: {
        name: 'reactHotLoader'
      },
      property: {
        name: 'register'
      }
    }
  });
}
 
function validateReferences(references) {
  references.forEach(ref => {
    const { parentPath, parent, node } = ref;
    if (parentPath.isCallExpression() && parent.callee === node) return;
    if (parentPath.isSpreadElement()) return;
    if (parentPath.isMemberExpression()) return;
 
    // The return value from `style9.create` should be a function, but the
    // compiler turns it into an object. Therefore only access to properties
    // is allowed. React Hot Loader accesses all bindings, so a temporary
    // workaround is required. React Fast Refresh does not have this problem.
    assert(
      isHMR(ref),
      ref.buildCodeFrameError(
        'Return value from style9.create has to be called as a function or accessed as an object'
      )
    );
  });
}
 
function evalKey(objProp) {
  const keyPath = objProp.get('key');
  if (objProp.node.computed) {
    return evaluateNodePath(keyPath);
  }
 
  if (keyPath.isStringLiteral()) {
    return keyPath.node.value;
  }
 
  return keyPath.node.name;
}
 
function validateStyleObjectInner(objExpr) {
  objExpr.traverse({
    ObjectProperty(path) {
      const key = evalKey(path);
 
      if (!path.get('value').isObjectExpression()) return;
 
      if (isAtRuleObject(key)) {
        // Skip direct props
        validateStyleObject(path.get('value'));
        path.skip();
      } else if (isAtRule(key) || isPseudoSelector(key)) {
        validateStyleObjectInner(path.get('value'));
        path.skip();
      } else {
        throw path
          .get('key')
          .buildCodeFrameError(
            `Invalid key ${key}. Object keys must be at-rules or pseudo selectors`
          );
      }
    }
  });
}
 
// Does not validate spread elements
function validateStyleObject(objExpr) {
  objExpr.get('properties').forEach(prop => {
    Iif (!prop.isObjectProperty()) return;
    validateStyleObjectInner(prop.get('value'));
  });
}
 
module.exports = { validateReferences, validateStyleObject };