diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 854d09761cd..372c606aaf8 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -3724,7 +3724,7 @@
"code": 95003
},
- "Extract to {0}": {
+ "Extract to {0} in {1}": {
"category": "Message",
"code": 95004
},
diff --git a/src/harness/unittests/extractConstants.ts b/src/harness/unittests/extractConstants.ts
index e2c64afb526..179affd86c9 100644
--- a/src/harness/unittests/extractConstants.ts
+++ b/src/harness/unittests/extractConstants.ts
@@ -40,7 +40,7 @@ namespace ts {
}
}`);
- testExtractConstant("extractConstant_ClassInsertionPosition",
+ testExtractConstant("extractConstant_ClassInsertionPosition1",
`class C {
a = 1;
b = 2;
@@ -51,6 +51,28 @@ namespace ts {
}
}`);
+ testExtractConstant("extractConstant_ClassInsertionPosition2",
+ `class C {
+ a = 1;
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ let x = [#|1|];
+ }
+}`);
+
+ testExtractConstant("extractConstant_ClassInsertionPosition3",
+ `class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ M3() {
+ let x = [#|1|];
+ }
+}`);
+
testExtractConstant("extractConstant_Parameters",
`function F() {
let w = 1;
@@ -62,26 +84,126 @@ namespace ts {
let x = [#|t + 1|];
}`);
-// TODO (acasey): handle repeated substitution
+// TODO (18857): handle repeated substitution
// testExtractConstant("extractConstant_RepeatedSubstitution",
// `namespace X {
// export const j = 10;
// export const y = [#|j * j|];
// }`);
- testExtractConstantFailed("extractConstant_BlockScopes_Dependencies",
- `for (let i = 0; i < 10; i++) {
+ testExtractConstant("extractConstant_VariableList_const",
+ `const a = 1, b = [#|a + 1|];`);
+
+ // NOTE: this test isn't normative - it just documents our sub-optimal behavior.
+ testExtractConstant("extractConstant_VariableList_let",
+ `let a = 1, b = [#|a + 1|];`);
+
+ // NOTE: this test isn't normative - it just documents our sub-optimal behavior.
+ testExtractConstant("extractConstant_VariableList_MultipleLines",
+ `const /*About A*/a = 1,
+ /*About B*/b = [#|a + 1|];`);
+
+ testExtractConstant("extractConstant_BlockScopeMismatch", `
+for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
- let x = [#|i + 1|];
+ const x = [#|i + 1|];
}
-}`);
+}
+ `);
+
+ testExtractConstant("extractConstant_StatementInsertionPosition1", `
+const i = 0;
+for (let j = 0; j < 10; j++) {
+ const x = [#|i + 1|];
+}
+ `);
+
+ testExtractConstant("extractConstant_StatementInsertionPosition2", `
+const i = 0;
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = [#|i + 1|];
+ }
+}
+ `);
+
+ testExtractConstant("extractConstant_StatementInsertionPosition3", `
+for (let j = 0; j < 10; j++) {
+ const x = [#|2 + 1|];
+}
+ `);
+
+ testExtractConstant("extractConstant_StatementInsertionPosition4", `
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = [#|2 + 1|];
+ }
+}
+ `);
+
+ testExtractConstant("extractConstant_StatementInsertionPosition5", `
+function F0() {
+ function F1() {
+ function F2(x = [#|2 + 1|]) {
+ }
+ }
+}
+ `);
+
+ testExtractConstant("extractConstant_StatementInsertionPosition6", `
+class C {
+ x = [#|2 + 1|];
+}
+ `);
+
+ testExtractConstant("extractConstant_StatementInsertionPosition7", `
+const i = 0;
+class C {
+ M() {
+ for (let j = 0; j < 10; j++) {
+ x = [#|i + 1|];
+ }
+ }
+}
+ `);
+
+ testExtractConstant("extractConstant_TripleSlash", `
+///
+
+const x = [#|2 + 1|];
+ `);
+
+ testExtractConstant("extractConstant_PinnedComment", `
+/*! Copyright */
+
+const x = [#|2 + 1|];
+ `);
+
+ testExtractConstant("extractConstant_Directive", `
+"strict";
+
+const x = [#|2 + 1|];
+ `);
+
+ testExtractConstant("extractConstant_MultipleHeaders", `
+/*! Copyright */
+
+///
+
+"strict";
+
+const x = [#|2 + 1|];
+ `);
+
+ testExtractConstant("extractConstant_PinnedCommentAndDocComment", `
+/*! Copyright */
+
+/* About x */
+const x = [#|2 + 1|];
+ `);
});
function testExtractConstant(caption: string, text: string) {
testExtractSymbol(caption, text, "extractConstant", Diagnostics.Extract_constant);
}
-
- function testExtractConstantFailed(caption: string, text: string) {
- testExtractSymbolFailed(caption, text, Diagnostics.Extract_constant);
- }
}
diff --git a/src/harness/unittests/extractFunctions.ts b/src/harness/unittests/extractFunctions.ts
index 27c21ce3fb6..291324e08f3 100644
--- a/src/harness/unittests/extractFunctions.ts
+++ b/src/harness/unittests/extractFunctions.ts
@@ -355,7 +355,7 @@ function parsePrimaryExpression(): any {
[#|function G() { }|]
}`);
-// TODO (acasey): handle repeated substitution
+// TODO (18857): handle repeated substitution
// testExtractFunction("extractFunction_RepeatedSubstitution",
// `namespace X {
// export const j = 10;
diff --git a/src/harness/unittests/extractTestHelpers.ts b/src/harness/unittests/extractTestHelpers.ts
index ea1cccd32ea..0d739919e1f 100644
--- a/src/harness/unittests/extractTestHelpers.ts
+++ b/src/harness/unittests/extractTestHelpers.ts
@@ -113,7 +113,7 @@ namespace ts {
if (hasSyntacticDiagnostics(program)) {
// Don't bother generating JS baselines for inputs that aren't valid JS.
- assert.equal(Extension.Js, extension);
+ assert.equal(Extension.Js, extension, "Syntactic diagnostics found in non-JS file");
return;
}
diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts
index 96f4b7ad4b5..f516bc15de3 100644
--- a/src/services/codefixes/importFixes.ts
+++ b/src/services/codefixes/importFixes.ts
@@ -407,28 +407,6 @@ namespace ts.codefix {
moduleSpecifierWithoutQuotes
);
- function getSourceFileImportLocation(node: SourceFile) {
- // For a source file, it is possible there are detached comments we should not skip
- const text = node.text;
- let ranges = getLeadingCommentRanges(text, 0);
- if (!ranges) return 0;
- let position = 0;
- // However we should still skip a pinned comment at the top
- if (ranges.length && ranges[0].kind === SyntaxKind.MultiLineCommentTrivia && isPinnedComment(text, ranges[0])) {
- position = ranges[0].end + 1;
- ranges = ranges.slice(1);
- }
- // As well as any triple slash references
- for (const range of ranges) {
- if (range.kind === SyntaxKind.SingleLineCommentTrivia && isRecognizedTripleSlashComment(node.text, range.pos, range.end)) {
- position = range.end + 1;
- continue;
- }
- break;
- }
- return position;
- }
-
function getSingleQuoteStyleFromExistingImports() {
const firstModuleSpecifier = forEach(sourceFile.statements, node => {
if (isImportDeclaration(node) || isExportDeclaration(node)) {
diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts
index b88a013f52b..df9da034da6 100644
--- a/src/services/refactors/extractSymbol.ts
+++ b/src/services/refactors/extractSymbol.ts
@@ -43,7 +43,7 @@ namespace ts.refactor.extractSymbol {
// Don't issue refactorings with duplicated names.
// Scopes come back in "innermost first" order, so extractions will
// preferentially go into nearer scopes
- const description = formatStringFromArgs(Diagnostics.Extract_to_0.message, [extraction.functionDescription]);
+ const description = formatStringFromArgs(Diagnostics.Extract_to_0_in_1.message, [extraction.functionDescription, extraction.functionScopeDescription]);
if (!usedFunctionNames.has(description)) {
usedFunctionNames.set(description, true);
functionActions.push({
@@ -58,7 +58,7 @@ namespace ts.refactor.extractSymbol {
// Don't issue refactorings with duplicated names.
// Scopes come back in "innermost first" order, so extractions will
// preferentially go into nearer scopes
- const description = formatStringFromArgs(Diagnostics.Extract_to_0.message, [extraction.constantDescription]);
+ const description = formatStringFromArgs(Diagnostics.Extract_to_0_in_1.message, [extraction.constantDescription, extraction.constantScopeDescription]);
if (!usedConstantNames.has(description)) {
usedConstantNames.set(description, true);
constantActions.push({
@@ -523,8 +523,10 @@ namespace ts.refactor.extractSymbol {
interface PossibleExtraction {
readonly functionDescription: string;
+ readonly functionScopeDescription: string;
readonly functionErrors: ReadonlyArray;
readonly constantDescription: string;
+ readonly constantScopeDescription: string;
readonly constantErrors: ReadonlyArray;
}
/**
@@ -535,12 +537,23 @@ namespace ts.refactor.extractSymbol {
function getPossibleExtractions(targetRange: TargetRange, context: RefactorContext): ReadonlyArray | undefined {
const { scopes, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context);
// Need the inner type annotation to avoid https://github.com/Microsoft/TypeScript/issues/7547
- const extractions = scopes.map((scope, i): PossibleExtraction => ({
- functionDescription: getDescriptionForFunctionInScope(scope),
- functionErrors: functionErrorsPerScope[i],
- constantDescription: getDescriptionForConstantInScope(scope),
- constantErrors: constantErrorsPerScope[i],
- }));
+ const extractions = scopes.map((scope, i): PossibleExtraction => {
+ const scopeDescription = isFunctionLikeDeclaration(scope)
+ ? getDescriptionForFunctionLikeDeclaration(scope)
+ : isClassLike(scope)
+ ? getDescriptionForClassLikeDeclaration(scope)
+ : getDescriptionForModuleLikeDeclaration(scope);
+ return {
+ functionDescription: getDescriptionForFunctionInScope(scope),
+ functionErrors: functionErrorsPerScope[i],
+ functionScopeDescription: scopeDescription,
+ constantDescription: getDescriptionForConstantInScope(scope),
+ constantErrors: constantErrorsPerScope[i],
+ constantScopeDescription: (i === 0 && !isClassLike(scope))
+ ? "enclosing scope" // Like "global scope" and "module scope", this is not localized.
+ : scopeDescription,
+ };
+ });
return extractions;
}
@@ -569,17 +582,15 @@ namespace ts.refactor.extractSymbol {
function getDescriptionForFunctionInScope(scope: Scope): string {
return isFunctionLikeDeclaration(scope)
- ? `inner function in ${getDescriptionForFunctionLikeDeclaration(scope)}`
+ ? "inner function"
: isClassLike(scope)
- ? `method in ${getDescriptionForClassLikeDeclaration(scope)}`
- : `function in ${getDescriptionForModuleLikeDeclaration(scope)}`;
+ ? "method"
+ : "function";
}
function getDescriptionForConstantInScope(scope: Scope): string {
- return isFunctionLikeDeclaration(scope)
- ? `constant in ${getDescriptionForFunctionLikeDeclaration(scope)}`
- : isClassLike(scope)
- ? `readonly field in ${getDescriptionForClassLikeDeclaration(scope)}`
- : `constant in ${getDescriptionForModuleLikeDeclaration(scope)}`;
+ return isClassLike(scope)
+ ? "readonly field"
+ : "constant";
}
function getDescriptionForFunctionLikeDeclaration(scope: FunctionLikeDeclaration): string {
switch (scope.kind) {
@@ -869,33 +880,61 @@ namespace ts.refactor.extractSymbol {
createIdentifier(localNameText));
// Declare
- const minInsertionPos = node.end;
- const nodeToInsertBefore = getNodeToInsertConstantBefore(minInsertionPos, scope);
+ const maxInsertionPos = node.pos;
+ const nodeToInsertBefore = getNodeToInsertPropertyBefore(maxInsertionPos, scope);
changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newVariable, { suffix: context.newLineCharacter + context.newLineCharacter });
// Consume
changeTracker.replaceNodeWithNodes(context.file, node, [localReference], { nodeSeparator: context.newLineCharacter });
}
else {
- const newVariable = createVariableStatement(
- /*modifiers*/ undefined,
- createVariableDeclarationList(
- [createVariableDeclaration(localNameText, variableType, initializer)],
- NodeFlags.Const));
+ const newVariableDeclaration = createVariableDeclaration(localNameText, variableType, initializer);
- // If the parent is an expression statement, replace the statement with the declaration
- if (node.parent.kind === SyntaxKind.ExpressionStatement) {
- changeTracker.replaceNodeWithNodes(context.file, node.parent, [newVariable], { nodeSeparator: context.newLineCharacter });
- }
- else {
+ // If the node is part of an initializer in a list of variable declarations, insert a new
+ // variable declaration into the list (in case it depends on earlier ones).
+ // CONSIDER: If the declaration list isn't const, we might want to split it into multiple
+ // lists so that the newly extracted one can be const.
+ const oldVariableDeclaration = getContainingVariableDeclarationIfInList(node, scope);
+ if (oldVariableDeclaration) {
// Declare
- const minInsertionPos = node.end;
- const nodeToInsertBefore = getNodeToInsertConstantBefore(minInsertionPos, scope);
- changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newVariable, { suffix: context.newLineCharacter + context.newLineCharacter });
+ // CONSIDER: could detect that each is on a separate line
+ changeTracker.insertNodeAt(context.file, oldVariableDeclaration.getStart(), newVariableDeclaration, { suffix: ", " });
// Consume
const localReference = createIdentifier(localNameText);
- changeTracker.replaceNodeWithNodes(context.file, node, [localReference], { nodeSeparator: context.newLineCharacter });
+ changeTracker.replaceRange(context.file, { pos: node.getStart(), end: node.end }, localReference);
+ }
+ else if (node.parent.kind === SyntaxKind.ExpressionStatement) {
+ // If the parent is an expression statement, replace the statement with the declaration.
+ const newVariableStatement = createVariableStatement(
+ /*modifiers*/ undefined,
+ createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const));
+ changeTracker.replaceNodeWithNodes(context.file, node.parent, [newVariableStatement], { nodeSeparator: context.newLineCharacter });
+ }
+ else {
+ const newVariableStatement = createVariableStatement(
+ /*modifiers*/ undefined,
+ createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const));
+
+ // Declare
+ const nodeToInsertBefore = getNodeToInsertConstantBefore(node, scope);
+ if (nodeToInsertBefore.pos === 0) {
+ // If we're at the beginning of the file, we need to take care not to insert before header comments
+ // (e.g. copyright, triple-slash references). Fortunately, this problem has already been solved
+ // for imports.
+ const insertionPos = getSourceFileImportLocation(file);
+ changeTracker.insertNodeAt(context.file, insertionPos, newVariableStatement, {
+ prefix: insertionPos === 0 ? undefined : context.newLineCharacter,
+ suffix: isLineBreak(file.text.charCodeAt(insertionPos)) ? context.newLineCharacter : context.newLineCharacter + context.newLineCharacter
+ });
+ }
+ else {
+ changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newVariableStatement, { suffix: context.newLineCharacter + context.newLineCharacter });
+ }
+
+ // Consume
+ const localReference = createIdentifier(localNameText);
+ changeTracker.replaceRange(context.file, { pos: node.getStart(), end: node.end }, localReference);
}
}
@@ -906,6 +945,22 @@ namespace ts.refactor.extractSymbol {
return { renameFilename, renameLocation, edits };
}
+ function getContainingVariableDeclarationIfInList(node: Node, scope: Scope) {
+ let prevNode = undefined;
+ while (node !== undefined && node !== scope) {
+ if (isVariableDeclaration(node) &&
+ node.initializer === prevNode &&
+ isVariableDeclarationList(node.parent) &&
+ node.parent.declarations.length > 1) {
+
+ return node;
+ }
+
+ prevNode = node;
+ node = node.parent;
+ }
+ }
+
/**
* @return The index of the (only) reference to the extracted symbol. We want the cursor
* to be on the reference, rather than the declaration, because it's closer to where the
@@ -1088,26 +1143,61 @@ namespace ts.refactor.extractSymbol {
child.pos >= minPos && isFunctionLikeDeclaration(child) && !isConstructorDeclaration(child));
}
- // TODO (acasey): need to dig into nested statements
- // TODO (acasey): don't insert before pinned comments, directives, or triple-slash references
- function getNodeToInsertConstantBefore(maxPos: number, scope: Scope): Node {
- const children = getStatementsOrClassElements(scope);
- Debug.assert(children.length > 0); // There must be at least one child, since we extracted from one.
+ function getNodeToInsertPropertyBefore(maxPos: number, scope: ClassLikeDeclaration): Node {
+ const members = scope.members;
+ Debug.assert(members.length > 0); // There must be at least one child, since we extracted from one.
- const isClassLikeScope = isClassLike(scope);
- let prevChild: Statement | ClassElement | undefined = undefined;
- for (const child of children) {
- if (child.pos >= maxPos) {
- break;
+ let prevMember: ClassElement | undefined = undefined;
+ let allProperties = true;
+ for (const member of members) {
+ if (member.pos > maxPos) {
+ return prevMember || members[0];
}
- prevChild = child;
- if (isClassLikeScope && !isPropertyDeclaration(child)) {
- break;
+ if (allProperties && !isPropertyDeclaration(member)) {
+ // If it is non-vacuously true that all preceding members are properties,
+ // insert before the current member (i.e. at the end of the list of properties).
+ if (prevMember !== undefined) {
+ return member;
+ }
+
+ allProperties = false;
+ }
+ prevMember = member;
+ }
+
+ Debug.assert(prevMember !== undefined); // If the loop didn't return, then it did set prevMember.
+ return prevMember;
+ }
+
+ function getNodeToInsertConstantBefore(node: Node, scope: Scope): Node {
+ Debug.assert(!isClassLike(scope));
+
+ let prevScope: Scope | undefined = undefined;
+ for (let curr = node; curr !== scope; curr = curr.parent) {
+ if (isScope(curr)) {
+ prevScope = curr;
}
}
- Debug.assert(prevChild !== undefined);
- return prevChild;
+ for (let curr = (prevScope || node).parent; ; curr = curr.parent) {
+ if (isBlockLike(curr)) {
+ let prevStatement = undefined;
+ for (const statement of curr.statements) {
+ if (statement.pos > node.pos) {
+ break;
+ }
+ prevStatement = statement;
+ }
+ // There must be at least one statement since we started in one.
+ Debug.assert(prevStatement !== undefined);
+ return prevStatement;
+ }
+
+ if (curr === scope) {
+ Debug.fail("Didn't encounter a block-like before encountering scope");
+ break;
+ }
+ }
}
function getPropertyAssignmentsForWrites(writes: ReadonlyArray): ShorthandPropertyAssignment[] {
@@ -1249,7 +1339,10 @@ namespace ts.refactor.extractSymbol {
for (let i = 0; i < scopes.length; i++) {
if (!isReadonlyArray(targetRange.range)) {
const scopeUsages = usagesPerScope[i];
- if (scopeUsages.usages.size > 0 || scopeUsages.typeParameterUsages.size > 0) {
+ // Special case: in the innermost scope, all usages are available.
+ // (The computed value reflects the value at the top-level of the scope, but the
+ // local will actually be declared at the same level as the extracted expression).
+ if (i > 0 && (scopeUsages.usages.size > 0 || scopeUsages.typeParameterUsages.size > 0)) {
constantErrorsPerScope[i].push(createDiagnosticForNode(targetRange.range, Messages.CannotAccessVariablesFromNestedScopes));
}
}
diff --git a/src/services/utilities.ts b/src/services/utilities.ts
index f367c48ac6f..ee74a8680eb 100644
--- a/src/services/utilities.ts
+++ b/src/services/utilities.ts
@@ -1332,4 +1332,26 @@ namespace ts {
export function getOpenBraceOfClassLike(declaration: ClassLikeDeclaration, sourceFile: SourceFile) {
return getTokenAtPosition(sourceFile, declaration.members.pos - 1, /*includeJsDocComment*/ false);
}
+
+ export function getSourceFileImportLocation(node: SourceFile) {
+ // For a source file, it is possible there are detached comments we should not skip
+ const text = node.text;
+ let ranges = getLeadingCommentRanges(text, 0);
+ if (!ranges) return 0;
+ let position = 0;
+ // However we should still skip a pinned comment at the top
+ if (ranges.length && ranges[0].kind === SyntaxKind.MultiLineCommentTrivia && isPinnedComment(text, ranges[0])) {
+ position = ranges[0].end + 1;
+ ranges = ranges.slice(1);
+ }
+ // As well as any triple slash references
+ for (const range of ranges) {
+ if (range.kind === SyntaxKind.SingleLineCommentTrivia && isRecognizedTripleSlashComment(node.text, range.pos, range.end)) {
+ position = range.end + 1;
+ continue;
+ }
+ break;
+ }
+ return position;
+ }
}
diff --git a/tests/baselines/reference/extractConstant/extractConstant_BlockScopeMismatch.js b/tests/baselines/reference/extractConstant/extractConstant_BlockScopeMismatch.js
new file mode 100644
index 00000000000..65871513e18
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_BlockScopeMismatch.js
@@ -0,0 +1,18 @@
+// ==ORIGINAL==
+
+for (let i = 0; i < 10; i++) {
+ for (let j = 0; j < 10; j++) {
+ const x = i + 1;
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+for (let i = 0; i < 10; i++) {
+ for (let j = 0; j < 10; j++) {
+ const newLocal = i + 1;
+
+ const x = /*RENAME*/newLocal;
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_BlockScopeMismatch.ts b/tests/baselines/reference/extractConstant/extractConstant_BlockScopeMismatch.ts
new file mode 100644
index 00000000000..65871513e18
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_BlockScopeMismatch.ts
@@ -0,0 +1,18 @@
+// ==ORIGINAL==
+
+for (let i = 0; i < 10; i++) {
+ for (let j = 0; j < 10; j++) {
+ const x = i + 1;
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+for (let i = 0; i < 10; i++) {
+ for (let j = 0; j < 10; j++) {
+ const newLocal = i + 1;
+
+ const x = /*RENAME*/newLocal;
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.js b/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.js
index 25609a3a801..4446502920a 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.js
@@ -4,11 +4,11 @@ for (let i = 0; i < 10; i++) {
let x = 1;
}
}
-// ==SCOPE::Extract to constant in global scope==
-const newLocal = 1;
-
+// ==SCOPE::Extract to constant in enclosing scope==
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
+ const newLocal = 1;
+
let x = /*RENAME*/newLocal;
}
}
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.ts b/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.ts
index 25609a3a801..4446502920a 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_BlockScopes_NoDependencies.ts
@@ -4,11 +4,11 @@ for (let i = 0; i < 10; i++) {
let x = 1;
}
}
-// ==SCOPE::Extract to constant in global scope==
-const newLocal = 1;
-
+// ==SCOPE::Extract to constant in enclosing scope==
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
+ const newLocal = 1;
+
let x = /*RENAME*/newLocal;
}
}
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition.js b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition1.js
similarity index 89%
rename from tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition.js
rename to tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition1.js
index 4e7bcc0521a..6fa63a655f5 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition1.js
@@ -8,7 +8,7 @@ class C {
let x = 1;
}
}
-// ==SCOPE::Extract to constant in method 'M3==
+// ==SCOPE::Extract to constant in enclosing scope==
class C {
a = 1;
b = 2;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition.ts b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition1.ts
similarity index 92%
rename from tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition.ts
rename to tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition1.ts
index e024fda34bc..15c5d22a34b 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition1.ts
@@ -8,7 +8,7 @@ class C {
let x = 1;
}
}
-// ==SCOPE::Extract to constant in method 'M3==
+// ==SCOPE::Extract to constant in enclosing scope==
class C {
a = 1;
b = 2;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition2.js b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition2.js
new file mode 100644
index 00000000000..3273cfbeaa0
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition2.js
@@ -0,0 +1,34 @@
+// ==ORIGINAL==
+class C {
+ a = 1;
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ let x = 1;
+ }
+}
+// ==SCOPE::Extract to constant in enclosing scope==
+class C {
+ a = 1;
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ const newLocal = 1;
+
+ let x = /*RENAME*/newLocal;
+ }
+}
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 1;
+
+class C {
+ a = 1;
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ let x = /*RENAME*/newLocal;
+ }
+}
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition2.ts b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition2.ts
new file mode 100644
index 00000000000..777173b0dcd
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition2.ts
@@ -0,0 +1,46 @@
+// ==ORIGINAL==
+class C {
+ a = 1;
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ let x = 1;
+ }
+}
+// ==SCOPE::Extract to constant in enclosing scope==
+class C {
+ a = 1;
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ const newLocal = 1;
+
+ let x = /*RENAME*/newLocal;
+ }
+}
+// ==SCOPE::Extract to readonly field in class 'C'==
+class C {
+ a = 1;
+ private readonly newProperty = 1;
+
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ let x = this./*RENAME*/newProperty;
+ }
+}
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 1;
+
+class C {
+ a = 1;
+ M1() { }
+ b = 2;
+ M2() { }
+ M3() {
+ let x = /*RENAME*/newLocal;
+ }
+}
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition3.js b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition3.js
new file mode 100644
index 00000000000..b990075166e
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition3.js
@@ -0,0 +1,34 @@
+// ==ORIGINAL==
+class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ M3() {
+ let x = 1;
+ }
+}
+// ==SCOPE::Extract to constant in enclosing scope==
+class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ M3() {
+ const newLocal = 1;
+
+ let x = /*RENAME*/newLocal;
+ }
+}
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 1;
+
+class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ M3() {
+ let x = /*RENAME*/newLocal;
+ }
+}
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition3.ts b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition3.ts
new file mode 100644
index 00000000000..516a24b8b20
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_ClassInsertionPosition3.ts
@@ -0,0 +1,46 @@
+// ==ORIGINAL==
+class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ M3() {
+ let x = 1;
+ }
+}
+// ==SCOPE::Extract to constant in enclosing scope==
+class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ M3() {
+ const newLocal = 1;
+
+ let x = /*RENAME*/newLocal;
+ }
+}
+// ==SCOPE::Extract to readonly field in class 'C'==
+class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ private readonly newProperty = 1;
+
+ M3() {
+ let x = this./*RENAME*/newProperty;
+ }
+}
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 1;
+
+class C {
+ M1() { }
+ a = 1;
+ b = 2;
+ M2() { }
+ M3() {
+ let x = /*RENAME*/newLocal;
+ }
+}
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Directive.js b/tests/baselines/reference/extractConstant/extractConstant_Directive.js
new file mode 100644
index 00000000000..85b9ff76200
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_Directive.js
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+"strict";
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+"strict";
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Directive.ts b/tests/baselines/reference/extractConstant/extractConstant_Directive.ts
new file mode 100644
index 00000000000..85b9ff76200
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_Directive.ts
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+"strict";
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+"strict";
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.js b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.js
index 6bf35cd17e1..c3ccdde3b4f 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.js
@@ -1,4 +1,4 @@
// ==ORIGINAL==
"hello";
-// ==SCOPE::Extract to constant in global scope==
+// ==SCOPE::Extract to constant in enclosing scope==
const /*RENAME*/newLocal = "hello";
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.ts b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.ts
index 6bf35cd17e1..c3ccdde3b4f 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatement.ts
@@ -1,4 +1,4 @@
// ==ORIGINAL==
"hello";
-// ==SCOPE::Extract to constant in global scope==
+// ==SCOPE::Extract to constant in enclosing scope==
const /*RENAME*/newLocal = "hello";
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.js b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.js
index 6bf35cd17e1..c3ccdde3b4f 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.js
@@ -1,4 +1,4 @@
// ==ORIGINAL==
"hello";
-// ==SCOPE::Extract to constant in global scope==
+// ==SCOPE::Extract to constant in enclosing scope==
const /*RENAME*/newLocal = "hello";
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.ts b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.ts
index 6bf35cd17e1..c3ccdde3b4f 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_ExpressionStatementExpression.ts
@@ -1,4 +1,4 @@
// ==ORIGINAL==
"hello";
-// ==SCOPE::Extract to constant in global scope==
+// ==SCOPE::Extract to constant in enclosing scope==
const /*RENAME*/newLocal = "hello";
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Function.js b/tests/baselines/reference/extractConstant/extractConstant_Function.js
index 67c8255c4b4..cff41806566 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_Function.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_Function.js
@@ -2,7 +2,7 @@
function F() {
let x = 1;
}
-// ==SCOPE::Extract to constant in function 'F'==
+// ==SCOPE::Extract to constant in enclosing scope==
function F() {
const newLocal = 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Function.ts b/tests/baselines/reference/extractConstant/extractConstant_Function.ts
index 67c8255c4b4..cff41806566 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_Function.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_Function.ts
@@ -2,7 +2,7 @@
function F() {
let x = 1;
}
-// ==SCOPE::Extract to constant in function 'F'==
+// ==SCOPE::Extract to constant in enclosing scope==
function F() {
const newLocal = 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Method.js b/tests/baselines/reference/extractConstant/extractConstant_Method.js
index bd7c7f86359..32b74d00576 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_Method.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_Method.js
@@ -4,7 +4,7 @@ class C {
let x = 1;
}
}
-// ==SCOPE::Extract to constant in method 'M==
+// ==SCOPE::Extract to constant in enclosing scope==
class C {
M() {
const newLocal = 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Method.ts b/tests/baselines/reference/extractConstant/extractConstant_Method.ts
index 1ae4c8b1cb5..5514b702597 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_Method.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_Method.ts
@@ -4,7 +4,7 @@ class C {
let x = 1;
}
}
-// ==SCOPE::Extract to constant in method 'M==
+// ==SCOPE::Extract to constant in enclosing scope==
class C {
M() {
const newLocal = 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_MultipleHeaders.js b/tests/baselines/reference/extractConstant/extractConstant_MultipleHeaders.js
new file mode 100644
index 00000000000..2ccf5932d38
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_MultipleHeaders.js
@@ -0,0 +1,22 @@
+// ==ORIGINAL==
+
+/*! Copyright */
+
+///
+
+"strict";
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+/*! Copyright */
+
+///
+
+"strict";
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_MultipleHeaders.ts b/tests/baselines/reference/extractConstant/extractConstant_MultipleHeaders.ts
new file mode 100644
index 00000000000..2ccf5932d38
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_MultipleHeaders.ts
@@ -0,0 +1,22 @@
+// ==ORIGINAL==
+
+/*! Copyright */
+
+///
+
+"strict";
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+/*! Copyright */
+
+///
+
+"strict";
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Namespace.ts b/tests/baselines/reference/extractConstant/extractConstant_Namespace.ts
index 8f25847165f..81a543d29c4 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_Namespace.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_Namespace.ts
@@ -2,7 +2,7 @@
namespace N {
let x = 1;
}
-// ==SCOPE::Extract to constant in namespace 'N'==
+// ==SCOPE::Extract to constant in enclosing scope==
namespace N {
const newLocal = 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Parameters.js b/tests/baselines/reference/extractConstant/extractConstant_Parameters.js
index e6c9c474fbc..b90f78d96af 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_Parameters.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_Parameters.js
@@ -3,7 +3,7 @@ function F() {
let w = 1;
let x = w + 1;
}
-// ==SCOPE::Extract to constant in function 'F'==
+// ==SCOPE::Extract to constant in enclosing scope==
function F() {
let w = 1;
const newLocal = w + 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_Parameters.ts b/tests/baselines/reference/extractConstant/extractConstant_Parameters.ts
index e6c9c474fbc..b90f78d96af 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_Parameters.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_Parameters.ts
@@ -3,7 +3,7 @@ function F() {
let w = 1;
let x = w + 1;
}
-// ==SCOPE::Extract to constant in function 'F'==
+// ==SCOPE::Extract to constant in enclosing scope==
function F() {
let w = 1;
const newLocal = w + 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_PinnedComment.js b/tests/baselines/reference/extractConstant/extractConstant_PinnedComment.js
new file mode 100644
index 00000000000..cc897b5c6b9
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_PinnedComment.js
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+/*! Copyright */
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+/*! Copyright */
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_PinnedComment.ts b/tests/baselines/reference/extractConstant/extractConstant_PinnedComment.ts
new file mode 100644
index 00000000000..cc897b5c6b9
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_PinnedComment.ts
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+/*! Copyright */
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+/*! Copyright */
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_PinnedCommentAndDocComment.js b/tests/baselines/reference/extractConstant/extractConstant_PinnedCommentAndDocComment.js
new file mode 100644
index 00000000000..9ee07c7cd6a
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_PinnedCommentAndDocComment.js
@@ -0,0 +1,16 @@
+// ==ORIGINAL==
+
+/*! Copyright */
+
+/* About x */
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+/*! Copyright */
+
+const newLocal = 2 + 1;
+
+/* About x */
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_PinnedCommentAndDocComment.ts b/tests/baselines/reference/extractConstant/extractConstant_PinnedCommentAndDocComment.ts
new file mode 100644
index 00000000000..9ee07c7cd6a
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_PinnedCommentAndDocComment.ts
@@ -0,0 +1,16 @@
+// ==ORIGINAL==
+
+/*! Copyright */
+
+/* About x */
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+/*! Copyright */
+
+const newLocal = 2 + 1;
+
+/* About x */
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition1.js b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition1.js
new file mode 100644
index 00000000000..2197dd13e3a
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition1.js
@@ -0,0 +1,16 @@
+// ==ORIGINAL==
+
+const i = 0;
+for (let j = 0; j < 10; j++) {
+ const x = i + 1;
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+const i = 0;
+for (let j = 0; j < 10; j++) {
+ const newLocal = i + 1;
+
+ const x = /*RENAME*/newLocal;
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition1.ts b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition1.ts
new file mode 100644
index 00000000000..2197dd13e3a
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition1.ts
@@ -0,0 +1,16 @@
+// ==ORIGINAL==
+
+const i = 0;
+for (let j = 0; j < 10; j++) {
+ const x = i + 1;
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+const i = 0;
+for (let j = 0; j < 10; j++) {
+ const newLocal = i + 1;
+
+ const x = /*RENAME*/newLocal;
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition2.js b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition2.js
new file mode 100644
index 00000000000..900798c19ab
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition2.js
@@ -0,0 +1,31 @@
+// ==ORIGINAL==
+
+const i = 0;
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = i + 1;
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+const i = 0;
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const newLocal = i + 1;
+
+ const x = /*RENAME*/newLocal;
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+
+const i = 0;
+const newLocal = i + 1;
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = /*RENAME*/newLocal;
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition2.ts b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition2.ts
new file mode 100644
index 00000000000..900798c19ab
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition2.ts
@@ -0,0 +1,31 @@
+// ==ORIGINAL==
+
+const i = 0;
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = i + 1;
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+const i = 0;
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const newLocal = i + 1;
+
+ const x = /*RENAME*/newLocal;
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+
+const i = 0;
+const newLocal = i + 1;
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = /*RENAME*/newLocal;
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition3.js b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition3.js
new file mode 100644
index 00000000000..3f2f7089ef3
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition3.js
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+for (let j = 0; j < 10; j++) {
+ const x = 2 + 1;
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+for (let j = 0; j < 10; j++) {
+ const newLocal = 2 + 1;
+
+ const x = /*RENAME*/newLocal;
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition3.ts b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition3.ts
new file mode 100644
index 00000000000..3f2f7089ef3
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition3.ts
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+for (let j = 0; j < 10; j++) {
+ const x = 2 + 1;
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+for (let j = 0; j < 10; j++) {
+ const newLocal = 2 + 1;
+
+ const x = /*RENAME*/newLocal;
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition4.js b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition4.js
new file mode 100644
index 00000000000..4c7c2a50217
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition4.js
@@ -0,0 +1,27 @@
+// ==ORIGINAL==
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = 2 + 1;
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const newLocal = 2 + 1;
+
+ const x = /*RENAME*/newLocal;
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 2 + 1;
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = /*RENAME*/newLocal;
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition4.ts b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition4.ts
new file mode 100644
index 00000000000..4c7c2a50217
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition4.ts
@@ -0,0 +1,27 @@
+// ==ORIGINAL==
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = 2 + 1;
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const newLocal = 2 + 1;
+
+ const x = /*RENAME*/newLocal;
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 2 + 1;
+
+function F() {
+ for (let j = 0; j < 10; j++) {
+ const x = /*RENAME*/newLocal;
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition5.js b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition5.js
new file mode 100644
index 00000000000..4b9647fa445
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition5.js
@@ -0,0 +1,41 @@
+// ==ORIGINAL==
+
+function F0() {
+ function F1() {
+ function F2(x = 2 + 1) {
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+function F0() {
+ function F1() {
+ const newLocal = 2 + 1;
+
+ function F2(x = /*RENAME*/newLocal) {
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in function 'F0'==
+
+function F0() {
+ const newLocal = 2 + 1;
+
+ function F1() {
+ function F2(x = /*RENAME*/newLocal) {
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 2 + 1;
+
+function F0() {
+ function F1() {
+ function F2(x = /*RENAME*/newLocal) {
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition5.ts b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition5.ts
new file mode 100644
index 00000000000..4b9647fa445
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition5.ts
@@ -0,0 +1,41 @@
+// ==ORIGINAL==
+
+function F0() {
+ function F1() {
+ function F2(x = 2 + 1) {
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+function F0() {
+ function F1() {
+ const newLocal = 2 + 1;
+
+ function F2(x = /*RENAME*/newLocal) {
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in function 'F0'==
+
+function F0() {
+ const newLocal = 2 + 1;
+
+ function F1() {
+ function F2(x = /*RENAME*/newLocal) {
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 2 + 1;
+
+function F0() {
+ function F1() {
+ function F2(x = /*RENAME*/newLocal) {
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition6.js b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition6.js
new file mode 100644
index 00000000000..0c81cb756a1
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition6.js
@@ -0,0 +1,13 @@
+// ==ORIGINAL==
+
+class C {
+ x = 2 + 1;
+}
+
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 2 + 1;
+
+class C {
+ x = /*RENAME*/newLocal;
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition6.ts b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition6.ts
new file mode 100644
index 00000000000..44a3456fc23
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition6.ts
@@ -0,0 +1,21 @@
+// ==ORIGINAL==
+
+class C {
+ x = 2 + 1;
+}
+
+// ==SCOPE::Extract to readonly field in class 'C'==
+
+class C {
+ private readonly newProperty = 2 + 1;
+
+ x = this./*RENAME*/newProperty;
+}
+
+// ==SCOPE::Extract to constant in global scope==
+const newLocal = 2 + 1;
+
+class C {
+ x = /*RENAME*/newLocal;
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition7.js b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition7.js
new file mode 100644
index 00000000000..f23db0c4aa9
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition7.js
@@ -0,0 +1,37 @@
+// ==ORIGINAL==
+
+const i = 0;
+class C {
+ M() {
+ for (let j = 0; j < 10; j++) {
+ x = i + 1;
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+const i = 0;
+class C {
+ M() {
+ for (let j = 0; j < 10; j++) {
+ const newLocal = i + 1;
+
+ x = /*RENAME*/newLocal;
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+
+const i = 0;
+const newLocal = i + 1;
+
+class C {
+ M() {
+ for (let j = 0; j < 10; j++) {
+ x = /*RENAME*/newLocal;
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition7.ts b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition7.ts
new file mode 100644
index 00000000000..6867685d6db
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_StatementInsertionPosition7.ts
@@ -0,0 +1,50 @@
+// ==ORIGINAL==
+
+const i = 0;
+class C {
+ M() {
+ for (let j = 0; j < 10; j++) {
+ x = i + 1;
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+const i = 0;
+class C {
+ M() {
+ for (let j = 0; j < 10; j++) {
+ const newLocal: any = i + 1;
+
+ x = /*RENAME*/newLocal;
+ }
+ }
+}
+
+// ==SCOPE::Extract to readonly field in class 'C'==
+
+const i = 0;
+class C {
+ private readonly newProperty: any = i + 1;
+
+ M() {
+ for (let j = 0; j < 10; j++) {
+ x = this./*RENAME*/newProperty;
+ }
+ }
+}
+
+// ==SCOPE::Extract to constant in global scope==
+
+const i = 0;
+const newLocal: any = i + 1;
+
+class C {
+ M() {
+ for (let j = 0; j < 10; j++) {
+ x = /*RENAME*/newLocal;
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_TopLevel.js b/tests/baselines/reference/extractConstant/extractConstant_TopLevel.js
index fb0447583ff..fc83d32123e 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_TopLevel.js
+++ b/tests/baselines/reference/extractConstant/extractConstant_TopLevel.js
@@ -1,6 +1,6 @@
// ==ORIGINAL==
let x = 1;
-// ==SCOPE::Extract to constant in global scope==
+// ==SCOPE::Extract to constant in enclosing scope==
const newLocal = 1;
let x = /*RENAME*/newLocal;
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_TopLevel.ts b/tests/baselines/reference/extractConstant/extractConstant_TopLevel.ts
index fb0447583ff..fc83d32123e 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_TopLevel.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_TopLevel.ts
@@ -1,6 +1,6 @@
// ==ORIGINAL==
let x = 1;
-// ==SCOPE::Extract to constant in global scope==
+// ==SCOPE::Extract to constant in enclosing scope==
const newLocal = 1;
let x = /*RENAME*/newLocal;
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_TripleSlash.js b/tests/baselines/reference/extractConstant/extractConstant_TripleSlash.js
new file mode 100644
index 00000000000..e5f87e5d8b8
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_TripleSlash.js
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+///
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+///
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_TripleSlash.ts b/tests/baselines/reference/extractConstant/extractConstant_TripleSlash.ts
new file mode 100644
index 00000000000..e5f87e5d8b8
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_TripleSlash.ts
@@ -0,0 +1,14 @@
+// ==ORIGINAL==
+
+///
+
+const x = 2 + 1;
+
+// ==SCOPE::Extract to constant in enclosing scope==
+
+///
+
+const newLocal = 2 + 1;
+
+const x = /*RENAME*/newLocal;
+
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_TypeParameters.ts b/tests/baselines/reference/extractConstant/extractConstant_TypeParameters.ts
index a323e988176..f9367ab787c 100644
--- a/tests/baselines/reference/extractConstant/extractConstant_TypeParameters.ts
+++ b/tests/baselines/reference/extractConstant/extractConstant_TypeParameters.ts
@@ -2,7 +2,7 @@
function F(t: T) {
let x = t + 1;
}
-// ==SCOPE::Extract to constant in function 'F'==
+// ==SCOPE::Extract to constant in enclosing scope==
function F(t: T) {
const newLocal = t + 1;
diff --git a/tests/baselines/reference/extractConstant/extractConstant_VariableList_MultipleLines.js b/tests/baselines/reference/extractConstant/extractConstant_VariableList_MultipleLines.js
new file mode 100644
index 00000000000..18bb4afc28f
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_VariableList_MultipleLines.js
@@ -0,0 +1,6 @@
+// ==ORIGINAL==
+const /*About A*/a = 1,
+ /*About B*/b = a + 1;
+// ==SCOPE::Extract to constant in enclosing scope==
+const /*About A*/a = 1,
+ /*About B*/newLocal = a + 1, b = /*RENAME*/newLocal;
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_VariableList_MultipleLines.ts b/tests/baselines/reference/extractConstant/extractConstant_VariableList_MultipleLines.ts
new file mode 100644
index 00000000000..18bb4afc28f
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_VariableList_MultipleLines.ts
@@ -0,0 +1,6 @@
+// ==ORIGINAL==
+const /*About A*/a = 1,
+ /*About B*/b = a + 1;
+// ==SCOPE::Extract to constant in enclosing scope==
+const /*About A*/a = 1,
+ /*About B*/newLocal = a + 1, b = /*RENAME*/newLocal;
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_VariableList_const.js b/tests/baselines/reference/extractConstant/extractConstant_VariableList_const.js
new file mode 100644
index 00000000000..161e5a6a02f
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_VariableList_const.js
@@ -0,0 +1,4 @@
+// ==ORIGINAL==
+const a = 1, b = a + 1;
+// ==SCOPE::Extract to constant in enclosing scope==
+const a = 1, newLocal = a + 1, b = /*RENAME*/newLocal;
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_VariableList_const.ts b/tests/baselines/reference/extractConstant/extractConstant_VariableList_const.ts
new file mode 100644
index 00000000000..161e5a6a02f
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_VariableList_const.ts
@@ -0,0 +1,4 @@
+// ==ORIGINAL==
+const a = 1, b = a + 1;
+// ==SCOPE::Extract to constant in enclosing scope==
+const a = 1, newLocal = a + 1, b = /*RENAME*/newLocal;
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_VariableList_let.js b/tests/baselines/reference/extractConstant/extractConstant_VariableList_let.js
new file mode 100644
index 00000000000..bc05b13ba7e
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_VariableList_let.js
@@ -0,0 +1,4 @@
+// ==ORIGINAL==
+let a = 1, b = a + 1;
+// ==SCOPE::Extract to constant in enclosing scope==
+let a = 1, newLocal = a + 1, b = /*RENAME*/newLocal;
\ No newline at end of file
diff --git a/tests/baselines/reference/extractConstant/extractConstant_VariableList_let.ts b/tests/baselines/reference/extractConstant/extractConstant_VariableList_let.ts
new file mode 100644
index 00000000000..bc05b13ba7e
--- /dev/null
+++ b/tests/baselines/reference/extractConstant/extractConstant_VariableList_let.ts
@@ -0,0 +1,4 @@
+// ==ORIGINAL==
+let a = 1, b = a + 1;
+// ==SCOPE::Extract to constant in enclosing scope==
+let a = 1, newLocal = a + 1, b = /*RENAME*/newLocal;
\ No newline at end of file