Skip to content

Commit c830841

Browse files
authored
fix: correct the selection range of the last import that doesn't have a semicolon (#2651)
1 parent 4ba7760 commit c830841

File tree

3 files changed

+98
-11
lines changed

3 files changed

+98
-11
lines changed

packages/language-server/src/plugins/typescript/features/SelectionRangeProvider.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import ts from 'typescript';
22
import { Position, Range, SelectionRange } from 'vscode-languageserver';
3-
import { Document, mapSelectionRangeToParent } from '../../../lib/documents';
3+
import { Document, mapRangeToOriginal } from '../../../lib/documents';
44
import { SelectionRangeProvider } from '../../interfaces';
55
import { SvelteDocumentSnapshot } from '../DocumentSnapshot';
66
import { LSAndTSDocResolver } from '../LSAndTSDocResolver';
@@ -20,7 +20,7 @@ export class SelectionRangeProviderImpl implements SelectionRangeProvider {
2020
tsDoc.offsetAt(tsDoc.getGeneratedPosition(position))
2121
);
2222
const selectionRange = this.toSelectionRange(tsDoc, tsSelectionRange);
23-
const mappedRange = mapSelectionRangeToParent(tsDoc, selectionRange);
23+
const mappedRange = this.mapSelectionRangeToParent(tsDoc, document, selectionRange);
2424

2525
return this.filterOutUnmappedRange(mappedRange);
2626
}
@@ -35,6 +35,35 @@ export class SelectionRangeProviderImpl implements SelectionRangeProvider {
3535
};
3636
}
3737

38+
private mapSelectionRangeToParent(
39+
tsDoc: SvelteDocumentSnapshot,
40+
document: Document,
41+
selectionRange: SelectionRange
42+
): SelectionRange {
43+
const { range, parent } = selectionRange;
44+
const originalRange = mapRangeToOriginal(tsDoc, range);
45+
46+
const originalLength = originalRange.end.character - originalRange.start.character;
47+
const generatedLength = range.end.character - range.start.character;
48+
49+
// sourcemap off by one character issue + a generated semicolon
50+
if (
51+
originalLength === generatedLength - 2 &&
52+
tsDoc.getFullText()[tsDoc.offsetAt(range.end) - 1] === ';'
53+
) {
54+
originalRange.end.character += 1;
55+
}
56+
57+
if (!parent) {
58+
return SelectionRange.create(originalRange);
59+
}
60+
61+
return SelectionRange.create(
62+
originalRange,
63+
this.mapSelectionRangeToParent(tsDoc, document, parent)
64+
);
65+
}
66+
3867
private filterOutUnmappedRange(selectionRange: SelectionRange): SelectionRange | null {
3968
const flattened = this.flattenAndReverseSelectionRange(selectionRange);
4069
const filtered = flattened.filter((range) => range.start.line > 0 && range.end.line > 0);

packages/language-server/test/plugins/typescript/features/SelectionRangeProvider.test.ts

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,11 @@ const selectionRangeTestDir = path.join(testDir, 'testfiles', 'selection-range')
1515
describe('SelectionRangeProvider', function () {
1616
serviceWarmup(this, selectionRangeTestDir, pathToUrl(testDir));
1717

18-
function setup() {
18+
function setup(fileName: string) {
1919
const docManager = new DocumentManager(
2020
(textDocument) => new Document(textDocument.uri, textDocument.text)
2121
);
22-
const filePath = path.join(
23-
testDir,
24-
'testfiles',
25-
'selection-range',
26-
'selection-range.svelte'
27-
);
22+
const filePath = path.join(testDir, 'testfiles', 'selection-range', fileName);
2823
const lsAndTsDocResolver = new LSAndTSDocResolver(
2924
docManager,
3025
[pathToUrl(testDir)],
@@ -39,7 +34,7 @@ describe('SelectionRangeProvider', function () {
3934
}
4035

4136
it('provides selection range', async () => {
42-
const { provider, document } = setup();
37+
const { provider, document } = setup('selection-range.svelte');
4338

4439
const selectionRange = await provider.getSelectionRange(document, Position.create(1, 9));
4540

@@ -72,8 +67,67 @@ describe('SelectionRangeProvider', function () {
7267
});
7368
});
7469

70+
it('provides selection range for import without semicolon', async () => {
71+
const { provider, document } = setup('selection-range-import.svelte');
72+
73+
const selectionRange = await provider.getSelectionRange(document, Position.create(2, 28));
74+
75+
assert.deepStrictEqual(selectionRange, <SelectionRange>{
76+
parent: {
77+
parent: {
78+
parent: {
79+
parent: undefined,
80+
range: {
81+
end: {
82+
character: 34,
83+
line: 2
84+
},
85+
start: {
86+
character: 4,
87+
line: 1
88+
}
89+
}
90+
},
91+
// import {onMount} from 'svelte';
92+
range: {
93+
end: {
94+
character: 34,
95+
line: 2
96+
},
97+
start: {
98+
character: 4,
99+
line: 2
100+
}
101+
}
102+
},
103+
// 'svelte';
104+
range: {
105+
end: {
106+
character: 34,
107+
line: 2
108+
},
109+
start: {
110+
character: 26,
111+
line: 2
112+
}
113+
}
114+
},
115+
// svelte
116+
range: {
117+
end: {
118+
character: 33,
119+
line: 2
120+
},
121+
start: {
122+
character: 27,
123+
line: 2
124+
}
125+
}
126+
});
127+
});
128+
75129
it('return null when in style', async () => {
76-
const { provider, document } = setup();
130+
const { provider, document } = setup('selection-range.svelte');
77131

78132
const selectionRange = await provider.getSelectionRange(document, Position.create(5, 0));
79133

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<script>
2+
import {} from 'svelte'
3+
import {onMount} from 'svelte'
4+
</script>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy