Skip to content

Commit 1b4893d

Browse files
author
Simon Holthausen
committed
(fix) more robust mapping for Svelte diagnostics
Try to catch some cases of invalid ranges which may cause the LSP to get confused and not update diagnostics anymore sveltejs#1019
1 parent ce4ba4e commit 1b4893d

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)