From dbb814e7e76ae421474a109d549172302b5ea98a Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Thu, 21 Jul 2022 15:17:40 -0700
Subject: [PATCH 1/3] Add failing test case
---
tests/cases/fourslash/issue49310.ts | 46 +++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 tests/cases/fourslash/issue49310.ts
diff --git a/tests/cases/fourslash/issue49310.ts b/tests/cases/fourslash/issue49310.ts
new file mode 100644
index 0000000000000..f75efd648f80d
--- /dev/null
+++ b/tests/cases/fourslash/issue49310.ts
@@ -0,0 +1,46 @@
+///
+
+// @filename: index.esm.d.ts
+//// export declare class Chart {
+//// constructor(config: ChartConfiguration);
+//// }
+////
+//// export interface ChartConfiguration {
+//// options?: Partial;
+//// }
+////
+//// export interface TickOptions {
+//// callback: (this: Scale, tickValue: number | string) => string | string[] | number | number[] | null | undefined;
+//// }
+////
+//// export interface CoreScaleOptions {
+//// opt: boolean;
+//// }
+////
+//// export interface Scale {
+//// opts: O;
+//// getLabelForValue(value: number): string;
+//// }
+
+// @filename: options.ts
+//// import { Chart } from './index.esm';
+////
+//// const chart = new Chart({
+//// options: {
+//// callback(tickValue) {
+//// /*a*/const value = this.getLabelForValue(tickValue as number);/*b*/
+//// return '$' + value;
+//// }
+//// }
+//// });
+
+goTo.file("options.ts");
+verify.noErrors();
+goTo.select("a", "b");
+edit.applyRefactor({
+ refactorName: "Extract Symbol",
+ actionName: "function_scope_0",
+ actionDescription: "Extract to inner function in method 'callback'",
+ newContent:
+`TODO`
+});
From cad26666515ef62b6fa9f7d2bcecd13e6cd358de Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Thu, 21 Jul 2022 16:52:17 -0700
Subject: [PATCH 2/3] Don't attempt to skipToEndOf a synthetic node during
formatting
---
src/services/formatting/formatting.ts | 4 ++--
...s => extractFunctionWithSyntheticNodes.ts} | 24 +++++++++++++++----
2 files changed, 22 insertions(+), 6 deletions(-)
rename tests/cases/fourslash/{issue49310.ts => extractFunctionWithSyntheticNodes.ts} (64%)
diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts
index 609246d0d7253..8c47cd6f8588b 100644
--- a/src/services/formatting/formatting.ts
+++ b/src/services/formatting/formatting.ts
@@ -716,7 +716,7 @@ namespace ts.formatting {
}
// child node is outside the target range - do not dive inside
- if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
+ if (!nodeIsSynthesized(child) && !rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
if (child.end < originalRange.pos) {
formattingScanner.skipToEndOf(child);
}
@@ -784,7 +784,7 @@ namespace ts.formatting {
let listDynamicIndentation = parentDynamicIndentation;
let startLine = parentStartLine;
// node range is outside the target range - do not dive inside
- if (!rangeOverlapsWithStartEnd(originalRange, nodes.pos, nodes.end)) {
+ if (!nodeIsSynthesized(nodes) && !rangeOverlapsWithStartEnd(originalRange, nodes.pos, nodes.end)) {
if (nodes.end < originalRange.pos) {
formattingScanner.skipToEndOf(nodes);
}
diff --git a/tests/cases/fourslash/issue49310.ts b/tests/cases/fourslash/extractFunctionWithSyntheticNodes.ts
similarity index 64%
rename from tests/cases/fourslash/issue49310.ts
rename to tests/cases/fourslash/extractFunctionWithSyntheticNodes.ts
index f75efd648f80d..ef3081d375998 100644
--- a/tests/cases/fourslash/issue49310.ts
+++ b/tests/cases/fourslash/extractFunctionWithSyntheticNodes.ts
@@ -1,6 +1,9 @@
///
-// @filename: index.esm.d.ts
+// @filename: /project/tsconfig.json
+//// {}
+
+// @filename: /project/index.esm.d.ts
//// export declare class Chart {
//// constructor(config: ChartConfiguration);
//// }
@@ -22,7 +25,7 @@
//// getLabelForValue(value: number): string;
//// }
-// @filename: options.ts
+// @filename: /project/options.ts
//// import { Chart } from './index.esm';
////
//// const chart = new Chart({
@@ -34,7 +37,7 @@
//// }
//// });
-goTo.file("options.ts");
+goTo.file("/project/options.ts");
verify.noErrors();
goTo.select("a", "b");
edit.applyRefactor({
@@ -42,5 +45,18 @@ edit.applyRefactor({
actionName: "function_scope_0",
actionDescription: "Extract to inner function in method 'callback'",
newContent:
-`TODO`
+`import { Chart } from './index.esm';
+
+const chart = new Chart({
+ options: {
+ callback(tickValue) {
+ const value = /*RENAME*/newFunction.call(this);
+ return '$' + value;
+
+ function newFunction(this: import("/project/index.esm").Scale) {
+ return this.getLabelForValue(tickValue as number);
+ }
+ }
+ }
+});`
});
From 06b06229450ab58306bbc8571a8d407d79ad2636 Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Fri, 22 Jul 2022 16:35:52 -0700
Subject: [PATCH 3/3] Remove uses of visitNodes and visitNode in visitEachChild
---
src/compiler/visitorPublic.ts | 12 ++++++------
src/services/formatting/formatting.ts | 6 ++++--
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts
index 619348685efbc..372eb47c50307 100644
--- a/src/compiler/visitorPublic.ts
+++ b/src/compiler/visitorPublic.ts
@@ -616,7 +616,7 @@ namespace ts {
nodeVisitor(node.argument, visitor, isTypeNode),
nodeVisitor(node.assertions, visitor, isNode),
nodeVisitor(node.qualifier, visitor, isEntityName),
- visitNodes(node.typeArguments, visitor, isTypeNode),
+ nodesVisitor(node.typeArguments, visitor, isTypeNode),
node.isTypeOf
);
@@ -630,10 +630,10 @@ namespace ts {
case SyntaxKind.NamedTupleMember:
Debug.type(node);
return factory.updateNamedTupleMember(node,
- visitNode(node.dotDotDotToken, visitor, isDotDotDotToken),
- visitNode(node.name, visitor, isIdentifier),
- visitNode(node.questionToken, visitor, isQuestionToken),
- visitNode(node.type, visitor, isTypeNode),
+ nodeVisitor(node.dotDotDotToken, visitor, isDotDotDotToken),
+ nodeVisitor(node.name, visitor, isIdentifier),
+ nodeVisitor(node.questionToken, visitor, isQuestionToken),
+ nodeVisitor(node.type, visitor, isTypeNode),
);
case SyntaxKind.ParenthesizedType:
@@ -761,7 +761,7 @@ namespace ts {
Debug.type(node);
return factory.updateTaggedTemplateExpression(node,
nodeVisitor(node.tag, visitor, isExpression),
- visitNodes(node.typeArguments, visitor, isTypeNode),
+ nodesVisitor(node.typeArguments, visitor, isTypeNode),
nodeVisitor(node.template, visitor, isTemplateLiteral));
case SyntaxKind.TypeAssertionExpression:
diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts
index 8c47cd6f8588b..3f81d4d374da8 100644
--- a/src/services/formatting/formatting.ts
+++ b/src/services/formatting/formatting.ts
@@ -691,6 +691,7 @@ namespace ts.formatting {
undecoratedParentStartLine: number,
isListItem: boolean,
isFirstListItem?: boolean): number {
+ Debug.assert(!nodeIsSynthesized(child));
if (nodeIsMissing(child)) {
return inheritedIndentation;
@@ -716,7 +717,7 @@ namespace ts.formatting {
}
// child node is outside the target range - do not dive inside
- if (!nodeIsSynthesized(child) && !rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
+ if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
if (child.end < originalRange.pos) {
formattingScanner.skipToEndOf(child);
}
@@ -778,13 +779,14 @@ namespace ts.formatting {
parentStartLine: number,
parentDynamicIndentation: DynamicIndentation): void {
Debug.assert(isNodeArray(nodes));
+ Debug.assert(!nodeIsSynthesized(nodes));
const listStartToken = getOpenTokenForList(parent, nodes);
let listDynamicIndentation = parentDynamicIndentation;
let startLine = parentStartLine;
// node range is outside the target range - do not dive inside
- if (!nodeIsSynthesized(nodes) && !rangeOverlapsWithStartEnd(originalRange, nodes.pos, nodes.end)) {
+ if (!rangeOverlapsWithStartEnd(originalRange, nodes.pos, nodes.end)) {
if (nodes.end < originalRange.pos) {
formattingScanner.skipToEndOf(nodes);
}