Skip to content

Commit 63498df

Browse files
committed
refactor(client): Show warning message if a project uses a newer version than extension
When the installed extension version is less than the major version of the project, there is likely to be errors. Because new features are added in major/minor releases, a the bundled compiler version in an old extension version may completely fail to even parse a template if there are new syntax features. This problem is very apparent with the new control flow syntax. If a project uses v17 and uses the new control flow, a v16 language service will show all kinds of parse errors. fixes #1941
1 parent f7505e5 commit 63498df

File tree

2 files changed

+32
-10
lines changed

2 files changed

+32
-10
lines changed

client/src/client.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as lsp from 'vscode-languageclient/node';
1313

1414
import {OpenOutputChannel, ProjectLoadingFinish, ProjectLoadingStart, SuggestStrictMode, SuggestStrictModeParams} from '../../common/notifications';
1515
import {GetComponentsWithTemplateFile, GetTcbRequest, GetTemplateLocationForComponent, IsInAngularProject} from '../../common/requests';
16+
import {resolve} from '../../common/resolver';
1617

1718
import {isInsideComponentDecorator, isInsideInlineTemplateRegion, isInsideStringLiteral} from './embedded_support';
1819

@@ -404,7 +405,7 @@ function getProbeLocations(bundled: string): string[] {
404405
* Construct the arguments that's used to spawn the server process.
405406
* @param ctx vscode extension context
406407
*/
407-
function constructArgs(ctx: vscode.ExtensionContext, isTrustedWorkspace: boolean): string[] {
408+
function constructArgs(ctx: vscode.ExtensionContext): string[] {
408409
const config = vscode.workspace.getConfiguration();
409410
const args: string[] = ['--logToConsole'];
410411

@@ -451,19 +452,20 @@ function getServerOptions(ctx: vscode.ExtensionContext, debug: boolean): lsp.Nod
451452
NG_DEBUG: true,
452453
};
453454

454-
// Because the configuration is typed as "boolean" in package.json, vscode
455-
// will return false even when the value is not set. If value is false, then
456-
// we need to check if all projects support Ivy language service.
457-
const config = vscode.workspace.getConfiguration();
458-
459455
// Node module for the language server
460-
const args = constructArgs(ctx, vscode.workspace.isTrusted);
456+
const args = constructArgs(ctx);
461457
const prodBundle = ctx.asAbsolutePath('server');
462458
const devBundle = ctx.asAbsolutePath(path.join('bazel-bin', 'server', 'src', 'server.js'));
463459
// VS Code Insider launches extensions in debug mode by default but users
464460
// install prod bundle so we have to check whether dev bundle exists.
465461
const latestServerModule = debug && fs.existsSync(devBundle) ? devBundle : prodBundle;
466462

463+
if (!extensionVersionCompatibleWithAllProjects(latestServerModule)) {
464+
vscode.window.showWarningMessage(
465+
`A project in the workspace is using a newer version of Angular than the language service extension. ` +
466+
`This may cause the extension to show incorrect diagnostics.`)
467+
}
468+
467469
// Argv options for Node.js
468470
const prodExecArgv: string[] = [];
469471
const devExecArgv: string[] = [
@@ -483,3 +485,23 @@ function getServerOptions(ctx: vscode.ExtensionContext, debug: boolean): lsp.Nod
483485
},
484486
};
485487
}
488+
489+
function extensionVersionCompatibleWithAllProjects(serverModuleLocation: string): boolean {
490+
const languageServiceVersion =
491+
resolve('@angular/language-service', serverModuleLocation)?.version;
492+
if (languageServiceVersion === undefined) {
493+
return true;
494+
}
495+
496+
const workspaceFolders = vscode.workspace.workspaceFolders || [];
497+
for (const workspaceFolder of workspaceFolders) {
498+
const angularCore = resolve('@angular/core', workspaceFolder.uri.fsPath);
499+
if (angularCore === undefined) {
500+
continue;
501+
}
502+
if (!languageServiceVersion.greaterThanOrEqual(angularCore.version, 'minor')) {
503+
return false;
504+
}
505+
}
506+
return true;
507+
}

common/resolver.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,17 @@ export class Version {
5151
this.patch = patch;
5252
}
5353

54-
greaterThanOrEqual(other: Version): boolean {
54+
greaterThanOrEqual(other: Version, compare: 'patch'|'minor'|'major' = 'patch'): boolean {
5555
if (this.major < other.major) {
5656
return false;
5757
}
58-
if (this.major > other.major) {
58+
if (this.major > other.major || (this.major === other.major && compare === 'major')) {
5959
return true;
6060
}
6161
if (this.minor < other.minor) {
6262
return false;
6363
}
64-
if (this.minor > other.minor) {
64+
if (this.minor > other.minor || (this.minor === other.minor && compare === 'minor')) {
6565
return true;
6666
}
6767
return this.patch >= other.patch;

0 commit comments

Comments
 (0)