Skip to content

Commit 3ad36ca

Browse files
committed
fix(33511): show jsx namespace default import quick fix if it does not exists in the current scope
1 parent 9a5c007 commit 3ad36ca

8 files changed

+192
-6
lines changed

src/services/codefixes/importFixes.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -491,12 +491,7 @@ namespace ts.codefix {
491491

492492
function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): FixesInfo | undefined {
493493
const checker = program.getTypeChecker();
494-
// If we're at `<Foo/>`, we must check if `Foo` is already in scope, and if so, get an import for `React` instead.
495-
const symbolName = isJsxOpeningLikeElement(symbolToken.parent)
496-
&& symbolToken.parent.tagName === symbolToken
497-
&& (isIntrinsicJsxName(symbolToken.text) || checker.resolveName(symbolToken.text, symbolToken, SymbolFlags.All, /*excludeGlobals*/ false))
498-
? checker.getJsxNamespace(sourceFile)
499-
: symbolToken.text;
494+
const symbolName = getSymbolName(sourceFile, checker, symbolToken);
500495
// "default" is a keyword and not a legal identifier for the import, so we don't expect it here
501496
Debug.assert(symbolName !== InternalSymbolName.Default, "'default' isn't a legal identifier and couldn't occur here");
502497

@@ -509,6 +504,17 @@ namespace ts.codefix {
509504
return { fixes, symbolName };
510505
}
511506

507+
function getSymbolName(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier): string {
508+
const parent = symbolToken.parent;
509+
if ((isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken) {
510+
const jsxNamespace = checker.getJsxNamespace(sourceFile);
511+
if (isIntrinsicJsxName(symbolToken.text) || !checker.resolveName(jsxNamespace, parent, SymbolFlags.Value, /*excludeGlobals*/ true)) {
512+
return jsxNamespace;
513+
}
514+
}
515+
return symbolToken.text;
516+
}
517+
512518
// Returns a map from an exported symbol's ID to a list of every way it's (re-)exported.
513519
function getExportInfos(
514520
symbolName: string,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @jsx: react
4+
// @module: esnext
5+
// @esModuleInterop: true
6+
// @moduleResolution: node
7+
8+
// @Filename: /node_modules/react/index.d.ts
9+
////export = React;
10+
////export as namespace React;
11+
////declare namespace React {
12+
//// class Component {}
13+
////}
14+
15+
// @Filename: /node_modules/react-native/index.d.ts
16+
////import * as React from "react";
17+
////export class Text extends React.Component {};
18+
19+
// @Filename: /a.tsx
20+
////import React from "react";
21+
////<[|Text|]></Text>;
22+
23+
goTo.file("/a.tsx");
24+
verify.codeFix({
25+
index: 0,
26+
description: `Import 'Text' from module "react-native"`,
27+
newFileContent:
28+
`import React from "react";
29+
import { Text } from "react-native";
30+
<Text></Text>;`
31+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @jsx: react
4+
// @module: esnext
5+
// @esModuleInterop: true
6+
// @moduleResolution: node
7+
8+
// @Filename: /node_modules/react/index.d.ts
9+
////export = React;
10+
////export as namespace React;
11+
////declare namespace React {
12+
//// class Component {}
13+
////}
14+
15+
// @Filename: /node_modules/react-native/index.d.ts
16+
////import * as React from "react";
17+
////export class Text extends React.Component {};
18+
19+
// @Filename: /a.tsx
20+
////import React from "react";
21+
////<Text></[|Text|]>;
22+
23+
goTo.file("/a.tsx");
24+
verify.codeFix({
25+
index: 0,
26+
description: `Import 'Text' from module "react-native"`,
27+
newFileContent:
28+
`import React from "react";
29+
import { Text } from "react-native";
30+
<Text></Text>;`
31+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @jsx: react
4+
// @module: esnext
5+
// @esModuleInterop: true
6+
// @moduleResolution: node
7+
8+
// @Filename: /node_modules/react/index.d.ts
9+
////export = React;
10+
////export as namespace React;
11+
////declare namespace React {
12+
//// class Component {}
13+
////}
14+
15+
// @Filename: /node_modules/react-native/index.d.ts
16+
////import * as React from "react";
17+
////export class Text extends React.Component {};
18+
19+
// @Filename: /a.tsx
20+
////import { Text } from "react-native";
21+
////<Text></Text>;
22+
23+
goTo.file("/a.tsx");
24+
verify.codeFix({
25+
index: 0,
26+
description: `Import default 'React' from module "react"`,
27+
newFileContent:
28+
`import { Text } from "react-native";
29+
import React from "react";
30+
<Text></Text>;`
31+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @jsx: react
4+
// @module: esnext
5+
// @esModuleInterop: true
6+
// @moduleResolution: node
7+
8+
// @Filename: /node_modules/react/index.d.ts
9+
////export = React;
10+
////export as namespace React;
11+
////declare namespace React {
12+
//// class Component {}
13+
////}
14+
15+
// @Filename: /node_modules/react-native/index.d.ts
16+
////import * as React from "react";
17+
////export class Text extends React.Component {};
18+
19+
// @Filename: /a.tsx
20+
////import React from "react";
21+
////<[|Text|] />;
22+
23+
goTo.file("/a.tsx");
24+
verify.codeFix({
25+
index: 0,
26+
description: `Import 'Text' from module "react-native"`,
27+
newFileContent:
28+
`import React from "react";
29+
import { Text } from "react-native";
30+
<Text />;`
31+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @jsx: react
4+
// @module: esnext
5+
// @esModuleInterop: true
6+
// @moduleResolution: node
7+
8+
// @Filename: /node_modules/react/index.d.ts
9+
////export = React;
10+
////export as namespace React;
11+
////declare namespace React {
12+
//// class Component {}
13+
////}
14+
15+
// @Filename: /node_modules/react-native/index.d.ts
16+
////import * as React from "react";
17+
////export class Text extends React.Component {};
18+
19+
// @Filename: /a.tsx
20+
////<[|Text|]></Text>;
21+
22+
goTo.file("/a.tsx");
23+
verify.codeFix({
24+
index: 0,
25+
description: `Import default 'React' from module "react"`,
26+
applyChanges: true,
27+
newFileContent:
28+
`import React from "react";
29+
30+
<Text></Text>;`
31+
});
32+
33+
verify.codeFix({
34+
index: 0,
35+
description: `Import 'Text' from module "react-native"`,
36+
newFileContent:
37+
`import React from "react";
38+
import { Text } from "react-native";
39+
40+
<Text></Text>;`
41+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @jsx: react
4+
// @module: esnext
5+
// @esModuleInterop: true
6+
// @moduleResolution: node
7+
8+
// @Filename: /node_modules/react/index.d.ts
9+
////// React was not defined
10+
11+
// @Filename: /a.tsx
12+
////<[|Text|]></Text>;
13+
14+
goTo.file("/a.tsx");
15+
verify.not.codeFixAvailable();

0 commit comments

Comments
 (0)