fix(33511): show jsx namespace default import quick fix if it does not exists in the current scope (#38419)

This commit is contained in:
Alexander T
2020-07-15 01:43:18 +03:00
committed by GitHub
parent 98ab3a788f
commit ececf3b0a7
8 changed files with 192 additions and 6 deletions

View File

@@ -491,12 +491,7 @@ namespace ts.codefix {
function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): FixesInfo | undefined {
const checker = program.getTypeChecker();
// If we're at `<Foo/>`, we must check if `Foo` is already in scope, and if so, get an import for `React` instead.
const symbolName = isJsxOpeningLikeElement(symbolToken.parent)
&& symbolToken.parent.tagName === symbolToken
&& (isIntrinsicJsxName(symbolToken.text) || checker.resolveName(symbolToken.text, symbolToken, SymbolFlags.All, /*excludeGlobals*/ false))
? checker.getJsxNamespace(sourceFile)
: symbolToken.text;
const symbolName = getSymbolName(sourceFile, checker, symbolToken);
// "default" is a keyword and not a legal identifier for the import, so we don't expect it here
Debug.assert(symbolName !== InternalSymbolName.Default, "'default' isn't a legal identifier and couldn't occur here");
@@ -509,6 +504,17 @@ namespace ts.codefix {
return { fixes, symbolName };
}
function getSymbolName(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier): string {
const parent = symbolToken.parent;
if ((isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken) {
const jsxNamespace = checker.getJsxNamespace(sourceFile);
if (isIntrinsicJsxName(symbolToken.text) || !checker.resolveName(jsxNamespace, parent, SymbolFlags.Value, /*excludeGlobals*/ true)) {
return jsxNamespace;
}
}
return symbolToken.text;
}
// Returns a map from an exported symbol's ID to a list of every way it's (re-)exported.
function getExportInfos(
symbolName: string,

View File

@@ -0,0 +1,31 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @module: esnext
// @esModuleInterop: true
// @moduleResolution: node
// @Filename: /node_modules/react/index.d.ts
////export = React;
////export as namespace React;
////declare namespace React {
//// class Component {}
////}
// @Filename: /node_modules/react-native/index.d.ts
////import * as React from "react";
////export class Text extends React.Component {};
// @Filename: /a.tsx
////import React from "react";
////<[|Text|]></Text>;
goTo.file("/a.tsx");
verify.codeFix({
index: 0,
description: [ts.Diagnostics.Import_0_from_module_1.message, "Text", "react-native"],
newFileContent:
`import React from "react";
import { Text } from "react-native";
<Text></Text>;`
});

View File

@@ -0,0 +1,31 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @module: esnext
// @esModuleInterop: true
// @moduleResolution: node
// @Filename: /node_modules/react/index.d.ts
////export = React;
////export as namespace React;
////declare namespace React {
//// class Component {}
////}
// @Filename: /node_modules/react-native/index.d.ts
////import * as React from "react";
////export class Text extends React.Component {};
// @Filename: /a.tsx
////import React from "react";
////<Text></[|Text|]>;
goTo.file("/a.tsx");
verify.codeFix({
index: 0,
description: [ts.Diagnostics.Import_0_from_module_1.message, "Text", "react-native"],
newFileContent:
`import React from "react";
import { Text } from "react-native";
<Text></Text>;`
});

View File

@@ -0,0 +1,31 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @module: esnext
// @esModuleInterop: true
// @moduleResolution: node
// @Filename: /node_modules/react/index.d.ts
////export = React;
////export as namespace React;
////declare namespace React {
//// class Component {}
////}
// @Filename: /node_modules/react-native/index.d.ts
////import * as React from "react";
////export class Text extends React.Component {};
// @Filename: /a.tsx
////import { Text } from "react-native";
////<Text></Text>;
goTo.file("/a.tsx");
verify.codeFix({
index: 0,
description: [ts.Diagnostics.Import_default_0_from_module_1.message, "React", "react"],
newFileContent:
`import React from "react";
import { Text } from "react-native";
<Text></Text>;`
});

View File

@@ -0,0 +1,31 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @module: esnext
// @esModuleInterop: true
// @moduleResolution: node
// @Filename: /node_modules/react/index.d.ts
////export = React;
////export as namespace React;
////declare namespace React {
//// class Component {}
////}
// @Filename: /node_modules/react-native/index.d.ts
////import * as React from "react";
////export class Text extends React.Component {};
// @Filename: /a.tsx
////import React from "react";
////<[|Text|] />;
goTo.file("/a.tsx");
verify.codeFix({
index: 0,
description: [ts.Diagnostics.Import_0_from_module_1.message, "Text", "react-native"],
newFileContent:
`import React from "react";
import { Text } from "react-native";
<Text />;`
});

View File

@@ -0,0 +1,41 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @module: esnext
// @esModuleInterop: true
// @moduleResolution: node
// @Filename: /node_modules/react/index.d.ts
////export = React;
////export as namespace React;
////declare namespace React {
//// class Component {}
////}
// @Filename: /node_modules/react-native/index.d.ts
////import * as React from "react";
////export class Text extends React.Component {};
// @Filename: /a.tsx
////<[|Text|]></Text>;
goTo.file("/a.tsx");
verify.codeFix({
index: 0,
description: [ts.Diagnostics.Import_default_0_from_module_1.message, "React", "react"],
applyChanges: true,
newFileContent:
`import React from "react";
<Text></Text>;`
});
verify.codeFix({
index: 0,
description: [ts.Diagnostics.Import_0_from_module_1.message, "Text", "react-native"],
newFileContent:
`import React from "react";
import { Text } from "react-native";
<Text></Text>;`
});

View File

@@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @module: esnext
// @esModuleInterop: true
// @moduleResolution: node
// @Filename: /node_modules/react/index.d.ts
////// React was not defined
// @Filename: /a.tsx
////<[|Text|]></Text>;
goTo.file("/a.tsx");
verify.not.codeFixAvailable();