refactor(language-service): Return ts.Diagnostic[] for getDiagnostics (#32115)
Part 2/3 of language service refactoring: Now that the language service is a proper tsserver plugin, all LS interfaces should return TS values. This PR refactors the ng.getDiagnostics() API to return ts.Diagnostic[] instead of ng.Diagnostic[]. PR Close #32115
This commit is contained in:
parent
a91ab15525
commit
a5f39aeda6
@ -7,13 +7,52 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {NgAnalyzedModules, StaticSymbol} from '@angular/compiler';
|
import {NgAnalyzedModules, StaticSymbol} from '@angular/compiler';
|
||||||
|
import {DiagnosticTemplateInfo, getTemplateExpressionDiagnostics} from '@angular/compiler-cli/src/language_services';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {AstResult} from './common';
|
import {AstResult} from './common';
|
||||||
import {Declarations, Diagnostic, DiagnosticKind, DiagnosticMessageChain, Diagnostics, Span, TemplateSource} from './types';
|
import {Declarations, Diagnostic, DiagnosticKind, DiagnosticMessageChain, Diagnostics, Span, TemplateSource} from './types';
|
||||||
|
import {offsetSpan, spanOf} from './utils';
|
||||||
|
|
||||||
export interface AstProvider {
|
export interface AstProvider {
|
||||||
getTemplateAst(template: TemplateSource, fileName: string): AstResult;
|
getTemplateAst(template: TemplateSource, fileName: string): AstResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTemplateDiagnostics(template: TemplateSource, ast: AstResult): Diagnostics {
|
||||||
|
const results: Diagnostics = [];
|
||||||
|
|
||||||
|
if (ast.parseErrors && ast.parseErrors.length) {
|
||||||
|
results.push(...ast.parseErrors.map<Diagnostic>(e => {
|
||||||
|
return {
|
||||||
|
kind: DiagnosticKind.Error,
|
||||||
|
span: offsetSpan(spanOf(e.span), template.span.start),
|
||||||
|
message: e.msg,
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
} else if (ast.templateAst && ast.htmlAst) {
|
||||||
|
const info: DiagnosticTemplateInfo = {
|
||||||
|
templateAst: ast.templateAst,
|
||||||
|
htmlAst: ast.htmlAst,
|
||||||
|
offset: template.span.start,
|
||||||
|
query: template.query,
|
||||||
|
members: template.members,
|
||||||
|
};
|
||||||
|
const expressionDiagnostics = getTemplateExpressionDiagnostics(info);
|
||||||
|
results.push(...expressionDiagnostics);
|
||||||
|
}
|
||||||
|
if (ast.errors) {
|
||||||
|
results.push(...ast.errors.map<Diagnostic>(e => {
|
||||||
|
return {
|
||||||
|
kind: e.kind,
|
||||||
|
span: e.span || template.span,
|
||||||
|
message: e.message,
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
export function getDeclarationDiagnostics(
|
export function getDeclarationDiagnostics(
|
||||||
declarations: Declarations, modules: NgAnalyzedModules): Diagnostics {
|
declarations: Declarations, modules: NgAnalyzedModules): Diagnostics {
|
||||||
const results: Diagnostics = [];
|
const results: Diagnostics = [];
|
||||||
@ -60,3 +99,34 @@ export function getDeclarationDiagnostics(
|
|||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function diagnosticChainToDiagnosticChain(chain: DiagnosticMessageChain):
|
||||||
|
ts.DiagnosticMessageChain {
|
||||||
|
return {
|
||||||
|
messageText: chain.message,
|
||||||
|
category: ts.DiagnosticCategory.Error,
|
||||||
|
code: 0,
|
||||||
|
next: chain.next ? diagnosticChainToDiagnosticChain(chain.next) : undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function diagnosticMessageToDiagnosticMessageText(message: string | DiagnosticMessageChain): string|
|
||||||
|
ts.DiagnosticMessageChain {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
return diagnosticChainToDiagnosticChain(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ngDiagnosticToTsDiagnostic(
|
||||||
|
d: Diagnostic, file: ts.SourceFile | undefined): ts.Diagnostic {
|
||||||
|
return {
|
||||||
|
file,
|
||||||
|
start: d.span.start,
|
||||||
|
length: d.span.end - d.span.start,
|
||||||
|
messageText: diagnosticMessageToDiagnosticMessageText(d.message),
|
||||||
|
category: ts.DiagnosticCategory.Error,
|
||||||
|
code: 0,
|
||||||
|
source: 'ng',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -6,16 +6,15 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileMetadataResolver, CompilePipeSummary} from '@angular/compiler';
|
import {CompilePipeSummary} from '@angular/compiler';
|
||||||
import {DiagnosticTemplateInfo, getTemplateExpressionDiagnostics} from '@angular/compiler-cli/src/language_services';
|
|
||||||
import * as tss from 'typescript/lib/tsserverlibrary';
|
import * as tss from 'typescript/lib/tsserverlibrary';
|
||||||
|
|
||||||
import {getTemplateCompletions} from './completions';
|
import {getTemplateCompletions} from './completions';
|
||||||
import {getDefinitionAndBoundSpan} from './definitions';
|
import {getDefinitionAndBoundSpan} from './definitions';
|
||||||
import {getDeclarationDiagnostics} from './diagnostics';
|
import {getDeclarationDiagnostics, getTemplateDiagnostics, ngDiagnosticToTsDiagnostic} from './diagnostics';
|
||||||
import {getHover} from './hover';
|
import {getHover} from './hover';
|
||||||
import {Completion, Diagnostic, DiagnosticKind, Diagnostics, Hover, LanguageService, LanguageServiceHost, Location, Span, TemplateSource} from './types';
|
import {Completion, Diagnostic, LanguageService, Span} from './types';
|
||||||
import {offsetSpan, spanOf} from './utils';
|
import {TypeScriptServiceHost} from './typescript_host';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,20 +22,21 @@ import {offsetSpan, spanOf} from './utils';
|
|||||||
*
|
*
|
||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export function createLanguageService(host: LanguageServiceHost): LanguageService {
|
export function createLanguageService(host: TypeScriptServiceHost): LanguageService {
|
||||||
return new LanguageServiceImpl(host);
|
return new LanguageServiceImpl(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
class LanguageServiceImpl implements LanguageService {
|
class LanguageServiceImpl implements LanguageService {
|
||||||
constructor(private host: LanguageServiceHost) {}
|
constructor(private readonly host: TypeScriptServiceHost) {}
|
||||||
|
|
||||||
getTemplateReferences(): string[] { return this.host.getTemplateReferences(); }
|
getTemplateReferences(): string[] { return this.host.getTemplateReferences(); }
|
||||||
|
|
||||||
getDiagnostics(fileName: string): Diagnostic[] {
|
getDiagnostics(fileName: string): tss.Diagnostic[] {
|
||||||
const results: Diagnostic[] = [];
|
const results: Diagnostic[] = [];
|
||||||
const templates = this.host.getTemplates(fileName);
|
const templates = this.host.getTemplates(fileName);
|
||||||
if (templates && templates.length) {
|
for (const template of templates) {
|
||||||
results.push(...this.getTemplateDiagnostics(fileName, templates));
|
const ast = this.host.getTemplateAst(template, fileName);
|
||||||
|
results.push(...getTemplateDiagnostics(template, ast));
|
||||||
}
|
}
|
||||||
|
|
||||||
const declarations = this.host.getDeclarations(fileName);
|
const declarations = this.host.getDeclarations(fileName);
|
||||||
@ -44,8 +44,11 @@ class LanguageServiceImpl implements LanguageService {
|
|||||||
const summary = this.host.getAnalyzedModules();
|
const summary = this.host.getAnalyzedModules();
|
||||||
results.push(...getDeclarationDiagnostics(declarations, summary));
|
results.push(...getDeclarationDiagnostics(declarations, summary));
|
||||||
}
|
}
|
||||||
|
if (!results.length) {
|
||||||
return uniqueBySpan(results);
|
return [];
|
||||||
|
}
|
||||||
|
const sourceFile = fileName.endsWith('.ts') ? this.host.getSourceFile(fileName) : undefined;
|
||||||
|
return uniqueBySpan(results).map(d => ngDiagnosticToTsDiagnostic(d, sourceFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
getPipesAt(fileName: string, position: number): CompilePipeSummary[] {
|
getPipesAt(fileName: string, position: number): CompilePipeSummary[] {
|
||||||
@ -76,38 +79,6 @@ class LanguageServiceImpl implements LanguageService {
|
|||||||
return getHover(templateInfo);
|
return getHover(templateInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTemplateDiagnostics(fileName: string, templates: TemplateSource[]): Diagnostics {
|
|
||||||
const results: Diagnostics = [];
|
|
||||||
for (const template of templates) {
|
|
||||||
const ast = this.host.getTemplateAst(template, fileName);
|
|
||||||
if (ast) {
|
|
||||||
if (ast.parseErrors && ast.parseErrors.length) {
|
|
||||||
results.push(...ast.parseErrors.map<Diagnostic>(
|
|
||||||
e => ({
|
|
||||||
kind: DiagnosticKind.Error,
|
|
||||||
span: offsetSpan(spanOf(e.span), template.span.start),
|
|
||||||
message: e.msg
|
|
||||||
})));
|
|
||||||
} else if (ast.templateAst && ast.htmlAst) {
|
|
||||||
const info: DiagnosticTemplateInfo = {
|
|
||||||
templateAst: ast.templateAst,
|
|
||||||
htmlAst: ast.htmlAst,
|
|
||||||
offset: template.span.start,
|
|
||||||
query: template.query,
|
|
||||||
members: template.members
|
|
||||||
};
|
|
||||||
const expressionDiagnostics = getTemplateExpressionDiagnostics(info);
|
|
||||||
results.push(...expressionDiagnostics);
|
|
||||||
}
|
|
||||||
if (ast.errors) {
|
|
||||||
results.push(...ast.errors.map<Diagnostic>(
|
|
||||||
e => ({kind: e.kind, span: e.span || template.span, message: e.message})));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function uniqueBySpan<T extends{span: Span}>(elements: T[]): T[] {
|
function uniqueBySpan<T extends{span: Span}>(elements: T[]): T[] {
|
||||||
|
@ -10,7 +10,7 @@ import * as ts from 'typescript'; // used as value, passed in by tsserver at run
|
|||||||
import * as tss from 'typescript/lib/tsserverlibrary'; // used as type only
|
import * as tss from 'typescript/lib/tsserverlibrary'; // used as type only
|
||||||
|
|
||||||
import {createLanguageService} from './language_service';
|
import {createLanguageService} from './language_service';
|
||||||
import {Completion, Diagnostic, DiagnosticMessageChain} from './types';
|
import {Completion} from './types';
|
||||||
import {TypeScriptServiceHost} from './typescript_host';
|
import {TypeScriptServiceHost} from './typescript_host';
|
||||||
|
|
||||||
const projectHostMap = new WeakMap<tss.server.Project, TypeScriptServiceHost>();
|
const projectHostMap = new WeakMap<tss.server.Project, TypeScriptServiceHost>();
|
||||||
@ -33,36 +33,6 @@ function completionToEntry(c: Completion): tss.CompletionEntry {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function diagnosticChainToDiagnosticChain(chain: DiagnosticMessageChain):
|
|
||||||
ts.DiagnosticMessageChain {
|
|
||||||
return {
|
|
||||||
messageText: chain.message,
|
|
||||||
category: ts.DiagnosticCategory.Error,
|
|
||||||
code: 0,
|
|
||||||
next: chain.next ? diagnosticChainToDiagnosticChain(chain.next) : undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function diagnosticMessageToDiagnosticMessageText(message: string | DiagnosticMessageChain): string|
|
|
||||||
tss.DiagnosticMessageChain {
|
|
||||||
if (typeof message === 'string') {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
return diagnosticChainToDiagnosticChain(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function diagnosticToDiagnostic(d: Diagnostic, file: tss.SourceFile | undefined): tss.Diagnostic {
|
|
||||||
return {
|
|
||||||
file,
|
|
||||||
start: d.span.start,
|
|
||||||
length: d.span.end - d.span.start,
|
|
||||||
messageText: diagnosticMessageToDiagnosticMessageText(d.message),
|
|
||||||
category: ts.DiagnosticCategory.Error,
|
|
||||||
code: 0,
|
|
||||||
source: 'ng'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
|
export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
|
||||||
const {project, languageService: tsLS, languageServiceHost: tsLSHost, config} = info;
|
const {project, languageService: tsLS, languageServiceHost: tsLSHost, config} = info;
|
||||||
// This plugin could operate under two different modes:
|
// This plugin could operate under two different modes:
|
||||||
@ -115,16 +85,10 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
|
|||||||
function getSemanticDiagnostics(fileName: string): tss.Diagnostic[] {
|
function getSemanticDiagnostics(fileName: string): tss.Diagnostic[] {
|
||||||
const results: tss.Diagnostic[] = [];
|
const results: tss.Diagnostic[] = [];
|
||||||
if (!angularOnly) {
|
if (!angularOnly) {
|
||||||
const tsResults = tsLS.getSemanticDiagnostics(fileName);
|
results.push(...tsLS.getSemanticDiagnostics(fileName));
|
||||||
results.push(...tsResults);
|
|
||||||
}
|
}
|
||||||
// For semantic diagnostics we need to combine both TS + Angular results
|
// For semantic diagnostics we need to combine both TS + Angular results
|
||||||
const ngResults = ngLS.getDiagnostics(fileName);
|
results.push(...ngLS.getDiagnostics(fileName));
|
||||||
if (!ngResults.length) {
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
const sourceFile = fileName.endsWith('.ts') ? ngLSHost.getSourceFile(fileName) : undefined;
|
|
||||||
results.push(...ngResults.map(d => diagnosticToDiagnostic(d, sourceFile)));
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ export interface LanguageServiceHost {
|
|||||||
* Return the template source information for all templates in `fileName` or for `fileName` if
|
* Return the template source information for all templates in `fileName` or for `fileName` if
|
||||||
* it is a template file.
|
* it is a template file.
|
||||||
*/
|
*/
|
||||||
getTemplates(fileName: string): TemplateSources;
|
getTemplates(fileName: string): TemplateSource[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Angular declarations in the given file.
|
* Returns the Angular declarations in the given file.
|
||||||
@ -386,7 +386,7 @@ export interface LanguageService {
|
|||||||
/**
|
/**
|
||||||
* Returns a list of all error for all templates in the given file.
|
* Returns a list of all error for all templates in the given file.
|
||||||
*/
|
*/
|
||||||
getDiagnostics(fileName: string): Diagnostic[];
|
getDiagnostics(fileName: string): tss.Diagnostic[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the completions at the given position.
|
* Return the completions at the given position.
|
||||||
|
@ -166,16 +166,16 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||||||
return analyzedModules;
|
return analyzedModules;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTemplates(fileName: string): TemplateSources {
|
getTemplates(fileName: string): TemplateSource[] {
|
||||||
|
const results: TemplateSource[] = [];
|
||||||
if (fileName.endsWith('.ts')) {
|
if (fileName.endsWith('.ts')) {
|
||||||
let version = this.host.getScriptVersion(fileName);
|
let version = this.host.getScriptVersion(fileName);
|
||||||
let result: TemplateSource[] = [];
|
|
||||||
|
|
||||||
// Find each template string in the file
|
// Find each template string in the file
|
||||||
let visit = (child: ts.Node) => {
|
let visit = (child: ts.Node) => {
|
||||||
let templateSource = this.getSourceFromNode(fileName, version, child);
|
let templateSource = this.getSourceFromNode(fileName, version, child);
|
||||||
if (templateSource) {
|
if (templateSource) {
|
||||||
result.push(templateSource);
|
results.push(templateSource);
|
||||||
} else {
|
} else {
|
||||||
ts.forEachChild(child, visit);
|
ts.forEachChild(child, visit);
|
||||||
}
|
}
|
||||||
@ -185,17 +185,17 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||||||
if (sourceFile) {
|
if (sourceFile) {
|
||||||
ts.forEachChild(sourceFile, visit);
|
ts.forEachChild(sourceFile, visit);
|
||||||
}
|
}
|
||||||
return result.length ? result : undefined;
|
|
||||||
} else {
|
} else {
|
||||||
this.ensureTemplateMap();
|
this.ensureTemplateMap();
|
||||||
const componentSymbol = this.fileToComponent.get(fileName);
|
const componentSymbol = this.fileToComponent.get(fileName);
|
||||||
if (componentSymbol) {
|
if (componentSymbol) {
|
||||||
const templateSource = this.getTemplateAt(fileName, 0);
|
const templateSource = this.getTemplateAt(fileName, 0);
|
||||||
if (templateSource) {
|
if (templateSource) {
|
||||||
return [templateSource];
|
results.push(templateSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDeclarations(fileName: string): Declarations {
|
getDeclarations(fileName: string): Declarations {
|
||||||
|
@ -34,7 +34,7 @@ describe('diagnostics', () => {
|
|||||||
describe('for semantic errors', () => {
|
describe('for semantic errors', () => {
|
||||||
const fileName = '/app/test.ng';
|
const fileName = '/app/test.ng';
|
||||||
|
|
||||||
function diagnostics(template: string): Diagnostics {
|
function diagnostics(template: string): ts.Diagnostic[] {
|
||||||
try {
|
try {
|
||||||
mockHost.override(fileName, template);
|
mockHost.override(fileName, template);
|
||||||
return ngService.getDiagnostics(fileName) !;
|
return ngService.getDiagnostics(fileName) !;
|
||||||
@ -185,7 +185,7 @@ describe('diagnostics', () => {
|
|||||||
addCode(code, fileName => {
|
addCode(code, fileName => {
|
||||||
const diagnostic = findDiagnostic(ngService.getDiagnostics(fileName) !, 'pipe') !;
|
const diagnostic = findDiagnostic(ngService.getDiagnostics(fileName) !, 'pipe') !;
|
||||||
expect(diagnostic).not.toBeUndefined();
|
expect(diagnostic).not.toBeUndefined();
|
||||||
expect(diagnostic.span.end - diagnostic.span.start).toBeLessThan(11);
|
expect(diagnostic.length).toBeLessThan(11);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -379,13 +379,13 @@ describe('diagnostics', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectOnlyModuleDiagnostics(diagnostics: Diagnostics | undefined) {
|
function expectOnlyModuleDiagnostics(diagnostics: ts.Diagnostic[] | undefined) {
|
||||||
// Expect only the 'MyComponent' diagnostic
|
// Expect only the 'MyComponent' diagnostic
|
||||||
if (!diagnostics) throw new Error('Expecting Diagnostics');
|
if (!diagnostics) throw new Error('Expecting Diagnostics');
|
||||||
if (diagnostics.length > 1) {
|
if (diagnostics.length > 1) {
|
||||||
const unexpectedDiagnostics =
|
const unexpectedDiagnostics =
|
||||||
diagnostics.filter(diag => !diagnosticMessageContains(diag.message, 'MyComponent'))
|
diagnostics.filter(diag => !diagnosticMessageContains(diag.messageText, 'MyComponent'))
|
||||||
.map(diag => `(${diag.span.start}:${diag.span.end}): ${diag.message}`);
|
.map(diag => `(${diag.start}:${diag.start! + diag.length!}): ${diag.messageText}`);
|
||||||
|
|
||||||
if (unexpectedDiagnostics.length) {
|
if (unexpectedDiagnostics.length) {
|
||||||
fail(`Unexpected diagnostics:\n ${unexpectedDiagnostics.join('\n ')}`);
|
fail(`Unexpected diagnostics:\n ${unexpectedDiagnostics.join('\n ')}`);
|
||||||
@ -393,7 +393,7 @@ describe('diagnostics', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect(diagnostics.length).toBe(1);
|
expect(diagnostics.length).toBe(1);
|
||||||
expect(diagnosticMessageContains(diagnostics[0].message, 'MyComponent')).toBeTruthy();
|
expect(diagnosticMessageContains(diagnostics[0].messageText, 'MyComponent')).toBeTruthy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -331,18 +331,19 @@ function removeReferenceMarkers(value: string): string {
|
|||||||
return value.replace(referenceMarker, (match, text) => text.replace(/ᐱ/g, ''));
|
return value.replace(referenceMarker, (match, text) => text.replace(/ᐱ/g, ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function noDiagnostics(diagnostics: Diagnostics) {
|
export function noDiagnostics(diagnostics: ts.Diagnostic[]) {
|
||||||
if (diagnostics && diagnostics.length) {
|
if (diagnostics && diagnostics.length) {
|
||||||
throw new Error(`Unexpected diagnostics: \n ${diagnostics.map(d => d.message).join('\n ')}`);
|
throw new Error(
|
||||||
|
`Unexpected diagnostics: \n ${diagnostics.map(d => d.messageText).join('\n ')}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function diagnosticMessageContains(
|
export function diagnosticMessageContains(
|
||||||
message: string | DiagnosticMessageChain, messageFragment: string): boolean {
|
message: string | ts.DiagnosticMessageChain, messageFragment: string): boolean {
|
||||||
if (typeof message == 'string') {
|
if (typeof message == 'string') {
|
||||||
return message.indexOf(messageFragment) >= 0;
|
return message.indexOf(messageFragment) >= 0;
|
||||||
}
|
}
|
||||||
if (message.message.indexOf(messageFragment) >= 0) {
|
if (message.messageText.indexOf(messageFragment) >= 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (message.next) {
|
if (message.next) {
|
||||||
@ -351,16 +352,17 @@ export function diagnosticMessageContains(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findDiagnostic(diagnostics: Diagnostic[], messageFragment: string): Diagnostic|
|
export function findDiagnostic(
|
||||||
undefined {
|
diagnostics: ts.Diagnostic[], messageFragment: string): ts.Diagnostic|undefined {
|
||||||
return diagnostics.find(d => diagnosticMessageContains(d.message, messageFragment));
|
return diagnostics.find(d => diagnosticMessageContains(d.messageText, messageFragment));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function includeDiagnostic(
|
export function includeDiagnostic(
|
||||||
diagnostics: Diagnostics, message: string, text?: string, len?: string): void;
|
diagnostics: ts.Diagnostic[], message: string, text?: string, len?: string): void;
|
||||||
export function includeDiagnostic(
|
export function includeDiagnostic(
|
||||||
diagnostics: Diagnostics, message: string, at?: number, len?: number): void;
|
diagnostics: ts.Diagnostic[], message: string, at?: number, len?: number): void;
|
||||||
export function includeDiagnostic(diagnostics: Diagnostics, message: string, p1?: any, p2?: any) {
|
export function includeDiagnostic(
|
||||||
|
diagnostics: ts.Diagnostic[], message: string, p1?: any, p2?: any) {
|
||||||
expect(diagnostics).toBeDefined();
|
expect(diagnostics).toBeDefined();
|
||||||
if (diagnostics) {
|
if (diagnostics) {
|
||||||
const diagnostic = findDiagnostic(diagnostics, message);
|
const diagnostic = findDiagnostic(diagnostics, message);
|
||||||
@ -368,13 +370,12 @@ export function includeDiagnostic(diagnostics: Diagnostics, message: string, p1?
|
|||||||
if (diagnostic && p1 != null) {
|
if (diagnostic && p1 != null) {
|
||||||
const at = typeof p1 === 'number' ? p1 : p2.indexOf(p1);
|
const at = typeof p1 === 'number' ? p1 : p2.indexOf(p1);
|
||||||
const len = typeof p2 === 'number' ? p2 : p1.length;
|
const len = typeof p2 === 'number' ? p2 : p1.length;
|
||||||
expect(diagnostic.span.start)
|
expect(diagnostic.start)
|
||||||
.toEqual(
|
.toEqual(
|
||||||
at,
|
at,
|
||||||
`expected message '${message}' was reported at ${diagnostic.span.start} but should be ${at}`);
|
`expected message '${message}' was reported at ${diagnostic.start} but should be ${at}`);
|
||||||
if (len != null) {
|
if (len != null) {
|
||||||
expect(diagnostic.span.end - diagnostic.span.start)
|
expect(diagnostic.length).toEqual(len, `expected '${message}'s span length to be ${len}`);
|
||||||
.toEqual(len, `expected '${message}'s span length to be ${len}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user