Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃 Pick PR #54315 (add baseline for linked editing) into release-5.1 #54419

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 67 additions & 0 deletions src/harness/fourslashImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3576,6 +3576,73 @@ export class TestState {
}
}

public baselineLinkedEditing(): void {
const baselineFile = this.getBaselineFileNameForContainingTestFile(".linkedEditing.txt");
const files = this.testData.files;

let baselineContent = "";
let offset = 0;
for (const f of files) {
const result = getLinkedEditingBaselineWorker(f, offset, this.languageService);
baselineContent += result.baselineContent + `\n\n\n`;
offset = result.offset;
}

Harness.Baseline.runBaseline(baselineFile, baselineContent);

function getLinkedEditingBaselineWorker(activeFile: FourSlashFile, offset: number, languageService: ts.LanguageService) {
const fileName = activeFile.fileName;
let baselineContent = `=== ${fileName} ===\n`;

// get linkedEdit at every position in the file, then group positions by their linkedEdit
const linkedEditsInFile = new Map<string, number[]>();
for(let pos = 0; pos < activeFile.content.length; pos++) {
const linkedEditAtPosition = languageService.getLinkedEditingRangeAtPosition(fileName, pos);
if (!linkedEditAtPosition) continue;

const linkedEditString = JSON.stringify(linkedEditAtPosition);
const existingPositions = linkedEditsInFile.get(linkedEditString) ?? [];
linkedEditsInFile.set(linkedEditString, [...existingPositions, pos]);
}

const linkedEditsByRange = [...linkedEditsInFile.entries()].sort((a, b) => a[1][0] - b[1][0]);
if (linkedEditsByRange.length === 0) {
return { baselineContent: baselineContent + activeFile.content + `\n\n--No linked edits found--`, offset };
}

let inlineLinkedEditBaselines: { start: number, end: number, index: number }[] = [];
let linkedEditInfoBaseline = "";
for (const edit of linkedEditsByRange) {
const [linkedEdit, positions] = edit;
let rangeStart = 0;
for (let j = 0; j < positions.length - 1; j++) {
// for each distinct range in the list of positions, add an entry to the list of places that need to be annotated in the baseline
if (positions[j] + 1 !== positions[j + 1]) {
inlineLinkedEditBaselines.push({ start: positions[rangeStart], end: positions[j], index: offset });
rangeStart = j + 1;
}
}
inlineLinkedEditBaselines.push({ start: positions[rangeStart], end: positions[positions.length - 1], index: offset });

// add the LinkedEditInfo with its index to the baseline
linkedEditInfoBaseline += `\n\n=== ${offset} ===\n` + linkedEdit;
offset++;
}

inlineLinkedEditBaselines = inlineLinkedEditBaselines.sort((a, b) => a.start - b.start);
const fileText = activeFile.content;
baselineContent += fileText.slice(0, inlineLinkedEditBaselines[0].start);
for (let i = 0; i < inlineLinkedEditBaselines.length; i++) {
const e = inlineLinkedEditBaselines[i];
const sliceEnd = inlineLinkedEditBaselines[i + 1]?.start;
baselineContent += `[|/*${e.index}*/` + fileText.slice(e.start, e.end) + `|]` + fileText.slice(e.end, sliceEnd);
}

baselineContent += linkedEditInfoBaseline;
return { baselineContent, offset };
}
}

public verifyMatchingBracePosition(bracePosition: number, expectedMatchPosition: number) {
const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition);

Expand Down
4 changes: 4 additions & 0 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ export class VerifyNegatable {
this.state.verifyLinkedEditingRange(map);
}

public baselineLinkedEditing(): void {
this.state.baselineLinkedEditing();
}

public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
}
Expand Down
97 changes: 97 additions & 0 deletions tests/baselines/reference/linkedEditingJsxTag10.linkedEditing.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
=== /jsx0.tsx ===
const jsx = <>

--No linked edits found--


=== /jsx1.tsx ===
const jsx = </>

--No linked edits found--


=== /jsx2.tsx ===
const jsx = <div>

--No linked edits found--


=== /jsx3.tsx ===
const jsx = </div>

--No linked edits found--


=== /jsx4.tsx ===
const jsx = <div> </>;

--No linked edits found--


=== /jsx5.tsx ===
const jsx = <> </div>;

--No linked edits found--


=== /jsx6.tsx ===
const jsx = div> </div>;

--No linked edits found--


=== /jsx7.tsx ===
const jsx = <div> /div>;

--No linked edits found--


=== /jsx8.tsx ===
const jsx = <div </div>;

--No linked edits found--


=== /jsx9.tsx ===
const jsx = <[|/*0*/div|]> </[|/*0*/div|];

=== 0 ===
{"ranges":[{"start":13,"length":3},{"start":20,"length":3}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}


=== /jsx10.tsx ===
const jsx = <> </;

--No linked edits found--


=== /jsx11.tsx ===
const jsx = < </>;

--No linked edits found--


=== /jsx12.tsx ===
const jsx = > </>;

--No linked edits found--


=== /jsx13.tsx ===
const jsx = <> />;

--No linked edits found--


=== /jsx14.tsx ===
const jsx = <> <div> </> </div>;

--No linked edits found--


=== /jsx15.tsx ===
const jsx = <div> <> </div> </>;

--No linked edits found--


27 changes: 27 additions & 0 deletions tests/baselines/reference/linkedEditingJsxTag11.linkedEditing.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
=== /customElements.tsx ===
const jsx = <[|/*0*/fbt:enum|] knownProp="accepted"
unknownProp="rejected">
</[|/*0*/fbt:enum|]>;

const customElement = <[|/*1*/custom-element|]></[|/*1*/custom-element|]>;

const standardElement =
<[|/*2*/Link|] href="/hello" passHref>
<[|/*3*/Button|] component="a">
Next
</[|/*3*/Button|]>
</[|/*2*/Link|]>;

=== 0 ===
{"ranges":[{"start":13,"length":8},{"start":73,"length":8}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}

=== 1 ===
{"ranges":[{"start":108,"length":14},{"start":125,"length":14}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}

=== 2 ===
{"ranges":[{"start":172,"length":4},{"start":269,"length":4}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}

=== 3 ===
{"ranges":[{"start":209,"length":6},{"start":256,"length":6}],"wordPattern":"[a-zA-Z0-9:\\-\\._$]*"}


1 change: 1 addition & 0 deletions tests/cases/fourslash/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ declare namespace FourSlashInterface {
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
linkedEditing(map: { [markerName: string]: LinkedEditingInfo | undefined }): void;
baselineLinkedEditing(): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
codeFix(options: {
description: string | [string, ...(string | number)[]] | DiagnosticIgnoredInterpolations,
Expand Down
42 changes: 2 additions & 40 deletions tests/cases/fourslash/linkedEditingJsxTag10.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,43 +48,5 @@
// @Filename: /jsx15.tsx
////const jsx = </*15*/div> </*15a*/> <//*15b*/div> <//*15c*/>;

const wordPattern = "[a-zA-Z0-9:\\-\\._$]*";
const linkedCursors9 = {
ranges: [{ start: test.markerByName("9").position, length: 3 }, { start: test.markerByName("9a").position, length: 3 }],
wordPattern,
};

verify.linkedEditing( {
"0": undefined,
"1": undefined,
"2": undefined,
"3": undefined,
"4": undefined,
"4a": undefined,
"5": undefined,
"5a": undefined,
"6": undefined,
"6a": undefined,
"7": undefined,
"7a": undefined,
"8": undefined,
"8a": undefined,
"9": linkedCursors9,
"9a": linkedCursors9,
"10": undefined,
"10a": undefined,
"11": undefined,
"11a": undefined,
"12": undefined,
"12a": undefined,
"13": undefined,
"13a": undefined,
"14": undefined,
"14a": undefined,
"14b": undefined,
"14c": undefined,
"15": undefined,
"15a": undefined,
"15b": undefined,
"15c": undefined,
});
verify.baselineLinkedEditing();

58 changes: 8 additions & 50 deletions tests/cases/fourslash/linkedEditingJsxTag11.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,19 @@
/// <reference path='fourslash.ts' />

// for readability
////const jsx = (
//// <div style={{ color: 'red' }}>
//// <p>
//// <img />
//// </p>
//// </div>
////);

// @Filename: /customElements.tsx
//// const jsx = </*1*/fbt/*2*/:en/*3*/um knownProp="accepted"
//// const jsx = <fbt:enum knownProp="accepted"
//// unknownProp="rejected">
//// </f/*4*/bt:e/*5*/num>;
//// </fbt:enum>;
////
//// const customElement = </*6*/custom/*7*/-element/*8*/></custom/*9*/-element>;
//// const customElement = <custom-element></custom-element>;
////
//// const standardElement =
//// </*10*/Link/*11*/ href="/hello" passHref>
//// </*12*/But/*13*/ton component="a">
//// <Link href="/hello" passHref>
//// <Button component="a">
//// Next
//// </But/*14*/ton>
//// </Li/*15*/nk>;
//// </Button>
//// </Link>;

const wordPattern = "[a-zA-Z0-9:\\-\\._$]*";

const linkedCursors1 = {
ranges: [{ start: test.markerByName("1").position, length: 8 }, { start: test.markerByName("4").position - 1, length: 8 }],
wordPattern,
};
const linkedCursors2 = {
ranges: [{ start: test.markerByName("6").position, length: 14 }, { start: test.markerByName("9").position - 6, length: 14 }],
wordPattern,
};
const linkedCursors3 = {
ranges: [{ start: test.markerByName("10").position, length: 4 }, { start: test.markerByName("15").position - 2, length: 4 }],
wordPattern,
};
const linkedCursors4 = {
ranges: [{ start: test.markerByName("12").position, length: 6 }, { start: test.markerByName("14").position - 3, length: 6 }],
wordPattern,
};

verify.linkedEditing( {
"1": linkedCursors1,
"2": linkedCursors1,
"3": linkedCursors1,
"4": linkedCursors1,
"5": linkedCursors1,
"6": linkedCursors2,
"7": linkedCursors2,
"8": linkedCursors2,
"9": linkedCursors2,
"10": linkedCursors3,
"11": linkedCursors3,
"12": linkedCursors4,
"13": linkedCursors4,
"14": linkedCursors4,
"15": linkedCursors3,
});
verify.baselineLinkedEditing();