Skip to content

Commit 82451d3

Browse files
authored
(fix) more robust mapping for Svelte diagnostics (#1035)
Try to catch some cases of invalid ranges which may cause the LSP to get confused and not update diagnostics anymore #1019
1 parent ce4ba4e commit 82451d3

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

packages/language-server/src/plugins/svelte/features/getDiagnostics.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { Warning } from 'svelte/types/compiler/interfaces';
22
import { Diagnostic, DiagnosticSeverity, Position, Range } from 'vscode-languageserver';
3-
import { Document, isInTag, mapObjWithRangeToOriginal } from '../../../lib/documents';
3+
import {
4+
Document,
5+
isInTag,
6+
mapObjWithRangeToOriginal,
7+
TagInformation
8+
} from '../../../lib/documents';
49
import { Logger } from '../../../logger';
510
import { CompilerWarningsSettings } from '../../../ls-config';
6-
import { getLastPartOfPath } from '../../../utils';
11+
import { getLastPartOfPath, moveRangeStartToEndIfNecessary } from '../../../utils';
712
import { SvelteDocument, TranspileErrorSource } from '../SvelteDocument';
813

914
/**
@@ -56,6 +61,7 @@ async function tryGetDiagnostics(
5661
};
5762
})
5863
.map((diag) => mapObjWithRangeToOriginal(transpiled, diag))
64+
.map((diag) => adjustMappings(diag, document))
5965
.filter((diag) => isNoFalsePositive(diag, document));
6066
} catch (err) {
6167
return (await createParserErrorDiagnostic(err, document)).map((diag) =>
@@ -273,5 +279,35 @@ function isNoFalsePositive(diag: Diagnostic, doc: Document): boolean {
273279
return !hasExportedEnumWithThatName;
274280
}
275281

282+
/**
283+
* Some mappings might be invalid. Try to catch these cases here.
284+
*/
285+
function adjustMappings(diag: Diagnostic, doc: Document): Diagnostic {
286+
if (diag.range.start.character < 0) {
287+
diag.range.start.character = 0;
288+
}
289+
if (diag.range.end.character < 0) {
290+
diag.range.end.character = 0;
291+
}
292+
if (diag.range.start.line < 0) {
293+
diag.range.start = { line: 0, character: 0 };
294+
}
295+
if (diag.range.end.line < 0) {
296+
diag.range.end = { line: 0, character: 0 };
297+
}
298+
diag.range = moveRangeStartToEndIfNecessary(diag.range);
299+
300+
if (
301+
diag.code === 'css-unused-selector' &&
302+
doc.styleInfo &&
303+
!isInTag(diag.range.start, doc.styleInfo)
304+
) {
305+
diag.range.start = (doc.styleInfo as TagInformation).startPos;
306+
diag.range.end = diag.range.start;
307+
}
308+
309+
return diag;
310+
}
311+
276312
const scssNodeRuntimeHint =
277313
'If you use SCSS, it may be necessary to add the path to your NODE runtime to the setting `svelte.language-server.runtime`, or use `sass` instead of `node-sass`. ';

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { LSAndTSDocResolver } from '../LSAndTSDocResolver';
1111
import { convertRange, getDiagnosticTag, mapSeverity } from '../utils';
1212
import { SvelteDocumentSnapshot } from '../DocumentSnapshot';
1313
import { isInGeneratedCode } from './utils';
14+
import { swapRangeStartEndIfNecessary } from '../../../utils';
1415

1516
export class DiagnosticsProviderImpl implements DiagnosticsProvider {
1617
constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {}
@@ -65,7 +66,7 @@ export class DiagnosticsProviderImpl implements DiagnosticsProvider {
6566
.filter(hasNoNegativeLines)
6667
.filter(isNoFalsePositive(document, tsDoc))
6768
.map(enhanceIfNecessary)
68-
.map(swapRangeStartEndIfNecessary);
69+
.map(swapDiagRangeStartEndIfNecessary);
6970
}
7071

7172
private async getLSAndTSDoc(document: Document) {
@@ -190,16 +191,8 @@ function enhanceIfNecessary(diagnostic: Diagnostic): Diagnostic {
190191
/**
191192
* Due to source mapping, some ranges may be swapped: Start is end. Swap back in this case.
192193
*/
193-
function swapRangeStartEndIfNecessary(diag: Diagnostic): Diagnostic {
194-
if (
195-
diag.range.end.line < diag.range.start.line ||
196-
(diag.range.end.line === diag.range.start.line &&
197-
diag.range.end.character < diag.range.start.character)
198-
) {
199-
const start = diag.range.start;
200-
diag.range.start = diag.range.end;
201-
diag.range.end = start;
202-
}
194+
function swapDiagRangeStartEndIfNecessary(diag: Diagnostic): Diagnostic {
195+
diag.range = swapRangeStartEndIfNecessary(diag.range);
203196
return diag;
204197
}
205198

packages/language-server/src/utils.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,29 @@ export function isInRange(range: Range, positionToTest: Position): boolean {
4545
);
4646
}
4747

48+
export function isRangeStartAfterEnd(range: Range): boolean {
49+
return (
50+
range.end.line < range.start.line ||
51+
(range.end.line === range.start.line && range.end.character < range.start.character)
52+
);
53+
}
54+
55+
export function swapRangeStartEndIfNecessary(range: Range): Range {
56+
if (isRangeStartAfterEnd(range)) {
57+
const start = range.start;
58+
range.start = range.end;
59+
range.end = start;
60+
}
61+
return range;
62+
}
63+
64+
export function moveRangeStartToEndIfNecessary(range: Range): Range {
65+
if (isRangeStartAfterEnd(range)) {
66+
range.start = range.end;
67+
}
68+
return range;
69+
}
70+
4871
export function isBeforeOrEqualToPosition(position: Position, positionToTest: Position): boolean {
4972
return (
5073
positionToTest.line < position.line ||

0 commit comments

Comments
 (0)