Skip to content

Commit d627c08

Browse files
committed
feat(language-service): Support importing the external module's export about the angular metadata.
Enable the developer to disable the auto-import for the external module. If disabled, the completion only includes the info from the file scope and the ng-module scope. Fixes #2132
1 parent 41a695a commit d627c08

File tree

9 files changed

+81
-5
lines changed

9 files changed

+81
-5
lines changed

.aspect/rules/external_repository_action_cache/npm_translate_lock_LTE4Nzc1MDcwNjU=

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
.npmrc=974837034
55
pnpm-lock.yaml=1493175183
66
yarn.lock=485928896
7-
package.json=-1370450906
7+
package.json=-100959756
88
pnpm-workspace.yaml=1711114604

client/src/client.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,13 @@ export class AngularLanguageClient implements vscode.Disposable {
316316
args.push('--includeCompletionsWithSnippetText');
317317
}
318318

319+
const includeCompletionsForModuleExports = config.get<boolean>('angular.suggest.autoImports');
320+
args.push(
321+
'--includeCompletionsForModuleExports',
322+
includeCompletionsForModuleExports === undefined ?
323+
'true' :
324+
includeCompletionsForModuleExports.toString());
325+
319326
// Sort the versions from oldest to newest.
320327
const angularVersions = (await getAngularVersionsInWorkspace(this.outputChannel))
321328
.sort((a, b) => a.version.greaterThanOrEqual(b.version) ? 1 : -1);

integration/lsp/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ jasmine_test(
66
data = [
77
"//integration",
88
"//integration/project",
9+
"//integration/project:node_modules/@angular/core",
10+
"//integration/project:node_modules/@angular/common",
911
"//integration/pre_standalone_project",
1012
"//integration/pre_standalone_project:node_modules/@angular/core",
1113
"//integration/pre_standalone_project:node_modules/@angular/common",

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@
143143
"default": true,
144144
"markdownDescription": "Enable snippet completions from Angular language server. Requires using TypeScript 4.3+ in the workspace."
145145
},
146+
"angular.suggest.autoImports": {
147+
"type": "boolean",
148+
"default": true,
149+
"markdownDescription": "Enable/disable auto import suggestions for the exported Angular components from the current project."
150+
},
146151
"angular.forceStrictTemplates": {
147152
"type": "boolean",
148153
"default": false,

server/src/cmdline_utils.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,31 @@ function findArgument(argv: string[], argName: string): string|undefined {
1414
return argv[index + 1];
1515
}
1616

17+
function findArgumentWithDefault<T>(argv: string[], argName: string, defaultValue: T): T|string|
18+
undefined {
19+
const index = argv.indexOf(argName);
20+
if (index < 0) {
21+
return defaultValue;
22+
}
23+
if (index === argv.length - 1) {
24+
return undefined;
25+
}
26+
const argValue = argv[index + 1];
27+
if (argValue.startsWith('-')) {
28+
return undefined;
29+
} else {
30+
return argValue;
31+
}
32+
}
33+
34+
function parseBooleanArgument(argv: string[], argName: string): boolean {
35+
const argValue = findArgumentWithDefault(argv, argName, 'true');
36+
if (argValue === undefined || argValue === 'true') {
37+
return true;
38+
}
39+
return false;
40+
}
41+
1742
function parseStringArray(argv: string[], argName: string): string[] {
1843
const arg = findArgument(argv, argName);
1944
if (!arg) {
@@ -36,6 +61,7 @@ interface CommandLineOptions {
3661
tsdk: string|null;
3762
includeAutomaticOptionalChainCompletions: boolean;
3863
includeCompletionsWithSnippetText: boolean;
64+
includeCompletionsForModuleExports: boolean;
3965
forceStrictTemplates: boolean;
4066
disableBlockSyntax: boolean;
4167
disableLetSyntax: boolean;
@@ -55,6 +81,8 @@ export function parseCommandLine(argv: string[]): CommandLineOptions {
5581
includeAutomaticOptionalChainCompletions:
5682
hasArgument(argv, '--includeAutomaticOptionalChainCompletions'),
5783
includeCompletionsWithSnippetText: hasArgument(argv, '--includeCompletionsWithSnippetText'),
84+
includeCompletionsForModuleExports:
85+
parseBooleanArgument(argv, '--includeCompletionsForModuleExports'),
5886
forceStrictTemplates: hasArgument(argv, '--forceStrictTemplates'),
5987
disableBlockSyntax: hasArgument(argv, '--disableBlockSyntax'),
6088
disableLetSyntax: hasArgument(argv, '--disableLetSyntax'),

server/src/completion.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export interface NgCompletionOriginData {
4747

4848
filePath: string;
4949
position: lsp.Position;
50+
51+
tsData?: ts.CompletionEntryData;
5052
}
5153

5254
/**
@@ -135,6 +137,7 @@ export function tsCompletionEntryToLspCompletionItem(
135137
kind: 'ngCompletionOriginData',
136138
filePath: scriptInfo.fileName,
137139
position,
140+
tsData: entry.data,
138141
} as NgCompletionOriginData;
139142
return item;
140143
}

server/src/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ function main() {
4747
logToConsole: options.logToConsole,
4848
includeAutomaticOptionalChainCompletions: options.includeAutomaticOptionalChainCompletions,
4949
includeCompletionsWithSnippetText: options.includeCompletionsWithSnippetText,
50+
includeCompletionsForModuleExports: options.includeCompletionsForModuleExports,
5051
forceStrictTemplates: isG3 || options.forceStrictTemplates,
5152
disableBlockSyntax: options.disableBlockSyntax,
5253
disableLetSyntax: options.disableLetSyntax,

server/src/session.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface SessionOptions {
3232
logToConsole: boolean;
3333
includeAutomaticOptionalChainCompletions: boolean;
3434
includeCompletionsWithSnippetText: boolean;
35+
includeCompletionsForModuleExports: boolean;
3536
forceStrictTemplates: boolean;
3637
disableBlockSyntax: boolean;
3738
disableLetSyntax: boolean;
@@ -49,7 +50,7 @@ const EMPTY_RANGE = lsp.Range.create(0, 0, 0, 0);
4950
const setImmediateP = promisify(setImmediate);
5051

5152
const defaultFormatOptions: ts.FormatCodeSettings = {};
52-
const defaultPreferences: ts.UserPreferences = {};
53+
let defaultPreferences: ts.UserPreferences = {};
5354

5455
const htmlLS = getHTMLLanguageService();
5556

@@ -70,6 +71,7 @@ export class Session {
7071
private readonly openFiles = new MruTracker();
7172
private readonly includeAutomaticOptionalChainCompletions: boolean;
7273
private readonly includeCompletionsWithSnippetText: boolean;
74+
private readonly includeCompletionsForModuleExports: boolean;
7375
private snippetSupport: boolean|undefined;
7476
private diagnosticsTimeout: NodeJS.Timeout|null = null;
7577
private isProjectLoading = false;
@@ -86,8 +88,13 @@ export class Session {
8688
this.includeAutomaticOptionalChainCompletions =
8789
options.includeAutomaticOptionalChainCompletions;
8890
this.includeCompletionsWithSnippetText = options.includeCompletionsWithSnippetText;
91+
this.includeCompletionsForModuleExports = options.includeCompletionsForModuleExports;
8992
this.logger = options.logger;
9093
this.logToConsole = options.logToConsole;
94+
defaultPreferences = {
95+
...defaultPreferences,
96+
includeCompletionsForModuleExports: options.includeCompletionsForModuleExports,
97+
};
9198
// Create a connection for the server. The connection uses Node's IPC as a transport.
9299
this.connection = lsp.createConnection({
93100
// cancelUndispatched is a "middleware" to handle all cancellation requests.
@@ -150,6 +157,7 @@ export class Session {
150157
// We don't want the AutoImportProvider projects to be created. See
151158
// https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/#smarter-auto-imports
152159
includePackageJsonAutoImports: 'off',
160+
includeCompletionsForModuleExports: this.includeCompletionsForModuleExports,
153161
},
154162
watchOptions: {
155163
// Used as watch options when not specified by user's `tsconfig`.
@@ -1234,12 +1242,14 @@ export class Session {
12341242
let options: ts.GetCompletionsAtPositionOptions = {};
12351243
const includeCompletionsWithSnippetText =
12361244
this.includeCompletionsWithSnippetText && this.snippetSupport;
1237-
if (this.includeAutomaticOptionalChainCompletions || includeCompletionsWithSnippetText) {
1245+
if (this.includeAutomaticOptionalChainCompletions || includeCompletionsWithSnippetText ||
1246+
this.includeCompletionsForModuleExports) {
12381247
options = {
12391248
includeAutomaticOptionalChainCompletions: this.includeAutomaticOptionalChainCompletions,
12401249
includeCompletionsWithSnippetText: includeCompletionsWithSnippetText,
12411250
includeCompletionsWithInsertText:
12421251
this.includeAutomaticOptionalChainCompletions || includeCompletionsWithSnippetText,
1252+
includeCompletionsForModuleExports: this.includeCompletionsForModuleExports,
12431253
};
12441254
}
12451255

@@ -1269,8 +1279,8 @@ export class Session {
12691279

12701280
const offset = lspPositionToTsPosition(scriptInfo, position);
12711281
const details = languageService.getCompletionEntryDetails(
1272-
filePath, offset, item.insertText ?? item.label, undefined, undefined, undefined,
1273-
undefined);
1282+
filePath, offset, item.insertText ?? item.label, undefined, undefined, defaultPreferences,
1283+
data.tsData);
12741284
if (details === undefined) {
12751285
return item;
12761286
}

server/src/tests/cmdline_utils_spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,24 @@ describe('parseCommandLine', () => {
3333
const options = parseCommandLine(['--tsProbeLocations', '/baz,/qux']);
3434
expect(options.tsProbeLocations).toEqual(['/baz', '/qux']);
3535
});
36+
37+
it('should parse without "includeCompletionsForModuleExports"', () => {
38+
const options = parseCommandLine(['--tsProbeLocations', '/baz,/qux']);
39+
expect(options.includeCompletionsForModuleExports).toEqual(true);
40+
});
41+
42+
it('should parse with "--includeCompletionsForModuleExports --help"', () => {
43+
const options = parseCommandLine(['--includeCompletionsForModuleExports', '--help']);
44+
expect(options.includeCompletionsForModuleExports).toEqual(true);
45+
});
46+
47+
it('should parse with "--includeCompletionsForModuleExports true --help"', () => {
48+
const options = parseCommandLine(['--includeCompletionsForModuleExports', 'true', '--help']);
49+
expect(options.includeCompletionsForModuleExports).toEqual(true);
50+
});
51+
52+
it('should parse with "--includeCompletionsForModuleExports false --help"', () => {
53+
const options = parseCommandLine(['--includeCompletionsForModuleExports', 'false', '--help']);
54+
expect(options.includeCompletionsForModuleExports).toEqual(false);
55+
});
3656
});

0 commit comments

Comments
 (0)