-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Extract Method #17625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extract Method #17625
Changes from all commits
c7f665f
12403d9
1ad411e
f957429
a04633c
db37cea
24de14a
c27ee81
8a92315
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2631,9 +2631,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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment on the implementation. |
||
/* @internal */ getJsxNamespace(): string; | ||
/* @internal */ resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined; | ||
} | ||
|
||
export enum NodeBuilderFlags { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -967,9 +978,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 { | ||
|
@@ -1180,7 +1191,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")); | ||
|
@@ -1776,19 +1787,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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This seems like a particularly expensive way to accomplish the copy. #WontFix There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
// 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; | ||
|
@@ -1803,8 +1811,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; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we avoid this work by sorting the edits in descending order of start position? (That would also make it easy to restore the no-overlap assertion.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that this is test code, I don't particularly care about the extra work, but having the assert seems worthwhile. In reply to: 132300325 [](ancestors = 132300325) |
||
} | ||
|
||
if (isFormattingEdit) { | ||
|
@@ -1888,7 +1901,7 @@ namespace FourSlash { | |
this.goToPosition(len); | ||
} | ||
|
||
public goToRangeStart({fileName, start}: Range) { | ||
public goToRangeStart({ fileName, start }: Range) { | ||
this.openFile(fileName); | ||
this.goToPosition(start); | ||
} | ||
|
@@ -2062,7 +2075,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); | ||
} | ||
|
||
|
@@ -2348,7 +2361,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; | ||
} | ||
|
@@ -2723,6 +2736,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: ${refactors.map(r => r.name).join(", ")}`); | ||
} | ||
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)) { | ||
|
@@ -2739,6 +2776,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, | ||
|
@@ -3483,6 +3534,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 { | ||
|
@@ -3604,6 +3659,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 { | ||
|
@@ -3999,6 +4058,10 @@ namespace FourSlashInterface { | |
public disableFormatting() { | ||
this.state.enableFormatting = false; | ||
} | ||
|
||
public applyRefactor(refactorName: string, actionName: string) { | ||
this.state.applyRefactor(refactorName, actionName); | ||
} | ||
} | ||
|
||
export class Debug { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allows debugging single tests from VS Code by pressing F5 in the testcase's editor window
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds great. How does it do that?