babel-plugin-mockable-imports
Advanced tools
Comparing version 1.5.2 to 1.6.0
@@ -8,2 +8,8 @@ # Changelog | ||
## [1.6.0] - 2020-01-20 | ||
- Support mocking CommonJS imports of a specific export in the form | ||
`var alias = require("module/path").exportName` or | ||
`var alias = require("module/path")["exportName"]` [#22](https://github.com/robertknight/babel-plugin-mockable-imports/pull/22) | ||
## [1.5.2] - 2019-11-04 | ||
@@ -10,0 +16,0 @@ |
90
index.js
@@ -47,2 +47,45 @@ "use strict"; | ||
/** | ||
* Parse a `require("...")` expression and return the module path and imported | ||
* symbol name or "<CJS>" if the entire module is being imported. If the expression | ||
* is not recognized as a CommonJS import, return `null`. | ||
* | ||
* Several forms are supported: | ||
* | ||
* 1. require("foo") // Plain require | ||
* 2. require("foo").exportName // Import of a specific export | ||
* 3. require("foo")["exportName"] // Import of a specific export | ||
* 4. (..., ..., require("foo")) // `require` expression wrapped in a sequence expression | ||
* | ||
* Form (4) is often generated by code coverage tools. | ||
*/ | ||
function parseRequireExpression(node) { | ||
if (t.isSequenceExpression(node)) { | ||
node = node.expressions[node.expressions.length - 1]; | ||
} | ||
if (t.isCallExpression(node)) { | ||
const source = commonJSRequireSource(node); | ||
if (source) { | ||
return { source, symbol: "<CJS>" }; | ||
} | ||
} else if (t.isMemberExpression(node) && t.isCallExpression(node.object)) { | ||
const source = commonJSRequireSource(node.object); | ||
if (!source) { | ||
return null; | ||
} | ||
let symbol; | ||
if (t.isIdentifier(node.property)) { | ||
symbol = node.property.name; | ||
} else if (t.isLiteral(node.property)) { | ||
symbol = node.property.value; | ||
} else { | ||
return null; | ||
} | ||
return { source, symbol }; | ||
} else { | ||
return null; | ||
} | ||
} | ||
/** | ||
* Create an `$imports.$add(alias, source, symbol, value)` method call. | ||
@@ -104,10 +147,2 @@ */ | ||
function lastExprInSequence(node) { | ||
if (t.isSequenceExpression(node)) { | ||
return node.expressions[node.expressions.length - 1]; | ||
} else { | ||
return node; | ||
} | ||
} | ||
// Visitor which collects information about CommonJS imports in a variable | ||
@@ -117,19 +152,9 @@ // declaration and populates `state.imports`. | ||
VariableDeclarator(path, { excludeImportsFromModules, imports }) { | ||
// If the `require` is wrapped in some way, we just ignore it, since | ||
// we cannot determine which symbols are being required without knowing | ||
// what the wrapping expression does. | ||
// | ||
// An exception is made where the `require` statement is wrapped in | ||
// a sequence (`var foo = (..., require('blah'))`) as some code coverage | ||
// transforms do. We know in this case that the result will be the | ||
// result of the require. | ||
const init = lastExprInSequence(path.node.init); | ||
if (!t.isCallExpression(init)) { | ||
let requireInfo = parseRequireExpression(path.node.init); | ||
if (!requireInfo) { | ||
return; | ||
} | ||
const source = commonJSRequireSource(init); | ||
if (!source) { | ||
return; | ||
} | ||
const { source, symbol } = requireInfo; | ||
if (excludeImportsFrom(source, excludeImportsFromModules)) { | ||
@@ -148,3 +173,2 @@ return; | ||
const symbol = "<CJS>"; | ||
imports.push({ | ||
@@ -277,20 +301,14 @@ alias: id.name, | ||
// Handle Common JS imports where the variable declaration and | ||
// initialization are separate. ie. `var foo; foo = require("./foo")`. | ||
// | ||
// Currently there is no support for destructuring here or anything on | ||
// the right side of the assignment other than the `require` call. | ||
if ( | ||
!t.isIdentifier(path.node.left) || | ||
!t.isCallExpression(path.node.right) | ||
) { | ||
if (!t.isIdentifier(path.node.left)) { | ||
return; | ||
} | ||
const ident = path.node.left; | ||
const callExpr = path.node.right; | ||
const source = commonJSRequireSource(callExpr); | ||
if (!source) { | ||
const requireInfo = parseRequireExpression(path.node.right); | ||
if (!requireInfo) { | ||
return; | ||
} | ||
const { source, symbol } = requireInfo; | ||
// Look up the original identifier node that introduced this binding. | ||
@@ -312,3 +330,3 @@ const binding = path.scope.getBinding(ident.name, /* noGlobal */ true); | ||
path.insertAfter( | ||
createAddImportCall(ident.name, source, "<CJS>", ident) | ||
createAddImportCall(ident.name, source, symbol, ident) | ||
); | ||
@@ -315,0 +333,0 @@ }, |
{ | ||
"name": "babel-plugin-mockable-imports", | ||
"version": "1.5.2", | ||
"version": "1.6.0", | ||
"description": "Babel plugin for mocking ES imports", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38372
569