Require decoratorsBeforeExport option for decorators (#8465)

* Require decoratorsBeforeExport option for syntax-decorators

* Also babylon

* Enable test
This commit is contained in:
Nicolò Ribaudo 2018-08-15 09:04:52 +02:00 committed by GitHub
parent 1e0b649485
commit d79b5eeeff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 111 additions and 24 deletions

View File

@ -23,7 +23,9 @@ describe("parse", function() {
const output = require(fixture("output.json"));
const result = parse(input, {
parserOpts: { plugins: ["decorators"] },
parserOpts: {
plugins: [["decorators", { decoratorsBeforeExport: false }]],
},
cwd: fixture(),
});
expect(JSON.parse(JSON.stringify(result))).toEqual(output);

View File

@ -41,15 +41,28 @@ export function getPluginOption(
const PIPELINE_PROPOSALS = ["minimal"];
export function validatePlugins(plugins: PluginList) {
if (
hasPlugin(plugins, "decorators") &&
hasPlugin(plugins, "decorators-legacy")
) {
if (hasPlugin(plugins, "decorators")) {
if (hasPlugin(plugins, "decorators-legacy")) {
throw new Error(
"Cannot use the decorators and decorators-legacy plugin together",
);
}
const decoratorsBeforeExport = getPluginOption(
plugins,
"decorators",
"decoratorsBeforeExport",
);
if (decoratorsBeforeExport == null) {
throw new Error(
"The 'decorators' plugin requires a" +
" 'decoratorsBeforeExport' option, whose value must be a boolean.",
);
} else if (typeof decoratorsBeforeExport !== "boolean") {
throw new Error("'decoratorsBeforeExport' must be a boolean.");
}
}
if (hasPlugin(plugins, "flow") && hasPlugin(plugins, "typescript")) {
throw new Error("Cannot combine flow and typescript plugins.");
}

View File

@ -1,3 +1,7 @@
{
"plugins": ["classProperties", "classPrivateProperties", "decorators"]
"plugins": [
"classProperties",
"classPrivateProperties",
["decorators", { "decoratorsBeforeExport": false }]
]
}

View File

@ -1,3 +1,6 @@
{
"plugins": ["decorators", "classProperties"]
"plugins": [
["decorators", { "decoratorsBeforeExport": false }],
"classProperties"
]
}

View File

@ -0,0 +1,6 @@
{
"plugins": [
["decorators", { "decoratorsBeforeExport": "yes" }]
],
"throws": "'decoratorsBeforeExport' must be a boolean."
}

View File

@ -0,0 +1,4 @@
{
"plugins": ["decorators"],
"throws": "The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean."
}

View File

@ -1,3 +1,5 @@
{
"plugins": ["decorators"]
"plugins": [
["decorators", { "decoratorsBeforeExport": false }]
]
}

View File

@ -1,3 +1,7 @@
{
"plugins": ["classProperties", "classPrivateProperties", "decorators"]
"plugins": [
"classProperties",
"classPrivateProperties",
["decorators", { "decoratorsBeforeExport": false }]
]
}

View File

@ -1,3 +1,6 @@
{
"plugins": ["classProperties", "decorators"]
"plugins": [
"classProperties",
["decorators", { "decoratorsBeforeExport": false }]
]
}

View File

@ -9,19 +9,56 @@ describe("plugin options", function() {
// NOTE: This test is not specific about decorators, it can be applied
// to any plugin with options.
it("when they aren't specified", function() {
const WITHOUT_FLAG = "flow";
const WITH_FLAG = ["flow", { all: true }];
const CODE = "new Foo<x>(y)";
const AST_WITHOUT_FLAG = {
type: "BinaryExpression",
operator: ">",
left: {
type: "BinaryExpression",
operator: "<",
left: { type: "NewExpression" },
right: { type: "Identifier" },
},
right: { type: "Identifier", extra: { parenthesized: true } },
};
const AST_WITH_FLAG = {
type: "NewExpression",
callee: { type: "Identifier" },
arguments: [{ type: "Identifier" }],
typeArguments: {
type: "TypeParameterInstantiation",
params: [
{ type: "GenericTypeAnnotation", id: { type: "Identifier" } },
],
},
};
expect(
getParser(CODE, [WITHOUT_FLAG, WITH_FLAG])().program.body[0].expression,
).toMatchObject(AST_WITHOUT_FLAG);
expect(
getParser(CODE, [WITHOUT_FLAG])().program.body[0].expression,
).toMatchObject(AST_WITHOUT_FLAG);
expect(
getParser(CODE, [WITH_FLAG])().program.body[0].expression,
).toMatchObject(AST_WITH_FLAG);
});
it("when they are specified", function() {
const NAME = "decorators";
const OPT_1 = [NAME, { decoratorsBeforeExport: true }];
const OPT_2 = [NAME, { decoratorsBeforeExport: false }];
const SYNTAX_1 = "@dec export class C {}";
const SYNTAX_2 = "export @dec class C {}";
const SYNTAX_DEFAULT = "export @dec class C {}";
it("when they aren't specified", function() {
expect(getParser(SYNTAX_DEFAULT, [NAME, OPT_1])).not.toThrow();
expect(getParser(SYNTAX_DEFAULT, [NAME, OPT_2])).not.toThrow();
});
it("when they are specified", function() {
expect(getParser(SYNTAX_1, [OPT_1, OPT_2])).not.toThrow();
expect(getParser(SYNTAX_2, [OPT_2, OPT_1])).not.toThrow();
expect(getParser(SYNTAX_1, [OPT_2, OPT_1])).toThrow();

View File

@ -17,7 +17,14 @@ export default declare((api, options) => {
}
const { decoratorsBeforeExport } = options;
if (decoratorsBeforeExport !== undefined) {
if (decoratorsBeforeExport === undefined) {
if (!legacy) {
throw new Error(
"The '@babel/plugin-syntax-decorators' plugin requires a" +
" 'decoratorsBeforeExport' option, whose value must be a boolean.",
);
}
} else {
if (legacy) {
throw new Error(
"'decoratorsBeforeExport' can't be used with legacy decorators.",

View File

@ -37,6 +37,10 @@ describe("'decoratorsBeforeExport' option", function() {
expect(makeParser("", { decoratorsBeforeExport: "before" })).toThrow();
});
test.skip("is required", function() {
expect(makeParser("", { legacy: false })).toThrow(/decoratorsBeforeExport/);
});
test("is incompatible with legacy", function() {
expect(
makeParser("", { decoratorsBeforeExport: false, legacy: true }),
@ -47,8 +51,6 @@ describe("'decoratorsBeforeExport' option", function() {
const AFTER = "export @dec class Foo {}";
// These are skipped
run(BEFORE, undefined, true);
run(AFTER, undefined, false);
run(BEFORE, true, false);
run(AFTER, true, true);
run(BEFORE, false, true);