Extract Method (squash)
This commit is contained in:
parent
8f7a582fc5
commit
c7f665faa1
7
.vscode/tasks.json
vendored
7
.vscode/tasks.json
vendored
|
@ -18,6 +18,13 @@
|
|||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "tests",
|
||||
"showOutput": "silent",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -133,6 +133,7 @@ var harnessSources = harnessCoreSources.concat([
|
|||
"projectErrors.ts",
|
||||
"matchFiles.ts",
|
||||
"initializeTSConfig.ts",
|
||||
"extractMethods.ts",
|
||||
"printer.ts",
|
||||
"textChanges.ts",
|
||||
"telemetry.ts",
|
||||
|
|
|
@ -223,11 +223,10 @@ namespace ts {
|
|||
getSuggestionForNonexistentProperty: (node, type) => unescapeLeadingUnderscores(getSuggestionForNonexistentProperty(node, type)),
|
||||
getSuggestionForNonexistentSymbol: (location, name, meaning) => unescapeLeadingUnderscores(getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning)),
|
||||
getBaseConstraintOfType,
|
||||
getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()),
|
||||
resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined {
|
||||
location = getParseTreeNode(location);
|
||||
return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, escapeLeadingUnderscores(name));
|
||||
resolveName(name, location, meaning) {
|
||||
return resolveName(location, name as __String, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
|
||||
},
|
||||
getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()),
|
||||
};
|
||||
|
||||
const tupleTypes: GenericType[] = [];
|
||||
|
|
|
@ -3673,5 +3673,15 @@
|
|||
"Convert function '{0}' to class": {
|
||||
"category": "Message",
|
||||
"code": 95002
|
||||
},
|
||||
|
||||
"Extract function": {
|
||||
"category": "Message",
|
||||
"code": 95003
|
||||
},
|
||||
|
||||
"Extract function into '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95004
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,7 +394,7 @@ namespace ts {
|
|||
function shouldVisitNode(node: Node): boolean {
|
||||
return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
|
||||
|| convertedLoopState !== undefined
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isStatement(node))
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isStatementOrBlock(node))
|
||||
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatementBody(node))
|
||||
|| isTypeScriptClassWrapper(node);
|
||||
}
|
||||
|
|
|
@ -2606,9 +2606,8 @@ namespace ts {
|
|||
* Does not include properties of primitive types.
|
||||
*/
|
||||
/* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[];
|
||||
|
||||
/* @internal */ resolveName(name: string, location: Node, meaning: SymbolFlags): Symbol | undefined;
|
||||
/* @internal */ getJsxNamespace(): string;
|
||||
/* @internal */ resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined;
|
||||
}
|
||||
|
||||
export enum NodeBuilderFlags {
|
||||
|
|
|
@ -693,7 +693,7 @@ namespace ts {
|
|||
// At this point, node is either a qualified name or an identifier
|
||||
Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression,
|
||||
"'node' was expected to be a qualified name, identifier or property access in 'isPartOfTypeNode'.");
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.QualifiedName:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
|
@ -968,7 +968,7 @@ namespace ts {
|
|||
if (!includeArrowFunctions) {
|
||||
continue;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
|
@ -1027,7 +1027,7 @@ namespace ts {
|
|||
if (!stopOnFunctions) {
|
||||
continue;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
|
@ -1211,7 +1211,7 @@ namespace ts {
|
|||
if (node.parent.kind === SyntaxKind.TypeQuery || isJSXTagName(node)) {
|
||||
return true;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
|
@ -1499,8 +1499,8 @@ namespace ts {
|
|||
parent.parent.kind === SyntaxKind.VariableStatement;
|
||||
const variableStatementNode =
|
||||
isInitializerOfVariableDeclarationInStatement ? parent.parent.parent :
|
||||
isVariableOfVariableDeclarationStatement ? parent.parent :
|
||||
undefined;
|
||||
isVariableOfVariableDeclarationStatement ? parent.parent :
|
||||
undefined;
|
||||
if (variableStatementNode) {
|
||||
getJSDocCommentsAndTagsWorker(variableStatementNode);
|
||||
}
|
||||
|
@ -1614,7 +1614,7 @@ namespace ts {
|
|||
if (isInJavaScriptFile(node)) {
|
||||
if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType ||
|
||||
forEach(getJSDocParameterTags(node),
|
||||
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
|
||||
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1907,7 +1907,7 @@ namespace ts {
|
|||
if (node.asteriskToken) {
|
||||
flags |= FunctionFlags.Generator;
|
||||
}
|
||||
// falls through
|
||||
// falls through
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if (hasModifier(node, ModifierFlags.Async)) {
|
||||
flags |= FunctionFlags.Async;
|
||||
|
@ -5123,6 +5123,19 @@ namespace ts {
|
|||
return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpression | PostfixUnaryExpression {
|
||||
switch (expr.kind) {
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
return true;
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
return (<PrefixUnaryExpression>expr).operator === SyntaxKind.PlusPlusToken ||
|
||||
(<PrefixUnaryExpression>expr).operator === SyntaxKind.MinusMinusToken;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isExpressionKind(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.ConditionalExpression
|
||||
|| kind === SyntaxKind.YieldExpression
|
||||
|
@ -5337,7 +5350,25 @@ namespace ts {
|
|||
const kind = node.kind;
|
||||
return isStatementKindButNotDeclarationKind(kind)
|
||||
|| isDeclarationStatementKind(kind)
|
||||
|| kind === SyntaxKind.Block;
|
||||
|| isBlockStatement(node);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isStatementOrBlock(node: Node): node is Statement {
|
||||
const kind = node.kind;
|
||||
return isStatementKindButNotDeclarationKind(kind)
|
||||
|| isDeclarationStatementKind(kind)
|
||||
|| node.kind === SyntaxKind.Block;
|
||||
}
|
||||
|
||||
function isBlockStatement(node: Node): node is Block {
|
||||
if (node.kind !== SyntaxKind.Block) return false;
|
||||
if (node.parent !== undefined) {
|
||||
if (node.parent.kind === SyntaxKind.TryStatement || node.parent.kind === SyntaxKind.CatchClause) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !isFunctionBlock(node);
|
||||
}
|
||||
|
||||
// Module references
|
||||
|
|
|
@ -187,6 +187,9 @@ namespace FourSlash {
|
|||
|
||||
// The current caret position in the active file
|
||||
public currentCaretPosition = 0;
|
||||
// The position of the end of the current selection, or -1 if nothing is selected
|
||||
public selectionEnd = -1;
|
||||
|
||||
public lastKnownMarker = "";
|
||||
|
||||
// The file that's currently 'opened'
|
||||
|
@ -433,11 +436,19 @@ namespace FourSlash {
|
|||
|
||||
public goToPosition(pos: number) {
|
||||
this.currentCaretPosition = pos;
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
const start = this.getMarkerByName(startMarker), end = this.getMarkerByName(endMarker);
|
||||
this.goToPosition(start.position);
|
||||
this.selectionEnd = end.position;
|
||||
}
|
||||
|
||||
public moveCaretRight(count = 1) {
|
||||
this.currentCaretPosition += count;
|
||||
this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length);
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
// Opens a file given its 0-based index or fileName
|
||||
|
@ -980,9 +991,9 @@ namespace FourSlash {
|
|||
}
|
||||
|
||||
for (const reference of expectedReferences) {
|
||||
const {fileName, start, end} = reference;
|
||||
const { fileName, start, end } = reference;
|
||||
if (reference.marker && reference.marker.data) {
|
||||
const {isWriteAccess, isDefinition} = reference.marker.data;
|
||||
const { isWriteAccess, isDefinition } = reference.marker.data;
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
else {
|
||||
|
@ -1193,7 +1204,7 @@ namespace FourSlash {
|
|||
displayParts: ts.SymbolDisplayPart[],
|
||||
documentation: ts.SymbolDisplayPart[],
|
||||
tags: ts.JSDocTagInfo[]
|
||||
) {
|
||||
) {
|
||||
|
||||
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind"));
|
||||
|
@ -1789,19 +1800,16 @@ namespace FourSlash {
|
|||
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
|
||||
// of the incremental offset from each edit to the next. We assume these edit ranges don't overlap
|
||||
|
||||
edits = edits.sort((a, b) => a.span.start - b.span.start);
|
||||
for (let i = 0; i < edits.length - 1; i++) {
|
||||
const firstEditSpan = edits[i].span;
|
||||
const firstEditEnd = firstEditSpan.start + firstEditSpan.length;
|
||||
assert.isTrue(firstEditEnd <= edits[i + 1].span.start);
|
||||
}
|
||||
// Copy this so we don't ruin someone else's copy
|
||||
edits = JSON.parse(JSON.stringify(edits));
|
||||
|
||||
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
|
||||
const oldContent = this.getFileContent(fileName);
|
||||
let runningOffset = 0;
|
||||
|
||||
for (const edit of edits) {
|
||||
const offsetStart = edit.span.start + runningOffset;
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
const edit = edits[i];
|
||||
const offsetStart = edit.span.start;
|
||||
const offsetEnd = offsetStart + edit.span.length;
|
||||
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
|
||||
const editDelta = edit.newText.length - edit.span.length;
|
||||
|
@ -1816,8 +1824,13 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
runningOffset += editDelta;
|
||||
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
|
||||
// this.languageService.getScriptLexicalStructure(fileName);
|
||||
|
||||
// Update positions of any future edits affected by this change
|
||||
for (let j = i + 1; j < edits.length; j++) {
|
||||
if (edits[j].span.start >= edits[i].span.start) {
|
||||
edits[j].span.start += editDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFormattingEdit) {
|
||||
|
@ -1901,7 +1914,7 @@ namespace FourSlash {
|
|||
this.goToPosition(len);
|
||||
}
|
||||
|
||||
public goToRangeStart({fileName, start}: Range) {
|
||||
public goToRangeStart({ fileName, start }: Range) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
}
|
||||
|
@ -2075,7 +2088,7 @@ namespace FourSlash {
|
|||
return result;
|
||||
}
|
||||
|
||||
private rangeText({fileName, start, end}: Range): string {
|
||||
private rangeText({ fileName, start, end }: Range): string {
|
||||
return this.getFileContent(fileName).slice(start, end);
|
||||
}
|
||||
|
||||
|
@ -2361,7 +2374,7 @@ namespace FourSlash {
|
|||
private applyCodeActions(actions: ts.CodeAction[], index?: number): void {
|
||||
if (index === undefined) {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" }`);
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
|
@ -2736,6 +2749,30 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
private getSelection() {
|
||||
return ({
|
||||
pos: this.currentCaretPosition,
|
||||
end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd
|
||||
});
|
||||
}
|
||||
|
||||
public verifyRefactorAvailable(negative: boolean, name?: string, subName?: string) {
|
||||
const selection = this.getSelection();
|
||||
|
||||
let refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, selection) || [];
|
||||
if (name) {
|
||||
refactors = refactors.filter(r => r.name === name && (subName === undefined || r.actions.some(a => a.name === subName)));
|
||||
}
|
||||
const isAvailable = refactors.length > 0;
|
||||
|
||||
if (negative && isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some.`);
|
||||
}
|
||||
else if (!negative && !isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyApplicableRefactorAvailableForRange(negative: boolean) {
|
||||
const ranges = this.getRanges();
|
||||
if (!(ranges && ranges.length === 1)) {
|
||||
|
@ -2752,6 +2789,20 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
const range = this.getSelection();
|
||||
const refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, range);
|
||||
const refactor = ts.find(refactors, r => r.name === refactorName);
|
||||
if (!refactor) {
|
||||
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.`);
|
||||
}
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName);
|
||||
for (const edit of editInfo.edits) {
|
||||
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyFileAfterApplyingRefactorAtMarker(
|
||||
markerName: string,
|
||||
expectedContent: string,
|
||||
|
@ -3496,6 +3547,10 @@ namespace FourSlashInterface {
|
|||
public file(indexOrName: any, content?: string, scriptKindName?: string): void {
|
||||
this.state.openFile(indexOrName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
this.state.select(startMarker, endMarker);
|
||||
}
|
||||
}
|
||||
|
||||
export class VerifyNegatable {
|
||||
|
@ -3617,6 +3672,10 @@ namespace FourSlashInterface {
|
|||
public applicableRefactorAvailableForRange() {
|
||||
this.state.verifyApplicableRefactorAvailableForRange(this.negative);
|
||||
}
|
||||
|
||||
public refactorAvailable(name?: string, subName?: string) {
|
||||
this.state.verifyRefactorAvailable(this.negative, name, subName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Verify extends VerifyNegatable {
|
||||
|
@ -4012,6 +4071,10 @@ namespace FourSlashInterface {
|
|||
public disableFormatting() {
|
||||
this.state.enableFormatting = false;
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
this.state.applyRefactor(refactorName, actionName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Debug {
|
||||
|
|
591
src/harness/unittests/extractMethods.ts
Normal file
591
src/harness/unittests/extractMethods.ts
Normal file
|
@ -0,0 +1,591 @@
|
|||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="tsserverProjectSystem.ts" />
|
||||
|
||||
namespace ts {
|
||||
interface Range {
|
||||
start: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
function extractTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, start: text.length, end: undefined });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop();
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
const newLineCharacter = "\n";
|
||||
function getRuleProvider(action?: (opts: FormatCodeSettings) => void) {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
if (action) {
|
||||
action(options);
|
||||
}
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
}
|
||||
|
||||
function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) {
|
||||
return it(caption, () => {
|
||||
const t = extractTest(s);
|
||||
const file = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(file, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
});
|
||||
}
|
||||
|
||||
function testExtractRange(s: string): void {
|
||||
const t = extractTest(s);
|
||||
const f = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(f, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let start: number, end: number;
|
||||
if (ts.isArray(result.targetRange.range)) {
|
||||
start = result.targetRange.range[0].getStart(f);
|
||||
end = ts.lastOrUndefined(result.targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
start = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(start, expectedRange.start, "incorrect start of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
}
|
||||
else {
|
||||
assert.isTrue(!result.targetRange, `expected range to extract to be undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
describe("extractMethods", () => {
|
||||
it("get extract range from selection", () => {
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|var x = 1;
|
||||
var y = 2;|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
var x = 1;
|
||||
var y = 2|];
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|var x = 1|];
|
||||
var y = 2;
|
||||
`);
|
||||
testExtractRange(`
|
||||
if ([#|[#extracted|a && b && c && d|]|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if [#|(a && b && c && d|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if (a && b && c && d) {
|
||||
[#| [$|var x = 1;
|
||||
console.log(x);|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
if (a) {
|
||||
return 100;
|
||||
} |]
|
||||
`);
|
||||
testExtractRange(`
|
||||
function foo() {
|
||||
[#| [$|if (a) {
|
||||
}
|
||||
return 100|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l1:
|
||||
if (x) {
|
||||
break l1;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l2:
|
||||
{
|
||||
if (x) {
|
||||
}
|
||||
break l2;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
break; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
continue; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
l3:
|
||||
{
|
||||
[#|
|
||||
if (x) {
|
||||
}
|
||||
break l3; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
if (x) {
|
||||
return;
|
||||
} |]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
[$|if (x) {
|
||||
}
|
||||
return;|]
|
||||
|]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [#| [$|1 + 2|] |]+ 3;
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + [#|2 + 3|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + 2 + [#|3 + 4|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed1",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed2",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed3",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
continue;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed4",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
l1: {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break l1;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing labeled break or continue with target outside of the range."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed5",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
return 10;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed6",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
}
|
||||
catch (e) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractMethod("extractMethod1",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod2",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod3",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
[#|
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod4",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
[#|
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod5",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod6",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod7",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod8",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return 1 + [#|a1 + x|] + 100;
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod9",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod10",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod11",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod12",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
});
|
||||
|
||||
|
||||
function testExtractMethod(caption: string, text: string) {
|
||||
it(caption, () => {
|
||||
Harness.Baseline.runBaseline(`extractMethod/${caption}.js`, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const sourceFile = program.getSourceFile(f.path);
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
|
||||
newLineCharacter,
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: -1,
|
||||
rulesProvider: getRuleProvider()
|
||||
};
|
||||
const result = refactor.extractMethod.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.equal(result.errors, undefined, "expect no errors");
|
||||
const results = refactor.extractMethod.extractRange(result.targetRange, context);
|
||||
const data: string[] = [];
|
||||
data.push(`==ORIGINAL==`);
|
||||
data.push(sourceFile.text);
|
||||
for (const r of results) {
|
||||
const changes = refactor.extractMethod.extractRange(result.targetRange, context, results.indexOf(r))[0].changes;
|
||||
data.push(`==SCOPE::${r.scopeDescription}==`);
|
||||
data.push(textChanges.applyChanges(sourceFile.text, changes[0].textChanges));
|
||||
}
|
||||
return data.join(newLineCharacter);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -147,7 +147,7 @@ namespace ts.codefix {
|
|||
}
|
||||
else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) {
|
||||
// The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`.
|
||||
symbol = checker.getAliasedSymbol(checker.resolveNameAtLocation(token, checker.getJsxNamespace(), SymbolFlags.Value));
|
||||
symbol = checker.getAliasedSymbol(checker.resolveName(checker.getJsxNamespace(), token.parent.tagName, SymbolFlags.Value));
|
||||
symbolName = symbol.name;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* @internal */
|
||||
|
||||
namespace ts.refactor {
|
||||
namespace ts.refactor.convertFunctionToES6Class {
|
||||
const actionName = "convert";
|
||||
|
||||
const convertFunctionToES6Class: Refactor = {
|
||||
|
|
1154
src/services/refactors/extractMethod.ts
Normal file
1154
src/services/refactors/extractMethod.ts
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1 +1,2 @@
|
|||
/// <reference path="convertFunctionToEs6Class.ts" />
|
||||
/// <reference path="extractMethod.ts" />
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace ts.textChanges {
|
|||
*/
|
||||
export type ConfigurableStartEnd = ConfigurableStart & ConfigurableEnd;
|
||||
|
||||
export interface InsertNodeOptions {
|
||||
interface InsertNodeOptions {
|
||||
/**
|
||||
* Text to be inserted before the new node
|
||||
*/
|
||||
|
@ -83,16 +83,43 @@ namespace ts.textChanges {
|
|||
delta?: number;
|
||||
}
|
||||
|
||||
export type ChangeNodeOptions = ConfigurableStartEnd & InsertNodeOptions;
|
||||
enum ChangeKind {
|
||||
Remove,
|
||||
ReplaceWithSingleNode,
|
||||
ReplaceWithMultipleNodes
|
||||
}
|
||||
|
||||
interface Change {
|
||||
type Change = ReplaceWithSingleNode | ReplaceWithMultipleNodes | RemoveNode;
|
||||
|
||||
interface BaseChange {
|
||||
readonly sourceFile: SourceFile;
|
||||
readonly range: TextRange;
|
||||
}
|
||||
|
||||
interface ChangeNodeOptions extends ConfigurableStartEnd, InsertNodeOptions {
|
||||
readonly useIndentationFromFile?: boolean;
|
||||
readonly node?: Node;
|
||||
}
|
||||
interface ReplaceWithSingleNode extends BaseChange {
|
||||
readonly kind: ChangeKind.ReplaceWithSingleNode;
|
||||
readonly node: Node;
|
||||
readonly options?: ChangeNodeOptions;
|
||||
}
|
||||
|
||||
interface RemoveNode extends BaseChange {
|
||||
readonly kind: ChangeKind.Remove;
|
||||
readonly node?: never;
|
||||
readonly options?: never;
|
||||
}
|
||||
|
||||
interface ChangeMultipleNodesOptions extends ChangeNodeOptions {
|
||||
nodeSeparator: string;
|
||||
}
|
||||
interface ReplaceWithMultipleNodes extends BaseChange {
|
||||
readonly kind: ChangeKind.ReplaceWithMultipleNodes;
|
||||
readonly nodes: ReadonlyArray<Node>;
|
||||
readonly options?: ChangeMultipleNodesOptions;
|
||||
}
|
||||
|
||||
export function getSeparatorCharacter(separator: Token<SyntaxKind.CommaToken | SyntaxKind.SemicolonToken>) {
|
||||
return tokenToString(separator.kind);
|
||||
}
|
||||
|
@ -153,12 +180,16 @@ namespace ts.textChanges {
|
|||
return s;
|
||||
}
|
||||
|
||||
function getNewlineKind(context: { newLineCharacter: string }) {
|
||||
return context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed;
|
||||
}
|
||||
|
||||
export class ChangeTracker {
|
||||
private changes: Change[] = [];
|
||||
private readonly newLineCharacter: string;
|
||||
|
||||
public static fromCodeFixContext(context: { newLineCharacter: string, rulesProvider: formatting.RulesProvider }) {
|
||||
return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.rulesProvider);
|
||||
public static fromCodeFixContext(context: { newLineCharacter: string, rulesProvider?: formatting.RulesProvider }) {
|
||||
return new ChangeTracker(getNewlineKind(context), context.rulesProvider);
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
@ -168,22 +199,22 @@ namespace ts.textChanges {
|
|||
this.newLineCharacter = getNewLineCharacter({ newLine });
|
||||
}
|
||||
|
||||
public deleteNode(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, node, options, Position.FullStart);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, node, options);
|
||||
this.changes.push({ sourceFile, options, range: { pos: startPosition, end: endPosition } });
|
||||
public deleteRange(sourceFile: SourceFile, range: TextRange) {
|
||||
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range });
|
||||
return this;
|
||||
}
|
||||
|
||||
public deleteRange(sourceFile: SourceFile, range: TextRange) {
|
||||
this.changes.push({ sourceFile, range });
|
||||
public deleteNode(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, node, options, Position.FullStart);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, node, options);
|
||||
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range: { pos: startPosition, end: endPosition } });
|
||||
return this;
|
||||
}
|
||||
|
||||
public deleteNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.FullStart);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
this.changes.push({ sourceFile, options, range: { pos: startPosition, end: endPosition } });
|
||||
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range: { pos: startPosition, end: endPosition } });
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -223,33 +254,74 @@ namespace ts.textChanges {
|
|||
}
|
||||
|
||||
public replaceRange(sourceFile: SourceFile, range: TextRange, newNode: Node, options: InsertNodeOptions = {}) {
|
||||
this.changes.push({ sourceFile, range, options, node: newNode });
|
||||
this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, range, options, node: newNode });
|
||||
return this;
|
||||
}
|
||||
|
||||
public replaceNode(sourceFile: SourceFile, oldNode: Node, newNode: Node, options: ChangeNodeOptions = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, oldNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, oldNode, options);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: startPosition, end: endPosition } });
|
||||
return this;
|
||||
return this.replaceWithSingle(sourceFile, startPosition, endPosition, newNode, options);
|
||||
}
|
||||
|
||||
public replaceNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, newNode: Node, options: ChangeNodeOptions = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: startPosition, end: endPosition } });
|
||||
return this.replaceWithSingle(sourceFile, startPosition, endPosition, newNode, options);
|
||||
}
|
||||
|
||||
private replaceWithSingle(sourceFile: SourceFile, startPosition: number, endPosition: number, newNode: Node, options: ChangeNodeOptions): this {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
options,
|
||||
node: newNode,
|
||||
range: { pos: startPosition, end: endPosition }
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
private replaceWithMultiple(sourceFile: SourceFile, startPosition: number, endPosition: number, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions): this {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithMultipleNodes,
|
||||
sourceFile,
|
||||
options,
|
||||
nodes: newNodes,
|
||||
range: { pos: startPosition, end: endPosition }
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public replaceNodeWithNodes(sourceFile: SourceFile, oldNode: Node, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, oldNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, oldNode, options);
|
||||
return this.replaceWithMultiple(sourceFile, startPosition, endPosition, newNodes, options);
|
||||
}
|
||||
|
||||
public replaceNodesWithNodes(sourceFile: SourceFile, oldNodes: ReadonlyArray<Node>, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, oldNodes[0], options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, lastOrUndefined(oldNodes), options);
|
||||
return this.replaceWithMultiple(sourceFile, startPosition, endPosition, newNodes, options);
|
||||
}
|
||||
|
||||
public replaceRangeWithNodes(sourceFile: SourceFile, range: TextRange, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
return this.replaceWithMultiple(sourceFile, range.pos, range.end, newNodes, options);
|
||||
}
|
||||
|
||||
public replaceNodeRangeWithNodes(sourceFile: SourceFile, startNode: Node, endNode: Node, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
return this.replaceWithMultiple(sourceFile, startPosition, endPosition, newNodes, options);
|
||||
}
|
||||
|
||||
public insertNodeAt(sourceFile: SourceFile, pos: number, newNode: Node, options: InsertNodeOptions = {}) {
|
||||
this.changes.push({ sourceFile, options, node: newNode, range: { pos, end: pos } });
|
||||
this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, options, node: newNode, range: { pos, end: pos } });
|
||||
return this;
|
||||
}
|
||||
|
||||
public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, options: InsertNodeOptions & ConfigurableStart = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, before, options, Position.Start);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: startPosition, end: startPosition } });
|
||||
return this;
|
||||
return this.replaceWithSingle(sourceFile, startPosition, startPosition, newNode, options);
|
||||
}
|
||||
|
||||
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node, options: InsertNodeOptions & ConfigurableEnd = {}) {
|
||||
|
@ -261,6 +333,7 @@ namespace ts.textChanges {
|
|||
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
|
||||
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
options: {},
|
||||
range: { pos: after.end, end: after.end },
|
||||
|
@ -269,8 +342,7 @@ namespace ts.textChanges {
|
|||
}
|
||||
}
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, after, options);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: endPosition, end: endPosition } });
|
||||
return this;
|
||||
return this.replaceWithSingle(sourceFile, endPosition, endPosition, newNode, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,10 +411,10 @@ namespace ts.textChanges {
|
|||
}
|
||||
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: startPos, end: containingList[index + 1].getStart(sourceFile) },
|
||||
node: newNode,
|
||||
useIndentationFromFile: true,
|
||||
options: {
|
||||
prefix,
|
||||
// write separator and leading trivia of the next element as suffix
|
||||
|
@ -383,6 +455,7 @@ namespace ts.textChanges {
|
|||
if (multilineList) {
|
||||
// insert separator immediately following the 'after' node to preserve comments in trailing trivia
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: end, end },
|
||||
node: createToken(separator),
|
||||
|
@ -396,6 +469,7 @@ namespace ts.textChanges {
|
|||
insertPos--;
|
||||
}
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: insertPos, end: insertPos },
|
||||
node: newNode,
|
||||
|
@ -404,6 +478,7 @@ namespace ts.textChanges {
|
|||
}
|
||||
else {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: end, end },
|
||||
node: newNode,
|
||||
|
@ -446,38 +521,51 @@ namespace ts.textChanges {
|
|||
}
|
||||
|
||||
private computeNewText(change: Change, sourceFile: SourceFile): string {
|
||||
if (!change.node) {
|
||||
if (change.kind === ChangeKind.Remove) {
|
||||
// deletion case
|
||||
return "";
|
||||
}
|
||||
|
||||
const options = change.options || {};
|
||||
const nonFormattedText = getNonformattedText(change.node, sourceFile, this.newLine);
|
||||
let text: string;
|
||||
const pos = change.range.pos;
|
||||
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
|
||||
if (change.kind === ChangeKind.ReplaceWithMultipleNodes) {
|
||||
const parts = change.nodes.map(n => this.getFormattedTextOfNode(n, sourceFile, pos, options));
|
||||
text = parts.join(change.options.nodeSeparator);
|
||||
}
|
||||
else {
|
||||
Debug.assert(change.kind === ChangeKind.ReplaceWithSingleNode, "change.kind === ReplaceWithSingleNode");
|
||||
text = this.getFormattedTextOfNode(change.node, sourceFile, pos, options);
|
||||
}
|
||||
// strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
|
||||
text = (posStartsLine || options.indentation !== undefined) ? text : text.replace(/^\s+/, "");
|
||||
return (options.prefix || "") + text + (options.suffix || "");
|
||||
}
|
||||
|
||||
private getFormattedTextOfNode(node: Node, sourceFile: SourceFile, pos: number, options: ChangeNodeOptions): string {
|
||||
const nonformattedText = getNonformattedText(node, sourceFile, this.newLine);
|
||||
if (this.validator) {
|
||||
this.validator(nonFormattedText);
|
||||
this.validator(nonformattedText);
|
||||
}
|
||||
|
||||
const formatOptions = this.rulesProvider.getFormatOptions();
|
||||
const pos = change.range.pos;
|
||||
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
|
||||
|
||||
const initialIndentation =
|
||||
change.options.indentation !== undefined
|
||||
? change.options.indentation
|
||||
: change.useIndentationFromFile
|
||||
? formatting.SmartIndenter.getIndentation(change.range.pos, sourceFile, formatOptions, posStartsLine || (change.options.prefix === this.newLineCharacter))
|
||||
options.indentation !== undefined
|
||||
? options.indentation
|
||||
: (options.useIndentationFromFile !== false)
|
||||
? formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, posStartsLine || (options.prefix === this.newLineCharacter))
|
||||
: 0;
|
||||
const delta =
|
||||
change.options.delta !== undefined
|
||||
? change.options.delta
|
||||
: formatting.SmartIndenter.shouldIndentChildNode(change.node)
|
||||
? formatOptions.indentSize
|
||||
options.delta !== undefined
|
||||
? options.delta
|
||||
: formatting.SmartIndenter.shouldIndentChildNode(node)
|
||||
? (formatOptions.indentSize || 0)
|
||||
: 0;
|
||||
|
||||
let text = applyFormatting(nonFormattedText, sourceFile, initialIndentation, delta, this.rulesProvider);
|
||||
// strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
|
||||
// however keep indentation if it is was forced
|
||||
text = posStartsLine || change.options.indentation !== undefined ? text : text.replace(/^\s+/, "");
|
||||
return (options.prefix || "") + text + (options.suffix || "");
|
||||
return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.rulesProvider);
|
||||
}
|
||||
|
||||
private static normalize(changes: Change[]): Change[] {
|
||||
|
@ -654,4 +742,4 @@ namespace ts.textChanges {
|
|||
this.lastNonTriviaPosition = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,7 +271,6 @@ namespace ts {
|
|||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
|
||||
|
||||
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[];
|
||||
|
||||
getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined;
|
||||
|
||||
|
|
98
tests/baselines/reference/extractMethod/extractMethod1.js
Normal file
98
tests/baselines/reference/extractMethod/extractMethod1.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
a = newFunction(a);
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
a = newFunction(a);
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return a;
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
a = newFunction(x, a, foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: number, a: number, foo: () => void) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return a;
|
||||
}
|
55
tests/baselines/reference/extractMethod/extractMethod10.js
Normal file
55
tests/baselines/reference/extractMethod/extractMethod10.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::class C==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return this.newFunction();
|
||||
}
|
||||
|
||||
private newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction() {
|
||||
let a1: A.I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
69
tests/baselines/reference/extractMethod/extractMethod11.js
Normal file
69
tests/baselines/reference/extractMethod/extractMethod11.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::class C==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ __return, z } = this.newFunction(z));
|
||||
return __return;
|
||||
}
|
||||
|
||||
private newFunction(z: number) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return { __return: a1.x + 10, z };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ __return, z } = newFunction(z));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(z: number) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return { __return: a1.x + 10, z };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ __return, y, z } = newFunction(y, z));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(y: number, z: number) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return { __return: a1.x + 10, y, z };
|
||||
}
|
36
tests/baselines/reference/extractMethod/extractMethod12.js
Normal file
36
tests/baselines/reference/extractMethod/extractMethod12.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::class C==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ __return, z } = this.newFunction(z));
|
||||
return __return;
|
||||
}
|
||||
|
||||
private newFunction(z: number) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return { __return: a1.x + 10, z };
|
||||
}
|
||||
}
|
||||
}
|
85
tests/baselines/reference/extractMethod/extractMethod2.js
Normal file
85
tests/baselines/reference/extractMethod/extractMethod2.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction();
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction(x, foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: number, foo: () => void) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
80
tests/baselines/reference/extractMethod/extractMethod3.js
Normal file
80
tests/baselines/reference/extractMethod/extractMethod3.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction();
|
||||
|
||||
function* newFunction() {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction(z);
|
||||
}
|
||||
|
||||
function* newFunction(z: number) {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction(z);
|
||||
}
|
||||
}
|
||||
|
||||
function* newFunction(z: number) {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction(z, foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
function* newFunction(z: number, foo: () => void) {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
90
tests/baselines/reference/extractMethod/extractMethod4.js
Normal file
90
tests/baselines/reference/extractMethod/extractMethod4.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction();
|
||||
|
||||
async function newFunction() {
|
||||
let y = 5;
|
||||
if(z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction(z, z1);
|
||||
}
|
||||
|
||||
async function newFunction(z: number, z1: any) {
|
||||
let y = 5;
|
||||
if(z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction(z, z1);
|
||||
}
|
||||
}
|
||||
|
||||
async function newFunction(z: number, z1: any) {
|
||||
let y = 5;
|
||||
if(z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction(z, z1, foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function newFunction(z: number, z1: any, foo: () => void) {
|
||||
let y = 5;
|
||||
if(z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
98
tests/baselines/reference/extractMethod/extractMethod5.js
Normal file
98
tests/baselines/reference/extractMethod/extractMethod5.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
a = newFunction(a);
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
a = newFunction(a);
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return a;
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
a = newFunction(x, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: number, a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
A.foo();
|
||||
return a;
|
||||
}
|
101
tests/baselines/reference/extractMethod/extractMethod6.js
Normal file
101
tests/baselines/reference/extractMethod/extractMethod6.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ __return, a } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { __return: foo(), a };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ __return, a } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { __return: foo(), a };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ __return, a } = newFunction(x, a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: number, a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { __return: A.foo(), a };
|
||||
}
|
111
tests/baselines/reference/extractMethod/extractMethod7.js
Normal file
111
tests/baselines/reference/extractMethod/extractMethod7.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ __return, a } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { __return: C.foo(), a };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ __return, a } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { __return: C.foo(), a };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ __return, a } = newFunction(x, a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: number, a: number) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { __return: A.C.foo(), a };
|
||||
}
|
65
tests/baselines/reference/extractMethod/extractMethod8.js
Normal file
65
tests/baselines/reference/extractMethod/extractMethod8.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return 1 + a1 + x + 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction() + 100;
|
||||
|
||||
function newFunction() {
|
||||
return 1 + a1 + x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction(a1) + 100;
|
||||
}
|
||||
|
||||
function newFunction(a1: number) {
|
||||
return 1 + a1 + x;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction(a1) + 100;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a1: number) {
|
||||
return 1 + a1 + x;
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction(a1, x) + 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(a1: number, x: number) {
|
||||
return 1 + a1 + x;
|
||||
}
|
65
tests/baselines/reference/extractMethod/extractMethod9.js
Normal file
65
tests/baselines/reference/extractMethod/extractMethod9.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction() {
|
||||
let a1: A.I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
98
tests/baselines/reference/extractMethod1.js
Normal file
98
tests/baselines/reference/extractMethod1.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
({ a } = newFunction(a));
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return { a };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
({ a } = newFunction(a));
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return { a };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
({ a } = newFunction(x, a, foo));
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: any, a: any, foo: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return { a };
|
||||
}
|
70
tests/baselines/reference/extractMethod10.js
Normal file
70
tests/baselines/reference/extractMethod10.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::method a==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::class C==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return this.newFunction();
|
||||
}
|
||||
|
||||
private newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction() {
|
||||
let a1: A.I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
86
tests/baselines/reference/extractMethod11.js
Normal file
86
tests/baselines/reference/extractMethod11.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::method a==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::class C==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ z, __return } = this.newFunction(z));
|
||||
return __return;
|
||||
}
|
||||
|
||||
private newFunction(z: any) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return { z, __return: a1.x + 10 };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ z, __return } = newFunction(z));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(z: any) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return { z, __return: a1.x + 10 };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ y, z, __return } = newFunction(y, z));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(y: any, z: any) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return { y, z, __return: a1.x + 10 };
|
||||
}
|
36
tests/baselines/reference/extractMethod12.js
Normal file
36
tests/baselines/reference/extractMethod12.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::class C==
|
||||
namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
var __return: any;
|
||||
({ z, __return } = this.newFunction(z));
|
||||
return __return;
|
||||
}
|
||||
|
||||
private newFunction(z: any) {
|
||||
let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return { z, __return: a1.x + 10 };
|
||||
}
|
||||
}
|
||||
}
|
85
tests/baselines/reference/extractMethod2.js
Normal file
85
tests/baselines/reference/extractMethod2.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction();
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
|
||||
return newFunction(x, foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: any, foo: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();
|
||||
}
|
80
tests/baselines/reference/extractMethod3.js
Normal file
80
tests/baselines/reference/extractMethod3.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction();
|
||||
|
||||
function* newFunction() {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction(z);
|
||||
}
|
||||
|
||||
function* newFunction(z: any) {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction(z);
|
||||
}
|
||||
}
|
||||
|
||||
function* newFunction(z: any) {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
|
||||
return yield* newFunction(z, foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
function* newFunction(z: any, foo: any) {
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();
|
||||
}
|
90
tests/baselines/reference/extractMethod4.js
Normal file
90
tests/baselines/reference/extractMethod4.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction();
|
||||
|
||||
async function newFunction() {
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction(z, z1);
|
||||
}
|
||||
|
||||
async function newFunction(z: any, z1: any) {
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction(z, z1);
|
||||
}
|
||||
}
|
||||
|
||||
async function newFunction(z: any, z1: any) {
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
|
||||
return await newFunction(z, z1, foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function newFunction(z: any, z1: any, foo: any) {
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();
|
||||
}
|
98
tests/baselines/reference/extractMethod5.js
Normal file
98
tests/baselines/reference/extractMethod5.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
({ a } = newFunction(a));
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return { a };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
({ a } = newFunction(a));
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();
|
||||
return { a };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
({ a } = newFunction(x, a));
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: any, a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
A.foo();
|
||||
return { a };
|
||||
}
|
101
tests/baselines/reference/extractMethod6.js
Normal file
101
tests/baselines/reference/extractMethod6.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ a, __return } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { a, __return: foo() };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ a, __return } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { a, __return: foo() };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ a, __return } = newFunction(x, a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: any, a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { a, __return: A.foo() };
|
||||
}
|
111
tests/baselines/reference/extractMethod7.js
Normal file
111
tests/baselines/reference/extractMethod7.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ a, __return } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { a, __return: C.foo() };
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ a, __return } = newFunction(a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { a, __return: C.foo() };
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
|
||||
var __return: any;
|
||||
({ a, __return } = newFunction(x, a));
|
||||
return __return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(x: any, a: any) {
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return { a, __return: A.C.foo() };
|
||||
}
|
57
tests/baselines/reference/extractMethod8.js
Normal file
57
tests/baselines/reference/extractMethod8.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return 1 + a1 + x + 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction() + 100;
|
||||
|
||||
function newFunction() { 1 + a1 + x; }
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction(a1) + 100;
|
||||
}
|
||||
|
||||
function newFunction(a1: any) { 1 + a1 + x; }
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction(a1) + 100;
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction(a1: any) { 1 + a1 + x; }
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return newFunction(a1, x) + 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(a1: any, x: any) { 1 + a1 + x; }
|
65
tests/baselines/reference/extractMethod9.js
Normal file
65
tests/baselines/reference/extractMethod9.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
==ORIGINAL==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::function a==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace B==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
==SCOPE::namespace A==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction() {
|
||||
let a1: I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
||||
}
|
||||
==SCOPE::file '/a.ts'==
|
||||
namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
return newFunction();
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction() {
|
||||
let a1: A.I = { x: 1 };
|
||||
return a1.x + 10;
|
||||
}
|
|
@ -47,7 +47,7 @@ verify.completionListIsGlobal(true);
|
|||
goTo.marker("6");
|
||||
verify.completionListIsGlobal(false);
|
||||
goTo.marker("7");
|
||||
verify.completionListIsGlobal(true);
|
||||
verify.completionListIsGlobal(false);
|
||||
goTo.marker("8");
|
||||
verify.completionListIsGlobal(false);
|
||||
goTo.marker("9");
|
||||
|
|
33
tests/cases/fourslash/extract-method1.ts
Normal file
33
tests/cases/fourslash/extract-method1.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// class Foo {
|
||||
//// someMethod(m: number) {
|
||||
//// /*start*/var x = m;
|
||||
//// x = x * 3;
|
||||
//// var y = 30;
|
||||
//// var z = y + x;
|
||||
//// console.log(z);/*end*/
|
||||
//// var q = 10;
|
||||
//// return q;
|
||||
//// }
|
||||
//// }
|
||||
|
||||
goTo.select('start', 'end')
|
||||
verify.refactorAvailable('Extract Method');
|
||||
edit.applyRefactor('Extract Method', "scope_0");
|
||||
verify.currentFileContentIs(
|
||||
`class Foo {
|
||||
someMethod(m: number) {
|
||||
this.newFunction(m);
|
||||
var q = 10;
|
||||
return q;
|
||||
}
|
||||
|
||||
private newFunction(m: number) {
|
||||
var x = m;
|
||||
x = x * 3;
|
||||
var y = 30;
|
||||
var z = y + x;
|
||||
console.log(z);
|
||||
}
|
||||
}`);
|
6
tests/cases/fourslash/extract-method10.ts
Normal file
6
tests/cases/fourslash/extract-method10.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// (x => x)(/*1*/x => x/*2*/)(1);
|
||||
|
||||
goTo.select('1', '2');
|
||||
edit.applyRefactor('Extract Method', 'scope_0');
|
28
tests/cases/fourslash/extract-method11.ts
Normal file
28
tests/cases/fourslash/extract-method11.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Nonexhaustive list of things it should be illegal to be extract-method on
|
||||
|
||||
// * Import declarations
|
||||
// * Super calls
|
||||
// * Function body blocks
|
||||
// * try/catch blocks
|
||||
|
||||
//// /*1a*/import * as x from 'y';/*1b*/
|
||||
//// namespace N {
|
||||
//// /*oka*/class C extends B {
|
||||
//// constructor() {
|
||||
//// /*2a*/super();/*2b*/
|
||||
//// }
|
||||
//// }/*okb*/
|
||||
//// }
|
||||
//// function f() /*3a*/{ return 0 }/*3b*/
|
||||
//// try /*4a*/{ console.log }/*4b*/ catch (e) /*5a*/{ console.log; }/*5b*/
|
||||
|
||||
for (const m of ['1', '2', '3', '4', '5']) {
|
||||
goTo.select(m + 'a', m + 'b');
|
||||
verify.not.refactorAvailable('Extract Method');
|
||||
}
|
||||
|
||||
// Verify we can still extract the entire class
|
||||
goTo.select('oka', 'okb');
|
||||
verify.refactorAvailable('Extract Method');
|
30
tests/cases/fourslash/extract-method13.ts
Normal file
30
tests/cases/fourslash/extract-method13.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Extracting from a static context should make static methods.
|
||||
// Also checks that we correctly find non-conflicting names in static contexts.
|
||||
|
||||
//// class C {
|
||||
//// static j = /*c*/100/*d*/;
|
||||
//// constructor(q: string = /*a*/"hello"/*b*/) {
|
||||
//// }
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b');
|
||||
edit.applyRefactor('Extract Method', 'scope_0');
|
||||
|
||||
goTo.select('c', 'd');
|
||||
edit.applyRefactor('Extract Method', 'scope_0');
|
||||
|
||||
verify.currentFileContentIs(`class C {
|
||||
static j = C.newFunction_1();
|
||||
constructor(q: string = C.newFunction()) {
|
||||
}
|
||||
|
||||
private static newFunction(): string {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
private static newFunction_1() {
|
||||
return 100;
|
||||
}
|
||||
}`);
|
24
tests/cases/fourslash/extract-method14.ts
Normal file
24
tests/cases/fourslash/extract-method14.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Don't emit type annotations in JavaScript files
|
||||
// Also tests that single-variable return extractions don't get superfluous destructuring
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: foo.js
|
||||
//// function foo() {
|
||||
//// var i = 10;
|
||||
//// /*a*/return i++;/*b*/
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b');
|
||||
edit.applyRefactor('Extract Method', 'scope_1');
|
||||
verify.currentFileContentIs(`function foo() {
|
||||
var i = 10;
|
||||
var __return: any;
|
||||
({ __return, i } = newFunction(i));
|
||||
return __return;
|
||||
}
|
||||
function newFunction(i) {
|
||||
return { __return: i++, i };
|
||||
}
|
||||
`);
|
22
tests/cases/fourslash/extract-method15.ts
Normal file
22
tests/cases/fourslash/extract-method15.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Extracting an increment expression (not statement) should do the right thing,
|
||||
// including not generating extra destructuring unless needed
|
||||
|
||||
//// function foo() {
|
||||
//// var i = 10;
|
||||
//// /*a*/i++/*b*/;
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b');
|
||||
edit.applyRefactor('Extract Method', 'scope_1');
|
||||
|
||||
verify.currentFileContentIs(`function foo() {
|
||||
var i = 10;
|
||||
i = newFunction(i);
|
||||
}
|
||||
function newFunction(i: number) {
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
`);
|
10
tests/cases/fourslash/extract-method17.ts
Normal file
10
tests/cases/fourslash/extract-method17.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// function foo () {
|
||||
//// var x = 3;
|
||||
//// var y = /*start*/x++ + 5/*end*/;
|
||||
//// }
|
||||
|
||||
goTo.select('start', 'end')
|
||||
verify.refactorAvailable('Extract Method', 'scope_0');
|
||||
verify.not.refactorAvailable('Extract Method', 'scope_1');
|
21
tests/cases/fourslash/extract-method18.ts
Normal file
21
tests/cases/fourslash/extract-method18.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Don't try to propagate property accessed variables back,
|
||||
// or emit spurious returns when the value is clearly ignored
|
||||
|
||||
//// function fn() {
|
||||
//// const x = { m: 1 };
|
||||
//// /*a*/x.m = 3/*b*/;
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b')
|
||||
verify.refactorAvailable('Extract Method');
|
||||
edit.applyRefactor('Extract Method', "scope_1");
|
||||
verify.currentFileContentIs(`function fn() {
|
||||
const x = { m: 1 };
|
||||
newFunction(x);
|
||||
}
|
||||
function newFunction(x: { m: number; }) {
|
||||
x.m = 3;
|
||||
}
|
||||
`);
|
22
tests/cases/fourslash/extract-method19.ts
Normal file
22
tests/cases/fourslash/extract-method19.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// New function names should be totally new to the file
|
||||
|
||||
//// function fn() {
|
||||
//// /*a*/console.log("hi");/*b*/
|
||||
//// }
|
||||
////
|
||||
//// function newFunction() { }
|
||||
|
||||
goTo.select('a', 'b')
|
||||
verify.refactorAvailable('Extract Method');
|
||||
edit.applyRefactor('Extract Method', "scope_0");
|
||||
verify.currentFileContentIs(`function fn() {
|
||||
newFunction_1();
|
||||
|
||||
function newFunction_1() {
|
||||
console.log("hi");
|
||||
}
|
||||
}
|
||||
|
||||
function newFunction() { }`);
|
28
tests/cases/fourslash/extract-method2.ts
Normal file
28
tests/cases/fourslash/extract-method2.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// namespace NS {
|
||||
//// class Q {
|
||||
//// foo() {
|
||||
//// console.log('100');
|
||||
//// const m = 10, j = "hello", k = {x: "what"};
|
||||
//// const q = /*start*/m + j + k/*end*/;
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
goTo.select('start', 'end')
|
||||
verify.refactorAvailable('Extract Method');
|
||||
edit.applyRefactor('Extract Method', "scope_2");
|
||||
verify.currentFileContentIs(
|
||||
`namespace NS {
|
||||
class Q {
|
||||
foo() {
|
||||
console.log('100');
|
||||
const m = 10, j = "hello", k = {x: "what"};
|
||||
const q = newFunction(m, j, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
function newFunction(m: number, j: string, k: { x: string; }) {
|
||||
return m + j + k;
|
||||
}
|
||||
`);
|
14
tests/cases/fourslash/extract-method20.ts
Normal file
14
tests/cases/fourslash/extract-method20.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Shouldn't be able to extract a readonly property initializer outside the constructor
|
||||
|
||||
//// class Foo {
|
||||
//// readonly prop;
|
||||
//// constructor() {
|
||||
//// /*a*/this.prop = 10;/*b*/
|
||||
//// }
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b')
|
||||
verify.refactorAvailable('Extract Method', 'scope_0');
|
||||
verify.not.refactorAvailable('Extract Method', 'scope_1');
|
25
tests/cases/fourslash/extract-method21.ts
Normal file
25
tests/cases/fourslash/extract-method21.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Extracting from a static method should create a static method
|
||||
|
||||
//// class Foo {
|
||||
//// static method() {
|
||||
//// /*start*/return 1;/*end*/
|
||||
//// }
|
||||
//// }
|
||||
|
||||
goTo.select('start', 'end')
|
||||
|
||||
verify.refactorAvailable('Extract Method');
|
||||
|
||||
edit.applyRefactor('Extract Method', "scope_0");
|
||||
|
||||
verify.currentFileContentIs(`class Foo {
|
||||
static method() {
|
||||
return Foo.newFunction();
|
||||
}
|
||||
|
||||
private static newFunction() {
|
||||
return 1;
|
||||
}
|
||||
}`);
|
10
tests/cases/fourslash/extract-method22.ts
Normal file
10
tests/cases/fourslash/extract-method22.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// You may not extract variable declarations with the export modifier
|
||||
|
||||
//// namespace NS {
|
||||
//// /*start*/export var x = 10;/*end*/
|
||||
//// }
|
||||
|
||||
goTo.select('start', 'end')
|
||||
verify.not.refactorAvailable('Extract Method');
|
8
tests/cases/fourslash/extract-method23.ts
Normal file
8
tests/cases/fourslash/extract-method23.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// declare namespace Foo {
|
||||
//// const x = /*start*/3/*end*/;
|
||||
//// }
|
||||
|
||||
goTo.select('start', 'end')
|
||||
verify.not.refactorAvailable('Extract Method');
|
19
tests/cases/fourslash/extract-method24.ts
Normal file
19
tests/cases/fourslash/extract-method24.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// function M() {
|
||||
//// let a = [1,2,3];
|
||||
//// let x = 0;
|
||||
//// console.log(/*a*/a[x]/*b*/);
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b')
|
||||
edit.applyRefactor('Extract Method', 'scope_1');
|
||||
verify.currentFileContentIs(`function M() {
|
||||
let a = [1,2,3];
|
||||
let x = 0;
|
||||
console.log(newFunction(a, x));
|
||||
}
|
||||
function newFunction(a: number[], x: number): any {
|
||||
return a[x];
|
||||
}
|
||||
`);
|
18
tests/cases/fourslash/extract-method3.ts
Normal file
18
tests/cases/fourslash/extract-method3.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// namespace NS {
|
||||
//// class Q {
|
||||
//// foo() {
|
||||
//// console.log('100');
|
||||
//// const m = 10, j = "hello", k = {x: "what"};
|
||||
//// const q = /*a*/m/*b*/;
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
// Don't offer to to 'extract method' a single identifier
|
||||
|
||||
goTo.marker('a');
|
||||
verify.not.refactorAvailable('Extract Method');
|
||||
goTo.select('a', 'b');
|
||||
verify.not.refactorAvailable('Extract Method');
|
14
tests/cases/fourslash/extract-method4.ts
Normal file
14
tests/cases/fourslash/extract-method4.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// let a = 1, b = 2, c = 3, d = 4;
|
||||
//// namespace NS {
|
||||
//// class Q {
|
||||
//// foo() {
|
||||
//// a = /*1*/b = c/*2*/ = d;
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
// Should rewrite to a = newFunc(); function() { return b = c = d; }
|
||||
goTo.select('1', '2');
|
||||
verify.not.refactorAvailable('Extract Method');
|
20
tests/cases/fourslash/extract-method5.ts
Normal file
20
tests/cases/fourslash/extract-method5.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Extraction in the context of a contextual
|
||||
// type needs to produce an explicit return type
|
||||
// annotation in the extracted function
|
||||
|
||||
//// function f() {
|
||||
//// var x: 1 | 2 | 3 = /*start*/2/*end*/;
|
||||
//// }
|
||||
|
||||
goTo.select('start', 'end');
|
||||
edit.applyRefactor('Extract Method', 'scope_0');
|
||||
verify.currentFileContentIs(
|
||||
`function f() {
|
||||
var x: 1 | 2 | 3 = newFunction();
|
||||
|
||||
function newFunction(): 1 | 2 | 3 {
|
||||
return 2;
|
||||
}
|
||||
}`);
|
16
tests/cases/fourslash/extract-method6.ts
Normal file
16
tests/cases/fourslash/extract-method6.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Cannot extract globally-declared functions or
|
||||
// those with non-selected local references
|
||||
|
||||
//// /*f1a*/function f() {
|
||||
//// /*g1a*/function g() { }
|
||||
//// g();/*g1b*/
|
||||
//// g();
|
||||
//// }/*f1b*/
|
||||
|
||||
goTo.select('f1a', 'f1b');
|
||||
verify.not.refactorAvailable('Extract Method');
|
||||
goTo.select('g1a', 'g1b');
|
||||
verify.not.refactorAvailable('Extract Method');
|
||||
|
16
tests/cases/fourslash/extract-method7.ts
Normal file
16
tests/cases/fourslash/extract-method7.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// You cannot extract a function initializer into the function's body.
|
||||
// The innermost scope (scope_0) is the sibling of the function, not the function itself.
|
||||
|
||||
//// function fn(x = /*a*/3/*b*/) {
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b');
|
||||
edit.applyRefactor('Extract Method', 'scope_0');
|
||||
verify.currentFileContentIs(`function fn(x = newFunction()) {
|
||||
}
|
||||
function newFunction() {
|
||||
return 3;
|
||||
}
|
||||
`);
|
17
tests/cases/fourslash/extract-method8.ts
Normal file
17
tests/cases/fourslash/extract-method8.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// You cannot extract an exported function declaration
|
||||
|
||||
//// namespace ns {
|
||||
//// /*a*/export function fn() {
|
||||
////
|
||||
//// }
|
||||
//// fn();
|
||||
//// /*b*/
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b');
|
||||
verify.not.refactorAvailable("Extract Method");
|
||||
edit.deleteAtCaret('export'.length);
|
||||
goTo.select('a', 'b');
|
||||
verify.refactorAvailable("Extract Method");
|
11
tests/cases/fourslash/extract-method9.ts
Normal file
11
tests/cases/fourslash/extract-method9.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// function f() {
|
||||
//// /*a*/function q() { }
|
||||
//// q();/*b*/
|
||||
//// q();
|
||||
//// }
|
||||
|
||||
goTo.select('a', 'b');
|
||||
verify.not.refactorAvailable("Extract Method");
|
||||
|
|
@ -130,6 +130,7 @@ declare namespace FourSlashInterface {
|
|||
position(position: number, fileName?: string): any;
|
||||
file(index: number, content?: string, scriptKindName?: string): any;
|
||||
file(name: string, content?: string, scriptKindName?: string): any;
|
||||
select(startMarker: string, endMarker: string): void;
|
||||
}
|
||||
class verifyNegatable {
|
||||
private negative;
|
||||
|
@ -156,6 +157,8 @@ declare namespace FourSlashInterface {
|
|||
applicableRefactorAvailableAtMarker(markerName: string): void;
|
||||
codeFixDiagnosticsAvailableAtMarkers(markerNames: string[], diagnosticCode?: number): void;
|
||||
applicableRefactorAvailableForRange(): void;
|
||||
|
||||
refactorAvailable(name?: string, subName?: string);
|
||||
}
|
||||
class verify extends verifyNegatable {
|
||||
assertHasRanges(ranges: Range[]): void;
|
||||
|
@ -305,6 +308,8 @@ declare namespace FourSlashInterface {
|
|||
moveLeft(count?: number): void;
|
||||
enableFormatting(): void;
|
||||
disableFormatting(): void;
|
||||
|
||||
applyRefactor(refactorName: string, actionName: string): void;
|
||||
}
|
||||
class debug {
|
||||
printCurrentParameterHelp(): void;
|
||||
|
|
Loading…
Reference in a new issue