diff --git a/other/mock-modules/babel-plugin-path-replace/index.js b/other/mock-modules/babel-plugin-path-replace/index.js new file mode 100644 index 0000000..0ff6f0a --- /dev/null +++ b/other/mock-modules/babel-plugin-path-replace/index.js @@ -0,0 +1,26 @@ +const types = require('babel-types') + +const problematicVisitor = { + VariableDeclarator: { + enter(path) { + const initPath = path.get('init') + + initPath.replaceWith( + types.sequenceExpression([ + types.stringLiteral('foobar'), + initPath.node, + ]), + ) + }, + }, +} + +module.exports = () => ({ + visitor: { + Program: { + enter(path) { + path.traverse(problematicVisitor) + }, + }, + }, +}) diff --git a/package.json b/package.json index 4d5e644..9c41ae5 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "ast-pretty-print": "^2.0.1", "babel-core": "7.0.0-beta.3", "babel-plugin-tester": "^5.0.0", + "babel-types": "^6.26.0", "babylon": "7.0.0-beta.34", "cpy": "^6.0.0", "kcd-scripts": "^0.32.1" diff --git a/src/__tests__/__snapshots__/index.js.snap b/src/__tests__/__snapshots__/index.js.snap index 2abf393..dfcc0f9 100644 --- a/src/__tests__/__snapshots__/index.js.snap +++ b/src/__tests__/__snapshots__/index.js.snap @@ -143,6 +143,21 @@ Error: The macro imported from "./fixtures/non-wrapped.macro" must be wrapped in `; +exports[`macros when a plugin that replaces paths is used, macros still work properly: when a plugin that replaces paths is used, macros still work properly 1`] = ` + +import myEval from '../eval.macro' + +const result = myEval\`+('4' + '2')\` + +global.result = result + + ↓ ↓ ↓ ↓ ↓ ↓ + +const result = ("foobar", 42); +global.result = result; + +`; + exports[`macros when there is an error reading the config, a helpful message is logged 1`] = ` Array [ There was an error trying to load the config "configurableMacro" for the macro imported from "./configurable.macro. Please see the error thrown for more information., diff --git a/src/__tests__/fixtures/path-replace-issue/.babelrc b/src/__tests__/fixtures/path-replace-issue/.babelrc new file mode 100644 index 0000000..a2fefd5 --- /dev/null +++ b/src/__tests__/fixtures/path-replace-issue/.babelrc @@ -0,0 +1,3 @@ +{ + "plugins": ["path-replace"] +} diff --git a/src/__tests__/fixtures/path-replace-issue/variable-assignment.js b/src/__tests__/fixtures/path-replace-issue/variable-assignment.js new file mode 100644 index 0000000..97f9c01 --- /dev/null +++ b/src/__tests__/fixtures/path-replace-issue/variable-assignment.js @@ -0,0 +1,5 @@ +import myEval from '../eval.macro' + +const result = myEval`+('4' + '2')` + +global.result = result diff --git a/src/__tests__/index.js b/src/__tests__/index.js index 1fae093..549506c 100644 --- a/src/__tests__/index.js +++ b/src/__tests__/index.js @@ -254,5 +254,16 @@ pluginTester({ } }, }, + { + title: + 'when a plugin that replaces paths is used, macros still work properly', + fixture: path.join( + __dirname, + 'fixtures/path-replace-issue/variable-assignment.js', + ), + babelOptions: { + babelrc: true, + }, + }, ], }) diff --git a/src/index.js b/src/index.js index 711611b..393afcc 100644 --- a/src/index.js +++ b/src/index.js @@ -124,7 +124,11 @@ function macrosPlugin(babel, {require: _require = require} = {}) { // eslint-disable-next-line complexity function applyMacros({path, imports, source, state, babel, interopRequire}) { - const {file: {opts: {filename}}} = state + const { + file: { + opts: {filename}, + }, + } = state let hasReferences = false const referencePathsByImportName = imports.reduce( (byName, {importedName, localName}) => { @@ -153,6 +157,18 @@ function applyMacros({path, imports, source, state, babel, interopRequire}) { } const config = getConfig(macro, filename, source) try { + /** + * Other plugins that run before babel-plugin-macros might use path.replace, where a path is + * put into its own replacement. Apparently babel does not update the scope after such + * an operation. As a remedy, the whole scope is traversed again with an empty "Identifier" + * visitor - this makes the problem go away. + * + * See: https://github.com/kentcdodds/import-all.macro/issues/7 + */ + state.file.scope.path.traverse({ + Identifier() {}, + }) + macro({ references: referencePathsByImportName, state,