diff --git a/packages/babel-core/package.json b/packages/babel-core/package.json index bf763769b6e7..8db53bca0f7c 100644 --- a/packages/babel-core/package.json +++ b/packages/babel-core/package.json @@ -49,6 +49,7 @@ "devDependencies": { "babel-helper-fixtures": "^6.9.0", "babel-helper-transform-fixture-test-runner": "^6.9.0", - "babel-polyfill": "^6.9.1" + "babel-polyfill": "^6.9.1", + "recast": "^0.11.10" } } diff --git a/packages/babel-core/src/transformation/file/index.js b/packages/babel-core/src/transformation/file/index.js index e4f5dbcbcb6f..13df4a7f14f1 100644 --- a/packages/babel-core/src/transformation/file/index.js +++ b/packages/babel-core/src/transformation/file/index.js @@ -21,6 +21,8 @@ import * as util from "../../util"; import path from "path"; import * as t from "babel-types"; +import resolve from "../../helpers/resolve"; + import blockHoistPlugin from "../internal-plugins/block-hoist"; import shadowFunctionsPlugin from "../internal-plugins/shadow-functions"; @@ -410,8 +412,30 @@ export default class File extends Store { } parse(code: string) { + let opts = this.opts; + let parseCode = parse; + if (opts.parserOpts.parser) { + parseCode = opts.parserOpts.parser; + + if (typeof opts.parserOpts.parser === "string") { + let parserPath = opts.parserOpts.parser; + let dirname = opts.generatorOpts.dirname || process.cwd(); + let parser = resolve(parserPath, dirname) || resolve(parserPath, dirname); + if (parser) { + parseCode = require(parser); + } else { + throw new Error(`Couldn't find parser ${JSON.stringify(parserPath)} relative to directory ${JSON.stringify(dirname)}`); + } + + } + + Object.assign(this.parserOpts, { + parser: require("babylon") + }); + } + this.log.debug("Parse start"); - let ast = parse(code, this.parserOpts); + let ast = parseCode(code, this.parserOpts); this.log.debug("Parse stop"); return ast; } @@ -568,9 +592,25 @@ export default class File extends Store { let result: BabelFileResult = { ast }; if (!opts.code) return this.makeResult(result); + let gen = generate; + if (opts.generatorOpts.generator) { + gen = opts.generatorOpts.generator; + + if (typeof opts.generatorOpts.generator === "string") { + let generatorPath = opts.generatorOpts.generator; + let dirname = opts.generatorOpts.dirname || process.cwd(); + let generator = resolve(generatorPath, dirname) || resolve(generatorPath, dirname); + if (generator) { + gen = require(generator); + } else { + throw new Error(`Couldn't find generator ${JSON.stringify(generatorPath)} relative to directory ${JSON.stringify(dirname)}`); + } + } + } + this.log.debug("Generation start"); - let _result = generate(ast, opts, this.code); + let _result = gen(ast, opts, this.code); result.code = _result.code; result.map = _result.map; diff --git a/packages/babel-core/src/transformation/file/options/config.js b/packages/babel-core/src/transformation/file/options/config.js index 56c98c95894d..33adc994a53a 100644 --- a/packages/babel-core/src/transformation/file/options/config.js +++ b/packages/babel-core/src/transformation/file/options/config.js @@ -193,4 +193,16 @@ module.exports = { default: false, hidden: true, }, + + // Deprecate top level parserOpts + parserOpts: { + description: "Options to pass into the parser, or to change parsers (parserOpts.parser)", + default: false + }, + + // Deprecate top level generatorOpts + generatorOpts: { + description: "Options to pass into the generator, or to change generators (generatorOpts.generator)", + default: false + } }; diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index 18ddd0d1b985..0e875d3c16d7 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -5,6 +5,7 @@ var sourceMap = require("source-map"); var assert = require("assert"); var File = require("../lib/transformation/file").default; var Plugin = require("../lib/transformation/plugin"); +var recast = require("recast"); function assertIgnored(result) { assert.ok(result.ignored); @@ -76,6 +77,68 @@ suite("api", function () { }); }); + suite("parser and generator options", function() { + function execTest() { + return babel.transform("var a = { b: b };", { + plugins: [ + new Plugin({ + pre: function() { + console.log("plugin called!"); + }, + visitor: { + ObjectProperty: function(path) { + console.log("visit ObjectProperty"); + var node = path.node; + if (!node.shorthand && + node.key.name === node.value.name) { + console.log("change to shorthand"); + node.shorthand = true; + } + } + } + }) + ], + parserOpts: { + parser: recast.parse + }, + generatorOpts: { + generator: recast.print + } + }); + } + + test("recast", function() { + // console.log(recast.types); + + var def = recast.types.Type.def + var or = recast.types.Type.or; + var defaults = { + "null": function() { return null }, + "emptyArray": function() { return [] }, + "false": function() { return false }, + "true": function() { return true }, + "undefined": function() {} + } + + def("ObjectProperty") + .bases("Node") // Want to be able to visit Property Nodes. + .build("key", "value", "computed", "shorthand", "decorators") + + .field("key", or(def("Literal"), def("Identifier"), def("Expression"))) + .field("value", or(def("Expression"), def("Pattern"))) + .field("shorthand", Boolean, defaults["false"]) + .field("computed", Boolean, defaults["false"]) + .field("decorators", + or([def("Decorator")], null), + defaults["null"]); + + recast.types.finalize(); + + var result = execTest(); + assert.equal(result.code, "var a = { b };"); + }); + }); + test("pass per preset", function () { var aliasBaseType = null;