refactor(language-service): reformat using clang-format (#36426)
clang-format was recently updated and any PRs that touch files in the language service will have to reformat all the files. Instead of changing the formatting in those PRs, this PR formats all files in language-service package once and for all. PR Close #36426
This commit is contained in:

committed by
Kara Erickson

parent
1b4df6484e
commit
1140bbc25c
@ -25,7 +25,9 @@ describe('completions', () => {
|
||||
const ngHost = new TypeScriptServiceHost(mockHost, tsLS);
|
||||
const ngLS = createLanguageService(ngHost);
|
||||
|
||||
beforeEach(() => { mockHost.reset(); });
|
||||
beforeEach(() => {
|
||||
mockHost.reset();
|
||||
});
|
||||
|
||||
it('should be able to get entity completions', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'entity-amp');
|
||||
@ -102,7 +104,7 @@ describe('completions', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h2-hero');
|
||||
const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start);
|
||||
expect(completions).toBeDefined();
|
||||
const internal = completions !.entries.find(e => e.name === 'internal');
|
||||
const internal = completions!.entries.find(e => e.name === 'internal');
|
||||
expect(internal).toBeUndefined();
|
||||
});
|
||||
|
||||
@ -202,7 +204,7 @@ describe('completions', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(completions).toBeDefined();
|
||||
expect(completions !.entries).toContain(jasmine.objectContaining({
|
||||
expect(completions!.entries).toContain(jasmine.objectContaining({
|
||||
name: 'myClick',
|
||||
kind: CompletionKind.METHOD as any,
|
||||
insertText: 'myClick()',
|
||||
@ -214,7 +216,7 @@ describe('completions', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'pipe-method');
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(completions).toBeDefined();
|
||||
expect(completions !.entries).toContain(jasmine.objectContaining({
|
||||
expect(completions!.entries).toContain(jasmine.objectContaining({
|
||||
name: 'lowercase',
|
||||
kind: CompletionKind.PIPE as any,
|
||||
insertText: 'lowercase',
|
||||
@ -234,7 +236,7 @@ describe('completions', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, location);
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(completions).toBeDefined();
|
||||
const {entries} = completions !;
|
||||
const {entries} = completions!;
|
||||
expect(entries).not.toContain(jasmine.objectContaining({name: 'div'}));
|
||||
expect(entries).not.toContain(jasmine.objectContaining({name: 'h1'}));
|
||||
expect(entries).not.toContain(jasmine.objectContaining({name: 'h2'}));
|
||||
@ -257,7 +259,7 @@ describe('completions', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'h1-after-space');
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(completions).toBeDefined();
|
||||
const {entries} = completions !;
|
||||
const {entries} = completions!;
|
||||
expect(entries).not.toContain(jasmine.objectContaining({name: 'class'}));
|
||||
expect(entries).not.toContain(jasmine.objectContaining({name: 'id'}));
|
||||
expect(entries).not.toContain(jasmine.objectContaining({name: 'onclick'}));
|
||||
@ -536,9 +538,9 @@ describe('completions', () => {
|
||||
}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'key');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'key') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'key')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe('property');
|
||||
expect(completion.replacementSpan).toBeUndefined();
|
||||
@ -553,9 +555,9 @@ describe('completions', () => {
|
||||
export class FooComponent {}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'start');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'acronym') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'acronym')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe('html element');
|
||||
expect(completion.replacementSpan).toEqual({start: location.start, length: 3});
|
||||
@ -570,9 +572,9 @@ describe('completions', () => {
|
||||
export class FooComponent {}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'end');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'acronym') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'acronym')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe('html element');
|
||||
expect(completion.replacementSpan).toEqual({start: location.start - 4, length: 4});
|
||||
@ -591,9 +593,9 @@ describe('completions', () => {
|
||||
}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'key');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'key') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'key')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe('property');
|
||||
expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 5});
|
||||
@ -612,9 +614,9 @@ describe('completions', () => {
|
||||
}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'field');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === '$title_1') !;
|
||||
const completion = completions.entries.find(entry => entry.name === '$title_1')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe('property');
|
||||
expect(completion.replacementSpan).toEqual({start: location.start, length: 8});
|
||||
@ -631,9 +633,9 @@ describe('completions', () => {
|
||||
export class FooComponent {}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'click');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'click') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'click')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe(CompletionKind.ATTRIBUTE);
|
||||
expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2});
|
||||
@ -652,9 +654,9 @@ describe('completions', () => {
|
||||
}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'handleClick');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'handleClick') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'handleClick')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe('method');
|
||||
expect(completion.replacementSpan).toEqual({start: location.start - 3, length: 3});
|
||||
@ -671,9 +673,9 @@ describe('completions', () => {
|
||||
export class FooComponent {}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'div');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'div') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'div')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe('html element');
|
||||
expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2});
|
||||
@ -690,9 +692,9 @@ describe('completions', () => {
|
||||
export class FooComponent {}
|
||||
`);
|
||||
const location = mockHost.getLocationMarkerFor(fileName, 'model');
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!;
|
||||
expect(completions).toBeDefined();
|
||||
const completion = completions.entries.find(entry => entry.name === 'ngModel') !;
|
||||
const completion = completions.entries.find(entry => entry.name === 'ngModel')!;
|
||||
expect(completion).toBeDefined();
|
||||
expect(completion.kind).toBe(CompletionKind.ATTRIBUTE);
|
||||
expect(completion.replacementSpan).toEqual({start: location.start - 5, length: 5});
|
||||
@ -741,14 +743,14 @@ describe('completions', () => {
|
||||
it('should be able to get the completions (ref- prefix)', () => {
|
||||
mockHost.override(TEST_TEMPLATE, `<form ref-itemForm="ngF~{reference}"></form>`);
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference');
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start)!;
|
||||
expectContain(completions, CompletionKind.REFERENCE, ['ngForm']);
|
||||
});
|
||||
|
||||
it('should be able to get the completions (# prefix)', () => {
|
||||
mockHost.override(TEST_TEMPLATE, `<form #itemForm="ngF~{reference}"></form>`);
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference');
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !;
|
||||
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start)!;
|
||||
expectContain(completions, CompletionKind.REFERENCE, ['ngForm']);
|
||||
});
|
||||
});
|
||||
@ -789,9 +791,9 @@ describe('completions', () => {
|
||||
});
|
||||
|
||||
function expectContain(
|
||||
completions: ts.CompletionInfo | undefined, kind: CompletionKind, names: string[]) {
|
||||
completions: ts.CompletionInfo|undefined, kind: CompletionKind, names: string[]) {
|
||||
expect(completions).toBeDefined();
|
||||
for (const name of names) {
|
||||
expect(completions !.entries).toContain(jasmine.objectContaining({ name, kind } as any));
|
||||
expect(completions!.entries).toContain(jasmine.objectContaining({name, kind} as any));
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,9 @@ describe('definitions', () => {
|
||||
const ngHost = new TypeScriptServiceHost(mockHost, service);
|
||||
const ngService = createLanguageService(ngHost);
|
||||
|
||||
beforeEach(() => { mockHost.reset(); });
|
||||
beforeEach(() => {
|
||||
mockHost.reset();
|
||||
});
|
||||
|
||||
it('should be able to find field in an interpolation', () => {
|
||||
const fileName = mockHost.addCode(`
|
||||
@ -36,12 +38,12 @@ describe('definitions', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'name');
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
expect(def.fileName).toBe(fileName);
|
||||
expect(def.name).toBe('name');
|
||||
@ -55,20 +57,20 @@ describe('definitions', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(definitions).toBeDefined();
|
||||
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
expect(def.fileName).toBe(PARSING_CASES);
|
||||
expect(def.name).toBe('title');
|
||||
expect(def.kind).toBe('property');
|
||||
|
||||
const fileContent = mockHost.readFile(def.fileName);
|
||||
expect(fileContent !.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length))
|
||||
expect(fileContent!.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length))
|
||||
.toEqual(`title = 'Some title';`);
|
||||
});
|
||||
|
||||
@ -84,12 +86,12 @@ describe('definitions', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'myClick');
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual(mockHost.getLocationMarkerFor(fileName, 'my'));
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
expect(def.fileName).toBe(fileName);
|
||||
expect(def.name).toBe('myClick');
|
||||
@ -109,12 +111,12 @@ describe('definitions', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'include');
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
expect(def.fileName).toBe(fileName);
|
||||
expect(def.name).toBe('include');
|
||||
@ -134,7 +136,7 @@ describe('definitions', () => {
|
||||
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
// Get the marker for bounded text in the code added above.
|
||||
const boundedText = mockHost.getLocationMarkerFor(fileName, 'my');
|
||||
@ -142,14 +144,14 @@ describe('definitions', () => {
|
||||
|
||||
// There should be exactly 1 definition
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
const refFileName = '/app/parsing-cases.ts';
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('TestComponent');
|
||||
expect(def.kind).toBe('component');
|
||||
const content = mockHost.readFile(refFileName) !;
|
||||
const content = mockHost.readFile(refFileName)!;
|
||||
const begin = '/*BeginTestComponent*/ ';
|
||||
const start = content.indexOf(begin) + begin.length;
|
||||
const end = content.indexOf(' /*EndTestComponent*/');
|
||||
@ -171,7 +173,7 @@ describe('definitions', () => {
|
||||
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
// Get the marker for bounded text in the code added above
|
||||
const boundedText = mockHost.getLocationMarkerFor(fileName, 'my');
|
||||
@ -179,14 +181,14 @@ describe('definitions', () => {
|
||||
|
||||
// There should be exactly 1 definition
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
const refFileName = '/app/parsing-cases.ts';
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('testEvent');
|
||||
expect(def.kind).toBe('event');
|
||||
const content = mockHost.readFile(refFileName) !;
|
||||
const content = mockHost.readFile(refFileName)!;
|
||||
const ref = `@Output('test') testEvent = new EventEmitter();`;
|
||||
expect(def.textSpan).toEqual({
|
||||
start: content.indexOf(ref),
|
||||
@ -208,7 +210,7 @@ describe('definitions', () => {
|
||||
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
// Get the marker for bounded text in the code added above
|
||||
const boundedText = mockHost.getLocationMarkerFor(fileName, 'my');
|
||||
@ -216,14 +218,14 @@ describe('definitions', () => {
|
||||
|
||||
// There should be exactly 1 definition
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
const refFileName = '/app/parsing-cases.ts';
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('name');
|
||||
expect(def.kind).toBe('property');
|
||||
const content = mockHost.readFile(refFileName) !;
|
||||
const content = mockHost.readFile(refFileName)!;
|
||||
const ref = `@Input('tcName') name = 'test';`;
|
||||
expect(def.textSpan).toEqual({
|
||||
start: content.indexOf(ref),
|
||||
@ -245,14 +247,14 @@ describe('definitions', () => {
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(4);
|
||||
expect(definitions!.length).toBe(4);
|
||||
|
||||
const refFileName = '/node_modules/@angular/common/common.d.ts';
|
||||
for (const def of definitions !) {
|
||||
for (const def of definitions!) {
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('async');
|
||||
expect(def.kind).toBe('pipe');
|
||||
@ -268,14 +270,14 @@ describe('definitions', () => {
|
||||
const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
expect(definitions!.length).toBe(1);
|
||||
|
||||
const refFileName = '/node_modules/@angular/common/common.d.ts';
|
||||
for (const def of definitions !) {
|
||||
for (const def of definitions!) {
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('date');
|
||||
expect(def.kind).toBe('pipe');
|
||||
@ -292,17 +294,17 @@ describe('definitions', () => {
|
||||
|
||||
const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
// Get the marker for bounded text in the code added above
|
||||
const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my');
|
||||
expect(textSpan).toEqual(boundedText);
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
expect(definitions!.length).toBe(1);
|
||||
|
||||
const refFileName = '/node_modules/@angular/common/common.d.ts';
|
||||
const def = definitions ![0];
|
||||
const def = definitions![0];
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('NgForOf');
|
||||
expect(def.kind).toBe('directive');
|
||||
@ -317,17 +319,17 @@ describe('definitions', () => {
|
||||
|
||||
const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
// Get the marker for bounded text in the code added above
|
||||
expect(textSpan).toEqual(marker);
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
// The two definitions are setter and getter of 'ngForTrackBy'.
|
||||
expect(definitions !.length).toBe(2);
|
||||
expect(definitions!.length).toBe(2);
|
||||
|
||||
const refFileName = '/node_modules/@angular/common/common.d.ts';
|
||||
definitions !.forEach(def => {
|
||||
definitions!.forEach(def => {
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('ngForTrackBy');
|
||||
expect(def.kind).toBe('method');
|
||||
@ -343,19 +345,19 @@ describe('definitions', () => {
|
||||
|
||||
const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual(marker);
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
expect(definitions!.length).toBe(1);
|
||||
|
||||
const refFileName = '/app/parsing-cases.ts';
|
||||
const def = definitions ![0];
|
||||
const def = definitions![0];
|
||||
expect(def.fileName).toBe(refFileName);
|
||||
expect(def.name).toBe('heroes');
|
||||
expect(def.kind).toBe('property');
|
||||
const content = mockHost.readFile(refFileName) !;
|
||||
const content = mockHost.readFile(refFileName)!;
|
||||
expect(content.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length))
|
||||
.toEqual(`heroes: Hero[] = [this.hero];`);
|
||||
});
|
||||
@ -370,28 +372,28 @@ describe('definitions', () => {
|
||||
|
||||
const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
// Get the marker for bounded text in the code added above
|
||||
const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my');
|
||||
expect(textSpan).toEqual(boundedText);
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(2);
|
||||
const [def1, def2] = definitions !;
|
||||
expect(definitions!.length).toBe(2);
|
||||
const [def1, def2] = definitions!;
|
||||
|
||||
const refFileName = '/app/parsing-cases.ts';
|
||||
expect(def1.fileName).toBe(refFileName);
|
||||
expect(def1.name).toBe('model');
|
||||
expect(def1.kind).toBe('property');
|
||||
let content = mockHost.readFile(refFileName) !;
|
||||
let content = mockHost.readFile(refFileName)!;
|
||||
expect(content.substring(def1.textSpan.start, def1.textSpan.start + def1.textSpan.length))
|
||||
.toEqual(`@Input() model: string = 'model';`);
|
||||
|
||||
expect(def2.fileName).toBe(refFileName);
|
||||
expect(def2.name).toBe('modelChange');
|
||||
expect(def2.kind).toBe('event');
|
||||
content = mockHost.readFile(refFileName) !;
|
||||
content = mockHost.readFile(refFileName)!;
|
||||
expect(content.substring(def2.textSpan.start, def2.textSpan.start + def2.textSpan.length))
|
||||
.toEqual(`@Output() modelChange: EventEmitter<string> = new EventEmitter();`);
|
||||
});
|
||||
@ -407,13 +409,13 @@ describe('definitions', () => {
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual({start: marker.start - 2, length: 9});
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const [def] = definitions !;
|
||||
expect(definitions!.length).toBe(1);
|
||||
const [def] = definitions!;
|
||||
expect(def.fileName).toBe('/app/test.ng');
|
||||
expect(def.textSpan).toEqual({start: 0, length: 0});
|
||||
});
|
||||
@ -430,13 +432,13 @@ describe('definitions', () => {
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual({start: marker.start - 2, length: 10});
|
||||
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const [def] = definitions !;
|
||||
expect(definitions!.length).toBe(1);
|
||||
const [def] = definitions!;
|
||||
expect(def.fileName).toBe('/app/test.css');
|
||||
expect(def.textSpan).toEqual({start: 0, length: 0});
|
||||
});
|
||||
@ -453,12 +455,12 @@ describe('definitions', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'name');
|
||||
const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start);
|
||||
expect(result).toBeDefined();
|
||||
const {textSpan, definitions} = result !;
|
||||
const {textSpan, definitions} = result!;
|
||||
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(definitions).toBeDefined();
|
||||
expect(definitions !.length).toBe(1);
|
||||
const def = definitions ![0];
|
||||
expect(definitions!.length).toBe(1);
|
||||
const def = definitions![0];
|
||||
|
||||
expect(def.fileName).toBe(fileName);
|
||||
expect(def.name).toBe('name');
|
||||
|
@ -7,7 +7,8 @@
|
||||
*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import {DiagnosticMessage, createDiagnostic} from '../src/diagnostic_messages';
|
||||
|
||||
import {createDiagnostic, DiagnosticMessage} from '../src/diagnostic_messages';
|
||||
|
||||
describe('create diagnostic', () => {
|
||||
it('should format and create diagnostics correctly', () => {
|
||||
|
@ -34,7 +34,9 @@ describe('diagnostics', () => {
|
||||
const ngHost = new TypeScriptServiceHost(mockHost, tsLS);
|
||||
const ngLS = createLanguageService(ngHost);
|
||||
|
||||
beforeEach(() => { mockHost.reset(); });
|
||||
beforeEach(() => {
|
||||
mockHost.reset();
|
||||
});
|
||||
|
||||
it('should produce no diagnostics for test.ng', () => {
|
||||
// there should not be any errors on existing external template
|
||||
@ -300,7 +302,8 @@ describe('diagnostics', () => {
|
||||
expect(messageText)
|
||||
.toBe(
|
||||
`The template context of 'CounterDirective' does not define an implicit value.\n` +
|
||||
`If the context type is a base type or 'any', consider refining it to a more specific type.`, );
|
||||
`If the context type is a base type or 'any', consider refining it to a more specific type.`,
|
||||
);
|
||||
|
||||
const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb');
|
||||
expect(start).toBe(span.start);
|
||||
@ -337,7 +340,8 @@ describe('diagnostics', () => {
|
||||
expect(category).toBe(ts.DiagnosticCategory.Error);
|
||||
expect(messageText)
|
||||
.toBe(
|
||||
`Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`, );
|
||||
`Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`,
|
||||
);
|
||||
const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb');
|
||||
expect(start).toBe(span.start);
|
||||
expect(length).toBe(span.length);
|
||||
@ -355,7 +359,8 @@ describe('diagnostics', () => {
|
||||
expect(category).toBe(ts.DiagnosticCategory.Error);
|
||||
expect(messageText)
|
||||
.toBe(
|
||||
`Identifier 'missingField' is not defined. 'Person' does not contain such a member`, );
|
||||
`Identifier 'missingField' is not defined. 'Person' does not contain such a member`,
|
||||
);
|
||||
const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb');
|
||||
expect(start).toBe(span.start);
|
||||
expect(length).toBe(span.length);
|
||||
@ -396,7 +401,7 @@ describe('diagnostics', () => {
|
||||
|
||||
it('should reject it when not in an event binding', () => {
|
||||
const content = mockHost.override(TEST_TEMPLATE, '<div [tabIndex]="$event"></div>');
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE)!;
|
||||
expect(diagnostics.length).toBe(1);
|
||||
const {messageText, start, length} = diagnostics[0];
|
||||
expect(messageText)
|
||||
@ -410,7 +415,7 @@ describe('diagnostics', () => {
|
||||
it('should reject invalid properties on an event type', () => {
|
||||
const content = mockHost.override(
|
||||
TEST_TEMPLATE, '<div string-model (modelChange)="$event.notSubstring()"></div>');
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE)!;
|
||||
expect(diagnostics.length).toBe(1);
|
||||
const {messageText, start, length} = diagnostics[0];
|
||||
expect(messageText)
|
||||
@ -436,14 +441,14 @@ describe('diagnostics', () => {
|
||||
template: '<div></div>'
|
||||
})
|
||||
export class MyComponent {}`);
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName)!;
|
||||
expect(diagnostics.length).toBe(1);
|
||||
const {messageText, start, length} = diagnostics[0];
|
||||
expect(messageText)
|
||||
.toBe(
|
||||
`Component 'MyComponent' is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration.`);
|
||||
const content = mockHost.readFile(fileName) !;
|
||||
expect(content.substring(start !, start ! + length !)).toBe('MyComponent');
|
||||
const content = mockHost.readFile(fileName)!;
|
||||
expect(content.substring(start!, start! + length!)).toBe('MyComponent');
|
||||
});
|
||||
|
||||
|
||||
@ -495,7 +500,7 @@ describe('diagnostics', () => {
|
||||
}`);
|
||||
const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT);
|
||||
expect(tsDiags).toEqual([]);
|
||||
const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT) !;
|
||||
const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT)!;
|
||||
expect(ngDiags.length).toBe(1);
|
||||
const {messageText, start, length} = ngDiags[0];
|
||||
const keyword = `() => 'foo'`;
|
||||
@ -504,9 +509,9 @@ describe('diagnostics', () => {
|
||||
// messageText is a three-part chain
|
||||
const firstPart = messageText as ts.DiagnosticMessageChain;
|
||||
expect(firstPart.messageText).toBe(`Error during template compile of 'AppComponent'`);
|
||||
const secondPart = firstPart.next !;
|
||||
const secondPart = firstPart.next!;
|
||||
expect(secondPart[0].messageText).toBe('Function expressions are not supported in decorators');
|
||||
const thirdPart = secondPart[0].next !;
|
||||
const thirdPart = secondPart[0].next!;
|
||||
expect(thirdPart[0].messageText)
|
||||
.toBe('Consider changing the function expression into an exported function');
|
||||
expect(thirdPart[0].next).toBeFalsy();
|
||||
@ -568,7 +573,7 @@ describe('diagnostics', () => {
|
||||
export class AppComponent {
|
||||
onClick() { }
|
||||
}`);
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT)!;
|
||||
const {messageText, start, length} = diagnostics[0];
|
||||
expect(messageText).toBe('Unexpected callable expression. Expected a method call');
|
||||
const keyword = `"onClick"`;
|
||||
@ -682,7 +687,7 @@ describe('diagnostics', () => {
|
||||
.toBe(
|
||||
'Invalid providers for "AppComponent in /app/app.component.ts" - only instances of Provider and Type are allowed, got: [?null?]');
|
||||
// TODO: Looks like this is the wrong span. Should point to 'null' instead.
|
||||
expect(content.substring(start !, start ! + length !)).toBe('AppComponent');
|
||||
expect(content.substring(start!, start! + length!)).toBe('AppComponent');
|
||||
});
|
||||
|
||||
// Issue #15768
|
||||
@ -815,12 +820,12 @@ describe('diagnostics', () => {
|
||||
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile');
|
||||
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName)!;
|
||||
const urlDiagnostic =
|
||||
diagnostics.find(d => d.messageText === 'URL does not point to a valid file');
|
||||
expect(urlDiagnostic).toBeDefined();
|
||||
|
||||
const {start, length} = urlDiagnostic !;
|
||||
const {start, length} = urlDiagnostic!;
|
||||
expect(start).toBe(marker.start);
|
||||
expect(length).toBe(marker.length);
|
||||
});
|
||||
@ -832,7 +837,7 @@ describe('diagnostics', () => {
|
||||
})
|
||||
export class MyComponent {}`);
|
||||
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName)!;
|
||||
const urlDiagnostic =
|
||||
diagnostics.find(d => d.messageText === 'URL does not point to a valid file');
|
||||
expect(urlDiagnostic).toBeUndefined();
|
||||
@ -849,9 +854,9 @@ describe('diagnostics', () => {
|
||||
const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT);
|
||||
expect(diags.length).toBe(1);
|
||||
const {file, messageText, start, length} = diags[0];
|
||||
expect(file !.fileName).toBe(APP_COMPONENT);
|
||||
expect(file!.fileName).toBe(APP_COMPONENT);
|
||||
expect(messageText).toBe(`Component 'AppComponent' must have a template or templateUrl`);
|
||||
expect(content.substring(start !, start ! + length !)).toBe('AppComponent');
|
||||
expect(content.substring(start!, start! + length!)).toBe('AppComponent');
|
||||
});
|
||||
|
||||
it('should report diagnostic for both template and templateUrl', () => {
|
||||
@ -867,10 +872,10 @@ describe('diagnostics', () => {
|
||||
const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT);
|
||||
expect(diags.length).toBe(1);
|
||||
const {file, messageText, start, length} = diags[0];
|
||||
expect(file !.fileName).toBe(APP_COMPONENT);
|
||||
expect(file!.fileName).toBe(APP_COMPONENT);
|
||||
expect(messageText)
|
||||
.toBe(`Component 'AppComponent' must not have both template and templateUrl`);
|
||||
expect(content.substring(start !, start ! + length !)).toBe('AppComponent');
|
||||
expect(content.substring(start!, start! + length!)).toBe('AppComponent');
|
||||
});
|
||||
|
||||
it('should report errors for invalid styleUrls', () => {
|
||||
@ -882,12 +887,12 @@ describe('diagnostics', () => {
|
||||
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile');
|
||||
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(fileName)!;
|
||||
const urlDiagnostic =
|
||||
diagnostics.find(d => d.messageText === 'URL does not point to a valid file');
|
||||
expect(urlDiagnostic).toBeDefined();
|
||||
|
||||
const {start, length} = urlDiagnostic !;
|
||||
const {start, length} = urlDiagnostic!;
|
||||
expect(start).toBe(marker.start);
|
||||
expect(length).toBe(marker.length);
|
||||
});
|
||||
@ -902,7 +907,7 @@ describe('diagnostics', () => {
|
||||
})
|
||||
export class AppComponent {}`);
|
||||
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !;
|
||||
const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT)!;
|
||||
expect(diagnostics.length).toBe(0);
|
||||
});
|
||||
});
|
||||
@ -926,14 +931,14 @@ describe('diagnostics', () => {
|
||||
`element references do not contain such a member`);
|
||||
// Assert that the span is actually highlight the bounded text. The span
|
||||
// would be off if CRLF endings are not handled properly.
|
||||
expect(content.substring(start !, start ! + length !)).toBe(`line${i}`);
|
||||
expect(content.substring(start!, start! + length!)).toBe(`line${i}`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should work correctly with CRLF endings in inline template', () => {
|
||||
const fileName = mockHost.addCode(
|
||||
'\n@Component({template:`\r\n\r\n{{line}}`})export class ComponentCRLF {}');
|
||||
const content = mockHost.readFile(fileName) !;
|
||||
const content = mockHost.readFile(fileName)!;
|
||||
const ngDiags = ngLS.getSemanticDiagnostics(fileName);
|
||||
expect(ngDiags.length).toBeGreaterThan(0);
|
||||
const {messageText, start, length} = ngDiags[0];
|
||||
@ -942,7 +947,7 @@ describe('diagnostics', () => {
|
||||
`Identifier 'line' is not defined. ` +
|
||||
`The component declaration, template variable declarations, and ` +
|
||||
`element references do not contain such a member`);
|
||||
expect(content.substring(start !, start ! + length !)).toBe('line');
|
||||
expect(content.substring(start!, start! + length!)).toBe('line');
|
||||
});
|
||||
|
||||
it('should not produce diagnostics for non-exported directives', () => {
|
||||
@ -972,8 +977,7 @@ describe('diagnostics', () => {
|
||||
`Consider using the safe navigation operator (optional?.toLowerCase) ` +
|
||||
`or non-null assertion operator (optional!.toLowerCase).`);
|
||||
expect(category).toBe(ts.DiagnosticCategory.Suggestion);
|
||||
expect(content.substring(start !, start ! + length !)).toBe('optional.toLowerCase()');
|
||||
|
||||
expect(content.substring(start!, start! + length!)).toBe('optional.toLowerCase()');
|
||||
});
|
||||
|
||||
it('should suggest ? or ! operator if property receiver is nullable', () => {
|
||||
@ -987,7 +991,7 @@ describe('diagnostics', () => {
|
||||
`Consider using the safe navigation operator (optional?.length) ` +
|
||||
`or non-null assertion operator (optional!.length).`);
|
||||
expect(category).toBe(ts.DiagnosticCategory.Suggestion);
|
||||
expect(content.substring(start !, start ! + length !)).toBe('optional.length');
|
||||
expect(content.substring(start!, start! + length!)).toBe('optional.length');
|
||||
});
|
||||
|
||||
it('should report error if method is not found on non-nullable receiver', () => {
|
||||
@ -1003,7 +1007,7 @@ describe('diagnostics', () => {
|
||||
expect(messageText)
|
||||
.toBe(`Identifier 'someMethod' is not defined. 'string' does not contain such a member`);
|
||||
expect(category).toBe(ts.DiagnosticCategory.Error);
|
||||
expect(content.substring(start !, start ! + length !)).toBe(expression);
|
||||
expect(content.substring(start!, start! + length!)).toBe(expression);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1020,7 +1024,7 @@ describe('diagnostics', () => {
|
||||
expect(messageText)
|
||||
.toBe(`Identifier 'someProp' is not defined. 'string' does not contain such a member`);
|
||||
expect(category).toBe(ts.DiagnosticCategory.Error);
|
||||
expect(content.substring(start !, start ! + length !)).toBe(expression);
|
||||
expect(content.substring(start!, start! + length!)).toBe(expression);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1030,12 +1034,12 @@ describe('diagnostics', () => {
|
||||
<p>{{myClick()()}}</p>
|
||||
`);
|
||||
|
||||
const content = mockHost.readFile(TEST_TEMPLATE) !;
|
||||
const content = mockHost.readFile(TEST_TEMPLATE)!;
|
||||
const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE);
|
||||
expect(diags.length).toBe(1);
|
||||
const {messageText, start, length} = diags[0] !;
|
||||
const {messageText, start, length} = diags[0]!;
|
||||
expect(messageText).toBe(`Call target 'myClick()' has non-callable type 'void'.`);
|
||||
expect(content.substring(start !, start ! + length !)).toBe('myClick()()');
|
||||
expect(content.substring(start!, start! + length!)).toBe('myClick()()');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ import * as ts from 'typescript';
|
||||
|
||||
import {getTemplateExpressionDiagnostics} from '../src/expression_diagnostics';
|
||||
|
||||
import {DiagnosticContext, MockLanguageServiceHost, getDiagnosticTemplateInfo} from './mocks';
|
||||
import {DiagnosticContext, getDiagnosticTemplateInfo, MockLanguageServiceHost} from './mocks';
|
||||
|
||||
describe('expression diagnostics', () => {
|
||||
let registry: ts.DocumentRegistry;
|
||||
@ -27,15 +27,15 @@ describe('expression diagnostics', () => {
|
||||
registry = ts.createDocumentRegistry(false, '/src');
|
||||
host = new MockLanguageServiceHost(['app/app.component.ts'], FILES, '/src');
|
||||
service = ts.createLanguageService(host, registry);
|
||||
const program = service.getProgram() !;
|
||||
const program = service.getProgram()!;
|
||||
const checker = program.getTypeChecker();
|
||||
const symbolResolverHost = new ReflectorHost(() => program !, host);
|
||||
context = new DiagnosticContext(service, program !, checker, symbolResolverHost);
|
||||
const symbolResolverHost = new ReflectorHost(() => program!, host);
|
||||
context = new DiagnosticContext(service, program!, checker, symbolResolverHost);
|
||||
type = context.getStaticSymbol('app/app.component.ts', 'AppComponent');
|
||||
});
|
||||
|
||||
it('should have no diagnostics in default app', () => {
|
||||
function messageToString(messageText: string | ts.DiagnosticMessageChain): string {
|
||||
function messageToString(messageText: string|ts.DiagnosticMessageChain): string {
|
||||
if (typeof messageText == 'string') {
|
||||
return messageText;
|
||||
} else {
|
||||
@ -107,13 +107,14 @@ describe('expression diagnostics', () => {
|
||||
{{p.name.first}} {{p.name.last}}
|
||||
</div>
|
||||
`));
|
||||
it('should reject misspelled field in *ngFor', () => reject(
|
||||
`
|
||||
it('should reject misspelled field in *ngFor',
|
||||
() => reject(
|
||||
`
|
||||
<div *ngFor="let p of people">
|
||||
{{p.names.first}} {{p.name.last}}
|
||||
</div>
|
||||
`,
|
||||
'Identifier \'names\' is not defined'));
|
||||
'Identifier \'names\' is not defined'));
|
||||
it('should accept an async expression',
|
||||
() => accept('{{(promised_person | async)?.name.first || ""}}'));
|
||||
it('should reject an async misspelled field',
|
||||
@ -124,25 +125,27 @@ describe('expression diagnostics', () => {
|
||||
{{p.name.first}} {{p.name.last}}
|
||||
</div>
|
||||
`));
|
||||
it('should reject misspelled field an async *ngFor', () => reject(
|
||||
`
|
||||
it('should reject misspelled field an async *ngFor',
|
||||
() => reject(
|
||||
`
|
||||
<div *ngFor="let p of promised_people | async">
|
||||
{{p.name.first}} {{p.nume.last}}
|
||||
</div>
|
||||
`,
|
||||
'Identifier \'nume\' is not defined'));
|
||||
'Identifier \'nume\' is not defined'));
|
||||
it('should accept an async *ngIf', () => accept(`
|
||||
<div *ngIf="promised_person | async as p">
|
||||
{{p.name.first}} {{p.name.last}}
|
||||
</div>
|
||||
`));
|
||||
it('should reject misspelled field in async *ngIf', () => reject(
|
||||
`
|
||||
it('should reject misspelled field in async *ngIf',
|
||||
() => reject(
|
||||
`
|
||||
<div *ngIf="promised_person | async as p">
|
||||
{{p.name.first}} {{p.nume.last}}
|
||||
</div>
|
||||
`,
|
||||
'Identifier \'nume\' is not defined'));
|
||||
'Identifier \'nume\' is not defined'));
|
||||
it('should reject access to potentially undefined field',
|
||||
() => reject(
|
||||
`<div>{{maybe_person.name.first}}`,
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import * as ts from 'typescript/lib/tsserverlibrary';
|
||||
|
||||
import {EMPTY_SYMBOL_TABLE, createGlobalSymbolTable} from '../src/global_symbols';
|
||||
import {createGlobalSymbolTable, EMPTY_SYMBOL_TABLE} from '../src/global_symbols';
|
||||
import {getSymbolQuery} from '../src/typescript_symbols';
|
||||
|
||||
import {MockTypescriptHost} from './test_utils';
|
||||
@ -18,7 +18,7 @@ describe('GlobalSymbolTable', () => {
|
||||
const tsLS = ts.createLanguageService(mockHost);
|
||||
|
||||
it(`contains $any()`, () => {
|
||||
const program = tsLS.getProgram() !;
|
||||
const program = tsLS.getProgram()!;
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const source = ts.createSourceFile('foo.ts', '', ts.ScriptTarget.ES2015);
|
||||
const query = getSymbolQuery(program, typeChecker, source, () => EMPTY_SYMBOL_TABLE);
|
||||
|
@ -22,7 +22,9 @@ describe('hover', () => {
|
||||
const ngLSHost = new TypeScriptServiceHost(mockHost, tsLS);
|
||||
const ngLS = createLanguageService(ngLSHost);
|
||||
|
||||
beforeEach(() => { mockHost.reset(); });
|
||||
beforeEach(() => {
|
||||
mockHost.reset();
|
||||
});
|
||||
|
||||
describe('location of hover', () => {
|
||||
it('should find members in a text interpolation', () => {
|
||||
@ -30,7 +32,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.title: string');
|
||||
});
|
||||
@ -40,7 +42,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.title: string');
|
||||
});
|
||||
@ -50,7 +52,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.title: string');
|
||||
});
|
||||
@ -60,7 +62,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.title: string');
|
||||
});
|
||||
@ -70,7 +72,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.title: string');
|
||||
});
|
||||
@ -80,7 +82,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'anyValue');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.anyValue: any');
|
||||
});
|
||||
@ -92,7 +94,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeDefined();
|
||||
const documentation = toText(quickInfo !.documentation);
|
||||
const documentation = toText(quickInfo!.documentation);
|
||||
expect(documentation).toBe('This is the title of the `TemplateReference` Component.');
|
||||
});
|
||||
|
||||
@ -102,7 +104,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.title: string');
|
||||
});
|
||||
@ -112,7 +114,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(variable) hero: Hero');
|
||||
});
|
||||
@ -123,7 +125,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(variable) hero: Readonly<Hero>');
|
||||
});
|
||||
@ -133,7 +135,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'name');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(variable) name: { readonly name: "name"; }');
|
||||
});
|
||||
@ -144,7 +146,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'myClick');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(method) TemplateReference.myClick: (event: any) => void');
|
||||
});
|
||||
@ -154,7 +156,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'trackBy');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(method) NgForOf<T, U>.ngForTrackBy: TrackByFunction<T>');
|
||||
});
|
||||
@ -164,7 +166,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'heroes');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.heroes: Hero[]');
|
||||
});
|
||||
@ -175,7 +177,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'date');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts))
|
||||
.toBe(
|
||||
@ -187,7 +189,7 @@ describe('hover', () => {
|
||||
const position = content.indexOf('$any');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, position);
|
||||
expect(quickInfo).toBeDefined();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual({
|
||||
start: position,
|
||||
length: '$any(title)'.length,
|
||||
@ -202,7 +204,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeDefined();
|
||||
const documentation = toText(quickInfo !.documentation);
|
||||
const documentation = toText(quickInfo!.documentation);
|
||||
expect(documentation).toBe('This Component provides the `test-comp` selector.');
|
||||
});
|
||||
|
||||
@ -211,7 +213,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeDefined();
|
||||
const {displayParts, documentation} = quickInfo !;
|
||||
const {displayParts, documentation} = quickInfo!;
|
||||
expect(toText(displayParts))
|
||||
.toBe('(component) AppModule.TestComponent: typeof TestComponent');
|
||||
expect(toText(documentation)).toBe('This Component provides the `test-comp` selector.');
|
||||
@ -222,7 +224,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeDefined();
|
||||
const {displayParts, textSpan} = quickInfo !;
|
||||
const {displayParts, textSpan} = quickInfo!;
|
||||
expect(toText(displayParts)).toBe('(directive) AppModule.StringModel: typeof StringModel');
|
||||
expect(content.substring(textSpan.start, textSpan.start + textSpan.length))
|
||||
.toBe('string-model');
|
||||
@ -233,7 +235,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'test');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(event) TestComponent.testEvent: EventEmitter<any>');
|
||||
});
|
||||
@ -243,7 +245,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'tcName');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TestComponent.name: string');
|
||||
});
|
||||
@ -254,7 +256,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'model');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) StringModel.model: string');
|
||||
});
|
||||
@ -264,7 +266,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'ngFor');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(directive) NgForOf: typeof NgForOf');
|
||||
});
|
||||
@ -272,12 +274,12 @@ describe('hover', () => {
|
||||
|
||||
describe('hovering on TypeScript nodes', () => {
|
||||
it('should work for component TypeScript declarations', () => {
|
||||
const content = mockHost.readFile(PARSING_CASES) !;
|
||||
const content = mockHost.readFile(PARSING_CASES)!;
|
||||
const position = content.indexOf('TemplateReference');
|
||||
expect(position).toBeGreaterThan(0);
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(PARSING_CASES, position);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual({
|
||||
start: position,
|
||||
length: 'TemplateReference'.length,
|
||||
@ -286,12 +288,12 @@ describe('hover', () => {
|
||||
});
|
||||
|
||||
it('should work for directive TypeScript declarations', () => {
|
||||
const content = mockHost.readFile(PARSING_CASES) !;
|
||||
const content = mockHost.readFile(PARSING_CASES)!;
|
||||
const position = content.indexOf('StringModel');
|
||||
expect(position).toBeGreaterThan(0);
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(PARSING_CASES, position);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual({
|
||||
start: position,
|
||||
length: 'StringModel'.length,
|
||||
@ -313,7 +315,7 @@ describe('hover', () => {
|
||||
const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
const {textSpan, displayParts} = quickInfo!;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(property) TemplateReference.title: string');
|
||||
});
|
||||
|
@ -32,7 +32,6 @@ describe('html_info', () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function uniqueElements<T>(a: T[], b: T[]): T[] {
|
||||
|
@ -21,20 +21,25 @@ describe('service without angular', () => {
|
||||
const fileName = '/app/test.ng';
|
||||
const position = mockHost.getLocationMarkerFor(fileName, 'h1-content').start;
|
||||
|
||||
beforeEach(() => { mockHost.reset(); });
|
||||
beforeEach(() => {
|
||||
mockHost.reset();
|
||||
});
|
||||
|
||||
it('should not crash a get diagnostics',
|
||||
() => { expect(() => ngService.getSemanticDiagnostics(fileName)).not.toThrow(); });
|
||||
it('should not crash a get diagnostics', () => {
|
||||
expect(() => ngService.getSemanticDiagnostics(fileName)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not crash a completion',
|
||||
() => { expect(() => ngService.getCompletionsAtPosition(fileName, position)).not.toThrow(); });
|
||||
it('should not crash a completion', () => {
|
||||
expect(() => ngService.getCompletionsAtPosition(fileName, position)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not crash a get definition', () => {
|
||||
expect(() => ngService.getDefinitionAndBoundSpan(fileName, position)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not crash a hover',
|
||||
() => { expect(() => ngService.getQuickInfoAtPosition(fileName, position)).not.toThrow(); });
|
||||
it('should not crash a hover', () => {
|
||||
expect(() => ngService.getQuickInfoAtPosition(fileName, position)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not crash with an incomplete class', () => {
|
||||
mockHost.addCode('\nexport class');
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AotSummaryResolver, CompileMetadataResolver, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, TemplateParser, analyzeNgModules, createOfflineCompileUrlResolver} from '@angular/compiler';
|
||||
import {analyzeNgModules, AotSummaryResolver, CompileMetadataResolver, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, TemplateParser} from '@angular/compiler';
|
||||
import {Directory, MockAotContext} from '@angular/compiler-cli/test/mocks';
|
||||
import {setup} from '@angular/compiler-cli/test/test_support';
|
||||
import {ViewEncapsulation, ɵConsole as Console} from '@angular/core';
|
||||
@ -45,11 +45,17 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost {
|
||||
this.context = new MockAotContext(currentDirectory, files);
|
||||
}
|
||||
|
||||
getCompilationSettings(): ts.CompilerOptions { return this.options; }
|
||||
getCompilationSettings(): ts.CompilerOptions {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
getScriptFileNames(): string[] { return this.scripts; }
|
||||
getScriptFileNames(): string[] {
|
||||
return this.scripts;
|
||||
}
|
||||
|
||||
getScriptVersion(fileName: string): string { return '0'; }
|
||||
getScriptVersion(fileName: string): string {
|
||||
return '0';
|
||||
}
|
||||
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot|undefined {
|
||||
const content = this.internalReadFile(fileName);
|
||||
@ -58,15 +64,25 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost {
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentDirectory(): string { return this.context.currentDirectory; }
|
||||
getCurrentDirectory(): string {
|
||||
return this.context.currentDirectory;
|
||||
}
|
||||
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; }
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string {
|
||||
return 'lib.d.ts';
|
||||
}
|
||||
|
||||
readFile(fileName: string): string { return this.internalReadFile(fileName) as string; }
|
||||
readFile(fileName: string): string {
|
||||
return this.internalReadFile(fileName) as string;
|
||||
}
|
||||
|
||||
readResource(fileName: string): Promise<string> { return Promise.resolve(''); }
|
||||
readResource(fileName: string): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
assumeFileExists(fileName: string): void { this.assumedExist.add(fileName); }
|
||||
assumeFileExists(fileName: string): void {
|
||||
this.assumedExist.add(fileName);
|
||||
}
|
||||
|
||||
fileExists(fileName: string): boolean {
|
||||
return this.assumedExist.has(fileName) || this.internalReadFile(fileName) != null;
|
||||
@ -99,10 +115,18 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost {
|
||||
const staticSymbolCache = new StaticSymbolCache();
|
||||
const summaryResolver = new AotSummaryResolver(
|
||||
{
|
||||
loadSummary(filePath: string) { return null; },
|
||||
isSourceFile(sourceFilePath: string) { return true; },
|
||||
toSummaryFileName(sourceFilePath: string) { return sourceFilePath; },
|
||||
fromSummaryFileName(filePath: string): string{return filePath;},
|
||||
loadSummary(filePath: string) {
|
||||
return null;
|
||||
},
|
||||
isSourceFile(sourceFilePath: string) {
|
||||
return true;
|
||||
},
|
||||
toSummaryFileName(sourceFilePath: string) {
|
||||
return sourceFilePath;
|
||||
},
|
||||
fromSummaryFileName(filePath: string): string {
|
||||
return filePath;
|
||||
},
|
||||
},
|
||||
staticSymbolCache);
|
||||
|
||||
@ -117,7 +141,9 @@ export class DiagnosticContext {
|
||||
public service: ts.LanguageService, public program: ts.Program,
|
||||
public checker: ts.TypeChecker, public host: StaticSymbolResolverHost) {}
|
||||
|
||||
private collectError(e: any, path?: string) { this._errors.push({e, path}); }
|
||||
private collectError(e: any, path?: string) {
|
||||
this._errors.push({e, path});
|
||||
}
|
||||
|
||||
private get staticSymbolResolver(): StaticSymbolResolver {
|
||||
let result = this._staticSymbolResolver;
|
||||
@ -133,7 +159,7 @@ export class DiagnosticContext {
|
||||
if (!this._reflector) {
|
||||
const ssr = this.staticSymbolResolver;
|
||||
const result = this._reflector = new StaticReflector(
|
||||
summaryResolver, ssr, [], [], (e, filePath) => this.collectError(e, filePath !));
|
||||
summaryResolver, ssr, [], [], (e, filePath) => this.collectError(e, filePath!));
|
||||
this._reflector = result;
|
||||
return result;
|
||||
}
|
||||
@ -148,11 +174,15 @@ export class DiagnosticContext {
|
||||
const pipeResolver = new PipeResolver(this.reflector);
|
||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
||||
const resourceLoader = new class extends ResourceLoader {
|
||||
get(url: string): Promise<string> { return Promise.resolve(''); }
|
||||
get(url: string): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
};
|
||||
const urlResolver = createOfflineCompileUrlResolver();
|
||||
const htmlParser = new class extends HtmlParser {
|
||||
parse(): ParseTreeResult { return new ParseTreeResult([], []); }
|
||||
parse(): ParseTreeResult {
|
||||
return new ParseTreeResult([], []);
|
||||
}
|
||||
};
|
||||
|
||||
// This tracks the CompileConfig in codegen.ts. Currently these options
|
||||
@ -174,7 +204,11 @@ export class DiagnosticContext {
|
||||
get analyzedModules(): NgAnalyzedModules {
|
||||
let analyzedModules = this._analyzedModules;
|
||||
if (!analyzedModules) {
|
||||
const analyzeHost = {isSourceFile(filePath: string) { return true; }};
|
||||
const analyzeHost = {
|
||||
isSourceFile(filePath: string) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
const programFiles = this.program.getSourceFiles().map(sf => sf.fileName);
|
||||
analyzedModules = this._analyzedModules =
|
||||
analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver);
|
||||
@ -198,7 +232,7 @@ function compileTemplate(context: DiagnosticContext, type: StaticSymbol, templat
|
||||
const config = new CompilerConfig();
|
||||
const parser = new TemplateParser(
|
||||
config, context.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser,
|
||||
null !, []);
|
||||
null!, []);
|
||||
const htmlResult = htmlParser.parse(template, '', {tokenizeExpansionForms: true});
|
||||
const analyzedModules = context.analyzedModules;
|
||||
// let errors: Diagnostic[]|undefined = undefined;
|
||||
@ -214,8 +248,11 @@ function compileTemplate(context: DiagnosticContext, type: StaticSymbol, templat
|
||||
return {
|
||||
htmlAst: htmlResult.rootNodes,
|
||||
templateAst: parseResult.templateAst,
|
||||
directive: metadata, directives, pipes,
|
||||
parseErrors: parseResult.errors, expressionParser
|
||||
directive: metadata,
|
||||
directives,
|
||||
pipes,
|
||||
parseErrors: parseResult.errors,
|
||||
expressionParser
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -236,7 +273,9 @@ export function getDiagnosticTemplateInfo(
|
||||
sourceFile, context.program, context.checker, compiledTemplate.pipes));
|
||||
return {
|
||||
fileName: templateFile,
|
||||
offset: 0, query, members,
|
||||
offset: 0,
|
||||
query,
|
||||
members,
|
||||
htmlAst: compiledTemplate.htmlAst,
|
||||
templateAst: compiledTemplate.templateAst,
|
||||
source: sourceFile.text,
|
||||
@ -246,6 +285,6 @@ export function getDiagnosticTemplateInfo(
|
||||
}
|
||||
}
|
||||
|
||||
function removeMissing<T>(values: (T | null | undefined)[]): T[] {
|
||||
function removeMissing<T>(values: (T|null|undefined)[]): T[] {
|
||||
return values.filter(e => !!e) as T[];
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import {TypeScriptServiceHost} from '../src/typescript_host';
|
||||
import {MockTypescriptHost} from './test_utils';
|
||||
|
||||
describe('reflector_host_spec', () => {
|
||||
|
||||
// Regression #21811
|
||||
it('should be able to find angular under windows', () => {
|
||||
const originalJoin = path.join;
|
||||
@ -24,15 +23,16 @@ describe('reflector_host_spec', () => {
|
||||
new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], 'node_modules', {
|
||||
...path,
|
||||
join: (...args: string[]) => originalJoin.apply(path, args),
|
||||
posix:
|
||||
{...path.posix, join: (...args: string[]) => originalPosixJoin.apply(path, args)}
|
||||
posix: {...path.posix, join: (...args: string[]) => originalPosixJoin.apply(path, args)}
|
||||
});
|
||||
const reflectorHost = new ReflectorHost(() => undefined as any, mockHost);
|
||||
|
||||
if (process.platform !== 'win32') {
|
||||
// If we call this in Windows it will cause a 'Maximum call stack size exceeded error'
|
||||
// Because we are spying on the same function that we are call faking
|
||||
spyOn(path, 'join').and.callFake((...args: string[]) => { return path.win32.join(...args); });
|
||||
spyOn(path, 'join').and.callFake((...args: string[]) => {
|
||||
return path.win32.join(...args);
|
||||
});
|
||||
}
|
||||
|
||||
const result = reflectorHost.moduleNameToFileName('@angular/core');
|
||||
|
@ -11,7 +11,6 @@ import {getClassDeclFromDecoratorProp} from '../src/template';
|
||||
import {MockTypescriptHost} from './test_utils';
|
||||
|
||||
describe('getClassDeclFromTemplateNode', () => {
|
||||
|
||||
it('should find class declaration in syntax-only mode', () => {
|
||||
const sourceFile = ts.createSourceFile(
|
||||
'foo.ts', `
|
||||
@ -28,24 +27,24 @@ describe('getClassDeclFromTemplateNode', () => {
|
||||
}
|
||||
const classDecl = sourceFile.forEachChild(visit);
|
||||
expect(classDecl).toBeTruthy();
|
||||
expect(classDecl !.kind).toBe(ts.SyntaxKind.ClassDeclaration);
|
||||
expect((classDecl as ts.ClassDeclaration).name !.text).toBe('MyComponent');
|
||||
expect(classDecl!.kind).toBe(ts.SyntaxKind.ClassDeclaration);
|
||||
expect((classDecl as ts.ClassDeclaration).name!.text).toBe('MyComponent');
|
||||
});
|
||||
|
||||
|
||||
it('should return class declaration for AppComponent', () => {
|
||||
const host = new MockTypescriptHost(['/app/app.component.ts']);
|
||||
const tsLS = ts.createLanguageService(host);
|
||||
const sourceFile = tsLS.getProgram() !.getSourceFile('/app/app.component.ts');
|
||||
const sourceFile = tsLS.getProgram()!.getSourceFile('/app/app.component.ts');
|
||||
expect(sourceFile).toBeTruthy();
|
||||
const classDecl = sourceFile !.forEachChild(function visit(node): ts.Node | undefined {
|
||||
const classDecl = sourceFile!.forEachChild(function visit(node): ts.Node|undefined {
|
||||
if (ts.isPropertyAssignment(node)) {
|
||||
return getClassDeclFromDecoratorProp(node);
|
||||
}
|
||||
return node.forEachChild(visit);
|
||||
});
|
||||
expect(classDecl).toBeTruthy();
|
||||
expect(ts.isClassDeclaration(classDecl !)).toBe(true);
|
||||
expect((classDecl as ts.ClassDeclaration).name !.text).toBe('AppComponent');
|
||||
expect(ts.isClassDeclaration(classDecl!)).toBe(true);
|
||||
expect((classDecl as ts.ClassDeclaration).name!.text).toBe('AppComponent');
|
||||
});
|
||||
});
|
||||
|
@ -57,11 +57,11 @@ function isFile(path: string) {
|
||||
function loadTourOfHeroes(): ReadonlyMap<string, string> {
|
||||
const {TEST_SRCDIR} = process.env;
|
||||
const root =
|
||||
path.join(TEST_SRCDIR !, 'angular', 'packages', 'language-service', 'test', 'project');
|
||||
path.join(TEST_SRCDIR!, 'angular', 'packages', 'language-service', 'test', 'project');
|
||||
const dirs = [root];
|
||||
const files = new Map<string, string>();
|
||||
while (dirs.length) {
|
||||
const dirPath = dirs.pop() !;
|
||||
const dirPath = dirs.pop()!;
|
||||
for (const filePath of fs.readdirSync(dirPath)) {
|
||||
const absPath = path.join(dirPath, filePath);
|
||||
if (isFile(absPath)) {
|
||||
@ -140,11 +140,17 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||
this.projectVersion++;
|
||||
}
|
||||
|
||||
getCompilationSettings(): ts.CompilerOptions { return {...this.options}; }
|
||||
getCompilationSettings(): ts.CompilerOptions {
|
||||
return {...this.options};
|
||||
}
|
||||
|
||||
getProjectVersion(): string { return this.projectVersion.toString(); }
|
||||
getProjectVersion(): string {
|
||||
return this.projectVersion.toString();
|
||||
}
|
||||
|
||||
getScriptFileNames(): string[] { return this.scriptNames; }
|
||||
getScriptFileNames(): string[] {
|
||||
return this.scriptNames;
|
||||
}
|
||||
|
||||
getScriptVersion(fileName: string): string {
|
||||
return (this.scriptVersion.get(fileName) || 0).toString();
|
||||
@ -156,9 +162,13 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getCurrentDirectory(): string { return '/'; }
|
||||
getCurrentDirectory(): string {
|
||||
return '/';
|
||||
}
|
||||
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; }
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string {
|
||||
return 'lib.d.ts';
|
||||
}
|
||||
|
||||
directoryExists(directoryName: string): boolean {
|
||||
if (this.overrideDirectory.has(directoryName)) return true;
|
||||
@ -172,7 +182,9 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||
return this.pathExists(effectiveName);
|
||||
}
|
||||
|
||||
fileExists(fileName: string): boolean { return this.getRawFileContent(fileName) != null; }
|
||||
fileExists(fileName: string): boolean {
|
||||
return this.getRawFileContent(fileName) != null;
|
||||
}
|
||||
|
||||
readFile(fileName: string): string|undefined {
|
||||
const content = this.getRawFileContent(fileName);
|
||||
@ -242,7 +254,7 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||
|
||||
private pathExists(path: string): boolean {
|
||||
if (this.existsCache.has(path)) {
|
||||
return this.existsCache.get(path) !;
|
||||
return this.existsCache.get(path)!;
|
||||
}
|
||||
|
||||
const exists = fs.existsSync(path);
|
||||
@ -411,8 +423,9 @@ function getReferenceMarkers(value: string): ReferenceResult {
|
||||
|
||||
let adjustment = 0;
|
||||
const text = value.replace(
|
||||
referenceMarker, (match: string, text: string, reference: string, _: string,
|
||||
definition: string, definitionName: string, index: number): string => {
|
||||
referenceMarker,
|
||||
(match: string, text: string, reference: string, _: string, definition: string,
|
||||
definitionName: string, index: number): string => {
|
||||
const result = reference ? text : text.replace(/ᐱ/g, '');
|
||||
const span: Span = {start: index - adjustment, end: index - adjustment + result.length};
|
||||
const markers = reference ? references : definitions;
|
||||
|
@ -26,7 +26,7 @@ const mockProject = {
|
||||
describe('plugin', () => {
|
||||
const mockHost = new MockTypescriptHost(['/app/main.ts']);
|
||||
const tsLS = ts.createLanguageService(mockHost);
|
||||
const program = tsLS.getProgram() !;
|
||||
const program = tsLS.getProgram()!;
|
||||
const plugin = create({
|
||||
languageService: tsLS,
|
||||
languageServiceHost: mockHost,
|
||||
@ -35,7 +35,9 @@ describe('plugin', () => {
|
||||
config: {},
|
||||
});
|
||||
|
||||
beforeEach(() => { mockHost.reset(); });
|
||||
beforeEach(() => {
|
||||
mockHost.reset();
|
||||
});
|
||||
|
||||
it('should produce TypeScript diagnostics', () => {
|
||||
const fileName = '/foo.ts';
|
||||
@ -117,7 +119,7 @@ describe('plugin', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(MY_COMPONENT, 'tree');
|
||||
const completions = plugin.getCompletionsAtPosition(MY_COMPONENT, marker.start, undefined);
|
||||
expect(completions).toBeDefined();
|
||||
expect(completions !.entries).toEqual([
|
||||
expect(completions!.entries).toEqual([
|
||||
{
|
||||
name: 'children',
|
||||
kind: CompletionKind.PROPERTY as any,
|
||||
|
@ -10,7 +10,7 @@ import * as ts from 'typescript';
|
||||
|
||||
import {TypeScriptServiceHost} from '../src/typescript_host';
|
||||
|
||||
import {MockTypescriptHost, findDirectiveMetadataByName} from './test_utils';
|
||||
import {findDirectiveMetadataByName, MockTypescriptHost} from './test_utils';
|
||||
|
||||
|
||||
describe('TypeScriptServiceHost', () => {
|
||||
@ -62,7 +62,7 @@ describe('TypeScriptServiceHost', () => {
|
||||
expect(oldModules.ngModules).toEqual([]);
|
||||
// Now add a script, this would change the program
|
||||
const fileName = '/app/main.ts';
|
||||
const content = tsLSHost.readFile(fileName) !;
|
||||
const content = tsLSHost.readFile(fileName)!;
|
||||
tsLSHost.addScript(fileName, content);
|
||||
// If the caches are not cleared, we would get back an empty array.
|
||||
// But if the caches are cleared then the analyzed modules will be non-empty.
|
||||
@ -121,8 +121,8 @@ describe('TypeScriptServiceHost', () => {
|
||||
expect(oldModules.symbolsMissingModule).toEqual([]);
|
||||
// Expect to find AppComponent in the old modules
|
||||
const oldFile = oldModules.files.find(f => f.fileName === fileName);
|
||||
expect(oldFile !.directives.length).toBe(1);
|
||||
const appComp = oldFile !.directives[0];
|
||||
expect(oldFile!.directives.length).toBe(1);
|
||||
const appComp = oldFile!.directives[0];
|
||||
expect(appComp.name).toBe('AppComponent');
|
||||
expect(oldModules.ngModuleByPipeOrDirective.has(appComp)).toBe(true);
|
||||
|
||||
@ -154,8 +154,8 @@ describe('TypeScriptServiceHost', () => {
|
||||
expect(newModules.symbolsMissingModule).toEqual([]);
|
||||
// Expect to find HelloComponent in the new modules
|
||||
const newFile = newModules.files.find(f => f.fileName === fileName);
|
||||
expect(newFile !.directives.length).toBe(1);
|
||||
const helloComp = newFile !.directives[0];
|
||||
expect(newFile!.directives.length).toBe(1);
|
||||
const helloComp = newFile!.directives[0];
|
||||
expect(helloComp.name).toBe('HelloComponent');
|
||||
expect(newModules.ngModuleByPipeOrDirective.has(helloComp)).toBe(true);
|
||||
expect(newModules.ngModuleByPipeOrDirective.has(appComp)).toBe(false);
|
||||
|
@ -18,9 +18,15 @@ import {DiagnosticContext, MockLanguageServiceHost} from './mocks';
|
||||
function emptyPipes(): SymbolTable {
|
||||
return {
|
||||
size: 0,
|
||||
get(key: string) { return undefined; },
|
||||
has(key: string) { return false; },
|
||||
values(): Symbol[]{return [];}
|
||||
get(key: string) {
|
||||
return undefined;
|
||||
},
|
||||
has(key: string) {
|
||||
return false;
|
||||
},
|
||||
values(): Symbol[] {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -35,9 +41,9 @@ describe('symbol query', () => {
|
||||
const host = new MockLanguageServiceHost(
|
||||
['/quickstart/app/app.component.ts'], QUICKSTART, '/quickstart');
|
||||
const service = ts.createLanguageService(host, registry);
|
||||
program = service.getProgram() !;
|
||||
program = service.getProgram()!;
|
||||
checker = program.getTypeChecker();
|
||||
sourceFile = program.getSourceFile('/quickstart/app/app.component.ts') !;
|
||||
sourceFile = program.getSourceFile('/quickstart/app/app.component.ts')!;
|
||||
const symbolResolverHost = new ReflectorHost(() => program, host);
|
||||
context = new DiagnosticContext(service, program, checker, symbolResolverHost);
|
||||
query = getSymbolQuery(program, checker, sourceFile, emptyPipes);
|
||||
@ -67,7 +73,7 @@ describe('symbol query', () => {
|
||||
} else {
|
||||
const symbol = query.getBuiltinType(builtinType);
|
||||
const got: ts.TypeFlags = (symbol as any).tsType.flags;
|
||||
expect(got).toBe(want !);
|
||||
expect(got).toBe(want!);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -75,8 +81,8 @@ describe('symbol query', () => {
|
||||
|
||||
describe('toSymbolTableFactory(tsVersion)', () => {
|
||||
it('should return a Map for versions of TypeScript >= 2.2', () => {
|
||||
const a = { name: 'a' } as ts.Symbol;
|
||||
const b = { name: 'b' } as ts.Symbol;
|
||||
const a = {name: 'a'} as ts.Symbol;
|
||||
const b = {name: 'b'} as ts.Symbol;
|
||||
expect(toSymbolTableFactory([a, b]) instanceof Map).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
@ -28,7 +28,7 @@ describe('getDirectiveClassLike', () => {
|
||||
}
|
||||
});
|
||||
expect(result).toBeTruthy();
|
||||
const {decoratorId, classId} = result !;
|
||||
const {decoratorId, classId} = result!;
|
||||
expect(decoratorId.kind).toBe(ts.SyntaxKind.Identifier);
|
||||
expect(decoratorId.text).toBe('NgModule');
|
||||
expect(classId.text).toBe('AppModule');
|
||||
|
Reference in New Issue
Block a user