fix: extract const in jsx (#37912)

* fix: extract const in jsx

* Update src/services/refactors/extractSymbol.ts

Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>

* Update src/services/refactors/extractSymbol.ts

Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>

Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>
This commit is contained in:
Jack Works 2020-05-20 05:29:49 +08:00 committed by GitHub
parent 46f100f8ac
commit 7ec467e270
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 5 deletions

View File

@ -28,7 +28,7 @@ namespace ts.refactor.extractSymbol {
const usedConstantNames: Map<boolean> = createMap();
let i = 0;
for (const {functionExtraction, constantExtraction} of extractions) {
for (const { functionExtraction, constantExtraction } of extractions) {
// Skip these since we don't have a way to report errors yet
if (functionExtraction.errors.length === 0) {
// Don't issue refactorings with duplicated names.
@ -1103,7 +1103,12 @@ namespace ts.refactor.extractSymbol {
changeTracker.delete(context.file, node.parent);
}
else {
const localReference = createIdentifier(localNameText);
let localReference: Expression = createIdentifier(localNameText);
// When extract to a new variable in JSX content, need to wrap a {} out of the new variable
// or it will become a plain text
if (isInJSXContent(node)) {
localReference = createJsxExpression(/*dotDotDotToken*/ undefined, localReference);
}
changeTracker.replaceNode(context.file, node, localReference);
}
}
@ -1115,6 +1120,12 @@ namespace ts.refactor.extractSymbol {
const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*isDeclaredBeforeUse*/ true);
return { renameFilename, renameLocation, edits };
function isInJSXContent(node: Node) {
if (!isJsxElement(node)) return false;
if (isJsxElement(node.parent)) return true;
return false;
}
function transformFunctionInitializerAndType(variableType: TypeNode | undefined, initializer: Expression): { variableType: TypeNode | undefined, initializer: Expression } {
// If no contextual type exists there is nothing to transfer to the function signature
if (variableType === undefined) return { variableType, initializer };
@ -1215,8 +1226,8 @@ namespace ts.refactor.extractSymbol {
}
function compareTypesByDeclarationOrder(
{type: type1, declaration: declaration1}: {type: Type, declaration?: Declaration},
{type: type2, declaration: declaration2}: {type: Type, declaration?: Declaration}) {
{ type: type1, declaration: declaration1 }: { type: Type, declaration?: Declaration },
{ type: type2, declaration: declaration2 }: { type: Type, declaration?: Declaration }) {
return compareProperties(declaration1, declaration2, "pos", compareValues)
|| compareStringsCaseSensitive(
@ -1621,7 +1632,7 @@ namespace ts.refactor.extractSymbol {
// a lot of properties, each of which the walker will visit. Unfortunately, the
// solution isn't as trivial as filtering to user types because of (e.g.) Array.
const symbolWalker = checker.getSymbolWalker(() => (cancellationToken.throwIfCancellationRequested(), true));
const {visitedTypes} = symbolWalker.walkType(type);
const { visitedTypes } = symbolWalker.walkType(type);
for (const visitedType of visitedTypes) {
if (visitedType.isTypeParameter()) {

View File

@ -0,0 +1,21 @@
/// <reference path='fourslash.ts' />
// GH#35372
// @jsx: preserve
// @filename: main.tsx
////function foo() {
//// return <div>/*a*/<a>content</a>/*b*/</div>;
////}
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Extract Symbol",
actionName: "constant_scope_0",
actionDescription: "Extract to constant in enclosing scope",
newContent:
`function foo() {
const /*RENAME*/newLocal = <a>content</a>;
return <div>{newLocal}</div>;
}`
});