All files / dist/helpers exports.js

86.17% Statements 81/94
78.79% Branches 52/66
95.65% Functions 22/23
93.42% Lines 71/76
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188    1x     1x 1x 1x 1x 1x   1x   1x   1x   1x   1x   1x   1x   1x   1x                                   11x 11x 11x 5x 6x     6x         6x   6x     2x 8x       4x   4x 8x           4x       11x 11x       11x 11x 57x   57x   113x 41x 41x 32x   31x   1x             11x       11x 11x   11x 3x     8x 1x     7x 5x     2x 2x                 6x                     11x 99x   13x 13x 9x   1x         8x 8x   4x       86x   48x   99x         3x 12x 7x 5x   5x               2x  
'use strict';
 
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.collapseNamedExports = collapseNamedExports;
exports.extendDefaultExportWithNamedExports = extendDefaultExportWithNamedExports;
exports.filterOutExportsWhichMatchPropsOnDefault = filterOutExportsWhichMatchPropsOnDefault;
exports.findPropertiesOfDeclaration = findPropertiesOfDeclaration;
exports.getPropNames = getPropNames;
 
require('source-map-support/register');
 
var _babelTypes = require('babel-types');
 
var t = _interopRequireWildcard(_babelTypes);
 
var _arrayFlatten = require('array-flatten');
 
var _arrayFlatten2 = _interopRequireDefault(_arrayFlatten);
 
var _ast = require('./ast');
 
var _templates = require('./templates');
 
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
function _interopRequireWildcard(obj) { Eif (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
 
/**
 * Collapse named exports onto the default export so that the default export can be returned directly,
 * so that exports can be easily used by code that does not include an import interop.
 * This includes the following:
 *  - Ignore named exports that already exist on the default export and which reference the same identifer.
 *  - If possible, assign any remaining exports to the default export.
 *    - This cannot be done if there is a naming conflict.
 *
 * In order to determine what properties the default export already has, the plugin will scan the
 * top level of the program to find any assignments, including Object.assign() and _extend() calls.
 * It does this recurively in the case of those method calls.
 *
 * If there are any named exports left, they get returned, so the main plugin can check the opts
 * and decide if an error should be thrown.
 */
function collapseNamedExports(programNode, defaultExportDeclaration, namedExports, opts) {
  namedExports = [...namedExports];
  namedExports = filterOutExportsWhichMatchPropsOnDefault(programNode, defaultExportDeclaration, namedExports);
  if (!namedExports.length) {
    return [];
  } else Iif (opts.noExportExtend) {
    return namedExports;
  } else {
    return extendDefaultExportWithNamedExports(programNode, defaultExportDeclaration, namedExports);
  }
}
 
function extendDefaultExportWithNamedExports(programNode, defaultExportDeclaration, namedExports) {
  namedExports = [...namedExports]; // Shallow clone for safe splicing
 
  if (!defaultExportDeclaration.name) {
    // Something anonymous
    //TODO see if we can give it a name
    return namedExports;
  } else Iif (namedExports.some(exp => exp.conflict)) {
    return namedExports.conflicts.filter(exp => exp.conflict);
  }
 
  const id = t.isIdentifier(defaultExportDeclaration) ? defaultExportDeclaration : t.identifier(defaultExportDeclaration.name);
 
  for (const namedExport of namedExports) {
    programNode.body.push((0, _templates.buildAssign)({
      OBJECT: id,
      NAME: namedExport.key,
      VALUE: namedExport.value
    }));
  }
  return [];
}
 
function filterOutExportsWhichMatchPropsOnDefault(programNode, defaultExportDeclaration, namedExports) {
  namedExports = [...namedExports]; // Shallow clone for safe splicing
  const defaultObjectInfo = findPropertiesOfDeclaration(programNode, defaultExportDeclaration);
 
  // Loop through the default object's props and see if it already has a matching definition of the named exports.
  // If the definition matches, we can ignore the named export. If the definition does not match, mark it as a conflict.
  Eif (defaultObjectInfo.properties) {
    for (const _ref of defaultObjectInfo.properties) {
      const { key, value } = _ref;
 
      if (t.isIdentifier(value)) {
        //let matchingNamedExportIndex = -1
        const matchingNamedExportIndex = namedExports.findIndex(namedExport => namedExport.key.name === key.name);
        const matchingNamedExport = namedExports[matchingNamedExportIndex];
        if (matchingNamedExport) {
          if (value.name === matchingNamedExport.value.name) {
            // Safe to ignore
            namedExports.splice(matchingNamedExportIndex, 1);
          } else {
            namedExports.conflict = true;
          }
        }
      }
    }
  }
 
  return namedExports;
}
 
function findPropertiesOfDeclaration(programNode, declaration) {
  const { type } = declaration;
  Iif (t.isFunctionDeclaration(declaration) || t.isArrowFunctionExpression(declaration)) {
    return { type };
  } else if (t.isObjectExpression(declaration)) {
    return {
      type, properties: declaration.properties
    };
  } else if (t.isClassDeclaration(declaration)) {
    return {
      type, properties: [...getStaticThingsOfClassDeclaration(declaration), ...getOtherPropertyOfIdentifier(programNode, declaration.id.name)]
    };
  } else if (t.isIdentifier(declaration)) {
    return {
      type, properties: getOtherPropertyOfIdentifier(programNode, declaration.name)
    };
  } else Eif ((0, _ast.isObjectAssignOrExtendsExpression)(declaration)) {
    return {
      type, properties: getPropertiesOfObjectAssignOrExtendHelper(declaration, programNode)
    };
  }
  // console.log(require('util').inspect(declaration, { depth: null }));
  return { type };
}
 
function getStaticThingsOfClassDeclaration(classDeclaration) {
  return classDeclaration.body.body.filter(item => item.static);
}
 
/**
 * Traverse the top level of the program body looking for either:
 *  - ObjectExpression assignments to the object variable.
 *  - Property assignments directly to our object (but not to nested properties).
 *
 *  @return Array<{key, value}>
 */
function getOtherPropertyOfIdentifier(programNode, idName) {
  return (0, _arrayFlatten2.default)(programNode.body.map(node => {
    if (t.isExpressionStatement(node)) {
      // ID = value | ID.key = value | ID.key.nested = value
      const { left, right } = node.expression;
      if (t.isAssignmentExpression(node.expression)) {
        if (t.isIdentifier(left) && left.name === idName) {
          // ID = value
          Iif (t.isObjectExpression(right)) {
            // ID = {}
            return right.properties; // Array<ObjectProperty>
          }
        } else {
          const { object, property: key } = left;
          if (t.isIdentifier(object) && object.name === idName) {
            // ID.key = value
            return { key, value: right }; // ObjectProperty-like (key, value)
          }
        }
      }
    } else if (t.isVariableDeclaration(node)) {
      // console.log(require('util').inspect(node, { depth: 4 }));
      return node.declarations.filter(declaration => declaration.id.name === idName).map(declaration => declaration.init).filter(init => init).filter(init => t.isObjectExpression(init) || (0, _ast.isObjectAssignOrExtendsExpression)(init)).map(init => t.isObjectExpression(init) ? init.properties : getPropertiesOfObjectAssignOrExtendHelper(init, programNode));
    }
  }).filter(item => item));
}
 
function getPropertiesOfObjectAssignOrExtendHelper(node, programNode) {
  // Object.assign(...). Check all the args and recursively try to get props of identifiers (although they may be imported)
  return (0, _arrayFlatten2.default)(node.arguments.map(arg => {
    if (t.isObjectExpression(arg)) {
      return arg.properties;
    } else Eif (t.isIdentifier(arg)) {
      // recurse. although props will be empty if arg is an imported object
      return getOtherPropertyOfIdentifier(programNode, arg.name);
    }
  }));
}
 
// function getPropsFromObjectAssign()
 
function getPropNames(props) {
  return props.map(prop => prop.key.name);
}