Skip to content

fix: try to infer languageId from extension when invalid provided #799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion src/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { extname } from 'node:path';
import { URI } from 'vscode-uri';
import * as lsp from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument';
import * as languageModeIds from './configuration/languageIds.js';
import { LspClient } from './lsp-client.js';
import { CommandTypes, type ts } from './ts-protocol.js';
import { ClientCapability, type ITypeScriptServiceClient } from './typescriptService.js';
import API from './utils/api.js';
Expand All @@ -26,6 +28,24 @@ function mode2ScriptKind(mode: string): ts.server.protocol.ScriptKindName | unde
return undefined;
}

/**
* @deprecated Remove in next major.
*/
function getModeFromFileUri(uri: string): string | undefined {
const extension = extname(uri).toUpperCase();
switch (extension) {
case '.TS':
return languageModeIds.typescript;
case '.TSX':
return languageModeIds.typescriptreact;
case '.JS':
return languageModeIds.javascript;
case '.JSX':
return languageModeIds.javascriptreact;
}
return undefined;
}

class PendingDiagnostics extends ResourceMap<number> {
public getOrderedFileSet(): ResourceMap<void> {
const orderedResources = Array.from(this.entries())
Expand Down Expand Up @@ -203,6 +223,7 @@ export class LspDocument {

export class LspDocuments {
private readonly client: ITypeScriptServiceClient;
private readonly lspClient: LspClient;

private _validateJavaScript = true;
private _validateTypeScript = true;
Expand All @@ -216,9 +237,11 @@ export class LspDocuments {

constructor(
client: ITypeScriptServiceClient,
lspClient: LspClient,
onCaseInsensitiveFileSystem: boolean,
) {
this.client = client;
this.lspClient = lspClient;
this.modeIds = new Set<string>(languageModeIds.jsTsLanguageModes);

const pathNormalizer = (path: URI) => this.client.toTsFilePath(path.toString());
Expand Down Expand Up @@ -251,7 +274,16 @@ export class LspDocuments {

public openTextDocument(textDocument: lsp.TextDocumentItem): boolean {
if (!this.modeIds.has(textDocument.languageId)) {
return false;
const detectedLanguageId = getModeFromFileUri(textDocument.uri);
if (detectedLanguageId) {
this.lspClient.logMessage({
type: lsp.MessageType.Warning,
message: `Invalid langaugeId "${textDocument.languageId}" provided for uri "${textDocument.uri}". Correcting to "${detectedLanguageId}"`,
});
textDocument.languageId = detectedLanguageId;
} else {
return false;
}
}
const resource = textDocument.uri;
const filepath = this.client.toTsFilePath(resource);
Expand Down
21 changes: 21 additions & 0 deletions src/lsp-server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2423,3 +2423,24 @@ describe('linked editing', () => {
]);
});
});

describe('handles invalid languageId', () => {
it('simple test', async () => {
const textDocument = {
uri: uri('foo.tsx'),
languageId: 'tsx',
version: 1,
text: 'let bar = <div></div>',
};
await openDocumentAndWaitForDiagnostics(server, textDocument);
const position = positionAfter(textDocument, '<div');
const linedEditRanges = await server.linkedEditingRange({
textDocument,
position,
});
expect(linedEditRanges?.ranges).toStrictEqual([
{ start: { line: 0, character: 11 }, end: { line: 0, character: 14 } },
{ start: { line: 0, character: 17 }, end: { line: 0, character: 20 } },
]);
});
});
2 changes: 1 addition & 1 deletion src/lsp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export class LspServer {
}

if (!this.tsClient.openTextDocument(params.textDocument)) {
throw new Error(`Cannot open document '${params.textDocument.uri}'.`);
throw new Error(`Cannot open document '${params.textDocument.uri}' (languageId: ${params.textDocument.languageId}).`);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/ts-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export class TsClient implements ITypeScriptServiceClient {
logger: Logger,
lspClient: LspClient,
) {
this.documents = new LspDocuments(this, onCaseInsensitiveFileSystem);
this.documents = new LspDocuments(this, lspClient, onCaseInsensitiveFileSystem);
this.logger = new PrefixingLogger(logger, '[tsclient]');
this.tsserverLogger = new PrefixingLogger(this.logger, '[tsserver]');
this.lspClient = lspClient;
Expand Down