Skip to content

Commit 791721e

Browse files
authored
(fix) ignore certain diagnostics for pug (#960)
Ignore all diagnostics inside the template and all unused import-diagnostics in the script #958
1 parent ef1d791 commit 791721e

File tree

5 files changed

+125
-12
lines changed

5 files changed

+125
-12
lines changed

packages/language-server/src/lib/documents/Document.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { urlToPath } from '../../utils';
22
import { WritableDocument } from './DocumentBase';
3-
import { extractScriptTags, extractStyleTag, TagInformation } from './utils';
3+
import { extractScriptTags, extractStyleTag, extractTemplateTag, TagInformation } from './utils';
44
import { parseHtml } from './parseHtml';
55
import { SvelteConfig, configLoader } from './configLoader';
66
import { HTMLDocument } from 'vscode-html-languageservice';
@@ -13,6 +13,7 @@ export class Document extends WritableDocument {
1313
scriptInfo: TagInformation | null = null;
1414
moduleScriptInfo: TagInformation | null = null;
1515
styleInfo: TagInformation | null = null;
16+
templateInfo: TagInformation | null = null;
1617
configPromise: Promise<SvelteConfig | undefined>;
1718
config?: SvelteConfig;
1819
html!: HTMLDocument;
@@ -25,8 +26,8 @@ export class Document extends WritableDocument {
2526

2627
private updateDocInfo() {
2728
this.html = parseHtml(this.content);
28-
const scriptTags = extractScriptTags(this.content, this.html);
2929
const update = (config: SvelteConfig | undefined) => {
30+
const scriptTags = extractScriptTags(this.content, this.html);
3031
this.config = config;
3132
this.scriptInfo = this.addDefaultLanguage(config, scriptTags?.script || null, 'script');
3233
this.moduleScriptInfo = this.addDefaultLanguage(
@@ -39,6 +40,11 @@ export class Document extends WritableDocument {
3940
extractStyleTag(this.content, this.html),
4041
'style'
4142
);
43+
this.templateInfo = this.addDefaultLanguage(
44+
config,
45+
extractTemplateTag(this.content, this.html),
46+
'markup'
47+
);
4248
};
4349

4450
const config = configLoader.getConfig(this.getFilePath() || '');
@@ -82,22 +88,24 @@ export class Document extends WritableDocument {
8288
}
8389

8490
/**
85-
* Returns the language associated to either script or style.
91+
* Returns the language associated to script, style or template.
8692
* Returns an empty string if there's nothing set.
8793
*/
88-
getLanguageAttribute(tag: 'script' | 'style'): string {
94+
getLanguageAttribute(tag: 'script' | 'style' | 'template'): string {
8995
const attrs =
9096
(tag === 'style'
9197
? this.styleInfo?.attributes
92-
: this.scriptInfo?.attributes || this.moduleScriptInfo?.attributes) || {};
98+
: tag === 'script'
99+
? this.scriptInfo?.attributes || this.moduleScriptInfo?.attributes
100+
: this.templateInfo?.attributes) || {};
93101
const lang = attrs.lang || attrs.type || '';
94102
return lang.replace(/^text\//, '');
95103
}
96104

97105
private addDefaultLanguage(
98106
config: SvelteConfig | undefined,
99107
tagInfo: TagInformation | null,
100-
tag: 'style' | 'script'
108+
tag: 'style' | 'script' | 'markup'
101109
): TagInformation | null {
102110
if (!tagInfo || !config) {
103111
return tagInfo;

packages/language-server/src/lib/documents/utils.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ function blankIfBlocks(text: string): string {
7272
* @param source text content to extract tag from
7373
* @param tag the tag to extract
7474
*/
75-
function extractTags(text: string, tag: 'script' | 'style', html?: HTMLDocument): TagInformation[] {
75+
function extractTags(
76+
text: string,
77+
tag: 'script' | 'style' | 'template',
78+
html?: HTMLDocument
79+
): TagInformation[] {
7680
text = blankIfBlocks(text);
7781
const rootNodes = html?.roots || parseHtml(text).roots;
7882
const matchedNodes = rootNodes
@@ -173,6 +177,16 @@ export function extractStyleTag(source: string, html?: HTMLDocument): TagInforma
173177
return styles[0];
174178
}
175179

180+
export function extractTemplateTag(source: string, html?: HTMLDocument): TagInformation | null {
181+
const templates = extractTags(source, 'template', html);
182+
if (!templates.length) {
183+
return null;
184+
}
185+
186+
// There should only be one style tag
187+
return templates[0];
188+
}
189+
176190
/**
177191
* Get the line and character based on the offset
178192
* @param offset The index of the position

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

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import ts from 'typescript';
22
import { Diagnostic, DiagnosticSeverity, DiagnosticTag } from 'vscode-languageserver';
3-
import { Document, mapObjWithRangeToOriginal, getTextInRange } from '../../../lib/documents';
3+
import {
4+
Document,
5+
mapObjWithRangeToOriginal,
6+
getTextInRange,
7+
isRangeInTag
8+
} from '../../../lib/documents';
49
import { DiagnosticsProvider } from '../../interfaces';
510
import { LSAndTSDocResolver } from '../LSAndTSDocResolver';
611
import { convertRange, mapSeverity } from '../utils';
@@ -52,7 +57,7 @@ export class DiagnosticsProviderImpl implements DiagnosticsProvider {
5257
}))
5358
.map((diagnostic) => mapObjWithRangeToOriginal(fragment, diagnostic))
5459
.filter(hasNoNegativeLines)
55-
.filter(isNoFalsePositive(document.getText(), tsDoc))
60+
.filter(isNoFalsePositive(document, tsDoc))
5661
.map(enhanceIfNecessary)
5762
.map(swapRangeStartEndIfNecessary);
5863
}
@@ -82,16 +87,32 @@ function hasNoNegativeLines(diagnostic: Diagnostic): boolean {
8287
return diagnostic.range.start.line >= 0 && diagnostic.range.end.line >= 0;
8388
}
8489

85-
function isNoFalsePositive(text: string, tsDoc: SvelteDocumentSnapshot) {
86-
return (diagnostic: Diagnostic, idx: number) => {
90+
function isNoFalsePositive(document: Document, tsDoc: SvelteDocumentSnapshot) {
91+
const text = document.getText();
92+
const usesPug = document.getLanguageAttribute('template') === 'pug';
93+
94+
return (diagnostic: Diagnostic) => {
8795
return (
8896
isNoJsxCannotHaveMultipleAttrsError(diagnostic) &&
8997
isNoUnusedLabelWarningForReactiveStatement(diagnostic) &&
90-
isNoUsedBeforeAssigned(diagnostic, text, tsDoc)
98+
isNoUsedBeforeAssigned(diagnostic, text, tsDoc) &&
99+
(!usesPug || isNoPugFalsePositive(diagnostic, document))
91100
);
92101
};
93102
}
94103

104+
/**
105+
* All diagnostics inside the template tag and the unused import/variable diagnostics
106+
* are marked as false positive.
107+
*/
108+
function isNoPugFalsePositive(diagnostic: Diagnostic, document: Document): boolean {
109+
return (
110+
!isRangeInTag(diagnostic.range, document.templateInfo) &&
111+
diagnostic.code !== 6133 &&
112+
diagnostic.code !== 6192
113+
);
114+
}
115+
95116
/**
96117
* Variable used before being assigned, can happen when you do `export let x`
97118
* without assigning a value in strict mode. Should not throw an error here

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

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,4 +871,63 @@ describe('DiagnosticsProvider', () => {
871871
}
872872
]);
873873
});
874+
875+
it('Pug: Ignores errors in template and unused warnings in script', async () => {
876+
const { plugin, document } = setup('diagnostics-pug.svelte');
877+
const diagnostics = await plugin.getDiagnostics(document);
878+
879+
assert.deepStrictEqual(diagnostics, [
880+
{
881+
code: 2307,
882+
message: "Cannot find module '.' or its corresponding type declarations.",
883+
range: {
884+
end: {
885+
character: 22,
886+
line: 1
887+
},
888+
start: {
889+
character: 19,
890+
line: 1
891+
}
892+
},
893+
severity: 1,
894+
source: 'ts',
895+
tags: []
896+
},
897+
{
898+
code: 2307,
899+
message: "Cannot find module '.' or its corresponding type declarations.",
900+
range: {
901+
end: {
902+
character: 30,
903+
line: 2
904+
},
905+
start: {
906+
character: 27,
907+
line: 2
908+
}
909+
},
910+
severity: 1,
911+
source: 'ts',
912+
tags: []
913+
},
914+
{
915+
code: 2322,
916+
message: "Type 'boolean' is not assignable to type 'string | number'.",
917+
range: {
918+
end: {
919+
character: 10,
920+
line: 4
921+
},
922+
start: {
923+
character: 9,
924+
line: 4
925+
}
926+
},
927+
severity: 1,
928+
source: 'ts',
929+
tags: []
930+
}
931+
]);
932+
});
874933
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script lang="ts">
2+
import Foo from '.';
3+
import { A, B, C } from '.';
4+
5+
const a: string | number = true;
6+
</script>
7+
8+
<template lang="pug">
9+
+if('typeof a === "number"')
10+
A(a='{a.toFixed(2)}')
11+
</template>

0 commit comments

Comments
 (0)