Skip to content

Commit aad663c

Browse files
author
Andy
authored
Merge pull request microsoft#11894 from Microsoft/for_loops
Simplify for loops in fourslash.ts
2 parents 231b5ac + eb45962 commit aad663c

File tree

2 files changed

+55
-93
lines changed

2 files changed

+55
-93
lines changed

src/compiler/core.ts

+7
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ namespace ts {
124124
return undefined;
125125
}
126126

127+
export function zipWith<T, U>(arrayA: T[], arrayB: U[], callback: (a: T, b: U, index: number) => void): void {
128+
Debug.assert(arrayA.length === arrayB.length);
129+
for (let i = 0; i < arrayA.length; i++) {
130+
callback(arrayA[i], arrayB[i], i);
131+
}
132+
}
133+
127134
/**
128135
* Iterates through `array` by index and performs the callback on each element of array until the callback
129136
* returns a falsey value, then returns false.

src/harness/fourslash.ts

+48-93
Original file line numberDiff line numberDiff line change
@@ -438,9 +438,8 @@ namespace FourSlash {
438438
private getAllDiagnostics(): ts.Diagnostic[] {
439439
const diagnostics: ts.Diagnostic[] = [];
440440

441-
const fileNames = this.languageServiceAdapterHost.getFilenames();
442-
for (let i = 0, n = fileNames.length; i < n; i++) {
443-
diagnostics.push.apply(this.getDiagnostics(fileNames[i]));
441+
for (const fileName of this.languageServiceAdapterHost.getFilenames()) {
442+
diagnostics.push.apply(this.getDiagnostics(fileName));
444443
}
445444

446445
return diagnostics;
@@ -580,12 +579,12 @@ namespace FourSlash {
580579
this.raiseError(`goToDefinitions failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}`);
581580
}
582581

583-
for (let i = 0; i < endMarkers.length; i++) {
584-
const marker = this.getMarkerByName(endMarkers[i]), definition = definitions[i];
582+
ts.zipWith(endMarkers, definitions, (endMarker, definition, i) => {
583+
const marker = this.getMarkerByName(endMarker);
585584
if (marker.fileName !== definition.fileName || marker.position !== definition.textSpan.start) {
586585
this.raiseError(`goToDefinition failed for definition ${i}: expected ${marker.fileName} at ${marker.position}, got ${definition.fileName} at ${definition.textSpan.start}`);
587586
}
588-
}
587+
});
589588
}
590589

591590
public verifyGetEmitOutputForCurrentFile(expected: string): void {
@@ -602,10 +601,10 @@ namespace FourSlash {
602601
public verifyGetEmitOutputContentsForCurrentFile(expected: ts.OutputFile[]): void {
603602
const emit = this.languageService.getEmitOutput(this.activeFile.fileName);
604603
assert.equal(emit.outputFiles.length, expected.length, "Number of emit output files");
605-
for (let i = 0; i < emit.outputFiles.length; i++) {
606-
assert.equal(emit.outputFiles[i].name, expected[i].name, "FileName");
607-
assert.equal(emit.outputFiles[i].text, expected[i].text, "Content");
608-
}
604+
ts.zipWith(emit.outputFiles, expected, (outputFile, expected) => {
605+
assert.equal(outputFile.name, expected.name, "FileName");
606+
assert.equal(outputFile.text, expected.text, "Content");
607+
});
609608
}
610609

611610
public verifyMemberListContains(symbol: string, text?: string, documentation?: string, kind?: string) {
@@ -668,9 +667,9 @@ namespace FourSlash {
668667

669668
const entries = this.getCompletionListAtCaret().entries;
670669
assert.isTrue(items.length <= entries.length, `Amount of expected items in completion list [ ${items.length} ] is greater than actual number of items in list [ ${entries.length} ]`);
671-
for (let i = 0; i < items.length; i++) {
672-
assert.equal(entries[i].name, items[i], `Unexpected item in completion list`);
673-
}
670+
ts.zipWith(entries, items, (entry, item) => {
671+
assert.equal(entry.name, item, `Unexpected item in completion list`);
672+
});
674673
}
675674

676675
public noItemsWithSameNameButDifferentKind(): void {
@@ -692,15 +691,7 @@ namespace FourSlash {
692691
this.raiseError("Member list is empty at Caret");
693692
}
694693
else if ((members && members.entries.length !== 0) && !negative) {
695-
696-
let errorMsg = "\n" + "Member List contains: [" + members.entries[0].name;
697-
for (let i = 1; i < members.entries.length; i++) {
698-
errorMsg += ", " + members.entries[i].name;
699-
}
700-
errorMsg += "]\n";
701-
702-
this.raiseError("Member list is not empty at Caret: " + errorMsg);
703-
694+
this.raiseError(`Member list is not empty at Caret:\nMember List contains: ${stringify(members.entries.map(e => e.name))}`);
704695
}
705696
}
706697

@@ -710,13 +701,8 @@ namespace FourSlash {
710701
this.raiseError("Completion list is empty at caret at position " + this.activeFile.fileName + " " + this.currentCaretPosition);
711702
}
712703
else if (completions && completions.entries.length !== 0 && !negative) {
713-
let errorMsg = "\n" + "Completion List contains: [" + completions.entries[0].name;
714-
for (let i = 1; i < completions.entries.length; i++) {
715-
errorMsg += ", " + completions.entries[i].name;
716-
}
717-
errorMsg += "]\n";
718-
719-
this.raiseError("Completion list is not empty at caret at position " + this.activeFile.fileName + " " + this.currentCaretPosition + errorMsg);
704+
this.raiseError(`Completion list is not empty at caret at position ${this.activeFile.fileName} ${this.currentCaretPosition}\n` +
705+
`Completion List contains: ${stringify(completions.entries.map(e => e.name))}`);
720706
}
721707
}
722708

@@ -890,8 +876,7 @@ namespace FourSlash {
890876
}
891877

892878
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
893-
for (let i = 0; i < references.length; i++) {
894-
const reference = references[i];
879+
for (const reference of references) {
895880
if (reference && reference.fileName === fileName && reference.textSpan.start === start && ts.textSpanEnd(reference.textSpan) === end) {
896881
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
897882
this.raiseError(`verifyReferencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${reference.isWriteAccess}, expected: ${isWriteAccess}.`);
@@ -1008,16 +993,11 @@ namespace FourSlash {
1008993
ranges = ranges.sort((r1, r2) => r1.start - r2.start);
1009994
references = references.sort((r1, r2) => r1.textSpan.start - r2.textSpan.start);
1010995

1011-
for (let i = 0, n = ranges.length; i < n; i++) {
1012-
const reference = references[i];
1013-
const range = ranges[i];
1014-
1015-
if (reference.textSpan.start !== range.start ||
1016-
ts.textSpanEnd(reference.textSpan) !== range.end) {
1017-
996+
ts.zipWith(references, ranges, (reference, range) => {
997+
if (reference.textSpan.start !== range.start || ts.textSpanEnd(reference.textSpan) !== range.end) {
1018998
this.raiseError("Rename location results do not match.\n\nExpected: " + stringify(ranges) + "\n\nActual:" + JSON.stringify(references));
1019999
}
1020-
}
1000+
});
10211001
}
10221002
else {
10231003
this.raiseError("Expected rename to succeed, but it actually failed.");
@@ -1247,8 +1227,7 @@ namespace FourSlash {
12471227
const emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on
12481228

12491229
const allFourSlashFiles = this.testData.files;
1250-
for (let idx = 0; idx < allFourSlashFiles.length; idx++) {
1251-
const file = allFourSlashFiles[idx];
1230+
for (const file of allFourSlashFiles) {
12521231
if (file.fileOptions[metadataOptionNames.emitThisFile] === "true") {
12531232
// Find a file with the flag emitThisFile turned on
12541233
emitFiles.push(file);
@@ -1273,8 +1252,8 @@ namespace FourSlash {
12731252
if (emitOutput.emitSkipped) {
12741253
resultString += "Diagnostics:" + Harness.IO.newLine();
12751254
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram());
1276-
for (let i = 0, n = diagnostics.length; i < n; i++) {
1277-
resultString += " " + diagnostics[0].messageText + Harness.IO.newLine();
1255+
for (const diagnostic of diagnostics) {
1256+
resultString += " " + diagnostic.messageText + Harness.IO.newLine();
12781257
}
12791258
}
12801259

@@ -1340,8 +1319,7 @@ namespace FourSlash {
13401319
}
13411320

13421321
public printCurrentFileState(makeWhitespaceVisible = false, makeCaretVisible = true) {
1343-
for (let i = 0; i < this.testData.files.length; i++) {
1344-
const file = this.testData.files[i];
1322+
for (const file of this.testData.files) {
13451323
const active = (this.activeFile === file);
13461324
Harness.IO.log(`=== Script (${file.fileName}) ${(active ? "(active, cursor at |)" : "")} ===`);
13471325
let content = this.getFileContent(file.fileName);
@@ -1576,10 +1554,10 @@ namespace FourSlash {
15761554
edits = edits.sort((a, b) => a.span.start - b.span.start);
15771555
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
15781556
const oldContent = this.getFileContent(this.activeFile.fileName);
1579-
for (let j = 0; j < edits.length; j++) {
1580-
this.languageServiceAdapterHost.editScript(fileName, edits[j].span.start + runningOffset, ts.textSpanEnd(edits[j].span) + runningOffset, edits[j].newText);
1581-
this.updateMarkersForEdit(fileName, edits[j].span.start + runningOffset, ts.textSpanEnd(edits[j].span) + runningOffset, edits[j].newText);
1582-
const change = (edits[j].span.start - ts.textSpanEnd(edits[j].span)) + edits[j].newText.length;
1557+
for (const edit of edits) {
1558+
this.languageServiceAdapterHost.editScript(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
1559+
this.updateMarkersForEdit(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
1560+
const change = (edit.span.start - ts.textSpanEnd(edit.span)) + edit.newText.length;
15831561
runningOffset += change;
15841562
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
15851563
// this.languageService.getScriptLexicalStructure(fileName);
@@ -1913,10 +1891,7 @@ namespace FourSlash {
19131891
jsonMismatchString());
19141892
}
19151893

1916-
for (let i = 0; i < expected.length; i++) {
1917-
const expectedClassification = expected[i];
1918-
const actualClassification = actual[i];
1919-
1894+
ts.zipWith(expected, actual, (expectedClassification, actualClassification) => {
19201895
const expectedType: string = (<any>ts.ClassificationTypeNames)[expectedClassification.classificationType];
19211896
if (expectedType !== actualClassification.classificationType) {
19221897
this.raiseError("verifyClassifications failed - expected classifications type to be " +
@@ -1946,7 +1921,7 @@ namespace FourSlash {
19461921
actualText +
19471922
jsonMismatchString());
19481923
}
1949-
}
1924+
});
19501925

19511926
function jsonMismatchString() {
19521927
return Harness.IO.newLine() +
@@ -1991,13 +1966,11 @@ namespace FourSlash {
19911966
this.raiseError(`verifyOutliningSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}`);
19921967
}
19931968

1994-
for (let i = 0; i < spans.length; i++) {
1995-
const expectedSpan = spans[i];
1996-
const actualSpan = actual[i];
1969+
ts.zipWith(spans, actual, (expectedSpan, actualSpan, i) => {
19971970
if (expectedSpan.start !== actualSpan.textSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan)) {
19981971
this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.start},${expectedSpan.end}), actual: (${actualSpan.textSpan.start},${ts.textSpanEnd(actualSpan.textSpan)})`);
19991972
}
2000-
}
1973+
});
20011974
}
20021975

20031976
public verifyTodoComments(descriptors: string[], spans: TextSpan[]) {
@@ -2008,15 +1981,13 @@ namespace FourSlash {
20081981
this.raiseError(`verifyTodoComments failed - expected total spans to be ${spans.length}, but was ${actual.length}`);
20091982
}
20101983

2011-
for (let i = 0; i < spans.length; i++) {
2012-
const expectedSpan = spans[i];
2013-
const actualComment = actual[i];
1984+
ts.zipWith(spans, actual, (expectedSpan, actualComment, i) => {
20141985
const actualCommentSpan = ts.createTextSpan(actualComment.position, actualComment.message.length);
20151986

20161987
if (expectedSpan.start !== actualCommentSpan.start || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan)) {
20171988
this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.start},${expectedSpan.end}), actual: (${actualCommentSpan.start},${ts.textSpanEnd(actualCommentSpan)})`);
20181989
}
2019-
}
1990+
});
20201991
}
20211992

20221993
private getCodeFixes(errorCode?: number) {
@@ -2163,11 +2134,9 @@ namespace FourSlash {
21632134
public verifyNavigationItemsCount(expected: number, searchValue: string, matchKind?: string, fileName?: string) {
21642135
const items = this.languageService.getNavigateToItems(searchValue, /*maxResultCount*/ undefined, fileName);
21652136
let actual = 0;
2166-
let item: ts.NavigateToItem;
21672137

21682138
// Count only the match that match the same MatchKind
2169-
for (let i = 0; i < items.length; i++) {
2170-
item = items[i];
2139+
for (const item of items) {
21712140
if (!matchKind || item.matchKind === matchKind) {
21722141
actual++;
21732142
}
@@ -2195,8 +2164,7 @@ namespace FourSlash {
21952164
this.raiseError("verifyNavigationItemsListContains failed - found 0 navigation items, expected at least one.");
21962165
}
21972166

2198-
for (let i = 0; i < items.length; i++) {
2199-
const item = items[i];
2167+
for (const item of items) {
22002168
if (item && item.name === name && item.kind === kind &&
22012169
(matchKind === undefined || item.matchKind === matchKind) &&
22022170
(fileName === undefined || item.fileName === fileName) &&
@@ -2247,24 +2215,16 @@ namespace FourSlash {
22472215

22482216
public printNavigationItems(searchValue: string) {
22492217
const items = this.languageService.getNavigateToItems(searchValue);
2250-
const length = items && items.length;
2251-
2252-
Harness.IO.log(`NavigationItems list (${length} items)`);
2253-
2254-
for (let i = 0; i < length; i++) {
2255-
const item = items[i];
2218+
Harness.IO.log(`NavigationItems list (${items.length} items)`);
2219+
for (const item of items) {
22562220
Harness.IO.log(`name: ${item.name}, kind: ${item.kind}, parentName: ${item.containerName}, fileName: ${item.fileName}`);
22572221
}
22582222
}
22592223

22602224
public printNavigationBar() {
22612225
const items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
2262-
const length = items && items.length;
2263-
2264-
Harness.IO.log(`Navigation bar (${length} items)`);
2265-
2266-
for (let i = 0; i < length; i++) {
2267-
const item = items[i];
2226+
Harness.IO.log(`Navigation bar (${items.length} items)`);
2227+
for (const item of items) {
22682228
Harness.IO.log(`${repeatString(item.indent, " ")}name: ${item.text}, kind: ${item.kind}, childItems: ${item.childItems.map(child => child.text)}`);
22692229
}
22702230
}
@@ -2385,8 +2345,7 @@ namespace FourSlash {
23852345
}
23862346

23872347
private assertItemInCompletionList(items: ts.CompletionEntry[], name: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
2388-
for (let i = 0; i < items.length; i++) {
2389-
const item = items[i];
2348+
for (const item of items) {
23902349
if (item.name === name) {
23912350
if (documentation != undefined || text !== undefined) {
23922351
const details = this.getCompletionEntryDetails(item.name);
@@ -2435,20 +2394,17 @@ namespace FourSlash {
24352394
name = name.indexOf("/") === -1 ? (this.basePath + "/" + name) : name;
24362395

24372396
const availableNames: string[] = [];
2438-
let foundIt = false;
2439-
for (let i = 0; i < this.testData.files.length; i++) {
2440-
const fn = this.testData.files[i].fileName;
2397+
result = ts.forEach(this.testData.files, file => {
2398+
const fn = file.fileName;
24412399
if (fn) {
24422400
if (fn === name) {
2443-
result = this.testData.files[i];
2444-
foundIt = true;
2445-
break;
2401+
return file;
24462402
}
24472403
availableNames.push(fn);
24482404
}
2449-
}
2405+
});
24502406

2451-
if (!foundIt) {
2407+
if (!result) {
24522408
throw new Error(`No test file named "${name}" exists. Available file names are: ${availableNames.join(", ")}`);
24532409
}
24542410
}
@@ -2549,8 +2505,8 @@ ${code}
25492505

25502506
function chompLeadingSpace(content: string) {
25512507
const lines = content.split("\n");
2552-
for (let i = 0; i < lines.length; i++) {
2553-
if ((lines[i].length !== 0) && (lines[i].charAt(0) !== " ")) {
2508+
for (const line of lines) {
2509+
if ((line.length !== 0) && (line.charAt(0) !== " ")) {
25542510
return content;
25552511
}
25562512
}
@@ -2588,8 +2544,7 @@ ${code}
25882544
currentFileName = fileName;
25892545
}
25902546

2591-
for (let i = 0; i < lines.length; i++) {
2592-
let line = lines[i];
2547+
for (let line of lines) {
25932548
const lineLength = line.length;
25942549

25952550
if (lineLength > 0 && line.charAt(lineLength - 1) === "\r") {

0 commit comments

Comments
 (0)