Skip to content

Commit d6b55bf

Browse files
committed
fixup! feat: add config to enable auto-apply optional chaining on nullable symbol
1 parent ba7ee34 commit d6b55bf

File tree

9 files changed

+84
-17
lines changed

9 files changed

+84
-17
lines changed

integration/lsp/ivy_spec.ts

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {URI} from 'vscode-uri';
1515
import {ProjectLanguageService, ProjectLanguageServiceParams, SuggestStrictMode, SuggestStrictModeParams} from '../../common/notifications';
1616
import {NgccProgress, NgccProgressToken, NgccProgressType} from '../../common/progress';
1717
import {GetComponentsWithTemplateFile, GetTcbRequest, IsInAngularProject} from '../../common/requests';
18-
import {APP_COMPONENT, APP_COMPONENT_URI, FOO_COMPONENT_URI, FOO_TEMPLATE, FOO_TEMPLATE_URI, PROJECT_PATH, TSCONFIG} from '../test_constants';
18+
import {APP_COMPONENT, APP_COMPONENT_URI, FOO_COMPONENT, FOO_COMPONENT_URI, FOO_TEMPLATE, FOO_TEMPLATE_URI, PROJECT_PATH, TSCONFIG} from '../test_constants';
1919

2020
import {createConnection, createTracer, initializeServer, openTextDocument} from './test_utils';
2121

@@ -197,7 +197,8 @@ describe('Angular Ivy language server', () => {
197197
}))!;
198198
expect(response).not.toBeNull();
199199
expect(response.signatures.length).toEqual(1);
200-
expect(response.signatures[0].label).toEqual('substr(from: number, length?: number): string');
200+
expect(response.signatures[0].label)
201+
.toEqual('substr(from: number, length?: number | undefined): string');
201202
expect(response.signatures[0].parameters).not.toBeUndefined();
202203
expect(response.activeParameter).toBe(1);
203204

@@ -206,7 +207,7 @@ describe('Angular Ivy language server', () => {
206207
const [start, end] = param.label as [number, number];
207208
return label.substring(start, end);
208209
});
209-
expect(paramLabels).toEqual(['from: number', 'length?: number']);
210+
expect(paramLabels).toEqual(['from: number', 'length?: number | undefined']);
210211
});
211212
});
212213

@@ -480,6 +481,67 @@ describe('Angular Ivy language server', () => {
480481
})
481482
});
482483

484+
describe('auto-apply optional chaining', () => {
485+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */
486+
487+
let client: MessageConnection;
488+
beforeEach(async () => {
489+
client = createConnection({
490+
ivy: true,
491+
includeAutomaticOptionalChainCompletions: true,
492+
});
493+
// If debugging, set to
494+
// - lsp.Trace.Messages to inspect request/response/notification, or
495+
// - lsp.Trace.Verbose to inspect payload
496+
client.trace(lsp.Trace.Off, createTracer());
497+
client.listen();
498+
await initializeServer(client);
499+
});
500+
501+
afterEach(() => {
502+
client.dispose();
503+
});
504+
505+
it('should work on nullable symbol', async () => {
506+
openTextDocument(client, FOO_COMPONENT, `
507+
import {Component} from '@angular/core';
508+
@Component({
509+
templateUrl: 'foo.component.html',
510+
})
511+
export class FooComponent {
512+
person?: undefined|{name: string};
513+
}
514+
`);
515+
openTextDocument(client, FOO_TEMPLATE, `{{ person.n }}`);
516+
const languageServiceEnabled = await waitForNgcc(client);
517+
expect(languageServiceEnabled).toBeTrue();
518+
const response = await client.sendRequest(lsp.CompletionRequest.type, {
519+
textDocument: {
520+
uri: FOO_TEMPLATE_URI,
521+
},
522+
position: {line: 0, character: 11},
523+
}) as lsp.CompletionItem[];
524+
const completion = response.find(i => i.label === 'name')!;
525+
expect(completion.kind).toEqual(lsp.CompletionItemKind.Property);
526+
expect((completion.textEdit as lsp.TextEdit).newText).toEqual('?.name');
527+
});
528+
529+
it('should work on NonNullable symbol', async () => {
530+
openTextDocument(client, FOO_TEMPLATE, `{{ title.substr }}`);
531+
const languageServiceEnabled = await waitForNgcc(client);
532+
expect(languageServiceEnabled).toBeTrue();
533+
const response = await client.sendRequest(lsp.CompletionRequest.type, {
534+
textDocument: {
535+
uri: FOO_TEMPLATE_URI,
536+
},
537+
position: {line: 0, character: 15},
538+
}) as lsp.CompletionItem[];
539+
const completion = response.find(i => i.label === 'substr')!;
540+
expect(completion.kind).toEqual(lsp.CompletionItemKind.Method);
541+
expect((completion.textEdit as lsp.TextEdit).newText).toEqual('substr');
542+
});
543+
});
544+
483545
function onNgccProgress(client: MessageConnection): Promise<string> {
484546
return new Promise(resolve => {
485547
client.onProgress(NgccProgressType, NgccProgressToken, (params: NgccProgress) => {

integration/lsp/test_utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {PROJECT_PATH, SERVER_PATH} from '../test_constants';
1515

1616
export interface ServerOptions {
1717
ivy: boolean;
18+
includeAutomaticOptionalChainCompletions?: boolean;
1819
}
1920

2021
export function createConnection(serverOptions: ServerOptions): MessageConnection {
@@ -28,6 +29,9 @@ export function createConnection(serverOptions: ServerOptions): MessageConnectio
2829
if (!serverOptions.ivy) {
2930
argv.push('--viewEngine');
3031
}
32+
if (serverOptions.includeAutomaticOptionalChainCompletions) {
33+
argv.push('--includeAutomaticOptionalChainCompletions');
34+
}
3135
const server = fork(SERVER_PATH, argv, {
3236
cwd: PROJECT_PATH,
3337
// uncomment to debug server process

integration/lsp/viewengine_spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ describe('Angular language server', () => {
6565
},
6666
newText: 'charAt()',
6767
},
68-
filterText: 'charAt()',
6968
// The 'data' field is only meaningful in Ivy mode.
7069
data: jasmine.anything(),
7170
});

integration/project/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"moduleResolution": "node",
44
"experimentalDecorators": true,
55
"target": "es2015",
6+
"strict": true,
67
"typeRoots": [
78
"node_modules/@types"
89
]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
"test:syntaxes": "yarn compile:syntaxes-test && yarn build:syntaxes && jasmine dist/syntaxes/test/driver.js"
170170
},
171171
"dependencies": {
172-
"@angular/language-service": "12.1.4",
172+
"@angular/language-service": "13.0.0-next.2",
173173
"typescript": "4.3.4",
174174
"vscode-jsonrpc": "6.0.0",
175175
"vscode-languageclient": "7.0.0",

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"ngserver": "./bin/ngserver"
1616
},
1717
"dependencies": {
18-
"@angular/language-service": "12.1.4",
18+
"@angular/language-service": "13.0.0-next.2",
1919
"vscode-jsonrpc": "6.0.0",
2020
"vscode-languageserver": "7.0.0",
2121
"vscode-uri": "3.0.2"

server/src/completion.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function ngCompletionKindToLspCompletionItemKind(kind: CompletionKind): lsp.Comp
104104
*/
105105
export function tsCompletionEntryToLspCompletionItem(
106106
entry: ts.CompletionEntry, position: lsp.Position, scriptInfo: ts.server.ScriptInfo,
107-
insertReplaceSupport: boolean): lsp.CompletionItem {
107+
insertReplaceSupport: boolean, isIvy: boolean): lsp.CompletionItem {
108108
const item = lsp.CompletionItem.create(entry.name);
109109
// Even though `entry.kind` is typed as ts.ScriptElementKind, it's
110110
// really Angular's CompletionKind. This is because ts.ScriptElementKind does
@@ -120,10 +120,12 @@ export function tsCompletionEntryToLspCompletionItem(
120120
const insertText = entry.insertText || entry.name;
121121
item.textEdit = createTextEdit(scriptInfo, entry, position, insertText, insertReplaceSupport);
122122

123-
// If the user enables the config `includeAutomaticOptionalChainCompletions`, the `insertText`
124-
// range will include the dot. the `insertText` should be assigned to the `filterText` to filter
125-
// the completion items.
126-
item.filterText = entry.insertText;
123+
if (isIvy) {
124+
// If the user enables the config `includeAutomaticOptionalChainCompletions`, the `insertText`
125+
// range will include the dot. the `insertText` should be assigned to the `filterText` to filter
126+
// the completion items.
127+
item.filterText = entry.insertText;
128+
}
127129

128130
item.data = {
129131
kind: 'ngCompletionOriginData',

server/src/session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,7 @@ export class Session {
10011001
false;
10021002
return completions.entries.map(
10031003
(e) => tsCompletionEntryToLspCompletionItem(
1004-
e, params.position, scriptInfo, clientSupportsInsertReplaceCompletion));
1004+
e, params.position, scriptInfo, clientSupportsInsertReplaceCompletion, this.ivy));
10051005
}
10061006

10071007
private onCompletionResolve(item: lsp.CompletionItem): lsp.CompletionItem {

yarn.lock

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
"@angular/dev-infra-private@https://github.com/angular/dev-infra-private-builds.git#5fad38db75f746e76af8b015dd8f674579a54ab3":
2121
version "0.0.0"
22-
uid "5fad38db75f746e76af8b015dd8f674579a54ab3"
2322
resolved "https://github.com/angular/dev-infra-private-builds.git#5fad38db75f746e76af8b015dd8f674579a54ab3"
2423
dependencies:
2524
"@angular/benchpress" "0.2.1"
@@ -53,10 +52,10 @@
5352
yaml "^1.10.0"
5453
yargs "^17.0.0"
5554

56-
"@angular/language-service@12.1.4":
57-
version "12.1.4"
58-
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-12.1.4.tgz#4ff59452864147f77996b05cb5a4125895fc0a5d"
59-
integrity sha512-NooCGWiTY74DN3uFE8eI1ATtxx4TQzulbV7qNNG9Bz8QJyLRykYart7Ajxh0bF5upR1bjPmHr6MvgO6aI43VUQ==
55+
"@angular/language-service@13.0.0-next.2":
56+
version "13.0.0-next.2"
57+
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-13.0.0-next.2.tgz#4027291ea734195f8518e2ea022c306b9127f49a"
58+
integrity sha512-zgzUrpQFzxRH9YFV0Fk21zu7bYpKn5lgeGtUyqgL23fi7BdjuXXyKiB7cnT+xxT4U5yNRlIq4mDQGJRscDvOMg==
6059

6160
"@babel/code-frame@^7.0.0":
6261
version "7.12.13"

0 commit comments

Comments
 (0)