import * as babel from "../lib/index"; import buildExternalHelpers from "../lib/tools/build-external-helpers"; import sourceMap from "source-map"; import assert from "assert"; import Plugin from "../lib/transformation/plugin"; import generator from "babel-generator"; function assertIgnored(result) { assert.ok(result.ignored); } function assertNotIgnored(result) { assert.ok(!result.ignored); } // shim function transformAsync(code, opts) { return { then: function (resolve) { resolve(babel.transform(code, opts)); }, }; } describe("parser and generator options", function() { const recast = { parse: function(code, opts) { return opts.parser.parse(code); }, print: function(ast) { return generator(ast); }, }; function newTransform(string) { return babel.transform(string, { parserOpts: { parser: recast.parse, plugins: ["flow"], allowImportExportEverywhere: true, }, generatorOpts: { generator: recast.print, }, }); } it("options", function() { const string = "original;"; assert.deepEqual(newTransform(string).ast, babel.transform(string).ast); assert.equal(newTransform(string).code, string); }); it("experimental syntax", function() { const experimental = "var a: number = 1;"; assert.deepEqual(newTransform(experimental).ast, babel.transform(experimental, { parserOpts: { plugins: ["flow"], }, }).ast); assert.equal(newTransform(experimental).code, experimental); function newTransformWithPlugins(string) { return babel.transform(string, { plugins: [__dirname + "/../../babel-plugin-syntax-flow"], parserOpts: { parser: recast.parse, }, generatorOpts: { generator: recast.print, }, }); } assert.deepEqual(newTransformWithPlugins(experimental).ast, babel.transform(experimental, { parserOpts: { plugins: ["flow"], }, }).ast); assert.equal(newTransformWithPlugins(experimental).code, experimental); }); it("other options", function() { const experimental = "if (true) {\n import a from 'a';\n}"; assert.notEqual(newTransform(experimental).ast, babel.transform(experimental, { parserOpts: { allowImportExportEverywhere: true, }, }).ast); assert.equal(newTransform(experimental).code, experimental); }); }); describe("api", function () { it("analyze", function () { assert.equal(babel.analyse("foobar;").marked.length, 0); assert.equal(babel.analyse("foobar;", { plugins: [new Plugin({ visitor: { Program: function (path) { path.mark("category", "foobar"); }, }, })], }).marked[0].message, "foobar"); assert.equal(babel.analyse("foobar;", {}, { Program: function (path) { path.mark("category", "foobar"); }, }).marked[0].message, "foobar"); }); it("exposes the resolvePlugin method", function() { assert.equal(babel.resolvePlugin("nonexistent-plugin"), null); }); it("exposes the resolvePreset method", function() { assert.equal(babel.resolvePreset("nonexistent-preset"), null); }); it("transformFile", function (done) { babel.transformFile(__dirname + "/fixtures/api/file.js", {}, function (err, res) { if (err) return done(err); assert.equal(res.code, "foo();"); done(); }); }); it("transformFileSync", function () { assert.equal(babel.transformFileSync(__dirname + "/fixtures/api/file.js", {}).code, "foo();"); }); it("options throw on falsy true", function () { return assert.throws( function () { babel.transform("", { plugins: [__dirname + "/../../babel-plugin-syntax-jsx", false], }); }, /TypeError: Falsy value found in plugins/ ); }); it("options merge backwards", function () { return transformAsync("", { presets: [__dirname + "/../../babel-preset-es2015"], plugins: [__dirname + "/../../babel-plugin-syntax-jsx"], }).then(function (result) { assert.ok(result.options.plugins[0][0].manipulateOptions.toString().indexOf("jsx") >= 0); }); }); it("option wrapPluginVisitorMethod", function () { let calledRaw = 0; let calledIntercept = 0; babel.transform("function foo() { bar(foobar); }", { wrapPluginVisitorMethod: function (pluginAlias, visitorType, callback) { if (pluginAlias !== "foobar") { return callback; } assert.equal(visitorType, "enter"); return function () { calledIntercept++; return callback.apply(this, arguments); }; }, plugins: [new Plugin({ name: "foobar", visitor: { "Program|Identifier": function () { calledRaw++; }, }, })], }); assert.equal(calledRaw, 4); assert.equal(calledIntercept, 4); }); it("pass per preset", function () { let aliasBaseType = null; function execTest(passPerPreset) { return babel.transform("type Foo = number; let x = (y): Foo => y;", { passPerPreset: passPerPreset, presets: [ // First preset with our plugin, "before" function () { return { plugins: [ new Plugin({ visitor: { Function: function (path) { const alias = path.scope.getProgramParent().path.get("body")[0].node; if (!babel.types.isTypeAlias(alias)) return; // In case of `passPerPreset` being `false`, the // alias node is already removed by Flow plugin. if (!alias) { return; } // In case of `passPerPreset` being `true`, the // alias node should still exist. aliasBaseType = alias.right.type; // NumberTypeAnnotation }, }, }), ], }; }, // ES2015 preset require(__dirname + "/../../babel-preset-es2015"), // Third preset for Flow. function () { return { plugins: [ require(__dirname + "/../../babel-plugin-syntax-flow"), require(__dirname + "/../../babel-plugin-transform-flow-strip-types"), ], }; }, ], }); } // 1. passPerPreset: true let result = execTest(true); assert.equal(aliasBaseType, "NumberTypeAnnotation"); assert.deepEqual([ "\"use strict\";", "", "var x = function x(y) {", " return y;", "};", ].join("\n"), result.code); // 2. passPerPreset: false aliasBaseType = null; result = execTest(false); assert.equal(aliasBaseType, null); assert.deepEqual([ "\"use strict\";", "", "var x = function x(y) {", " return y;", "};", ].join("\n"), result.code); }); it("source map merging", function () { const result = babel.transform([ /* eslint-disable max-len */ "function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }", "", "let Foo = function Foo() {", " _classCallCheck(this, Foo);", "};", "", "//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZG91dCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztJQUFNLEdBQUcsWUFBSCxHQUFHO3dCQUFILEdBQUciLCJmaWxlIjoidW5kZWZpbmVkIiwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgRm9vIHt9XG4iXX0=", /* eslint-enable max-len */ ].join("\n"), { sourceMap: true, }); assert.deepEqual([ "function _classCallCheck(instance, Constructor) {", " if (!(instance instanceof Constructor)) {", " throw new TypeError(\"Cannot call a class as a function\");", " }", "}", "", "let Foo = function Foo() {", " _classCallCheck(this, Foo);", "};", ].join("\n"), result.code); const consumer = new sourceMap.SourceMapConsumer(result.map); assert.deepEqual(consumer.originalPositionFor({ line: 7, column: 4, }), { name: null, source: "stdout", line: 1, column: 6, }); }); it("code option false", function () { return transformAsync("foo('bar');", { code: false }).then(function (result) { assert.ok(!result.code); }); }); it("ast option false", function () { return transformAsync("foo('bar');", { ast: false }).then(function (result) { assert.ok(!result.ast); }); }); it("auxiliaryComment option", function () { return transformAsync("class Foo {}", { auxiliaryCommentBefore: "before", auxiliaryCommentAfter: "after", plugins: [function (babel) { const t = babel.types; return { visitor: { Program: function (path) { path.unshiftContainer("body", t.expressionStatement(t.identifier("start"))); path.pushContainer("body", t.expressionStatement(t.identifier("end"))); }, }, }; }], }).then(function (result) { assert.equal(result.code, "/*before*/start;\n/*after*/class Foo {}\n/*before*/end;\n/*after*/"); }); }); it("modules metadata", function () { return Promise.all([ // eslint-disable-next-line max-len transformAsync("import { externalName as localName } from \"external\";").then(function (result) { assert.deepEqual(result.metadata.modules.imports[0], { source: "external", imported: ["externalName"], specifiers: [{ kind: "named", imported: "externalName", local: "localName", }], }); }), transformAsync("import * as localName2 from \"external\";").then(function (result) { assert.deepEqual(result.metadata.modules.imports[0], { source: "external", imported: ["*"], specifiers: [{ kind: "namespace", local: "localName2", }], }); }), transformAsync("import localName3 from \"external\";").then(function (result) { assert.deepEqual(result.metadata.modules.imports[0], { source: "external", imported: ["default"], specifiers: [{ kind: "named", imported: "default", local: "localName3", }], }); }), transformAsync("import localName from \"./array\";", { resolveModuleSource: function() { return "override-source"; }, }).then(function (result) { assert.deepEqual(result.metadata.modules.imports, [ { source: "override-source", imported: ["default"], specifiers: [ { "kind": "named", "imported": "default", "local": "localName", }, ], }, ]); }), transformAsync("export * as externalName1 from \"external\";", { plugins: [require("../../babel-plugin-syntax-export-extensions")], }).then(function (result) { assert.deepEqual(result.metadata.modules.exports, { exported: ["externalName1"], specifiers: [{ kind: "external-namespace", exported: "externalName1", source: "external", }], }); }), transformAsync("export externalName2 from \"external\";", { plugins: [require("../../babel-plugin-syntax-export-extensions")], }).then(function (result) { assert.deepEqual(result.metadata.modules.exports, { exported: ["externalName2"], specifiers: [{ kind: "external", local: "externalName2", exported: "externalName2", source: "external", }], }); }), transformAsync("export function namedFunction() {}").then(function (result) { assert.deepEqual(result.metadata.modules.exports, { exported: ["namedFunction"], specifiers: [{ kind: "local", local: "namedFunction", exported: "namedFunction", }], }); }), transformAsync("export var foo = \"bar\";").then(function (result) { assert.deepEqual(result.metadata.modules.exports, { "exported": ["foo"], specifiers: [{ kind: "local", local: "foo", exported: "foo", }], }); }), transformAsync("export { localName as externalName3 };").then(function (result) { assert.deepEqual(result.metadata.modules.exports, { exported: ["externalName3"], specifiers: [{ kind: "local", local: "localName", exported: "externalName3", }], }); }), transformAsync("export { externalName4 } from \"external\";").then(function (result) { assert.deepEqual(result.metadata.modules.exports, { exported: ["externalName4"], specifiers: [{ kind: "external", local: "externalName4", exported: "externalName4", source: "external", }], }); }), transformAsync("export * from \"external\";").then(function (result) { assert.deepEqual(result.metadata.modules.exports, { exported: [], specifiers: [{ kind: "external-all", source: "external", }], }); }), transformAsync("export default function defaultFunction() {}").then(function (result) { assert.deepEqual(result.metadata.modules.exports, { exported: ["defaultFunction"], specifiers: [{ kind: "local", local: "defaultFunction", exported: "default", }], }); }), ]); }); it("ignore option", function () { return Promise.all([ transformAsync("", { ignore: "node_modules", filename: "/foo/node_modules/bar", }).then(assertIgnored), transformAsync("", { ignore: "foo/node_modules", filename: "/foo/node_modules/bar", }).then(assertIgnored), transformAsync("", { ignore: "foo/node_modules/*.bar", filename: "/foo/node_modules/foo.bar", }).then(assertIgnored), ]); }); it("only option", function () { return Promise.all([ transformAsync("", { only: "node_modules", filename: "/foo/node_modules/bar", }).then(assertNotIgnored), transformAsync("", { only: "foo/node_modules", filename: "/foo/node_modules/bar", }).then(assertNotIgnored), transformAsync("", { only: "foo/node_modules/*.bar", filename: "/foo/node_modules/foo.bar", }).then(assertNotIgnored), transformAsync("", { only: "node_modules", filename: "/foo/node_module/bar", }).then(assertIgnored), transformAsync("", { only: "foo/node_modules", filename: "/bar/node_modules/foo", }).then(assertIgnored), transformAsync("", { only: "foo/node_modules/*.bar", filename: "/foo/node_modules/bar.foo", }).then(assertIgnored), ]); }); describe("env option", function () { const oldBabelEnv = process.env.BABEL_ENV; const oldNodeEnv = process.env.NODE_ENV; setup(function () { // Tests need to run with the default and specific values for these. They // need to be cleared for each test. delete process.env.BABEL_ENV; delete process.env.NODE_ENV; }); suiteTeardown(function () { process.env.BABEL_ENV = oldBabelEnv; process.env.NODE_ENV = oldNodeEnv; }); it("default", function () { const result = babel.transform("foo;", { env: { development: { code: false }, }, }); assert.equal(result.code, undefined); }); it("BABEL_ENV", function () { process.env.BABEL_ENV = "foo"; const result = babel.transform("foo;", { env: { foo: { code: false }, }, }); assert.equal(result.code, undefined); }); it("NODE_ENV", function () { process.env.NODE_ENV = "foo"; const result = babel.transform("foo;", { env: { foo: { code: false }, }, }); assert.equal(result.code, undefined); }); }); it("resolveModuleSource option", function () { /* eslint-disable max-len */ const actual = "import foo from \"foo-import-default\";\nimport \"foo-import-bare\";\nexport { foo } from \"foo-export-named\";"; const expected = "import foo from \"resolved/foo-import-default\";\nimport \"resolved/foo-import-bare\";\nexport { foo } from \"resolved/foo-export-named\";"; /* eslint-enable max-len */ return transformAsync(actual, { resolveModuleSource: function (originalSource) { return "resolved/" + originalSource; }, }).then(function (result) { assert.equal(result.code.trim(), expected); }); }); describe("buildExternalHelpers", function () { it("all", function () { const script = buildExternalHelpers(); assert.ok(script.indexOf("classCallCheck") >= -1); assert.ok(script.indexOf("inherits") >= 0); }); it("whitelist", function () { const script = buildExternalHelpers(["inherits"]); assert.ok(script.indexOf("classCallCheck") === -1); assert.ok(script.indexOf("inherits") >= 0); }); it("empty whitelist", function () { const script = buildExternalHelpers([]); assert.ok(script.indexOf("classCallCheck") === -1); assert.ok(script.indexOf("inherits") === -1); }); it("underscored", function () { const script = buildExternalHelpers(["typeof"]); assert.ok(script.indexOf("typeof") >= 0); }); }); });