Merge pull request #5468 from babel/react-preset
Add requireDirective to strip-flow-types for use in React preset
This commit is contained in:
commit
8c457e9283
@ -47,3 +47,13 @@ require("babel-core").transform("code", {
|
||||
plugins: ["transform-flow-strip-types"]
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### `requireDirective`
|
||||
|
||||
`boolean`, defaults to `false`.
|
||||
|
||||
Setting this to true will only strip annotations and declarations from files
|
||||
that contain the `// @flow` directive. It will also throw errors for any Flow
|
||||
annotations found in files without the directive.
|
||||
|
||||
@ -3,13 +3,20 @@ import syntaxFlow from "babel-plugin-syntax-flow";
|
||||
export default function({ types: t }) {
|
||||
const FLOW_DIRECTIVE = "@flow";
|
||||
|
||||
let skipStrip = false;
|
||||
|
||||
return {
|
||||
inherits: syntaxFlow,
|
||||
|
||||
visitor: {
|
||||
Program(path, { file: { ast: { comments } } }) {
|
||||
Program(path, { file: { ast: { comments } }, opts }) {
|
||||
skipStrip = false;
|
||||
let directiveFound = false;
|
||||
|
||||
for (const comment of (comments: Array<Object>)) {
|
||||
if (comment.value.indexOf(FLOW_DIRECTIVE) >= 0) {
|
||||
directiveFound = true;
|
||||
|
||||
// remove flow directive
|
||||
comment.value = comment.value.replace(FLOW_DIRECTIVE, "");
|
||||
|
||||
@ -17,9 +24,13 @@ export default function({ types: t }) {
|
||||
if (!comment.value.replace(/\*/g, "").trim()) comment.ignore = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
if (!directiveFound && opts.requireDirective) {
|
||||
skipStrip = true;
|
||||
}
|
||||
},
|
||||
ImportDeclaration(path) {
|
||||
if (skipStrip) return;
|
||||
if (!path.node.specifiers.length) return;
|
||||
|
||||
let typeCount = 0;
|
||||
@ -36,16 +47,25 @@ export default function({ types: t }) {
|
||||
},
|
||||
|
||||
Flow(path) {
|
||||
if (skipStrip) {
|
||||
throw path.buildCodeFrameError(
|
||||
"A @flow directive is required when using Flow annotations with " +
|
||||
"babel-preset-react or the `requireDirective` option.",
|
||||
);
|
||||
}
|
||||
|
||||
path.remove();
|
||||
},
|
||||
|
||||
ClassProperty(path) {
|
||||
if (skipStrip) return;
|
||||
path.node.variance = null;
|
||||
path.node.typeAnnotation = null;
|
||||
if (!path.node.value) path.remove();
|
||||
},
|
||||
|
||||
Class(path) {
|
||||
if (skipStrip) return;
|
||||
path.node.implements = null;
|
||||
|
||||
// We do this here instead of in a `ClassProperty` visitor because the class transform
|
||||
@ -59,10 +79,12 @@ export default function({ types: t }) {
|
||||
},
|
||||
|
||||
AssignmentPattern({ node }) {
|
||||
if (skipStrip) return;
|
||||
node.left.optional = false;
|
||||
},
|
||||
|
||||
Function({ node }) {
|
||||
if (skipStrip) return;
|
||||
for (let i = 0; i < node.params.length; i++) {
|
||||
const param = node.params[i];
|
||||
param.optional = false;
|
||||
@ -75,6 +97,7 @@ export default function({ types: t }) {
|
||||
},
|
||||
|
||||
TypeCastExpression(path) {
|
||||
if (skipStrip) return;
|
||||
let { node } = path;
|
||||
do {
|
||||
node = node.expression;
|
||||
|
||||
3
packages/babel-plugin-transform-flow-strip-types/test/fixtures/requireDirective/options.json
vendored
Normal file
3
packages/babel-plugin-transform-flow-strip-types/test/fixtures/requireDirective/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": [["transform-flow-strip-types", { "requireDirective": true }]]
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
function foo(numVal, strVal) {}
|
||||
@ -0,0 +1 @@
|
||||
function foo(numVal, strVal) {}
|
||||
@ -0,0 +1,3 @@
|
||||
// @flow
|
||||
|
||||
function foo(numVal: number, strVal: string) {}
|
||||
@ -0,0 +1 @@
|
||||
function foo(numVal, strVal) {}
|
||||
@ -0,0 +1 @@
|
||||
function foo(numVal: number, strVal: string) {}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "A @flow directive is required when using Flow annotations with babel-preset-react or the `requireDirective` option."
|
||||
}
|
||||
@ -2,13 +2,28 @@
|
||||
|
||||
> Babel preset for all React plugins.
|
||||
|
||||
This preset includes the following plugins/presets:
|
||||
This preset always includes the following plugins:
|
||||
|
||||
- [preset-flow](https://babeljs.io/docs/plugins/preset-flow/)
|
||||
- [syntax-jsx](https://babeljs.io/docs/plugins/syntax-jsx/)
|
||||
- [transform-flow-strip-types](https://babeljs.io/docs/plugins/transform-flow-strip-types/)
|
||||
- [transform-react-jsx](https://babeljs.io/docs/plugins/transform-react-jsx/)
|
||||
- [transform-react-display-name](https://babeljs.io/docs/plugins/transform-react-display-name/)
|
||||
|
||||
And with the `development` option:
|
||||
|
||||
- [transform-react-jsx-self](https://babeljs.io/docs/plugins/transform-react-jsx-self/)
|
||||
- [transform-react-jsx-source](https://babeljs.io/docs/plugins/transform-react-jsx-source/)
|
||||
|
||||
Note: This preset sets the `requireDirective` option on
|
||||
`transform-flow-strip-types`. This means Flow annotations and declarations
|
||||
will _only_ be removed in files that have a `// @flow ` directive. It will also
|
||||
throw errors for any Flow annotations found in files without the directive.
|
||||
|
||||
```js
|
||||
// @flow
|
||||
function foo(numVal: number, strVal: string) {}
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
> You can also check out the React [Getting Started page](https://facebook.github.io/react/docs/hello-world.html)
|
||||
@ -54,7 +69,7 @@ View the output
|
||||
### Via CLI
|
||||
|
||||
```sh
|
||||
babel script.js --presets react
|
||||
babel script.js --presets react
|
||||
```
|
||||
|
||||
### Via Node API
|
||||
@ -64,3 +79,42 @@ require("babel-core").transform("code", {
|
||||
presets: ["react"]
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### `development`
|
||||
|
||||
`boolean`, defaults to `false`.
|
||||
|
||||
Toggles plugins that aid in development, such as [`babel-plugin-transform-react-jsx-self`](https://babeljs.io/docs/plugins/transform-react-jsx-self/) and [`babel-plugin-transform-react-jsx-source`](https://babeljs.io/docs/plugins/transform-react-jsx-source/).
|
||||
|
||||
This is useful when combined with either a `babelrc.js` or [env option in a .babelrc](https://babeljs.io/docs/usage/babelrc/#env-option) configuration:
|
||||
|
||||
#### babelrc.js
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
presets: [
|
||||
["react", {
|
||||
development: process.env.BABEL_ENV === "development"
|
||||
}],
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
#### .babelrc
|
||||
|
||||
> Note: the `env` option will likely get deprecated soon
|
||||
|
||||
```json
|
||||
{
|
||||
"presets": ["react"],
|
||||
"env": {
|
||||
"development": {
|
||||
"presets": [
|
||||
["react", { "development": true }]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -9,10 +9,14 @@
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"babel-plugin-syntax-jsx": "7.0.0-alpha.18",
|
||||
"babel-plugin-transform-flow-strip-types": "7.0.0-alpha.18",
|
||||
"babel-plugin-transform-react-display-name": "7.0.0-alpha.18",
|
||||
"babel-plugin-transform-react-jsx": "7.0.0-alpha.18",
|
||||
"babel-plugin-transform-react-jsx-self": "7.0.0-alpha.18",
|
||||
"babel-plugin-transform-react-jsx-source": "7.0.0-alpha.18",
|
||||
"babel-preset-flow": "7.0.0-alpha.18"
|
||||
"babel-plugin-transform-react-jsx-source": "7.0.0-alpha.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-helper-plugin-test-runner": "7.0.0-alpha.18",
|
||||
"babel-helper-transform-fixture-test-runner": "7.0.0-alpha.18"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,26 @@
|
||||
import presetFlow from "babel-preset-flow";
|
||||
import transformFlowStripTypes from "babel-plugin-transform-flow-strip-types";
|
||||
import transformReactJSX from "babel-plugin-transform-react-jsx";
|
||||
import transformSyntaxJSX from "babel-plugin-syntax-jsx";
|
||||
import transformReactDisplayName from "babel-plugin-transform-react-display-name";
|
||||
import transformReactJSXSource from "babel-plugin-transform-react-jsx-source";
|
||||
import transformReactJSXSelf from "babel-plugin-transform-react-jsx-self";
|
||||
|
||||
export default function(context, opts = {}) {
|
||||
const development = opts.development || false;
|
||||
|
||||
if (typeof development !== "boolean") {
|
||||
throw new Error("Preset react 'development' option must be a boolean.");
|
||||
}
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
presets: [presetFlow],
|
||||
plugins: [transformReactJSX, transformSyntaxJSX, transformReactDisplayName],
|
||||
plugins: [
|
||||
transformReactJSX,
|
||||
transformSyntaxJSX,
|
||||
transformReactDisplayName,
|
||||
|
||||
development && transformReactJSXSource,
|
||||
development && transformReactJSXSelf,
|
||||
[transformFlowStripTypes, { requireDirective: true }],
|
||||
].filter(Boolean),
|
||||
};
|
||||
}
|
||||
|
||||
5
packages/babel-preset-react/test/fixtures/flow/options.json
vendored
Normal file
5
packages/babel-preset-react/test/fixtures/flow/options.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"presets": [
|
||||
"react"
|
||||
]
|
||||
}
|
||||
2
packages/babel-preset-react/test/fixtures/flow/strip-with-directive/actual.js
vendored
Normal file
2
packages/babel-preset-react/test/fixtures/flow/strip-with-directive/actual.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// @flow
|
||||
function foo(numVal: number, strVal: string) {}
|
||||
1
packages/babel-preset-react/test/fixtures/flow/strip-with-directive/expected.js
vendored
Normal file
1
packages/babel-preset-react/test/fixtures/flow/strip-with-directive/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
function foo(numVal, strVal) {}
|
||||
1
packages/babel-preset-react/test/fixtures/flow/throws-without-directive/actual.js
vendored
Normal file
1
packages/babel-preset-react/test/fixtures/flow/throws-without-directive/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
function foo(numVal: number, strVal: string) {}
|
||||
1
packages/babel-preset-react/test/fixtures/flow/throws-without-directive/expected.js
vendored
Normal file
1
packages/babel-preset-react/test/fixtures/flow/throws-without-directive/expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
function foo(numVal: number, strVal: string) {}
|
||||
3
packages/babel-preset-react/test/fixtures/flow/throws-without-directive/options.json
vendored
Normal file
3
packages/babel-preset-react/test/fixtures/flow/throws-without-directive/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "A @flow directive is required when using Flow annotations with babel-preset-react or the `requireDirective` option."
|
||||
}
|
||||
19
packages/babel-preset-react/test/fixtures/preset-options/development/exec.js
vendored
Normal file
19
packages/babel-preset-react/test/fixtures/preset-options/development/exec.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
const actual = transform(
|
||||
'<Foo bar="baz" />',
|
||||
Object.assign({}, opts, { filename: '/fake/path/mock.js' })
|
||||
).code;
|
||||
|
||||
const expected = multiline([
|
||||
'var _jsxFileName = "/fake/path/mock.js";',
|
||||
'React.createElement(Foo, {',
|
||||
' bar: "baz",',
|
||||
' __source: {',
|
||||
' fileName: _jsxFileName,',
|
||||
' lineNumber: 1',
|
||||
' },',
|
||||
' __self: this',
|
||||
'});',
|
||||
]);
|
||||
|
||||
|
||||
assert.equal(actual, expected);
|
||||
5
packages/babel-preset-react/test/fixtures/preset-options/development/options.json
vendored
Normal file
5
packages/babel-preset-react/test/fixtures/preset-options/development/options.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"presets": [
|
||||
["react", { "development": true }]
|
||||
]
|
||||
}
|
||||
1
packages/babel-preset-react/test/fixtures/preset-options/empty-options/actual.js
vendored
Normal file
1
packages/babel-preset-react/test/fixtures/preset-options/empty-options/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
<Foo bar="baz" />
|
||||
3
packages/babel-preset-react/test/fixtures/preset-options/empty-options/expected.js
vendored
Normal file
3
packages/babel-preset-react/test/fixtures/preset-options/empty-options/expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
React.createElement(Foo, {
|
||||
bar: "baz"
|
||||
});
|
||||
5
packages/babel-preset-react/test/fixtures/preset-options/empty-options/options.json
vendored
Normal file
5
packages/babel-preset-react/test/fixtures/preset-options/empty-options/options.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"presets": [
|
||||
["react", {}]
|
||||
]
|
||||
}
|
||||
1
packages/babel-preset-react/test/fixtures/preset-options/no-options/actual.js
vendored
Normal file
1
packages/babel-preset-react/test/fixtures/preset-options/no-options/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
<Foo bar="baz" />
|
||||
3
packages/babel-preset-react/test/fixtures/preset-options/no-options/expected.js
vendored
Normal file
3
packages/babel-preset-react/test/fixtures/preset-options/no-options/expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
React.createElement(Foo, {
|
||||
bar: "baz"
|
||||
});
|
||||
5
packages/babel-preset-react/test/fixtures/preset-options/no-options/options.json
vendored
Normal file
5
packages/babel-preset-react/test/fixtures/preset-options/no-options/options.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"presets": [
|
||||
"react"
|
||||
]
|
||||
}
|
||||
20
packages/babel-preset-react/test/index.js
Normal file
20
packages/babel-preset-react/test/index.js
Normal file
@ -0,0 +1,20 @@
|
||||
import react from "../lib";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("react preset", () => {
|
||||
it("doesn't throw with no options passed", () => {
|
||||
expect(() => {
|
||||
react(null);
|
||||
}).not.to.throw();
|
||||
});
|
||||
|
||||
describe("options", () => {
|
||||
describe("development", () => {
|
||||
it("throws on non-boolean value", () => {
|
||||
expect(function() {
|
||||
react(null, { development: 1 });
|
||||
}).to.throw(/must be a boolean/);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
3
packages/babel-preset-react/test/preset-options.js
Normal file
3
packages/babel-preset-react/test/preset-options.js
Normal file
@ -0,0 +1,3 @@
|
||||
import runner from "babel-helper-plugin-test-runner";
|
||||
|
||||
runner(__dirname);
|
||||
Loading…
x
Reference in New Issue
Block a user