153 lines
3.8 KiB
JavaScript
153 lines
3.8 KiB
JavaScript
|
/**
|
||
|
* Copyright (c) 2013-present, Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD-style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
/**
|
||
|
* Rewrites module string literals according to the `map` and `prefix` options.
|
||
|
* This allows other npm packages to be published and used directly without
|
||
|
* being a part of the same build.
|
||
|
*/
|
||
|
function mapModule(state, module) {
|
||
|
var moduleMap = state.opts.map || {};
|
||
|
if (moduleMap.hasOwnProperty(module)) {
|
||
|
return moduleMap[module];
|
||
|
}
|
||
|
// Jest understands the haste module system, so leave modules intact.
|
||
|
if (process.env.NODE_ENV !== 'test') {
|
||
|
var modulePrefix = state.opts.prefix;
|
||
|
if (modulePrefix == null) {
|
||
|
modulePrefix = './';
|
||
|
}
|
||
|
return modulePrefix + module;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
var jestMethods = [
|
||
|
'dontMock',
|
||
|
'genMockFromModule',
|
||
|
'mock',
|
||
|
'setMock',
|
||
|
'unmock',
|
||
|
];
|
||
|
|
||
|
function isJestProperty(t, property) {
|
||
|
return t.isIdentifier(property) && jestMethods.indexOf(property.name) !== -1;
|
||
|
}
|
||
|
|
||
|
module.exports = function(babel) {
|
||
|
|
||
|
var t = babel.types;
|
||
|
|
||
|
/**
|
||
|
* Transforms `require('Foo')` and `require.requireActual('Foo')`.
|
||
|
*/
|
||
|
function transformRequireCall(path, state) {
|
||
|
var calleePath = path.get('callee');
|
||
|
if (
|
||
|
!t.isIdentifier(calleePath.node, {name: 'require'}) &&
|
||
|
!(
|
||
|
t.isMemberExpression(calleePath.node) &&
|
||
|
t.isIdentifier(calleePath.node.object, {name: 'require'}) &&
|
||
|
t.isIdentifier(calleePath.node.property, {name: 'requireActual'})
|
||
|
)
|
||
|
) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var args = path.get('arguments');
|
||
|
if (!args.length) {
|
||
|
return;
|
||
|
}
|
||
|
var moduleArg = args[0];
|
||
|
if (moduleArg.node.type === 'StringLiteral') {
|
||
|
var module = mapModule(state, moduleArg.node.value);
|
||
|
if (module) {
|
||
|
moduleArg.replaceWith(t.stringLiteral(module));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Transforms `import type Bar from 'foo'`
|
||
|
*/
|
||
|
function transformTypeImport(path, state) {
|
||
|
var source = path.get('source');
|
||
|
if (source.type === 'StringLiteral') {
|
||
|
var module = mapModule(state, source.node.value);
|
||
|
if (module) {
|
||
|
source.replaceWith(t.stringLiteral(module));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Transforms either individual or chained calls to `jest.dontMock('Foo')`,
|
||
|
* `jest.mock('Foo')`, and `jest.genMockFromModule('Foo')`.
|
||
|
*/
|
||
|
function transformJestHelper(path, state) {
|
||
|
var calleePath = path.get('callee');
|
||
|
var args = path.get('arguments');
|
||
|
if (!args.length) {
|
||
|
return;
|
||
|
}
|
||
|
var moduleArg = args[0];
|
||
|
if (
|
||
|
moduleArg.node.type === 'StringLiteral' &&
|
||
|
calleePath.node &&
|
||
|
isJestProperty(t, calleePath.node.property)
|
||
|
) {
|
||
|
var module = mapModule(state, moduleArg.node.value);
|
||
|
if (module) {
|
||
|
moduleArg.replaceWith(t.stringLiteral(module));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const jestIdentifier = {
|
||
|
Identifier(path) {
|
||
|
if (path.node.name === 'jest') {
|
||
|
this.isJest = true;
|
||
|
}
|
||
|
},
|
||
|
};
|
||
|
|
||
|
function transformJestCall(path, state) {
|
||
|
let params = {isJest: false};
|
||
|
path.traverse(jestIdentifier, params);
|
||
|
if (params.isJest) {
|
||
|
transformJestHelper(path, state);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
visitor: {
|
||
|
CallExpression: {
|
||
|
exit(path, state) {
|
||
|
if (path.node.seen) {
|
||
|
return;
|
||
|
}
|
||
|
transformRequireCall(path, state);
|
||
|
transformJestCall(path, state);
|
||
|
path.node.seen = true;
|
||
|
},
|
||
|
},
|
||
|
ImportDeclaration: {
|
||
|
exit(path, state) {
|
||
|
let importKind = path.node.importKind;
|
||
|
if (importKind === 'type' || importKind === 'typeof') {
|
||
|
transformTypeImport(path, state);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
};
|
||
|
};
|