@samitouri / QOS-React / commits / d4f2b0379c

Add Auto Import to Babel Plugin (#16626)

This babel transform is a fork of the @babel/plugin-transform-react-jsx transform and is for experimentation purposes only. We don't plan to own this code in the future, and we will upstream this to Babel at some point once we've proven out the concept. As per the RFC to simplify element creation, we want to add the ability to auto import "react' directly from the babel plugin. This commit updates the babel plugin with two options: 1.) importSource: The React module to import from. Defaults to react. 2.) autoImport: The type of import. Defaults to none. - none: Does not import React. JSX compiles to React.jsx etc. - namespace: import * as _react from "react";. JSX compiles to _react.jsx etc. - default: import _default from "react"; JSX compiles to _default.jsx etc. - namedExports: import {jsx as _jsx} from "react"; JSX compiles to _jsx etc. - require: var _react = _interopRequireWildcard(require("react"));. jSX compiles to _react.jsx etc. namespace, default, and namedExports can only be used when sourceType: module and require can only be used when sourceType: script. It also adds two pragmas (jsxAutoImport and jsxImportSource) that allow users to specify autoImport and importSource in the docblock.

Luna Ruan committed Feb 13, 2020 at 12:36 UTC d4f2b0379c8ecf8266497f863ee5a2aa612ff4ba
6 files changed +836 -689
packages/babel-plugin-react-jsx/__tests__/TransformJSXToReactCreateElement-test.js deleted
-392
@@ -1,392 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -/* eslint-disable quotes */
8 -'use strict';
9 -
10 -const babel = require('@babel/core');
11 -const codeFrame = require('@babel/code-frame');
12 -const {wrap} = require('jest-snapshot-serializer-raw');
13 -
14 -function transform(input, options) {
15 - return wrap(
16 - babel.transform(input, {
17 - configFile: false,
18 - plugins: [
19 - '@babel/plugin-syntax-jsx',
20 - '@babel/plugin-transform-arrow-functions',
21 - ...(options && options.development
22 - ? [
23 - '@babel/plugin-transform-react-jsx-source',
24 - '@babel/plugin-transform-react-jsx-self',
25 - ]
26 - : []),
27 - [
28 - './packages/babel-plugin-react-jsx',
29 - {
30 - development: __DEV__,
31 - useBuiltIns: true,
32 - useCreateElement: true,
33 - ...options,
34 - },
35 - ],
36 - ],
37 - }).code
38 - );
39 -}
40 -
41 -describe('transform react to jsx', () => {
42 - it('fragment with no children', () => {
43 - expect(transform(`var x = <></>`)).toMatchSnapshot();
44 - });
45 -
46 - it('React.Fragment to set keys and source', () => {
47 - expect(
48 - transform(`var x = <React.Fragment key='foo'><div /></React.Fragment>`, {
49 - development: true,
50 - })
51 - ).toMatchSnapshot();
52 - });
53 -
54 - it('normal fragments not to set key and source', () => {
55 - expect(
56 - transform(`var x = <><div /></>`, {
57 - development: true,
58 - })
59 - ).toMatchSnapshot();
60 - });
61 -
62 - it('should properly handle comments adjacent to children', () => {
63 - expect(
64 - transform(`
65 - var x = (
66 - <div>
67 - {/* A comment at the beginning */}
68 - {/* A second comment at the beginning */}
69 - <span>
70 - {/* A nested comment */}
71 - </span>
72 - {/* A sandwiched comment */}
73 - <br />
74 - {/* A comment at the end */}
75 - {/* A second comment at the end */}
76 - </div>
77 - );
78 - `)
79 - ).toMatchSnapshot();
80 - });
81 -
82 - it('adds appropriate new lines when using spread attribute', () => {
83 - expect(transform(`<Component {...props} sound="moo" />`)).toMatchSnapshot();
84 - });
85 -
86 - it('arrow functions', () => {
87 - expect(
88 - transform(`
89 - var foo = function () {
90 - return () => <this />;
91 - };
92 -
93 - var bar = function () {
94 - return () => <this.foo />;
95 - };
96 -
97 - `)
98 - ).toMatchSnapshot();
99 - });
100 -
101 - it('assignment', () => {
102 - expect(
103 - transform(`var div = <Component {...props} foo="bar" />`)
104 - ).toMatchSnapshot();
105 - });
106 -
107 - it('concatenates adjacent string literals', () => {
108 - expect(
109 - transform(`
110 - var x =
111 - <div>
112 - foo
113 - {"bar"}
114 - baz
115 - <div>
116 - buz
117 - bang
118 - </div>
119 - qux
120 - {null}
121 - quack
122 - </div>
123 - `)
124 - ).toMatchSnapshot();
125 - });
126 -
127 - it('should allow constructor as prop', () => {
128 - expect(transform(`<Component constructor="foo" />;`)).toMatchSnapshot();
129 - });
130 -
131 - it('should allow deeper js namespacing', () => {
132 - expect(
133 - transform(`<Namespace.DeepNamespace.Component />;`)
134 - ).toMatchSnapshot();
135 - });
136 -
137 - it('should allow elements as attributes', () => {
138 - expect(transform(`<div attr=<div /> />`)).toMatchSnapshot();
139 - });
140 -
141 - it('should allow js namespacing', () => {
142 - expect(transform(`<Namespace.Component />;`)).toMatchSnapshot();
143 - });
144 -
145 - it('should allow nested fragments', () => {
146 - expect(
147 - transform(`
148 - <div>
149 - < >
150 - <>
151 - <span>Hello</span>
152 - <span>world</span>
153 - </>
154 - <>
155 - <span>Goodbye</span>
156 - <span>world</span>
157 - </>
158 - </>
159 - </div>
160 - `)
161 - ).toMatchSnapshot();
162 - });
163 -
164 - it('should avoid wrapping in extra parens if not needed', () => {
165 - expect(
166 - transform(`
167 - var x = <div>
168 - <Component />
169 - </div>;
170 -
171 - var x = <div>
172 - {props.children}
173 - </div>;
174 -
175 - var x = <Composite>
176 - {props.children}
177 - </Composite>;
178 -
179 - var x = <Composite>
180 - <Composite2 />
181 - </Composite>;
182 - `)
183 - ).toMatchSnapshot();
184 - });
185 -
186 - it('should convert simple tags', () => {
187 - expect(transform(`var x = <div></div>;`)).toMatchSnapshot();
188 - });
189 -
190 - it('should convert simple text', () => {
191 - expect(transform(`var x = <div>text</div>;`)).toMatchSnapshot();
192 - });
193 -
194 - it('should disallow spread children', () => {
195 - let _error;
196 - const code = `<div>{...children}</div>;`;
197 - try {
198 - transform(code);
199 - } catch (error) {
200 - _error = error;
201 - }
202 - expect(_error).toEqual(
203 - new SyntaxError(
204 - 'unknown: Spread children are not supported in React.' +
205 - '\n' +
206 - codeFrame.codeFrameColumns(
207 - code,
208 - {start: {line: 1, column: 6}, end: {line: 1, column: 19}},
209 - {highlightCode: true}
210 - )
211 - )
212 - );
213 - });
214 -
215 - it('should escape xhtml jsxattribute', () => {
216 - expect(
217 - transform(`
218 - <div id="wôw" />;
219 - <div id="\w" />;
220 - <div id="w &lt; w" />;
221 - `)
222 - ).toMatchSnapshot();
223 - });
224 -
225 - it('should escape xhtml jsxtext', () => {
226 - /* eslint-disable no-irregular-whitespace */
227 - expect(
228 - transform(`
229 - <div>wow</div>;
230 - <div>wôw</div>;
231 -
232 - <div>w & w</div>;
233 - <div>w &amp; w</div>;
234 -
235 - <div>w &nbsp; w</div>;
236 - <div>this should not parse as unicode: \u00a0</div>;
237 - <div>this should parse as nbsp:   </div>;
238 - <div>this should parse as unicode: {'\u00a0 '}</div>;
239 -
240 - <div>w &lt; w</div>;
241 - `)
242 - ).toMatchSnapshot();
243 - /*eslint-enable */
244 - });
245 -
246 - it('should handle attributed elements', () => {
247 - expect(
248 - transform(`
249 - var HelloMessage = React.createClass({
250 - render: function() {
251 - return <div>Hello {this.props.name}</div>;
252 - }
253 - });
254 -
255 - React.render(<HelloMessage name={
256 - <span>
257 - Sebastian
258 - </span>
259 - } />, mountNode);
260 - `)
261 - ).toMatchSnapshot();
262 - });
263 -
264 - it('should handle has own property correctly', () => {
265 - expect(
266 - transform(`<hasOwnProperty>testing</hasOwnProperty>;`)
267 - ).toMatchSnapshot();
268 - });
269 -
270 - it('should have correct comma in nested children', () => {
271 - expect(
272 - transform(`
273 - var x = <div>
274 - <div><br /></div>
275 - <Component>{foo}<br />{bar}</Component>
276 - <br />
277 - </div>;
278 - `)
279 - ).toMatchSnapshot();
280 - });
281 -
282 - it('should insert commas after expressions before whitespace', () => {
283 - expect(
284 - transform(`
285 - var x =
286 - <div
287 - attr1={
288 - "foo" + "bar"
289 - }
290 - attr2={
291 - "foo" + "bar" +
292 -
293 - "baz" + "bug"
294 - }
295 - attr3={
296 - "foo" + "bar" +
297 - "baz" + "bug"
298 - }
299 - attr4="baz">
300 - </div>
301 - `)
302 - ).toMatchSnapshot();
303 - });
304 -
305 - it('should not add quotes to identifier names', () => {
306 - expect(
307 - transform(`var e = <F aaa new const var default foo-bar/>;`)
308 - ).toMatchSnapshot();
309 - });
310 -
311 - it('should not strip nbsp even couple with other whitespace', () => {
312 - expect(transform(`<div>&nbsp; </div>;`)).toMatchSnapshot();
313 - });
314 -
315 - it('should not strip tags with a single child of nbsp', () => {
316 - expect(transform(`<div>&nbsp;</div>;`)).toMatchSnapshot();
317 - });
318 -
319 - it('should properly handle comments between props', () => {
320 - expect(
321 - transform(`
322 - var x = (
323 - <div
324 - /* a multi-line
325 - comment */
326 - attr1="foo">
327 - <span // a double-slash comment
328 - attr2="bar"
329 - />
330 - </div>
331 - );
332 - `)
333 - ).toMatchSnapshot();
334 - });
335 -
336 - it('should quote jsx attributes', () => {
337 - expect(
338 - transform(`<button data-value='a value'>Button</button>`)
339 - ).toMatchSnapshot();
340 - });
341 -
342 - it('should support xml namespaces if flag', () => {
343 - expect(
344 - transform('<f:image n:attr />', {throwIfNamespace: false})
345 - ).toMatchSnapshot();
346 - });
347 -
348 - it('should throw error namespaces if not flag', () => {
349 - let _error;
350 - const code = `<f:image />`;
351 - try {
352 - transform(code);
353 - } catch (error) {
354 - _error = error;
355 - }
356 - expect(_error).toEqual(
357 - new SyntaxError(
358 - "unknown: Namespace tags are not supported by default. React's " +
359 - "JSX doesn't support namespace tags. You can turn on the " +
360 - "'throwIfNamespace' flag to bypass this warning." +
361 - '\n' +
362 - codeFrame.codeFrameColumns(
363 - code,
364 - {start: {line: 1, column: 2}, end: {line: 1, column: 9}},
365 - {highlightCode: true}
366 - )
367 - )
368 - );
369 - });
370 -
371 - it('should transform known hyphenated tags', () => {
372 - expect(transform(`<font-face />`)).toMatchSnapshot();
373 - });
374 -
375 - it('wraps props in react spread for first spread attributes', () => {
376 - expect(transform(`<Component {...x} y={2} z />`)).toMatchSnapshot();
377 - });
378 -
379 - it('wraps props in react spread for last spread attributes', () => {
380 - expect(transform(`<Component y={2} z { ... x } />`)).toMatchSnapshot();
381 - });
382 -
383 - it('wraps props in react spread for middle spread attributes', () => {
384 - expect(transform(`<Component y={2} { ... x } z />`)).toMatchSnapshot();
385 - });
386 -
387 - it('useBuiltIns false uses extend instead of Object.assign', () => {
388 - expect(
389 - transform(`<Component y={2} {...x} />`, {useBuiltIns: false})
390 - ).toMatchSnapshot();
391 - });
392 -});
packages/babel-plugin-react-jsx/__tests__/TransformJSXToReactJSX-test.js
+369 -3
@@ -11,14 +11,15 @@ const babel = require('@babel/core');
11 const codeFrame = require('@babel/code-frame');
12 const {wrap} = require('jest-snapshot-serializer-raw');
13
14 -function transform(input, options) {
14 +function transform(input, pluginOpts, babelOpts) {
15 return wrap(
16 babel.transform(input, {
17 configFile: false,
18 + sourceType: 'module',
19 plugins: [
20 '@babel/plugin-syntax-jsx',
21 '@babel/plugin-transform-arrow-functions',
21 - ...(options && options.development
22 + ...(pluginOpts && pluginOpts.development
23 ? [
24 '@babel/plugin-transform-react-jsx-source',
25 '@babel/plugin-transform-react-jsx-self',
@@ -29,15 +30,380 @@ function transform(input, options) {
30 {
31 useBuiltIns: true,
32 useCreateElement: false,
32 - ...options,
33 + ...pluginOpts,
34 },
35 ],
36 ],
37 + ...babelOpts,
38 }).code
39 );
40 }
41
42 describe('transform react to jsx', () => {
43 + it('auto import pragma overrides regular pragma', () => {
44 + expect(
45 + transform(
46 + `/** @jsxAutoImport defaultExport */
47 + var x = <div><span /></div>
48 + `,
49 + {
50 + autoImport: 'namespace',
51 + importSource: 'foobar',
52 + }
53 + )
54 + ).toMatchSnapshot();
55 + });
56 +
57 + it('import source pragma overrides regular pragma', () => {
58 + expect(
59 + transform(
60 + `/** @jsxImportSource baz */
61 + var x = <div><span /></div>
62 + `,
63 + {
64 + autoImport: 'namespace',
65 + importSource: 'foobar',
66 + }
67 + )
68 + ).toMatchSnapshot();
69 + });
70 +
71 + it('multiple pragmas work', () => {
72 + expect(
73 + transform(
74 + `/** Some comment here
75 + * @jsxImportSource baz
76 + * @jsxAutoImport defaultExport
77 + */
78 + var x = <div><span /></div>
79 + `,
80 + {
81 + autoImport: 'namespace',
82 + importSource: 'foobar',
83 + }
84 + )
85 + ).toMatchSnapshot();
86 + });
87 +
88 + it('throws error when sourceType is module and autoImport is require', () => {
89 + const code = `var x = <div><span /></div>`;
90 + expect(() => {
91 + transform(code, {
92 + autoImport: 'require',
93 + });
94 + }).toThrow(
95 + 'Babel `sourceType` must be set to `script` for autoImport ' +
96 + 'to use `require` syntax. See Babel `sourceType` for details.\n' +
97 + codeFrame.codeFrameColumns(
98 + code,
99 + {start: {line: 1, column: 1}, end: {line: 1, column: 28}},
100 + {highlightCode: true}
101 + )
102 + );
103 + });
104 +
105 + it('throws error when sourceType is script and autoImport is not require', () => {
106 + const code = `var x = <div><span /></div>`;
107 + expect(() => {
108 + transform(
109 + code,
110 + {
111 + autoImport: 'namespace',
112 + },
113 + {sourceType: 'script'}
114 + );
115 + }).toThrow(
116 + 'Babel `sourceType` must be set to `module` for autoImport ' +
117 + 'to use `namespace` syntax. See Babel `sourceType` for details.\n' +
118 + codeFrame.codeFrameColumns(
119 + code,
120 + {start: {line: 1, column: 1}, end: {line: 1, column: 28}},
121 + {highlightCode: true}
122 + )
123 + );
124 + });
125 +
126 + it("auto import that doesn't exist should throw error", () => {
127 + const code = `var x = <div><span /></div>`;
128 + expect(() => {
129 + transform(code, {
130 + autoImport: 'foo',
131 + });
132 + }).toThrow(
133 + 'autoImport must be one of the following: none, require, namespace, defaultExport, namedExports\n' +
134 + codeFrame.codeFrameColumns(
135 + code,
136 + {start: {line: 1, column: 1}, end: {line: 1, column: 28}},
137 + {highlightCode: true}
138 + )
139 + );
140 + });
141 +
142 + it('auto import can specify source', () => {
143 + expect(
144 + transform(`var x = <div><span /></div>`, {
145 + autoImport: 'namespace',
146 + importSource: 'foobar',
147 + })
148 + ).toMatchSnapshot();
149 + });
150 +
151 + it('auto import require', () => {
152 + expect(
153 + transform(
154 + `var x = (
155 + <>
156 + <div>
157 + <div key="1" />
158 + <div key="2" meow="wolf" />
159 + <div key="3" />
160 + <div {...props} key="4" />
161 + </div>
162 + </>
163 + );`,
164 + {
165 + autoImport: 'require',
166 + },
167 + {
168 + sourceType: 'script',
169 + }
170 + )
171 + ).toMatchSnapshot();
172 + });
173 +
174 + it('auto import namespace', () => {
175 + expect(
176 + transform(
177 + `var x = (
178 + <>
179 + <div>
180 + <div key="1" />
181 + <div key="2" meow="wolf" />
182 + <div key="3" />
183 + <div {...props} key="4" />
184 + </div>
185 + </>
186 + );`,
187 + {
188 + autoImport: 'namespace',
189 + }
190 + )
191 + ).toMatchSnapshot();
192 + });
193 +
194 + it('auto import default', () => {
195 + expect(
196 + transform(
197 + `var x = (
198 + <>
199 + <div>
200 + <div key="1" />
201 + <div key="2" meow="wolf" />
202 + <div key="3" />
203 + <div {...props} key="4" />
204 + </div>
205 + </>
206 + );`,
207 + {
208 + autoImport: 'defaultExport',
209 + }
210 + )
211 + ).toMatchSnapshot();
212 + });
213 +
214 + it('auto import named exports', () => {
215 + expect(
216 + transform(
217 + `var x = (
218 + <>
219 + <div>
220 + <div key="1" />
221 + <div key="2" meow="wolf" />
222 + <div key="3" />
223 + <div {...props} key="4" />
224 + </div>
225 + </>
226 + );`,
227 + {
228 + autoImport: 'namedExports',
229 + }
230 + )
231 + ).toMatchSnapshot();
232 + });
233 +
234 + it('auto import with no JSX', () => {
235 + expect(
236 + transform(
237 + `var foo = "<div></div>"`,
238 + {
239 + autoImport: 'require',
240 + },
241 + {
242 + sourceType: 'script',
243 + }
244 + )
245 + ).toMatchSnapshot();
246 + });
247 +
248 + it('complicated scope require', () => {
249 + expect(
250 + transform(
251 + `
252 + const Bar = () => {
253 + const Foo = () => {
254 + const Component = ({thing, ..._react}) => {
255 + if (!thing) {
256 + var _react2 = "something useless";
257 + var b = _react3();
258 + var c = _react5();
259 + var jsx = 1;
260 + var _jsx = 2;
261 + return <div />;
262 + };
263 + return <span />;
264 + };
265 + }
266 + }
267 + `,
268 + {
269 + autoImport: 'require',
270 + },
271 + {
272 + sourceType: 'script',
273 + }
274 + )
275 + ).toMatchSnapshot();
276 + });
277 +
278 + it('complicated scope named exports', () => {
279 + expect(
280 + transform(
281 + `
282 + const Bar = () => {
283 + const Foo = () => {
284 + const Component = ({thing, ..._react}) => {
285 + if (!thing) {
286 + var _react2 = "something useless";
287 + var b = _react3();
288 + var jsx = 1;
289 + var _jsx = 2;
290 + return <div />;
291 + };
292 + return <span />;
293 + };
294 + }
295 + }
296 + `,
297 + {
298 + autoImport: 'namedExports',
299 + }
300 + )
301 + ).toMatchSnapshot();
302 + });
303 +
304 + it('auto import in dev', () => {
305 + expect(
306 + transform(
307 + `var x = (
308 + <>
309 + <div>
310 + <div key="1" />
311 + <div key="2" meow="wolf" />
312 + <div key="3" />
313 + <div {...props} key="4" />
314 + </div>
315 + </>
316 + );`,
317 + {
318 + autoImport: 'namedExports',
319 + development: true,
320 + }
321 + )
322 + ).toMatchSnapshot();
323 + });
324 +
325 + it('auto import none', () => {
326 + expect(
327 + transform(
328 + `var x = (
329 + <>
330 + <div>
331 + <div key="1" />
332 + <div key="2" meow="wolf" />
333 + <div key="3" />
334 + <div {...props} key="4" />
335 + </div>
336 + </>
337 + );`,
338 + {
339 + autoImport: 'none',
340 + }
341 + )
342 + ).toMatchSnapshot();
343 + });
344 +
345 + it('auto import undefined', () => {
346 + expect(
347 + transform(
348 + `var x = (
349 + <>
350 + <div>
351 + <div key="1" />
352 + <div key="2" meow="wolf" />
353 + <div key="3" />
354 + <div {...props} key="4" />
355 + </div>
356 + </>
357 + );`
358 + )
359 + ).toMatchSnapshot();
360 + });
361 +
362 + it('auto import with namespaces already defined', () => {
363 + expect(
364 + transform(
365 + `
366 + import * as _react from "foo";
367 + const react = _react(1);
368 + const _react1 = react;
369 + const _react2 = react;
370 + var x = (
371 + <div>
372 + <div key="1" />
373 + <div key="2" meow="wolf" />
374 + <div key="3" />
375 + <div {...props} key="4" />
376 + </div>
377 + );`,
378 + {
379 + autoImport: 'namespace',
380 + }
381 + )
382 + ).toMatchSnapshot();
383 + });
384 +
385 + it('auto import with react already defined', () => {
386 + expect(
387 + transform(
388 + `
389 + import * as react from "react";
390 + var y = react.createElement("div", {foo: 1});
391 + var x = (
392 + <div>
393 + <div key="1" />
394 + <div key="2" meow="wolf" />
395 + <div key="3" />
396 + <div {...props} key="4" />
397 + </div>
398 + );`,
399 +
400 + {
401 + autoImport: 'namespace',
402 + }
403 + )
404 + ).toMatchSnapshot();
405 + });
406 +
407 it('fragment with no children', () => {
408 expect(transform(`var x = <></>`)).toMatchSnapshot();
409 });
packages/babel-plugin-react-jsx/__tests__/__snapshots__/TransformJSXToReactCreateElement-test.js.snap deleted
-213
@@ -1,213 +0,0 @@
1 -// Jest Snapshot v1, https://goo.gl/fbAQLP
2 -
3 -exports[`transform react to jsx React.Fragment to set keys and source 1`] = `
4 -var _jsxFileName = "";
5 -var x = React.createElement(React.Fragment, {
6 - key: "foo",
7 - __source: {
8 - fileName: _jsxFileName,
9 - lineNumber: 1
10 - },
11 - __self: this
12 -}, React.createElement("div", {
13 - __source: {
14 - fileName: _jsxFileName,
15 - lineNumber: 1
16 - },
17 - __self: this
18 -}));
19 -`;
20 -
21 -exports[`transform react to jsx adds appropriate new lines when using spread attribute 1`] = `
22 -React.createElement(Component, Object.assign({}, props, {
23 - sound: "moo"
24 -}));
25 -`;
26 -
27 -exports[`transform react to jsx arrow functions 1`] = `
28 -var foo = function () {
29 - var _this = this;
30 -
31 - return function () {
32 - return React.createElement(_this, null);
33 - };
34 -};
35 -
36 -var bar = function () {
37 - var _this2 = this;
38 -
39 - return function () {
40 - return React.createElement(_this2.foo, null);
41 - };
42 -};
43 -`;
44 -
45 -exports[`transform react to jsx assignment 1`] = `
46 -var div = React.createElement(Component, Object.assign({}, props, {
47 - foo: "bar"
48 -}));
49 -`;
50 -
51 -exports[`transform react to jsx concatenates adjacent string literals 1`] = `var x = React.createElement("div", null, "foo", "bar", "baz", React.createElement("div", null, "buz bang"), "qux", null, "quack");`;
52 -
53 -exports[`transform react to jsx fragment with no children 1`] = `var x = React.createElement(React.Fragment, null);`;
54 -
55 -exports[`transform react to jsx normal fragments not to set key and source 1`] = `
56 -var _jsxFileName = "";
57 -var x = React.createElement(React.Fragment, null, React.createElement("div", {
58 - __source: {
59 - fileName: _jsxFileName,
60 - lineNumber: 1
61 - },
62 - __self: this
63 -}));
64 -`;
65 -
66 -exports[`transform react to jsx should allow constructor as prop 1`] = `
67 -React.createElement(Component, {
68 - constructor: "foo"
69 -});
70 -`;
71 -
72 -exports[`transform react to jsx should allow deeper js namespacing 1`] = `React.createElement(Namespace.DeepNamespace.Component, null);`;
73 -
74 -exports[`transform react to jsx should allow elements as attributes 1`] = `
75 -React.createElement("div", {
76 - attr: React.createElement("div", null)
77 -});
78 -`;
79 -
80 -exports[`transform react to jsx should allow js namespacing 1`] = `React.createElement(Namespace.Component, null);`;
81 -
82 -exports[`transform react to jsx should allow nested fragments 1`] = `React.createElement("div", null, React.createElement(React.Fragment, null, React.createElement(React.Fragment, null, React.createElement("span", null, "Hello"), React.createElement("span", null, "world")), React.createElement(React.Fragment, null, React.createElement("span", null, "Goodbye"), React.createElement("span", null, "world"))));`;
83 -
84 -exports[`transform react to jsx should avoid wrapping in extra parens if not needed 1`] = `
85 -var x = React.createElement("div", null, React.createElement(Component, null));
86 -var x = React.createElement("div", null, props.children);
87 -var x = React.createElement(Composite, null, props.children);
88 -var x = React.createElement(Composite, null, React.createElement(Composite2, null));
89 -`;
90 -
91 -exports[`transform react to jsx should convert simple tags 1`] = `var x = React.createElement("div", null);`;
92 -
93 -exports[`transform react to jsx should convert simple text 1`] = `var x = React.createElement("div", null, "text");`;
94 -
95 -exports[`transform react to jsx should escape xhtml jsxattribute 1`] = `
96 -React.createElement("div", {
97 - id: "w\\xF4w"
98 -});
99 -React.createElement("div", {
100 - id: "w"
101 -});
102 -React.createElement("div", {
103 - id: "w < w"
104 -});
105 -`;
106 -
107 -exports[`transform react to jsx should escape xhtml jsxtext 1`] = `
108 -React.createElement("div", null, "wow");
109 -React.createElement("div", null, "w\\xF4w");
110 -React.createElement("div", null, "w & w");
111 -React.createElement("div", null, "w & w");
112 -React.createElement("div", null, "w \\xA0 w");
113 -React.createElement("div", null, "this should not parse as unicode: \\xA0");
114 -React.createElement("div", null, "this should parse as nbsp: \\xA0 ");
115 -React.createElement("div", null, "this should parse as unicode: ", '  ');
116 -React.createElement("div", null, "w < w");
117 -`;
118 -
119 -exports[`transform react to jsx should handle attributed elements 1`] = `
120 -var HelloMessage = React.createClass({
121 - render: function () {
122 - return React.createElement("div", null, "Hello ", this.props.name);
123 - }
124 -});
125 -React.render(React.createElement(HelloMessage, {
126 - name: React.createElement("span", null, "Sebastian")
127 -}), mountNode);
128 -`;
129 -
130 -exports[`transform react to jsx should handle has own property correctly 1`] = `React.createElement("hasOwnProperty", null, "testing");`;
131 -
132 -exports[`transform react to jsx should have correct comma in nested children 1`] = `var x = React.createElement("div", null, React.createElement("div", null, React.createElement("br", null)), React.createElement(Component, null, foo, React.createElement("br", null), bar), React.createElement("br", null));`;
133 -
134 -exports[`transform react to jsx should insert commas after expressions before whitespace 1`] = `
135 -var x = React.createElement("div", {
136 - attr1: "foo" + "bar",
137 - attr2: "foo" + "bar" + "baz" + "bug",
138 - attr3: "foo" + "bar" + "baz" + "bug",
139 - attr4: "baz"
140 -});
141 -`;
142 -
143 -exports[`transform react to jsx should not add quotes to identifier names 1`] = `
144 -var e = React.createElement(F, {
145 - aaa: true,
146 - new: true,
147 - const: true,
148 - var: true,
149 - default: true,
150 - "foo-bar": true
151 -});
152 -`;
153 -
154 -exports[`transform react to jsx should not strip nbsp even couple with other whitespace 1`] = `React.createElement("div", null, "\\xA0 ");`;
155 -
156 -exports[`transform react to jsx should not strip tags with a single child of nbsp 1`] = `React.createElement("div", null, "\\xA0");`;
157 -
158 -exports[`transform react to jsx should properly handle comments adjacent to children 1`] = `var x = React.createElement("div", null, React.createElement("span", null), React.createElement("br", null));`;
159 -
160 -exports[`transform react to jsx should properly handle comments between props 1`] = `
161 -var x = React.createElement("div", {
162 - /* a multi-line
163 - comment */
164 - attr1: "foo"
165 -}, React.createElement("span", {
166 - // a double-slash comment
167 - attr2: "bar"
168 -}));
169 -`;
170 -
171 -exports[`transform react to jsx should quote jsx attributes 1`] = `
172 -React.createElement("button", {
173 - "data-value": "a value"
174 -}, "Button");
175 -`;
176 -
177 -exports[`transform react to jsx should support xml namespaces if flag 1`] = `
178 -React.createElement("f:image", {
179 - "n:attr": true
180 -});
181 -`;
182 -
183 -exports[`transform react to jsx should transform known hyphenated tags 1`] = `React.createElement("font-face", null);`;
184 -
185 -exports[`transform react to jsx useBuiltIns false uses extend instead of Object.assign 1`] = `
186 -function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
187 -
188 -React.createElement(Component, _extends({
189 - y: 2
190 -}, x));
191 -`;
192 -
193 -exports[`transform react to jsx wraps props in react spread for first spread attributes 1`] = `
194 -React.createElement(Component, Object.assign({}, x, {
195 - y: 2,
196 - z: true
197 -}));
198 -`;
199 -
200 -exports[`transform react to jsx wraps props in react spread for last spread attributes 1`] = `
201 -React.createElement(Component, Object.assign({
202 - y: 2,
203 - z: true
204 -}, x));
205 -`;
206 -
207 -exports[`transform react to jsx wraps props in react spread for middle spread attributes 1`] = `
208 -React.createElement(Component, Object.assign({
209 - y: 2
210 -}, x, {
211 - z: true
212 -}));
213 -`;
packages/babel-plugin-react-jsx/__tests__/__snapshots__/TransformJSXToReactJSX-test.js.snap
+245
@@ -38,6 +38,230 @@ var div = React.jsx(Component, Object.assign({}, props, {
38 }));
39 `;
40
41 +exports[`transform react to jsx auto import can specify source 1`] = `
42 +import * as _foobar from "foobar";
43 +
44 +var x = _foobar.jsx("div", {
45 + children: _foobar.jsx("span", {})
46 +});
47 +`;
48 +
49 +exports[`transform react to jsx auto import default 1`] = `
50 +import _default from "react";
51 +
52 +var x = _default.jsx(_default.Fragment, {
53 + children: _default.jsxs("div", {
54 + children: [_default.jsx("div", {}, "1"), _default.jsx("div", {
55 + meow: "wolf"
56 + }, "2"), _default.jsx("div", {}, "3"), _default.createElement("div", Object.assign({}, props, {
57 + key: "4"
58 + }))]
59 + })
60 +});
61 +`;
62 +
63 +exports[`transform react to jsx auto import in dev 1`] = `
64 +import { createElement as _createElement } from "react";
65 +import { jsxDEV as _jsxDEV } from "react";
66 +import { Fragment as _Fragment } from "react";
67 +var _jsxFileName = "";
68 +
69 +var x = _jsxDEV(_Fragment, {
70 + children: _jsxDEV("div", {
71 + children: [_jsxDEV("div", {}, "1", false, {
72 + fileName: _jsxFileName,
73 + lineNumber: 4
74 + }, this), _jsxDEV("div", {
75 + meow: "wolf"
76 + }, "2", false, {
77 + fileName: _jsxFileName,
78 + lineNumber: 5
79 + }, this), _jsxDEV("div", {}, "3", false, {
80 + fileName: _jsxFileName,
81 + lineNumber: 6
82 + }, this), _createElement("div", Object.assign({}, props, {
83 + key: "4",
84 + __source: {
85 + fileName: _jsxFileName,
86 + lineNumber: 7
87 + },
88 + __self: this
89 + }))]
90 + }, undefined, true, {
91 + fileName: _jsxFileName,
92 + lineNumber: 3
93 + }, this)
94 +}, undefined, false);
95 +`;
96 +
97 +exports[`transform react to jsx auto import named exports 1`] = `
98 +import { createElement as _createElement } from "react";
99 +import { jsx as _jsx } from "react";
100 +import { jsxs as _jsxs } from "react";
101 +import { Fragment as _Fragment } from "react";
102 +
103 +var x = _jsx(_Fragment, {
104 + children: _jsxs("div", {
105 + children: [_jsx("div", {}, "1"), _jsx("div", {
106 + meow: "wolf"
107 + }, "2"), _jsx("div", {}, "3"), _createElement("div", Object.assign({}, props, {
108 + key: "4"
109 + }))]
110 + })
111 +});
112 +`;
113 +
114 +exports[`transform react to jsx auto import namespace 1`] = `
115 +import * as _react from "react";
116 +
117 +var x = _react.jsx(_react.Fragment, {
118 + children: _react.jsxs("div", {
119 + children: [_react.jsx("div", {}, "1"), _react.jsx("div", {
120 + meow: "wolf"
121 + }, "2"), _react.jsx("div", {}, "3"), _react.createElement("div", Object.assign({}, props, {
122 + key: "4"
123 + }))]
124 + })
125 +});
126 +`;
127 +
128 +exports[`transform react to jsx auto import none 1`] = `
129 +var x = React.jsx(React.Fragment, {
130 + children: React.jsxs("div", {
131 + children: [React.jsx("div", {}, "1"), React.jsx("div", {
132 + meow: "wolf"
133 + }, "2"), React.jsx("div", {}, "3"), React.createElement("div", Object.assign({}, props, {
134 + key: "4"
135 + }))]
136 + })
137 +});
138 +`;
139 +
140 +exports[`transform react to jsx auto import pragma overrides regular pragma 1`] = `
141 +import _default from "foobar";
142 +
143 +/** @jsxAutoImport defaultExport */
144 +var x = _default.jsx("div", {
145 + children: _default.jsx("span", {})
146 +});
147 +`;
148 +
149 +exports[`transform react to jsx auto import require 1`] = `
150 +var _react = require("react");
151 +
152 +var x = _react.jsx(_react.Fragment, {
153 + children: _react.jsxs("div", {
154 + children: [_react.jsx("div", {}, "1"), _react.jsx("div", {
155 + meow: "wolf"
156 + }, "2"), _react.jsx("div", {}, "3"), _react.createElement("div", Object.assign({}, props, {
157 + key: "4"
158 + }))]
159 + })
160 +});
161 +`;
162 +
163 +exports[`transform react to jsx auto import undefined 1`] = `
164 +var x = React.jsx(React.Fragment, {
165 + children: React.jsxs("div", {
166 + children: [React.jsx("div", {}, "1"), React.jsx("div", {
167 + meow: "wolf"
168 + }, "2"), React.jsx("div", {}, "3"), React.createElement("div", Object.assign({}, props, {
169 + key: "4"
170 + }))]
171 + })
172 +});
173 +`;
174 +
175 +exports[`transform react to jsx auto import with namespaces already defined 1`] = `
176 +import * as _react3 from "react";
177 +import * as _react from "foo";
178 +
179 +const react = _react(1);
180 +
181 +const _react1 = react;
182 +const _react2 = react;
183 +
184 +var x = _react3.jsxs("div", {
185 + children: [_react3.jsx("div", {}, "1"), _react3.jsx("div", {
186 + meow: "wolf"
187 + }, "2"), _react3.jsx("div", {}, "3"), _react3.createElement("div", Object.assign({}, props, {
188 + key: "4"
189 + }))]
190 +});
191 +`;
192 +
193 +exports[`transform react to jsx auto import with no JSX 1`] = `var foo = "<div></div>";`;
194 +
195 +exports[`transform react to jsx auto import with react already defined 1`] = `
196 +import * as _react from "react";
197 +import * as react from "react";
198 +var y = react.createElement("div", {
199 + foo: 1
200 +});
201 +
202 +var x = _react.jsxs("div", {
203 + children: [_react.jsx("div", {}, "1"), _react.jsx("div", {
204 + meow: "wolf"
205 + }, "2"), _react.jsx("div", {}, "3"), _react.createElement("div", Object.assign({}, props, {
206 + key: "4"
207 + }))]
208 +});
209 +`;
210 +
211 +exports[`transform react to jsx complicated scope named exports 1`] = `
212 +import { jsx as _jsx2 } from "react";
213 +
214 +const Bar = function () {
215 + const Foo = function () {
216 + const Component = function ({
217 + thing,
218 + ..._react
219 + }) {
220 + if (!thing) {
221 + var _react2 = "something useless";
222 +
223 + var b = _react3();
224 +
225 + var jsx = 1;
226 + var _jsx = 2;
227 + return _jsx2("div", {});
228 + }
229 +
230 + ;
231 + return _jsx2("span", {});
232 + };
233 + };
234 +};
235 +`;
236 +
237 +exports[`transform react to jsx complicated scope require 1`] = `
238 +var _react4 = require("react");
239 +
240 +const Bar = function () {
241 + const Foo = function () {
242 + const Component = function ({
243 + thing,
244 + ..._react
245 + }) {
246 + if (!thing) {
247 + var _react2 = "something useless";
248 +
249 + var b = _react3();
250 +
251 + var c = _react5();
252 +
253 + var jsx = 1;
254 + var _jsx = 2;
255 + return _react4.jsx("div", {});
256 + }
257 +
258 + ;
259 + return _react4.jsx("span", {});
260 + };
261 + };
262 +};
263 +`;
264 +
265 exports[`transform react to jsx concatenates adjacent string literals 1`] = `
266 var x = React.jsxs("div", {
267 children: ["foo", "bar", "baz", React.jsx("div", {
@@ -92,6 +316,27 @@ var x = React.jsxDEV(React.Fragment, {
316
317 exports[`transform react to jsx fragments to set keys 1`] = `var x = React.jsx(React.Fragment, {}, "foo");`;
318
319 +exports[`transform react to jsx import source pragma overrides regular pragma 1`] = `
320 +import * as _baz from "baz";
321 +
322 +/** @jsxImportSource baz */
323 +var x = _baz.jsx("div", {
324 + children: _baz.jsx("span", {})
325 +});
326 +`;
327 +
328 +exports[`transform react to jsx multiple pragmas work 1`] = `
329 +import _default from "baz";
330 +
331 +/** Some comment here
332 + * @jsxImportSource baz
333 + * @jsxAutoImport defaultExport
334 + */
335 +var x = _default.jsx("div", {
336 + children: _default.jsx("span", {})
337 +});
338 +`;
339 +
340 exports[`transform react to jsx nonStatic children 1`] = `
341 var _jsxFileName = "";
342 var x = React.jsxDEV("div", {
packages/babel-plugin-react-jsx/package.json
+1 -1
@@ -5,8 +5,8 @@
5 "description": "@babel/plugin-transform-react-jsx",
6 "main": "index.js",
7 "dependencies": {
8 + "@babel/helper-module-imports": "^7.0.0",
9 "esutils": "^2.0.0"
9 -
10 },
11 "files": [
12 "README.md",
packages/babel-plugin-react-jsx/src/TransformJSXToReactBabelPlugin.js
+221 -80
@@ -24,6 +24,50 @@
24 'use strict';
25
26 const esutils = require('esutils');
27 +const {
28 + isModule,
29 + addNamespace,
30 + addNamed,
31 + addDefault,
32 +} = require('@babel/helper-module-imports');
33 +
34 +// These are all the valid auto import types (under the config autoImport)
35 +// that a user can specific
36 +const IMPORT_TYPES = {
37 + none: 'none', // default option. Will not import anything
38 + require: 'require', // var _react = require("react");
39 + namespace: 'namespace', // import * as _react from "react";
40 + defaultExport: 'defaultExport', // import _default from "react";
41 + namedExports: 'namedExports', // import { jsx } from "react";
42 +};
43 +
44 +const JSX_AUTO_IMPORT_ANNOTATION_REGEX = /\*?\s*@jsxAutoImport\s+([^\s]+)/;
45 +const JSX_IMPORT_SOURCE_ANNOTATION_REGEX = /\*?\s*@jsxImportSource\s+([^\s]+)/;
46 +
47 +// We want to use React.createElement, even in the case of
48 +// jsx, for <div {...props} key={key} /> to distinguish it
49 +// from <div key={key} {...props} />. This is an intermediary
50 +// step while we deprecate key spread from props. Afterwards,
51 +// we will remove createElement entirely
52 +function shouldUseCreateElement(path, types) {
53 + const openingPath = path.get('openingElement');
54 + const attributes = openingPath.node.attributes;
55 +
56 + let seenPropsSpread = false;
57 + for (let i = 0; i < attributes.length; i++) {
58 + const attr = attributes[i];
59 + if (
60 + seenPropsSpread &&
61 + types.isJSXAttribute(attr) &&
62 + attr.name.name === 'key'
63 + ) {
64 + return true;
65 + } else if (types.isJSXSpreadAttribute(attr)) {
66 + seenPropsSpread = true;
67 + }
68 + }
69 + return false;
70 +}
71
72 function helper(babel, opts) {
73 const {types: t} = babel;
@@ -52,7 +96,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
96 visitor.JSXElement = {
97 exit(path, file) {
98 let callExpr;
55 - if (file.opts.useCreateElement || shouldUseCreateElement(path)) {
99 + if (shouldUseCreateElement(path, t)) {
100 callExpr = buildCreateElementCall(path, file);
101 } else {
102 callExpr = buildJSXElementCall(path, file);
@@ -71,12 +115,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
115 'Fragment tags are only supported in React 16 and up.',
116 );
117 }
74 - let callExpr;
75 - if (file.opts.useCreateElement) {
76 - callExpr = buildCreateElementFragmentCall(path, file);
77 - } else {
78 - callExpr = buildJSXFragmentCall(path, file);
79 - }
118 + let callExpr = buildJSXFragmentCall(path, file);
119
120 if (callExpr) {
121 path.replaceWith(t.inherits(callExpr, path.node));
@@ -147,31 +186,6 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
186 return t.inherits(t.objectProperty(node.name, value), node);
187 }
188
150 - // We want to use React.createElement, even in the case of
151 - // jsx, for <div {...props} key={key} /> to distinguish it
152 - // from <div key={key} {...props} />. This is an intermediary
153 - // step while we deprecate key spread from props. Afterwards,
154 - // we will remove createElement entirely
155 - function shouldUseCreateElement(path) {
156 - const openingPath = path.get('openingElement');
157 - const attributes = openingPath.node.attributes;
158 -
159 - let seenPropsSpread = false;
160 - for (let i = 0; i < attributes.length; i++) {
161 - const attr = attributes[i];
162 - if (
163 - seenPropsSpread &&
164 - t.isJSXAttribute(attr) &&
165 - attr.name.name === 'key'
166 - ) {
167 - return true;
168 - } else if (t.isJSXSpreadAttribute(attr)) {
169 - seenPropsSpread = true;
170 - }
171 - }
172 - return false;
173 - }
174 -
189 // Builds JSX into:
190 // Production: React.jsx(type, arguments, key)
191 // Development: React.jsxDEV(type, arguments, key, isStaticChildren, source, self)
@@ -262,6 +276,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
276 if (opts.post) {
277 opts.post(state, file);
278 }
279 +
280 return (
281 state.call ||
282 t.callExpression(
@@ -561,38 +576,6 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
576
577 return attribs;
578 }
564 -
565 - function buildCreateElementFragmentCall(path, file) {
566 - if (opts.filter && !opts.filter(path.node, file)) {
567 - return;
568 - }
569 -
570 - const openingPath = path.get('openingElement');
571 - openingPath.parent.children = t.react.buildChildren(openingPath.parent);
572 -
573 - const args = [];
574 - const tagName = null;
575 - const tagExpr = file.get('jsxFragIdentifier')();
576 -
577 - const state = {
578 - tagExpr: tagExpr,
579 - tagName: tagName,
580 - args: args,
581 - };
582 -
583 - if (opts.pre) {
584 - opts.pre(state, file);
585 - }
586 -
587 - // no attributes are allowed with <> syntax
588 - args.push(t.nullLiteral(), ...path.node.children);
589 -
590 - if (opts.post) {
591 - opts.post(state, file);
592 - }
593 -
594 - return state.call || t.callExpression(state.oldCallee, args);
595 - }
579 }
580
581 module.exports = function(babel) {
@@ -623,25 +606,183 @@ module.exports = function(babel) {
606 },
607 });
608
626 - visitor.Program = {
627 - enter(path, state) {
628 - state.set(
629 - 'oldJSXIdentifier',
630 - createIdentifierParser('React.createElement'),
609 + const createIdentifierName = (path, autoImport, name, importName) => {
610 + if (autoImport === IMPORT_TYPES.none) {
611 + return `React.${name}`;
612 + } else if (autoImport === IMPORT_TYPES.namedExports) {
613 + if (importName) {
614 + const identifierName = `${importName[name]}`;
615 + return identifierName;
616 + }
617 + } else {
618 + return `${importName}.${name}`;
619 + }
620 + };
621 +
622 + function getImportNames(parentPath, state) {
623 + const imports = {};
624 + parentPath.traverse({
625 + JSXElement(path) {
626 + if (shouldUseCreateElement(path, t)) {
627 + imports.createElement = true;
628 + } else if (path.node.children.length > 1) {
629 + const importName = state.development ? 'jsxDEV' : 'jsxs';
630 + imports[importName] = true;
631 + } else {
632 + const importName = state.development ? 'jsxDEV' : 'jsx';
633 + imports[importName] = true;
634 + }
635 + },
636 +
637 + JSXFragment(path) {
638 + imports.Fragment = true;
639 + },
640 + });
641 + return imports;
642 + }
643 +
644 + function hasJSX(parentPath) {
645 + let fileHasJSX = false;
646 + parentPath.traverse({
647 + JSXElement(path) {
648 + fileHasJSX = true;
649 + path.stop();
650 + },
651 +
652 + JSXFragment(path) {
653 + fileHasJSX = true;
654 + path.stop();
655 + },
656 + });
657 +
658 + return fileHasJSX;
659 + }
660 +
661 + function addAutoImports(path, state) {
662 + if (state.autoImport === IMPORT_TYPES.none) {
663 + return;
664 + }
665 +
666 + if (IMPORT_TYPES[state.autoImport] === undefined) {
667 + throw path.buildCodeFrameError(
668 + 'autoImport must be one of the following: ' +
669 + Object.keys(IMPORT_TYPES).join(', '),
670 );
632 - state.set(
633 - 'jsxIdentifier',
634 - createIdentifierParser(
635 - state.opts.development ? 'React.jsxDEV' : 'React.jsx',
636 - ),
671 + }
672 + if (state.autoImport === IMPORT_TYPES.require && isModule(path)) {
673 + throw path.buildCodeFrameError(
674 + 'Babel `sourceType` must be set to `script` for autoImport ' +
675 + 'to use `require` syntax. See Babel `sourceType` for details.',
676 );
638 - state.set(
639 - 'jsxStaticIdentifier',
640 - createIdentifierParser(
641 - state.opts.development ? 'React.jsxDEV' : 'React.jsxs',
642 - ),
677 + }
678 + if (state.autoImport !== IMPORT_TYPES.require && !isModule(path)) {
679 + throw path.buildCodeFrameError(
680 + 'Babel `sourceType` must be set to `module` for autoImport to use `' +
681 + state.autoImport +
682 + '` syntax. See Babel `sourceType` for details.',
683 );
644 - state.set('jsxFragIdentifier', createIdentifierParser('React.Fragment'));
684 + }
685 +
686 + // import {jsx} from "react";
687 + // import {createElement} from "react";
688 + if (state.autoImport === IMPORT_TYPES.namedExports) {
689 + const imports = getImportNames(path, state);
690 + const importMap = {};
691 +
692 + Object.keys(imports).forEach(importName => {
693 + importMap[importName] = addNamed(path, importName, state.source).name;
694 + });
695 +
696 + return importMap;
697 + }
698 +
699 + // add import to file and get the import name
700 + let name;
701 + if (state.autoImport === IMPORT_TYPES.require) {
702 + // var _react = require("react");
703 + name = addNamespace(path, state.source, {
704 + importedInterop: 'uncompiled',
705 + }).name;
706 + } else if (state.autoImport === IMPORT_TYPES.namespace) {
707 + // import * as _react from "react";
708 + name = addNamespace(path, state.source).name;
709 + } else if (state.autoImport === IMPORT_TYPES.defaultExport) {
710 + // import _default from "react";
711 + name = addDefault(path, state.source).name;
712 + }
713 +
714 + return name;
715 + }
716 +
717 + visitor.Program = {
718 + enter(path, state) {
719 + if (hasJSX(path)) {
720 + let autoImport = state.opts.autoImport || IMPORT_TYPES.none;
721 + let source = state.opts.importSource || 'react';
722 + const {file} = state;
723 +
724 + if (file.ast.comments) {
725 + for (let i = 0; i < file.ast.comments.length; i++) {
726 + const comment = file.ast.comments[i];
727 + const jsxAutoImportMatches = JSX_AUTO_IMPORT_ANNOTATION_REGEX.exec(
728 + comment.value,
729 + );
730 + if (jsxAutoImportMatches) {
731 + autoImport = jsxAutoImportMatches[1];
732 + }
733 + const jsxImportSourceMatches = JSX_IMPORT_SOURCE_ANNOTATION_REGEX.exec(
734 + comment.value,
735 + );
736 + if (jsxImportSourceMatches) {
737 + source = jsxImportSourceMatches[1];
738 + }
739 + }
740 + }
741 +
742 + const importName = addAutoImports(path, {
743 + ...state.opts,
744 + autoImport,
745 + source,
746 + });
747 +
748 + state.set(
749 + 'oldJSXIdentifier',
750 + createIdentifierParser(
751 + createIdentifierName(path, autoImport, 'createElement', importName),
752 + ),
753 + );
754 +
755 + state.set(
756 + 'jsxIdentifier',
757 + createIdentifierParser(
758 + createIdentifierName(
759 + path,
760 + autoImport,
761 + state.opts.development ? 'jsxDEV' : 'jsx',
762 + importName,
763 + ),
764 + ),
765 + );
766 +
767 + state.set(
768 + 'jsxStaticIdentifier',
769 + createIdentifierParser(
770 + createIdentifierName(
771 + path,
772 + autoImport,
773 + state.opts.development ? 'jsxDEV' : 'jsxs',
774 + importName,
775 + ),
776 + ),
777 + );
778 +
779 + state.set(
780 + 'jsxFragIdentifier',
781 + createIdentifierParser(
782 + createIdentifierName(path, autoImport, 'Fragment', importName),
783 + ),
784 + );
785 + }
786 },
787 };
788