From ab0c9a36ba5dea972138a4051ec8f406cef7b180 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Thu, 9 Jun 2022 12:56:56 -0700 Subject: [PATCH] feat(extension): Update untrusted workspace support from 'false' to 'limited' The workspace trust guide for extension authors can be found here: https://github.com/microsoft/vscode/issues/120251 Importantly the sectino for evaluating whether the extension should work in an untrusted workspace asks "Does my extension treat any contents of the workspace as code?". The answer to this is "yes" for the extension because we execute `ngcc` from the `node_modules` folder. However, this isn't always necessary and becomes less so with time. As library authors publish their libraries with Ivy instructions, we will not need to run `ngcc`. This commit updates the workspace trust to indicate that it's 'limited' support due to `ngcc`. In addition the command to run `ngcc` is disabled on the server and removed from the command palette. --- client/src/client.ts | 8 ++++++-- package.json | 8 ++++++-- server/src/cmdline_utils.ts | 2 ++ server/src/server.ts | 3 ++- server/src/session.ts | 7 +++++++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/client/src/client.ts b/client/src/client.ts index f1406de3c3..2cbb7489aa 100644 --- a/client/src/client.ts +++ b/client/src/client.ts @@ -395,7 +395,7 @@ function getProbeLocations(bundled: string): string[] { * Construct the arguments that's used to spawn the server process. * @param ctx vscode extension context */ -function constructArgs(ctx: vscode.ExtensionContext, viewEngine: boolean): string[] { +function constructArgs(ctx: vscode.ExtensionContext, viewEngine: boolean, isTrustedWorkspace: boolean): string[] { const config = vscode.workspace.getConfiguration(); const args: string[] = ['--logToConsole']; @@ -440,6 +440,10 @@ function constructArgs(ctx: vscode.ExtensionContext, viewEngine: boolean): strin args.push('--forceStrictTemplates'); } + if (!isTrustedWorkspace) { + args.push('--untrustedWorkspace'); + } + const tsdk: string|null = config.get('typescript.tsdk', null); const tsProbeLocations = [tsdk, ...getProbeLocations(ctx.extensionPath)]; args.push('--tsProbeLocations', tsProbeLocations.join(',')); @@ -475,7 +479,7 @@ function getServerOptions(ctx: vscode.ExtensionContext, debug: boolean): lsp.Nod } // Node module for the language server - const args = constructArgs(ctx, viewEngine); + const args = constructArgs(ctx, viewEngine, vscode.workspace.isTrusted); const prodBundle = ctx.asAbsolutePath('server'); const devBundle = ctx.asAbsolutePath(path.join('dist', 'server', 'server.js')); // VS Code Insider launches extensions in debug mode by default but users diff --git a/package.json b/package.json index 127a3f6c81..7d2395e7dd 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ }, "capabilities": { "untrustedWorkspaces": { - "supported": false, - "description": "This extension requires workspace trust because it needs to execute ngcc from the node_modules in the workspace." + "supported": "limited", + "description": "This extension requires workspace trust because it needs to execute ngcc from the node_modules in the workspace. Projects do not require ngcc if all library dependencies are published with partial-Ivy or Full-Ivy." } }, "categories": [ @@ -64,6 +64,10 @@ { "command": "angular.goToTemplateForComponent", "when": "editorLangId == typescript" + }, + { + "command": "angular.runNgcc", + "when": "isWorkspaceTrusted" } ], "editor/context": [ diff --git a/server/src/cmdline_utils.ts b/server/src/cmdline_utils.ts index ae09133889..0d34e0346d 100644 --- a/server/src/cmdline_utils.ts +++ b/server/src/cmdline_utils.ts @@ -44,6 +44,7 @@ interface CommandLineOptions { includeAutomaticOptionalChainCompletions: boolean; includeCompletionsWithSnippetText: boolean; forceStrictTemplates: boolean; + untrustedWorkspace: boolean; } export function parseCommandLine(argv: string[]): CommandLineOptions { @@ -60,6 +61,7 @@ export function parseCommandLine(argv: string[]): CommandLineOptions { hasArgument(argv, '--includeAutomaticOptionalChainCompletions'), includeCompletionsWithSnippetText: hasArgument(argv, '--includeCompletionsWithSnippetText'), forceStrictTemplates: hasArgument(argv, '--forceStrictTemplates'), + untrustedWorkspace: hasArgument(argV, '--untrustedWorkspace'), }; } diff --git a/server/src/server.ts b/server/src/server.ts index e6250c6e8f..4a2227e3d5 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -43,11 +43,12 @@ function main() { ngPlugin: '@angular/language-service', resolvedNgLsPath: ng.resolvedPath, ivy: isG3 ? true : options.ivy, - disableAutomaticNgcc: options.disableAutomaticNgcc, + disableAutomaticNgcc: options.disableAutomaticNgcc || options.untrustedWorkspace, logToConsole: options.logToConsole, includeAutomaticOptionalChainCompletions: options.includeAutomaticOptionalChainCompletions, includeCompletionsWithSnippetText: options.includeCompletionsWithSnippetText, forceStrictTemplates: isG3 || options.forceStrictTemplates, + untrustedWorkspace: options.untrustedWorkspace, }); // Log initialization info diff --git a/server/src/session.ts b/server/src/session.ts index 664a434940..56c37edf60 100644 --- a/server/src/session.ts +++ b/server/src/session.ts @@ -32,6 +32,7 @@ export interface SessionOptions { includeAutomaticOptionalChainCompletions: boolean; includeCompletionsWithSnippetText: boolean; forceStrictTemplates: boolean; + untrustedWorkspace: boolean; } enum LanguageId { @@ -61,6 +62,7 @@ export class Session { private readonly openFiles = new MruTracker(); private readonly includeAutomaticOptionalChainCompletions: boolean; private readonly includeCompletionsWithSnippetText: boolean; + private readonly untrustedWorkspace: boolean; private snippetSupport: boolean|undefined; // Tracks the spawn order and status of the `ngcc` processes. This allows us to ensure we enable // the LS in the same order the projects were created in. @@ -84,6 +86,7 @@ export class Session { this.ivy = options.ivy; this.disableAutomaticNgcc = options.disableAutomaticNgcc; this.logToConsole = options.logToConsole; + this.untrustedWorkspace = options.untrustedWorkspace; // Create a connection for the server. The connection uses Node's IPC as a transport. this.connection = lsp.createConnection({ // cancelUndispatched is a "middleware" to handle all cancellation requests. @@ -1133,6 +1136,10 @@ export class Session { * Disable the language service, run ngcc, then re-enable language service. */ private async runNgcc(project: ts.server.Project): Promise { + if (this.untrustedWorkspace) { + this.error('Cannot run ngcc in an untrusted workspace.'); + return; + } if (!isConfiguredProject(project) || this.projectNgccQueue.some(p => p.project === project)) { return; }