From cb17f07ac9c91c4ea05d030656b174c8864befb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Wed, 30 May 2018 22:00:18 +0200 Subject: [PATCH] Update syntax-decorators options (#7938) * Add decoratorsBeforeExport to the syntax plugin * Require legacy: true, like in the transform plugin --- .../presets/es2015_default_function.js | 7 +- .../presets/es2015_default_object.js | 7 +- .../option-manager/presets/es5_function.js | 5 +- .../option-manager/presets/es5_object.js | 5 +- .../babel-plugin-syntax-decorators/README.md | 17 +++++ .../src/index.js | 28 +++++++- .../test/index.js | 71 +++++++++++++++++++ 7 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 packages/babel-plugin-syntax-decorators/test/index.js diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_function.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_function.js index 25ea910dec..a58f2d700d 100644 --- a/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_function.js +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_function.js @@ -12,6 +12,11 @@ Object.defineProperty(exports, "__esModule", { exports.default = function () { return { - plugins: [require('../../../../../babel-plugin-syntax-decorators')] + plugins: [ + [ + require('../../../../../babel-plugin-syntax-decorators'), + { legacy: true } + ], + ] }; }; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_object.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_object.js index 052829fe5b..cd1208bf35 100644 --- a/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_object.js +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_object.js @@ -9,6 +9,11 @@ exports.__esModule = true; module.exports = function() { return { - plugins: [require('../../../../../babel-plugin-syntax-decorators')] + plugins: [ + [ + require('../../../../../babel-plugin-syntax-decorators'), + { legacy: true } + ], + ] }; }; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es5_function.js b/packages/babel-core/test/fixtures/option-manager/presets/es5_function.js index 71c789f9df..539c58e164 100644 --- a/packages/babel-core/test/fixtures/option-manager/presets/es5_function.js +++ b/packages/babel-core/test/fixtures/option-manager/presets/es5_function.js @@ -1,7 +1,10 @@ module.exports = function () { return { plugins: [ - require('../../../../../babel-plugin-syntax-decorators'), + [ + require('../../../../../babel-plugin-syntax-decorators'), + { legacy: true } + ], ] }; }; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es5_object.js b/packages/babel-core/test/fixtures/option-manager/presets/es5_object.js index c3689a0c84..30c4d017c4 100644 --- a/packages/babel-core/test/fixtures/option-manager/presets/es5_object.js +++ b/packages/babel-core/test/fixtures/option-manager/presets/es5_object.js @@ -1,7 +1,10 @@ module.exports = function() { return { plugins: [ - require('../../../../../babel-plugin-syntax-decorators'), + [ + require('../../../../../babel-plugin-syntax-decorators'), + { legacy: true } + ], ] }; }; diff --git a/packages/babel-plugin-syntax-decorators/README.md b/packages/babel-plugin-syntax-decorators/README.md index a062755761..a5a5191b38 100644 --- a/packages/babel-plugin-syntax-decorators/README.md +++ b/packages/babel-plugin-syntax-decorators/README.md @@ -41,3 +41,20 @@ require("@babel/core").transform("code", { `boolean`, defaults to `false`. Use the legacy (stage 1) decorators syntax. + +### `decoratorsBeforeExport` + +`boolean`, defaults to `true`. + +```js +// decoratorsBeforeExport: true +@decorator +export class Foo {} + +// decoratorsBeforeExport: false +export @decorator class Bar {} +``` + +This option was added to help tc39 collect feedback from the community by allowing experimentation with both possible syntaxes. + +For more information, check out: [tc39/proposal-decorators#69](https://github.com/tc39/proposal-decorators/issues/69) diff --git a/packages/babel-plugin-syntax-decorators/src/index.js b/packages/babel-plugin-syntax-decorators/src/index.js index 8e3ed8d437..8f0c12fbc0 100644 --- a/packages/babel-plugin-syntax-decorators/src/index.js +++ b/packages/babel-plugin-syntax-decorators/src/index.js @@ -8,9 +8,35 @@ export default declare((api, options) => { throw new Error("'legacy' must be a boolean."); } + if (legacy !== true) { + throw new Error( + "The new decorators proposal is not supported yet." + + ' You must pass the `"legacy": true` option to' + + " @babel/plugin-syntax-decorators", + ); + } + + let { decoratorsBeforeExport } = options; + if (decoratorsBeforeExport !== undefined) { + if (legacy) { + throw new Error( + "'decoratorsBeforeExport' can't be used with legacy decorators.", + ); + } + if (typeof decoratorsBeforeExport !== "boolean") { + throw new Error("'decoratorsBeforeExport' must be a boolean."); + } + } else if (!legacy) { + decoratorsBeforeExport = true; + } + return { manipulateOptions(opts, parserOpts) { - parserOpts.plugins.push(legacy ? "decorators-legacy" : "decorators"); + parserOpts.plugins.push( + legacy + ? "decorators-legacy" + : ["decorators", { decoratorsBeforeExport }], + ); }, }; }); diff --git a/packages/babel-plugin-syntax-decorators/test/index.js b/packages/babel-plugin-syntax-decorators/test/index.js new file mode 100644 index 0000000000..79e201fcc2 --- /dev/null +++ b/packages/babel-plugin-syntax-decorators/test/index.js @@ -0,0 +1,71 @@ +import { parse } from "@babel/core"; +import syntaxDecorators from "../lib"; + +function makeParser(code, options) { + return () => + parse(code, { + babelrc: false, + configFile: false, + plugins: [[syntaxDecorators, options]], + }); +} + +describe("'legacy' option", function() { + test("must be boolean", function() { + expect(makeParser("", { legacy: "legacy" })).toThrow(); + }); + + test.skip("'legacy': false", function() { + expect(makeParser("({ @dec fn() {} })", { legacy: false })).toThrow(); + }); + + test("'legacy': true", function() { + expect(makeParser("({ @dec fn() {} })", { legacy: true })).not.toThrow(); + }); + + test.skip("defaults to 'false'", function() { + expect(makeParser("({ @dec fn() {} })", {})).toThrow(); + }); + + test("it must be true", function() { + expect(makeParser("", { legacy: false })).toThrow(); + }); +}); + +describe("'decoratorsBeforeExport' option", function() { + test.skip("must be boolean", function() { + expect(makeParser("", { decoratorsBeforeExport: "before" })).toThrow(); + }); + + test("is incompatible with legacy", function() { + expect( + makeParser("", { decoratorsBeforeExport: false, legacy: true }), + ).toThrow(); + }); + + const BEFORE = "@dec export class Foo {}"; + const AFTER = "export @dec class Foo {}"; + + // These are skipped + run(BEFORE, undefined, false); + run(AFTER, undefined, true); + run(BEFORE, true, false); + run(AFTER, true, true); + run(BEFORE, false, true); + run(AFTER, false, false); + + function run(code, before, throws) { + const name = + (before === undefined ? "default" : before) + + " - decorators " + + (code === BEFORE ? "before" : "after") + + "export"; + + test.skip(name, function() { + const expectTheParser = expect( + makeParser(code, { decoratorsBeforeExport: before }), + ); + throws ? expectTheParser.toThrow() : expectTheParser.not.toThrow(); + }); + } +});