All files / dist/helpers exports.js

84.62% Statements 55/65
73.58% Branches 39/53
100% Functions 8/8
100% Lines 52/52
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    1x     1x 1x   1x   1x   1x   1x   2x                                   19x   19x 4x           28x 4x   4x         11x 11x   11x   4x     4x 4x     11x   11x 24x             11x               11x       19x   19x     19x 17x 97x   2x     632x   95x   95x 72x 68x   4x           19x       72x 72x   72x   1x 71x 66x   66x   63x 3x   2x   5x     5x     3x         3x  
"use strict";
 
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.collapseNamedExports = collapseNamedExports;
exports.getDefaultExportName = getDefaultExportName;
 
require("source-map-support/register");
 
var _core = require("@babel/core");
 
var th = _interopRequireWildcard(require("./templates"));
 
var ast = _interopRequireWildcard(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)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { 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, defaultExport, namedExports, opts) {
  namedExports = filterOutExportsWhichAlreadyMatchPropsOnDefault(programNode, defaultExport, namedExports);
 
  if (!namedExports.length || opts.noExportExtend) {
    return {
      filteredExports: namedExports,
      newDefaultExportIdentifier: null
    };
  }
 
  if (namedExports.some(exp => exp.conflict)) {
    return {
      filteredExports: namedExports,
      conflictingExports: namedExports.filter(exp => exp.conflict),
      newDefaultExportIdentifier: null
    };
  }
 
  let exportVariableName = getDefaultExportName(defaultExport);
  let newDefaultExportIdentifier = null;
 
  if (!exportVariableName) {
    // Something anonymous (literal, anon function, etc...)
    programNode.body.push(th.buildTempExport({
      VALUE: defaultExport
    }));
    newDefaultExportIdentifier = th.exportsIdentifier;
    exportVariableName = newDefaultExportIdentifier.name;
  }
 
  const id = _core.types.identifier(exportVariableName);
 
  for (const namedExport of namedExports) {
    programNode.body.push(th.buildAssign({
      OBJECT: id,
      NAME: namedExport.key,
      VALUE: namedExport.value
    }));
  }
 
  return {
    filteredExports: [],
    conflictingExports: [],
    newDefaultExportIdentifier: newDefaultExportIdentifier
  };
}
 
function getDefaultExportName(defaultExport) {
  return defaultExport.name || ast.getIdName(defaultExport);
}
 
function filterOutExportsWhichAlreadyMatchPropsOnDefault(programNode, defaultExport, namedExports) {
  namedExports = [...namedExports]; // Shallow clone for safe splicing
 
  const defaultObjectProperties = ast.findPropertiesOfNode(programNode, defaultExport); // 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 defaultExportProperty of defaultObjectProperties) {
      if (!defaultExportProperty.key) {
        // i.e. SpreadProperty
        continue;
      }
 
      const matchingNamedExportIndex = namedExports.findIndex(namedExport => namedExport.key.name === defaultExportProperty.key.name); // get the index for splicing
 
      const matchingNamedExport = namedExports[matchingNamedExportIndex];
 
      if (matchingNamedExport && !matchingNamedExport.conflict) {
        if (areSame(defaultExportProperty, matchingNamedExport)) {
          namedExports.splice(matchingNamedExportIndex, 1);
        } else {
          matchingNamedExport.conflict = true;
        }
      }
    }
  }
 
  return namedExports;
}
 
function areSame(defaultExportProperty, matchingNamedExport) {
  const defaultExportValue = defaultExportProperty.value;
  const declaration = matchingNamedExport.declaration; // i.e. 'export const a = 1' or 'export let a = b'
 
  if (!defaultExportValue) {
    // i.e. object method
    return false; // always a conflict
  } else if (_core.types.isIdentifier(defaultExportValue)) {
    const valueName = defaultExportValue.name;
 
    if (valueName === matchingNamedExport.value.name) {
      // Same identifier reference. Safe to ignore
      return true;
    } else if (declaration && _core.types.isIdentifier(declaration.init) && declaration.init.name === valueName) {
      // i.e. 'export let a = b', and default value for a is 'b'.
      return true;
    }
  } else Eif (_core.types.isLiteral(defaultExportValue)) {
    // i.e. { a: 1 } or { a: '1' }
    // See if the original declaration for the matching export was for the same literal
    if (_core.types.isLiteral(declaration.init) && declaration.init.value === defaultExportValue.value) {
      // i.e. 'export const a = 1'
      // Same literal. Safe to ignore
      return true;
    }
  } // Either a conflicting value or no value at all (i.e. method)
 
 
  return false;
}