Skip to content

Commit

Permalink
[babel 8] Type checking preset-typescript options (#12460)
Browse files Browse the repository at this point in the history
* refactor: extract option normalization in preset-typescript

* breaking: type checking preset-typescript options

* chore: bundle preset-typescript into a single lib

* test: disable Babel 7 test on Babel 8 breaking change test

* workaround Jest 24 error snapshot dedent issue

* skip Babel 8 test when the Breaking ENV is not available

* chore: update test snapshot

* Update packages/babel-preset-typescript/test/normalize-options.spec.js

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>

* update test fixtures

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>
  • Loading branch information
JLHwung and nicolo-ribaudo committed Jan 7, 2021
1 parent 866a742 commit ff52ace
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 21 deletions.
1 change: 1 addition & 0 deletions Gulpfile.js
Expand Up @@ -361,6 +361,7 @@ function copyDts(packages) {
const libBundles = [
"packages/babel-parser",
"packages/babel-plugin-proposal-optional-chaining",
"packages/babel-preset-typescript",
"packages/babel-helper-member-expression-to-functions",
].map(src => ({
src,
Expand Down
26 changes: 5 additions & 21 deletions packages/babel-preset-typescript/src/index.js
@@ -1,35 +1,19 @@
import { declare } from "@babel/helper-plugin-utils";
import transformTypeScript from "@babel/plugin-transform-typescript";
import { OptionValidator } from "@babel/helper-validator-option";
const v = new OptionValidator("@babel/preset-typescript");
import normalizeOptions from "./normalize-options.js";

export default declare((api, opts) => {
api.assertVersion(7);

const {
allExtensions,
allowDeclareFields,
allowNamespaces,
isTSX,
jsxPragma,
jsxPragmaFrag,
onlyRemoveTypeImports,
} = opts;

const jsxPragmaFrag = v.validateStringOption(
"jsxPragmaFrag",
opts.jsxPragmaFrag,
"React.Fragment",
);

const allExtensions = v.validateBooleanOption(
"allExtensions",
opts.allExtensions,
false,
);

const isTSX = v.validateBooleanOption("isTSX", opts.isTSX, false);

if (isTSX) {
v.invariant(allExtensions, "isTSX:true requires allExtensions:true");
}
} = normalizeOptions(opts);

const pluginOptions = isTSX => ({
allowDeclareFields,
Expand Down
72 changes: 72 additions & 0 deletions packages/babel-preset-typescript/src/normalize-options.js
@@ -0,0 +1,72 @@
import { OptionValidator } from "@babel/helper-validator-option";
const v = new OptionValidator("@babel/preset-typescript");

export default function normalizeOptions(options = {}) {
let {
allowDeclareFields,
allowNamespaces,
jsxPragma,
onlyRemoveTypeImports,
} = options;

if (process.env.BABEL_8_BREAKING) {
const TopLevelOptions = {
allowDeclareFields: "allowDeclareFields",
allExtensions: "allExtensions",
allowNamespaces: "allowNamespaces",
isTSX: "isTSX",
jsxPragma: "jsxPragma",
jsxPragmaFrag: "jsxPragmaFrag",
onlyRemoveTypeImports: "onlyRemoveTypeImports",
};
v.validateTopLevelOptions(options, TopLevelOptions);
allowDeclareFields = v.validateBooleanOption(
TopLevelOptions.allowDeclareFields,
options.allowDeclareFields,
true,
);
allowNamespaces = v.validateBooleanOption(
TopLevelOptions.allowNamespaces,
options.allowNamespaces,
true,
);
jsxPragma = v.validateStringOption(
TopLevelOptions.jsxPragma,
options.jsxPragma,
"React",
);
onlyRemoveTypeImports = v.validateBooleanOption(
TopLevelOptions.onlyRemoveTypeImports,
options.onlyRemoveTypeImports,
true,
);
}

const jsxPragmaFrag = v.validateStringOption(
"jsxPragmaFrag",
options.jsxPragmaFrag,
"React.Fragment",
);

const allExtensions = v.validateBooleanOption(
"allExtensions",
options.allExtensions,
false,
);

const isTSX = v.validateBooleanOption("isTSX", options.isTSX, false);

if (isTSX) {
v.invariant(allExtensions, "isTSX:true requires allExtensions:true");
}

return {
allExtensions,
allowDeclareFields,
allowNamespaces,
isTSX,
jsxPragma,
jsxPragmaFrag,
onlyRemoveTypeImports,
};
}
93 changes: 93 additions & 0 deletions packages/babel-preset-typescript/test/normalize-options.spec.js
@@ -0,0 +1,93 @@
import normalizeOptions from "../src/normalize-options";
describe("normalize options", () => {
(process.env.BABEL_8_BREAKING ? describe : describe.skip)("Babel 8", () => {
it("should throw on unknown options", () => {
expect(() => normalizeOptions({ allowNamespace: true })).toThrowError(
"@babel/preset-typescript: 'allowNamespace' is not a valid top-level option.\n- Did you mean 'allowNamespaces'?",
);
});
it.each([
"allowDeclareFields",
"allExtensions",
"allowNamespaces",
"isTSX",
"onlyRemoveTypeImports",
])("should throw when `%p` is not a boolean", optionName => {
expect(() => normalizeOptions({ [optionName]: 0 })).toThrow(
`@babel/preset-typescript: '${optionName}' option must be a boolean.`,
);
});
it.each(["jsxPragma", "jsxPragmaFrag"])(
"should throw when `%p` is not a string",
optionName => {
expect(() => normalizeOptions({ [optionName]: 0 })).toThrow(
`@babel/preset-typescript: '${optionName}' option must be a string.`,
);
},
);
it("should not throw when options is not defined", () => {
expect(() => normalizeOptions()).not.toThrowError();
});
it("default values", () => {
expect(normalizeOptions({})).toMatchInlineSnapshot(`
Object {
"allExtensions": false,
"allowDeclareFields": true,
"allowNamespaces": true,
"isTSX": false,
"jsxPragma": "React",
"jsxPragmaFrag": "React.Fragment",
"onlyRemoveTypeImports": true,
}
`);
});
});
(process.env.BABEL_8_BREAKING ? describe.skip : describe)("Babel 7", () => {
it("should not throw on unknown options", () => {
expect(() =>
normalizeOptions({ allowNamespace: true }),
).not.toThrowError();
});
it.each(["allowDeclareFields", "allowNamespaces", "onlyRemoveTypeImports"])(
"should not throw when `%p` is not a boolean",
optionName => {
expect(() => normalizeOptions({ [optionName]: 0 })).not.toThrowError();
},
);
it.each(["jsxPragma"])(
"should throw when `%p` is not a string",
optionName => {
expect(() => normalizeOptions({ [optionName]: 0 })).not.toThrowError();
},
);
it.each(["allExtensions", "isTSX"])(
"should throw when `%p` is not a boolean",
optionName => {
expect(() => normalizeOptions({ [optionName]: 0 })).toThrow(
`@babel/preset-typescript: '${optionName}' option must be a boolean.`,
);
},
);
it.each(["jsxPragmaFrag"])(
"should throw when `%p` is not a string",
optionName => {
expect(() => normalizeOptions({ [optionName]: 0 })).toThrow(
`@babel/preset-typescript: '${optionName}' option must be a string.`,
);
},
);
it("default values", () => {
expect(normalizeOptions({})).toMatchInlineSnapshot(`
Object {
"allExtensions": false,
"allowDeclareFields": undefined,
"allowNamespaces": undefined,
"isTSX": false,
"jsxPragma": undefined,
"jsxPragmaFrag": "React.Fragment",
"onlyRemoveTypeImports": undefined,
}
`);
});
});
});

0 comments on commit ff52ace

Please sign in to comment.