From b2eb5eca6fe07bfbba6a8013fbe6ea3cf9c3aa3b Mon Sep 17 00:00:00 2001 From: Henry Zhu Date: Tue, 27 Sep 2016 09:09:31 -0400 Subject: [PATCH] babel-core: add options for different parser/generator (#3561) * babel-core: add options for different parser/generator * test for experiemental plugins, other babylon options * fix passing options into parser * Fix when no code is provided * fixup tests * fix tests again * use filename and fallback to cwd --- .../src/transformation/file/index.js | 48 ++++++++++++- .../src/transformation/file/options/config.js | 12 ++++ packages/babel-core/test/api.js | 72 +++++++++++++++++++ packages/babel-generator/src/index.js | 7 +- 4 files changed, 136 insertions(+), 3 deletions(-) diff --git a/packages/babel-core/src/transformation/file/index.js b/packages/babel-core/src/transformation/file/index.js index 794222e458..793d850adf 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"; @@ -411,8 +413,35 @@ export default class File extends Store { } parse(code: string) { + let parseCode = parse; + let parserOpts = this.opts.parserOpts || this.parserOpts; + + if (parserOpts) { + parserOpts = Object.assign({}, this.parserOpts, parserOpts); + + if (parserOpts.parser) { + if (typeof parserOpts.parser === "string") { + let dirname = path.dirname(this.opts.filename) || process.cwd(); + let parser = resolve(parserOpts.parser, dirname); + if (parser) { + parseCode = require(parser).parse; + } else { + throw new Error(`Couldn't find parser ${parserOpts.parser} with "parse" method relative to directory ${dirname}`); + } + } else { + parseCode = parserOpts.parser; + } + + parserOpts.parser = { + parse(source) { + return parse(source, parserOpts); + } + }; + } + } + this.log.debug("Parse start"); - let ast = parse(code, this.parserOpts); + let ast = parseCode(code, parserOpts); this.log.debug("Parse stop"); return ast; } @@ -573,9 +602,24 @@ 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 gen === "string") { + let dirname = path.dirname(this.opts.filename) || process.cwd(); + let generator = resolve(gen, dirname); + if (generator) { + gen = require(generator).print; + } else { + throw new Error(`Couldn't find generator ${gen} with "print" method relative to directory ${dirname}`); + } + } + } + this.log.debug("Generation start"); - let _result = generate(ast, opts, this.code); + let _result = gen(ast, opts.generatorOpts ? Object.assign(opts, opts.generatorOpts) : 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 18638da688..7b11963f38 100644 --- a/packages/babel-core/src/transformation/file/options/config.js +++ b/packages/babel-core/src/transformation/file/options/config.js @@ -198,4 +198,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 bae3b506b1..ef72572511 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 generator = require("babel-generator").default; function assertIgnored(result) { assert.ok(result.ignored); @@ -23,6 +24,77 @@ function transformAsync(code, opts) { }; } +suite("parser and generator options", function() { + var 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 + } + }); + } + + test("options", function() { + var string = "original;"; + assert.deepEqual(newTransform(string).ast, babel.transform(string).ast); + assert.equal(newTransform(string).code, string); + }); + + test("experimental syntax", function() { + var 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); + }); + + test("other options", function() { + var 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); + }); +}); + suite("api", function () { test("analyze", function () { assert.equal(babel.analyse("foobar;").marked.length, 0); diff --git a/packages/babel-generator/src/index.js b/packages/babel-generator/src/index.js index 5b106a401b..098a343256 100644 --- a/packages/babel-generator/src/index.js +++ b/packages/babel-generator/src/index.js @@ -93,6 +93,11 @@ function normalizeOptions(code, opts, tokens): Format { * Determine if input code uses more single or double quotes. */ function findCommonStringDelimiter(code, tokens) { + const DEFAULT_STRING_DELIMITER = "double"; + if (!code) { + return DEFAULT_STRING_DELIMITER; + } + let occurences = { single: 0, double: 0 @@ -117,7 +122,7 @@ function findCommonStringDelimiter(code, tokens) { if (occurences.single > occurences.double) { return "single"; } else { - return "double"; + return DEFAULT_STRING_DELIMITER; } }