All files / src index.ts

94.31% Statements 116/123
72.97% Branches 27/37
92.31% Functions 12/13
94.31% Lines 116/123

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 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 1245x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 340x 340x 335x 335x 335x 335x 5x 10x 10x 10x 10x 10x 5x 5x 10x     10x 10x 10x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 18x 18x 18x 18x 18x 5x 18x 18x 18x 18x 18x 18x 17x 18x 5x 18x 18x 18x 18x 18x 18x 18x 18x   5x 5x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 18x 5x 18x 14x 14x         14x 14x 14x 14x 14x 14x 14x 14x 13x 13x 13x 13x 27x 13x 13x 13x 13x 13x  
import { PluginObj, PluginOptions, types } from '@babel/core';
import { format } from 'util';
 
import getModuleExports = require('../lib/internal/getModuleExports');
import prepareModuleExports = require('../lib/internal/prepareModuleExports');
 
const modulesCache = new Map<string, string | undefined>();
function getCachedModules(modules: unknown[]): Map<string, string | undefined> {
  if (!modulesCache.size) {
    for (const { name, indexFile } of prepareModuleExports(modules)) {
      modulesCache.set(name, indexFile);
    }
  }
 
  return modulesCache;
}
 
const moduleExportsCache = new Map<
  string,
  ReturnType<typeof getModuleExports>
>();
 
function getCachedModuleExports(
  name: string,
  modules: unknown[],
): ReturnType<typeof getModuleExports> {
  let moduleExports = moduleExportsCache.get(name);
 
  if (!moduleExports) {
    const cachedModules = getCachedModules(modules);
 
    if (cachedModules.has(name)) {
      moduleExports = getModuleExports(name, cachedModules.get(name));
    } else {
      moduleExports = new Map();
    }
 
    moduleExportsCache.set(name, moduleExports);
  }

  return moduleExports;
}
 
function getModules(opts: PluginOptions): unknown[] {
  if (opts && 'modules' in opts) {
    const { modules } = opts as { modules?: unknown };
 
    if (modules) {
      return Array.isArray(modules) ? modules : [modules];
    }
  }
 
  return [];
}
 
export default function plugin(): PluginObj {
  return {
    visitor: {
      ImportDeclaration(declaration, { opts }) {
        const modules = getModules(opts);
        if (!modules.length) return;
 
        const { source, specifiers, importKind } = declaration.node;
        if (!specifiers.length || importKind === 'type') return;
 
        const moduleExports = getCachedModuleExports(source.value, modules);
        if (!moduleExports.size) return;
 
        for (const specifier of specifiers) {
          if (types.isImportNamespaceSpecifier(specifier)) {
            console.warn(
              format(
                'babel-plugin-direct-import: Can not optimize `import * as %s from "%s"`.'.concat(
                  '\n',
                  'See plugin limitations https://git.io/vFDOO for more details.',
                ),
                specifier.local.name,
                source.value,
              ),
            );
 
            continue;
          }

          const moduleName = types.isImportDefaultSpecifier(specifier)
            ? 'default'
            : types.isIdentifier(specifier.imported)
            ? specifier.imported.name
            : specifier.imported.value;
          const exports = moduleExports.get(moduleName);
 
          if (exports) {
            declaration.node.specifiers = declaration.node.specifiers.filter(
              (x) => x !== specifier,
            );
 
            declaration.insertBefore(
              types.importDeclaration(
                [
                  exports.internal === '*'
                    ? types.importNamespaceSpecifier(
                        types.identifier(specifier.local.name),
                      )
                    : exports.internal === 'default'
                    ? types.importDefaultSpecifier(
                        types.identifier(specifier.local.name),
                      )
                    : types.importSpecifier(
                        types.identifier(specifier.local.name),
                        types.identifier(exports.external),
                      ),
                ],
                types.stringLiteral(exports.source),
              ),
            );
          }
        }
 
        if (!declaration.node.specifiers.length) declaration.remove();
      },
    },
  };
}