diff --git a/.gitignore b/.gitignore index f446009999..c775418b4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store -node_modules +/node_modules +/packages/*/node_modules *.log *.cache /.eslintcache diff --git a/packages/babel-core/src/config/loading/files/plugins.js b/packages/babel-core/src/config/loading/files/plugins.js index e6704d5fe0..7828e90d02 100644 --- a/packages/babel-core/src/config/loading/files/plugins.js +++ b/packages/babel-core/src/config/loading/files/plugins.js @@ -5,25 +5,22 @@ */ import resolve from "resolve"; +import path from "path"; -export function resolvePlugin(pluginName: string, dirname: string): string|null { - const possibleNames = [`babel-plugin-${pluginName}`, pluginName]; +const EXACT_RE = /^module:/; +const BABEL_PLUGIN_PREFIX_RE = /^(?!@|module:|[^/\/]+[/\/]|babel-plugin-)/; +const BABEL_PRESET_PREFIX_RE = /^(?!@|module:|[^/\/]+[/\/]|babel-preset-)/; +const BABEL_PLUGIN_ORG_RE = /^(@babel[/\/])(?!plugin-|[^/\/]+[/\/])/; +const BABEL_PRESET_ORG_RE = /^(@babel[/\/])(?!preset-|[^/\/]+[/\/])/; +const OTHER_PLUGIN_ORG_RE = /^(@(?!babel[/\/])[^/\/]+[/\/])(?!babel-plugin-|[^/\/]+[/\/])/; +const OTHER_PRESET_ORG_RE = /^(@(?!babel[/\/])[^/\/]+[/\/])(?!babel-preset-|[^/\/]+[/\/])/; - return resolveFromPossibleNames(possibleNames, dirname); +export function resolvePlugin(name: string, dirname: string): string|null { + return resolveStandardizedName("plugin", name, dirname); } -export function resolvePreset(presetName: string, dirname: string): string|null { - const possibleNames = [`babel-preset-${presetName}`, presetName]; - - // trying to resolve @organization shortcat - // @foo/es2015 -> @foo/babel-preset-es2015 - const matches = presetName.match(/^(@[^/]+)\/(.+)$/); - if (matches) { - const [, orgName, presetPath] = matches; - possibleNames.push(`${orgName}/babel-preset-${presetPath}`); - } - - return resolveFromPossibleNames(possibleNames, dirname); +export function resolvePreset(name: string, dirname: string): string|null { + return resolveStandardizedName("preset", name, dirname); } export function loadPlugin(name: string, dirname: string): { filepath: string, value: mixed } { @@ -47,8 +44,7 @@ export function loadPreset(name: string, dirname: string): { filepath: string, v } export function loadParser(name: string, dirname: string): { filepath: string, value: Function } { - const filepath = resolveQuiet(name, dirname); - if (!filepath) throw new Error(`Parser ${name} not found relative to ${dirname}`); + const filepath = resolve.sync(name, { basedir: dirname }); const mod = requireModule(filepath); @@ -66,8 +62,7 @@ export function loadParser(name: string, dirname: string): { filepath: string, v } export function loadGenerator(name: string, dirname: string): { filepath: string, value: Function } { - const filepath = resolveQuiet(name, dirname); - if (!filepath) throw new Error(`Generator ${name} not found relative to ${dirname}`); + const filepath = resolve.sync(name, { basedir: dirname }); const mod = requireModule(filepath); @@ -84,25 +79,69 @@ export function loadGenerator(name: string, dirname: string): { filepath: string }; } -function resolveQuiet(name: string, dirname: string): string|null { - try { - return resolve.sync(name, { basedir: dirname }); - } catch (e) { - // The 'resolve' module can currently throw ENOTDIR - // https://github.com/substack/node-resolve/issues/121 - if (e.code !== "MODULE_NOT_FOUND" && e.code !== "ENOTDIR") throw e; +function standardizeName(type: "plugin"|"preset", name: string) { + // Let absolute and relative paths through. + if (path.isAbsolute(name)) return name; - // Silently fail and move to the next item. - } - return null; + const isPreset = type === "preset"; + + return name + // foo -> babel-preset-foo + .replace(isPreset ? BABEL_PRESET_PREFIX_RE : BABEL_PLUGIN_PREFIX_RE, `babel-${type}-`) + // @babel/es2015 -> @babel/preset-es2015 + .replace(isPreset ? BABEL_PRESET_ORG_RE : BABEL_PLUGIN_ORG_RE, `$1${type}-`) + // @foo/mypreset -> @foo/babel-preset-mypreset + .replace(isPreset ? OTHER_PRESET_ORG_RE : OTHER_PLUGIN_ORG_RE, `$1babel-${type}-`) + // module:mypreset -> mypreset + .replace(EXACT_RE, ""); } -function resolveFromPossibleNames(possibleNames: Array, dirname: string): string|null { - for (const name of possibleNames) { - const result = resolveQuiet(name, dirname); - if (result !== null) return result; +function resolveStandardizedName(type: "plugin"|"preset", name: string, dirname: string = process.cwd()) { + const standardizedName = standardizeName(type, name); + + try { + return resolve.sync(standardizedName, { basedir: dirname }); + } catch (e) { + if (e.code !== "MODULE_NOT_FOUND") throw e; + + if (standardizedName !== name) { + let resolvedOriginal = false; + try { + resolve.sync(name, { basedir: dirname }); + resolvedOriginal = true; + } catch (e2) { } + + if (resolvedOriginal) { + // eslint-disable-next-line max-len + e.message += `\n- If you want to resolve "${name}", use "module:${name}"`; + } + } + + let resolvedBabel = false; + try { + resolve.sync(standardizeName(type, "@babel/" + name), { basedir: dirname }); + resolvedBabel = true; + } catch (e2) { } + + if (resolvedBabel) { + // eslint-disable-next-line max-len + e.message += `\n- Did you mean "@babel/${name}"?`; + } + + let resolvedOppositeType = false; + const oppositeType = type === "preset" ? "plugin" : "preset"; + try { + resolve.sync(standardizeName(oppositeType, name), { basedir: dirname }); + resolvedOppositeType = true; + } catch (e2) { } + + if (resolvedOppositeType) { + // eslint-disable-next-line max-len + e.message += `\n- Did you accidentally pass a ${type} as a ${oppositeType}?`; + } + + throw e; } - return null; } function requireModule(name: string): mixed { diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index e86f2a54af..63598ab388 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -116,11 +116,13 @@ describe("api", function () { }); it("exposes the resolvePlugin method", function() { - assert.equal(babel.resolvePlugin("nonexistent-plugin"), null); + assert.throws(() => babel.resolvePlugin("nonexistent-plugin"), + /Cannot find module 'babel-plugin-nonexistent-plugin'/); }); it("exposes the resolvePreset method", function() { - assert.equal(babel.resolvePreset("nonexistent-preset"), null); + assert.throws(() => babel.resolvePreset("nonexistent-preset"), + /Cannot find module 'babel-preset-nonexistent-preset'/); }); it("transformFile", function (done) { diff --git a/packages/babel-core/test/fixtures/resolution/babel-org-paths/node_modules/@babel/plugin-foo/index.js b/packages/babel-core/test/fixtures/resolution/babel-org-paths/node_modules/@babel/plugin-foo/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/babel-org-paths/node_modules/@babel/preset-foo/index.js b/packages/babel-core/test/fixtures/resolution/babel-org-paths/node_modules/@babel/preset-foo/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/babel-scoped-nested-module-paths/node_modules/@babel/mod/plugin.js b/packages/babel-core/test/fixtures/resolution/babel-scoped-nested-module-paths/node_modules/@babel/mod/plugin.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/babel-scoped-nested-module-paths/node_modules/@babel/mod/preset.js b/packages/babel-core/test/fixtures/resolution/babel-scoped-nested-module-paths/node_modules/@babel/mod/preset.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/foo-org-paths/node_modules/@foo/babel-plugin-mod/index.js b/packages/babel-core/test/fixtures/resolution/foo-org-paths/node_modules/@foo/babel-plugin-mod/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/foo-org-paths/node_modules/@foo/babel-preset-mod/index.js b/packages/babel-core/test/fixtures/resolution/foo-org-paths/node_modules/@foo/babel-preset-mod/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/module-paths/node_modules/plugin/index.js b/packages/babel-core/test/fixtures/resolution/module-paths/node_modules/plugin/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/module-paths/node_modules/preset/index.js b/packages/babel-core/test/fixtures/resolution/module-paths/node_modules/preset/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/nested-module-paths/node_modules/mod/plugin.js b/packages/babel-core/test/fixtures/resolution/nested-module-paths/node_modules/mod/plugin.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/nested-module-paths/node_modules/mod/preset.js b/packages/babel-core/test/fixtures/resolution/nested-module-paths/node_modules/mod/preset.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/relative-paths/dir/plugin.js b/packages/babel-core/test/fixtures/resolution/relative-paths/dir/plugin.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/relative-paths/dir/preset.js b/packages/babel-core/test/fixtures/resolution/relative-paths/dir/preset.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/.gitignore b/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/.gitignore deleted file mode 100644 index ddf342489b..0000000000 --- a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!node_modules/ diff --git a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/actual.js b/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/actual.js deleted file mode 100644 index 9936933515..0000000000 --- a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/actual.js +++ /dev/null @@ -1 +0,0 @@ -var x = "before"; diff --git a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/expected.js b/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/expected.js deleted file mode 100644 index c981404e30..0000000000 --- a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/expected.js +++ /dev/null @@ -1 +0,0 @@ -var x = "AFTER"; diff --git a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/node_modules/addons/plugin.js b/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/node_modules/addons/plugin.js deleted file mode 100644 index 1ead11c44d..0000000000 --- a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/node_modules/addons/plugin.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = function () { - return { - visitor: { - StringLiteral: function (path) { - path.node.value = "after"; - }, - }, - }; -}; diff --git a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/node_modules/addons/preset.js b/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/node_modules/addons/preset.js deleted file mode 100644 index 1f313cfaa1..0000000000 --- a/packages/babel-core/test/fixtures/resolution/resolve-addons-relative-to-file/node_modules/addons/preset.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = function (context, options, fileContext) { - if (/resolve-addons-relative-to-file$/.test(fileContext.dirname)) { - return { - plugins: [plugin], - }; - } - return {}; -}; - -function plugin () { - return { - visitor: { - StringLiteral: function (path) { - path.node.value = - path.node.value.toUpperCase(); - }, - }, - }; -} diff --git a/packages/babel-core/test/fixtures/resolution/scoped-nested-module-paths/node_modules/@foo/mod/plugin.js b/packages/babel-core/test/fixtures/resolution/scoped-nested-module-paths/node_modules/@foo/mod/plugin.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/scoped-nested-module-paths/node_modules/@foo/mod/preset.js b/packages/babel-core/test/fixtures/resolution/scoped-nested-module-paths/node_modules/@foo/mod/preset.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/standard-paths/node_modules/babel-plugin-mod/index.js b/packages/babel-core/test/fixtures/resolution/standard-paths/node_modules/babel-plugin-mod/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/standard-paths/node_modules/babel-preset-mod/index.js b/packages/babel-core/test/fixtures/resolution/standard-paths/node_modules/babel-preset-mod/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/throw-babel-paths/node_modules/@babel/plugin-foo/index.js b/packages/babel-core/test/fixtures/resolution/throw-babel-paths/node_modules/@babel/plugin-foo/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/throw-babel-paths/node_modules/@babel/preset-foo/index.js b/packages/babel-core/test/fixtures/resolution/throw-babel-paths/node_modules/@babel/preset-foo/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/throw-missing-paths/.gitignore b/packages/babel-core/test/fixtures/resolution/throw-missing-paths/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/throw-module-paths/node_modules/foo/index.js b/packages/babel-core/test/fixtures/resolution/throw-module-paths/node_modules/foo/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/throw-opposite-paths/node_modules/babel-plugin-testplugin/index.js b/packages/babel-core/test/fixtures/resolution/throw-opposite-paths/node_modules/babel-plugin-testplugin/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/fixtures/resolution/throw-opposite-paths/node_modules/babel-preset-testpreset/index.js b/packages/babel-core/test/fixtures/resolution/throw-opposite-paths/node_modules/babel-preset-testpreset/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/babel-core/test/resolution.js b/packages/babel-core/test/resolution.js index da59ea5e51..3df806b515 100644 --- a/packages/babel-core/test/resolution.js +++ b/packages/babel-core/test/resolution.js @@ -1,56 +1,398 @@ import assert from "assert"; -import async from "async"; import * as babel from "../lib/index"; -import fs from "fs"; import path from "path"; -// Test that plugins & presets are resolved relative to `filename`. describe("addon resolution", function () { - it("addon resolution", function (done) { - const fixtures = {}; - const paths = {}; + const base = path.join(__dirname, "fixtures", "resolution"); - paths.fixtures = path.join( - __dirname, - "fixtures", - "resolution", - "resolve-addons-relative-to-file" - ); + beforeEach(function() { + this.cwd = process.cwd(); + process.chdir(base); + }); - async.each( - ["actual", "expected"], - function (key, mapDone) { - paths[key] = path.join(paths.fixtures, key + ".js"); - fs.readFile(paths[key], { encoding: "utf8" }, function (err, data) { - if (err) return mapDone(err); - fixtures[key] = data.trim(); - mapDone(); - }); - }, - fixturesReady - ); + afterEach(function() { + process.chdir(this.cwd); + }); - function fixturesReady (err) { - if (err) return done(err); + it("should find module: presets", function() { + process.chdir("module-paths"); - const orignalCwd = process.cwd(); - try { - process.chdir(paths.fixtures); + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "module:preset", + ], + }); + }); - const actual = babel.transform(fixtures.actual, { - babelrc: false, - filename: paths.actual, - plugins: ["addons/plugin"], - presets: ["addons/preset"], - }).code; + it("should find module: plugins", function() { + process.chdir("module-paths"); - assert.equal(actual, fixtures.expected); - } finally { - process.chdir(orignalCwd); - } + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "module:plugin", + ], + }); + }); - done(); - } - // fixturesReady + it("should find standard presets", function() { + process.chdir("standard-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "mod", + ], + }); + }); + + it("should find standard plugins", function() { + process.chdir("standard-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "mod", + ], + }); + }); + + it("should find standard presets with an existing prefix", function() { + process.chdir("standard-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "babel-preset-mod", + ], + }); + }); + + it("should find standard plugins with an existing prefix", function() { + process.chdir("standard-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "babel-plugin-mod", + ], + }); + }); + + it("should find @babel scoped presets", function() { + process.chdir("babel-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "@babel/foo", + ], + }); + }); + + it("should find @babel scoped plugins", function() { + process.chdir("babel-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "@babel/foo", + ], + }); + }); + + it("should find @babel scoped presets with an existing prefix", function() { + process.chdir("babel-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "@babel/preset-foo", + ], + }); + }); + + it("should find @babel scoped plugins", function() { + process.chdir("babel-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "@babel/plugin-foo", + ], + }); + }); + + it("should find @foo scoped presets", function() { + process.chdir("foo-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "@foo/mod", + ], + }); + }); + + it("should find @foo scoped plugins", function() { + process.chdir("foo-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "@foo/mod", + ], + }); + }); + + it("should find @foo scoped presets with an existing prefix", function() { + process.chdir("foo-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "@foo/babel-preset-mod", + ], + }); + }); + + it("should find @foo scoped plugins with an existing prefix", function() { + process.chdir("foo-org-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "@foo/babel-plugin-mod", + ], + }); + }); + + it("should find relative path presets", function() { + process.chdir("relative-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "./dir/preset.js", + ], + }); + }); + + it("should find relative path plugins", function() { + process.chdir("relative-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "./dir/plugin.js", + ], + }); + }); + + it("should find module file presets", function() { + process.chdir("nested-module-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "mod/preset", + ], + }); + }); + + it("should find module file plugins", function() { + process.chdir("nested-module-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "mod/plugin", + ], + }); + }); + + it("should find @foo scoped module file presets", function() { + process.chdir("scoped-nested-module-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "@foo/mod/preset", + ], + }); + }); + + it("should find @foo scoped module file plugins", function() { + process.chdir("scoped-nested-module-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "@foo/mod/plugin", + ], + }); + }); + + it("should find @babel scoped module file presets", function() { + process.chdir("babel-scoped-nested-module-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "@babel/mod/preset", + ], + }); + }); + + it("should find @babel scoped module file plugins", function() { + process.chdir("babel-scoped-nested-module-paths"); + + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "@babel/mod/plugin", + ], + }); + }); + + it("should throw about module: usage for presets", function() { + process.chdir("throw-module-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "foo", + ], + }); + // eslint-disable-next-line max-len + }, /Cannot find module 'babel-preset-foo'.*\n- If you want to resolve "foo", use "module:foo"/); + }); + + it("should throw about module: usage for plugins", function() { + process.chdir("throw-module-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "foo", + ], + }); + // eslint-disable-next-line max-len + }, /Cannot find module 'babel-plugin-foo'.*\n- If you want to resolve "foo", use "module:foo"/); + }); + + it("should throw about @babel usage for presets", function() { + process.chdir("throw-babel-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "foo", + ], + }); + // eslint-disable-next-line max-len + }, /Cannot find module 'babel-preset-foo'.*\n- Did you mean "@babel\/foo"\?/); + }); + + it("should throw about @babel usage for plugins", function() { + process.chdir("throw-babel-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "foo", + ], + }); + // eslint-disable-next-line max-len + }, /Cannot find module 'babel-plugin-foo'.*\n- Did you mean "@babel\/foo"\?/); + }); + + it("should throw about passing a preset as a plugin", function() { + process.chdir("throw-opposite-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "testplugin", + ], + }); + // eslint-disable-next-line max-len + }, /Cannot find module 'babel-preset-testplugin'.*\n- Did you accidentally pass a preset as a plugin\?/); + }); + + it("should throw about passing a plugin as a preset", function() { + process.chdir("throw-opposite-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "testpreset", + ], + }); + // eslint-disable-next-line max-len + }, /Cannot find module 'babel-plugin-testpreset'.*\n- Did you accidentally pass a plugin as a preset\?/); + }); + + it("should throw about missing presets", function() { + process.chdir("throw-missing-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + presets: [ + "foo", + ], + }); + }, /Cannot find module 'babel-preset-foo'/); + }); + + it("should throw about missing plugins", function() { + process.chdir("throw-missing-paths"); + + assert.throws(() => { + babel.transform("", { + filename: "filename.js", + babelrc: false, + plugins: [ + "foo", + ], + }); + }, /Cannot find module 'babel-plugin-foo'/); }); });