All files / dist/helpers exports.js

20% Statements 10/50
10.71% Branches 3/28
14.29% Functions 1/7
23.08% Lines 9/39
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    1x     1x 1x   1x   1x   1x   1x   1x   1x                                                                                                                                                            
'use strict';
 
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.collapseNamedExports = collapseNamedExports;
exports.extendDefaultExportWithNamedExports = extendDefaultExportWithNamedExports;
 
require('source-map-support/register');
 
var _babelTypes = require('babel-types');
 
var t = _interopRequireWildcard(_babelTypes);
 
var _templates = require('./templates');
 
var _ast = require('./ast');
 
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 recursively 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 = filterOutExportsWhichAlreadyMatchPropsOnDefault(programNode, defaultExportDeclaration, namedExports);
  if (!namedExports.length) {
    return [];
  } else if (opts.noExportExtend) {
    return namedExports;
  } else {
    return extendDefaultExportWithNamedExports(programNode, defaultExportDeclaration, namedExports);
  }
}
 
function extendDefaultExportWithNamedExports(programNode, defaultExportDeclaration, namedExports) {
  namedExports = [...namedExports]; // Shallow clone for safe splicing
  const variableName = defaultExportDeclaration.name || (0, _ast.getIdName)(defaultExportDeclaration);
  if (!variableName) {
    // Something anonymous
    return namedExports;
  } else if (namedExports.some(exp => exp.conflict)) {
    return namedExports.conflicts.filter(exp => exp.conflict);
  }
 
  const id = t.isIdentifier(defaultExportDeclaration) ? defaultExportDeclaration : t.identifier(variableName);
 
  for (const namedExport of namedExports) {
    programNode.body.push((0, _templates.buildAssign)({
      OBJECT: id,
      NAME: namedExport.key,
      VALUE: namedExport.value
    }));
  }
  return [];
}
 
function filterOutExportsWhichAlreadyMatchPropsOnDefault(programNode, defaultExportDeclaration, namedExports) {
  namedExports = [...namedExports]; // Shallow clone for safe splicing
  const defaultObjectProperties = (0, _ast.findPropertiesOfNode)(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.
  if (defaultObjectProperties) {
    for (const _ref of defaultObjectProperties) {
      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;
}