From d6ef82c0fd01910e496f162e05a71ad976235a68 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sun, 12 Apr 2020 18:28:33 +0800 Subject: [PATCH 1/3] fix: extract const in jsx --- src/services/refactors/extractSymbol.ts | 21 ++++++++++++++++----- tests/cases/fourslash/extract-const4.ts | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 tests/cases/fourslash/extract-const4.ts diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 30dcaeaebfaf6..6777fff0f9816 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -28,7 +28,7 @@ namespace ts.refactor.extractSymbol { const usedConstantNames: Map = 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. @@ -1100,7 +1100,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(void 0, localReference); + } changeTracker.replaceNode(context.file, node, localReference); } } @@ -1112,6 +1117,12 @@ namespace ts.refactor.extractSymbol { const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*isDeclaredBeforeUse*/ true); return { renameFilename, renameLocation, edits }; + function isInJSXContent(node: Node): node is JsxOpeningLikeElement { + 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 }; @@ -1212,8 +1223,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( @@ -1618,7 +1629,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()) { diff --git a/tests/cases/fourslash/extract-const4.ts b/tests/cases/fourslash/extract-const4.ts new file mode 100644 index 0000000000000..4130a168fdba8 --- /dev/null +++ b/tests/cases/fourslash/extract-const4.ts @@ -0,0 +1,21 @@ +/// + +// GH#35372 + +// @jsx: preserve +// @filename: main.tsx +////function foo() { +//// return
/*a*/content/*b*/
; +////} + +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 = content; + return
{newLocal}
; +}` +}); From 75fde272bfbc811e07186defc5d2a64c35f18b72 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 19 May 2020 11:27:46 +0800 Subject: [PATCH 2/3] Update src/services/refactors/extractSymbol.ts Co-authored-by: Andrew Branch --- src/services/refactors/extractSymbol.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 6777fff0f9816..43653c4f1b08b 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -1104,7 +1104,7 @@ namespace ts.refactor.extractSymbol { // 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(void 0, localReference); + localReference = createJsxExpression(/*dotDotDotToken*/ undefined, localReference); } changeTracker.replaceNode(context.file, node, localReference); } From c09b684666f700a6fd4594384056ae7d715aa06b Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 19 May 2020 11:28:24 +0800 Subject: [PATCH 3/3] Update src/services/refactors/extractSymbol.ts Co-authored-by: Andrew Branch --- src/services/refactors/extractSymbol.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 43653c4f1b08b..f246e9be2bb7b 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -1117,7 +1117,7 @@ namespace ts.refactor.extractSymbol { const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*isDeclaredBeforeUse*/ true); return { renameFilename, renameLocation, edits }; - function isInJSXContent(node: Node): node is JsxOpeningLikeElement { + function isInJSXContent(node: Node) { if (!isJsxElement(node)) return false; if (isJsxElement(node.parent)) return true; return false;