diff --git a/packages/language-server/src/plugins/svelte/SvelteDocument.ts b/packages/language-server/src/plugins/svelte/SvelteDocument.ts index 00cc12784..5cfc12bce 100644 --- a/packages/language-server/src/plugins/svelte/SvelteDocument.ts +++ b/packages/language-server/src/plugins/svelte/SvelteDocument.ts @@ -175,11 +175,16 @@ export class SvelteFragmentMapper { } static async createScript(originalDoc: Document, transpiled: string, processed: Processed[]) { + const scriptInfo = originalDoc.scriptInfo || originalDoc.moduleScriptInfo; + const maybeScriptTag = extractScriptTags(transpiled); + const maybeScriptTagInfo = + maybeScriptTag && (maybeScriptTag.script || maybeScriptTag.moduleScript); + return SvelteFragmentMapper.create( originalDoc, transpiled, - originalDoc.scriptInfo, - extractScriptTags(transpiled)?.script || null, + scriptInfo, + maybeScriptTagInfo || null, processed, ); } diff --git a/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts b/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts index a35d1a58b..fbbff5c30 100644 --- a/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts +++ b/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts @@ -78,7 +78,10 @@ async function createParserErrorDiagnostic(error: any, document: Document) { if (diagnostic.message.includes('expected')) { const isInStyle = isInTag(diagnostic.range.start, document.styleInfo); - const isInScript = isInTag(diagnostic.range.start, document.scriptInfo); + const isInScript = isInTag( + diagnostic.range.start, + document.scriptInfo || document.moduleScriptInfo, + ); if (isInStyle || isInScript) { diagnostic.message += diff --git a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts index c34cfde8b..b498b0236 100644 --- a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts +++ b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts @@ -151,7 +151,8 @@ function preprocessSvelteFile(document: Document, options: SvelteSnapshotOptions if (tsxMap) { tsxMap.sources = [document.uri]; - const tsCheck = getTsCheckComment(document.scriptInfo?.content); + const scriptInfo = document.scriptInfo || document.moduleScriptInfo; + const tsCheck = getTsCheckComment(scriptInfo?.content); if (tsCheck) { text = tsCheck + text; nrPrependedLines = 1; @@ -172,7 +173,8 @@ function preprocessSvelteFile(document: Document, options: SvelteSnapshotOptions }; // fall back to extracted script, if any - text = document.scriptInfo ? document.scriptInfo.content : ''; + const scriptInfo = document.scriptInfo || document.moduleScriptInfo; + text = scriptInfo ? scriptInfo.content : ''; } return { @@ -330,7 +332,7 @@ export class SvelteSnapshotFragment implements SnapshotFragment { ) {} get scriptInfo() { - return this.parent.scriptInfo; + return this.parent.scriptInfo || this.parent.moduleScriptInfo; } getOriginalPosition(pos: Position): Position { diff --git a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts index c9e76d44e..0b84b4244 100644 --- a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts @@ -55,7 +55,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { } private async organizeImports(document: Document): Promise { - if (!document.scriptInfo) { + if (!document.scriptInfo && !document.moduleScriptInfo) { return []; } diff --git a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts index d855f887b..542898c73 100644 --- a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts @@ -34,7 +34,7 @@ export interface CompletionEntryWithIdentifer extends ts.CompletionEntry, TextDo type validTriggerCharacter = '.' | '"' | "'" | '`' | '/' | '@' | '<' | '#'; export class CompletionsProviderImpl implements CompletionsProvider { - constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) { } + constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {} /** * The language service throws an error if the character is not a valid trigger character. diff --git a/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts b/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts index 1af048a2d..ed87d063c 100644 --- a/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts +++ b/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts @@ -1,4 +1,6 @@ import * as assert from 'assert'; +import * as path from 'path'; +import * as fs from 'fs'; import { Diagnostic, DiagnosticSeverity, Position } from 'vscode-languageserver'; import { Document } from '../../../../src/lib/documents'; import { getDiagnostics } from '../../../../src/plugins/svelte/features/getDiagnostics'; @@ -7,7 +9,9 @@ import { TranspileErrorSource, } from '../../../../src/plugins/svelte/SvelteDocument'; import { SvelteConfig } from '../../../../src/lib/documents/configLoader'; -import { CompilerWarningsSettings } from '../../../../src/ls-config'; +import { CompilerWarningsSettings, LSConfigManager } from '../../../../src/ls-config'; +import { pathToUrl } from '../../../../src/utils'; +import { SveltePlugin } from '../../../../src/plugins'; describe('SveltePlugin#getDiagnostics', () => { async function expectDiagnosticsFor({ @@ -31,6 +35,15 @@ describe('SveltePlugin#getDiagnostics', () => { }; } + function setupFromFile(filename: string) { + const testDir = path.join(__dirname, '..'); + const filePath = path.join(testDir, 'testfiles', filename); + const document = new Document(pathToUrl(filePath), fs.readFileSync(filePath, 'utf-8')); + const pluginManager = new LSConfigManager(); + const plugin = new SveltePlugin(pluginManager); + return { plugin, document }; + } + it('expect svelte.config.js error', async () => { ( await expectDiagnosticsFor({ @@ -369,4 +382,36 @@ describe('SveltePlugin#getDiagnostics', () => { }, ]); }); + + it('should correctly determine diagnostic position', async () => { + const { plugin, document } = setupFromFile('diagnostics.svelte'); + const diagnostics = await plugin.getDiagnostics(document); + + assert.deepStrictEqual(diagnostics, [ + { + range: { start: { line: 1, character: 15 }, end: { line: 1, character: 27 } }, + message: + "Component has unused export property 'name'. If it is for external reference only, please consider using `export const name`", + severity: 2, + source: 'svelte', + code: 'unused-export-let', + }, + ]); + }); + + it('should correctly determine diagnostic position for context="module"', async () => { + const { plugin, document } = setupFromFile('diagnostics-module.svelte'); + const diagnostics = await plugin.getDiagnostics(document); + + assert.deepStrictEqual(diagnostics, [ + { + range: { start: { line: 1, character: 15 }, end: { line: 1, character: 27 } }, + message: + "Component has unused export property 'name'. If it is for external reference only, please consider using `export const name`", + severity: 2, + source: 'svelte', + code: 'unused-export-let', + }, + ]); + }); }); diff --git a/packages/language-server/test/plugins/svelte/testfiles/diagnostics-module.svelte b/packages/language-server/test/plugins/svelte/testfiles/diagnostics-module.svelte new file mode 100644 index 000000000..3a26cafad --- /dev/null +++ b/packages/language-server/test/plugins/svelte/testfiles/diagnostics-module.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/language-server/test/plugins/svelte/testfiles/diagnostics.svelte b/packages/language-server/test/plugins/svelte/testfiles/diagnostics.svelte new file mode 100644 index 000000000..21a1eb089 --- /dev/null +++ b/packages/language-server/test/plugins/svelte/testfiles/diagnostics.svelte @@ -0,0 +1,3 @@ +