Skip to content

Commit 769e209

Browse files
authored
refactor(client): Show warning message if a project uses a newer version than extension (#1942)
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 769e209

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)