refactor(language-service): Remove NgLSHost -> NgLS dependency (#31122)
``` NgLSHost: AngularLanguageServiceHost NgLS: AngularLanguageService ``` NgLSHost should not depend on NgLS, because it introduces circular dependency. Instead, the `getTemplateAst` and `getTemplatAstAtPosition` methods should be moved to NgLSHost and exposed as public methods. This removes the circular dependency, and also removes the need for the awkward 'setSite' method in NgLSHost. PR Close #31122
This commit is contained in:
parent
c34abf2cbc
commit
4ec50811d4
|
@ -7,49 +7,13 @@
|
|||
*/
|
||||
|
||||
import {NgAnalyzedModules, StaticSymbol} from '@angular/compiler';
|
||||
import {DiagnosticTemplateInfo, getTemplateExpressionDiagnostics} from '@angular/compiler-cli/src/language_services';
|
||||
|
||||
import {AstResult} from './common';
|
||||
import {Declarations, Diagnostic, DiagnosticKind, DiagnosticMessageChain, Diagnostics, Span, TemplateSource} from './types';
|
||||
import {offsetSpan, spanOf} from './utils';
|
||||
|
||||
export interface AstProvider {
|
||||
getTemplateAst(template: TemplateSource, fileName: string): AstResult;
|
||||
}
|
||||
|
||||
export function getTemplateDiagnostics(
|
||||
fileName: string, astProvider: AstProvider, templates: TemplateSource[]): Diagnostics {
|
||||
const results: Diagnostics = [];
|
||||
for (const template of templates) {
|
||||
const ast = astProvider.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;
|
||||
}
|
||||
|
||||
export function getDeclarationDiagnostics(
|
||||
declarations: Declarations, modules: NgAnalyzedModules): Diagnostics {
|
||||
const results: Diagnostics = [];
|
||||
|
|
|
@ -6,14 +6,16 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, Lexer, NgAnalyzedModules, Parser, TemplateParser} from '@angular/compiler';
|
||||
import {CompileMetadataResolver, CompilePipeSummary} from '@angular/compiler';
|
||||
import {DiagnosticTemplateInfo, getTemplateExpressionDiagnostics} from '@angular/compiler-cli/src/language_services';
|
||||
|
||||
import {AstResult, TemplateInfo} from './common';
|
||||
import {getTemplateCompletions} from './completions';
|
||||
import {getDefinition} from './definitions';
|
||||
import {getDeclarationDiagnostics, getTemplateDiagnostics} from './diagnostics';
|
||||
import {getDeclarationDiagnostics} from './diagnostics';
|
||||
import {getHover} from './hover';
|
||||
import {Completions, Definition, Diagnostic, DiagnosticKind, Diagnostics, Hover, LanguageService, LanguageServiceHost, Span, TemplateSource} from './types';
|
||||
import {offsetSpan, spanOf} from './utils';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -36,7 +38,7 @@ class LanguageServiceImpl implements LanguageService {
|
|||
let results: Diagnostics = [];
|
||||
let templates = this.host.getTemplates(fileName);
|
||||
if (templates && templates.length) {
|
||||
results.push(...getTemplateDiagnostics(fileName, this, templates));
|
||||
results.push(...this.getTemplateDiagnostics(fileName, templates));
|
||||
}
|
||||
|
||||
let declarations = this.host.getDeclarations(fileName);
|
||||
|
@ -49,7 +51,7 @@ class LanguageServiceImpl implements LanguageService {
|
|||
}
|
||||
|
||||
getPipesAt(fileName: string, position: number): CompilePipeSummary[] {
|
||||
let templateInfo = this.getTemplateAstAtPosition(fileName, position);
|
||||
let templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
|
||||
if (templateInfo) {
|
||||
return templateInfo.pipes;
|
||||
}
|
||||
|
@ -57,100 +59,59 @@ class LanguageServiceImpl implements LanguageService {
|
|||
}
|
||||
|
||||
getCompletionsAt(fileName: string, position: number): Completions {
|
||||
let templateInfo = this.getTemplateAstAtPosition(fileName, position);
|
||||
let templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
|
||||
if (templateInfo) {
|
||||
return getTemplateCompletions(templateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
getDefinitionAt(fileName: string, position: number): Definition {
|
||||
let templateInfo = this.getTemplateAstAtPosition(fileName, position);
|
||||
let templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
|
||||
if (templateInfo) {
|
||||
return getDefinition(templateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
getHoverAt(fileName: string, position: number): Hover|undefined {
|
||||
let templateInfo = this.getTemplateAstAtPosition(fileName, position);
|
||||
let templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
|
||||
if (templateInfo) {
|
||||
return getHover(templateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private getTemplateAstAtPosition(fileName: string, position: number): TemplateInfo|undefined {
|
||||
let template = this.host.getTemplateAt(fileName, position);
|
||||
if (template) {
|
||||
let astResult = this.getTemplateAst(template, fileName);
|
||||
if (astResult && astResult.htmlAst && astResult.templateAst && astResult.directive &&
|
||||
astResult.directives && astResult.pipes && astResult.expressionParser)
|
||||
return {
|
||||
position,
|
||||
fileName,
|
||||
template,
|
||||
htmlAst: astResult.htmlAst,
|
||||
directive: astResult.directive,
|
||||
directives: astResult.directives,
|
||||
pipes: astResult.pipes,
|
||||
templateAst: astResult.templateAst,
|
||||
expressionParser: astResult.expressionParser
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getTemplateAst(template: TemplateSource, contextFile: string): AstResult {
|
||||
let result: AstResult|undefined = undefined;
|
||||
try {
|
||||
const resolvedMetadata =
|
||||
this.metadataResolver.getNonNormalizedDirectiveMetadata(template.type as any);
|
||||
const metadata = resolvedMetadata && resolvedMetadata.metadata;
|
||||
if (metadata) {
|
||||
const rawHtmlParser = new HtmlParser();
|
||||
const htmlParser = new I18NHtmlParser(rawHtmlParser);
|
||||
const expressionParser = new Parser(new Lexer());
|
||||
const config = new CompilerConfig();
|
||||
const parser = new TemplateParser(
|
||||
config, this.host.resolver.getReflector(), expressionParser,
|
||||
new DomElementSchemaRegistry(), htmlParser, null !, []);
|
||||
const htmlResult = htmlParser.parse(template.source, '', {tokenizeExpansionForms: true});
|
||||
const analyzedModules = this.host.getAnalyzedModules();
|
||||
let errors: Diagnostic[]|undefined = undefined;
|
||||
let ngModule = analyzedModules.ngModuleByPipeOrDirective.get(template.type);
|
||||
if (!ngModule) {
|
||||
// Reported by the the declaration diagnostics.
|
||||
ngModule = findSuitableDefaultModule(analyzedModules);
|
||||
}
|
||||
if (ngModule) {
|
||||
const resolvedDirectives = ngModule.transitiveModule.directives.map(
|
||||
d => this.host.resolver.getNonNormalizedDirectiveMetadata(d.reference));
|
||||
const directives = removeMissing(resolvedDirectives).map(d => d.metadata.toSummary());
|
||||
const pipes = ngModule.transitiveModule.pipes.map(
|
||||
p => this.host.resolver.getOrLoadPipeMetadata(p.reference).toSummary());
|
||||
const schemas = ngModule.schemas;
|
||||
const parseResult = parser.tryParseHtml(htmlResult, metadata, directives, pipes, schemas);
|
||||
result = {
|
||||
htmlAst: htmlResult.rootNodes,
|
||||
templateAst: parseResult.templateAst,
|
||||
directive: metadata, directives, pipes,
|
||||
parseErrors: parseResult.errors, expressionParser, errors
|
||||
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})));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
let span = template.span;
|
||||
if (e.fileName == contextFile) {
|
||||
span = template.query.getSpanAt(e.line, e.column) || span;
|
||||
}
|
||||
result = {errors: [{kind: DiagnosticKind.Error, message: e.message, span}]};
|
||||
}
|
||||
return result || {};
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
function removeMissing<T>(values: (T | null | undefined)[]): T[] {
|
||||
return values.filter(e => !!e) as T[];
|
||||
}
|
||||
|
||||
function uniqueBySpan < T extends {
|
||||
span: Span;
|
||||
}
|
||||
|
@ -173,16 +134,3 @@ function uniqueBySpan < T extends {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function findSuitableDefaultModule(modules: NgAnalyzedModules): CompileNgModuleMetadata|undefined {
|
||||
let result: CompileNgModuleMetadata|undefined = undefined;
|
||||
let resultSize = 0;
|
||||
for (const module of modules.ngModules) {
|
||||
const moduleSize = module.transitiveModule.directives.length;
|
||||
if (moduleSize > resultSize) {
|
||||
result = module;
|
||||
resultSize = moduleSize;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,6 @@ export function create(info: tss.server.PluginCreateInfo): ts.LanguageService {
|
|||
|
||||
const serviceHost = new TypeScriptServiceHost(info.languageServiceHost, oldLS);
|
||||
const ls = createLanguageService(serviceHost);
|
||||
serviceHost.setSite(ls);
|
||||
projectHostMap.set(info.project, serviceHost);
|
||||
|
||||
proxy.getCompletionsAtPosition = function(
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import {CompileDirectiveMetadata, CompileMetadataResolver, CompilePipeSummary, NgAnalyzedModules, StaticSymbol} from '@angular/compiler';
|
||||
import {BuiltinType, DeclarationKind, Definition, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from '@angular/compiler-cli/src/language_services';
|
||||
import {AstResult, TemplateInfo} from './common';
|
||||
|
||||
export {
|
||||
BuiltinType,
|
||||
|
@ -203,6 +204,16 @@ export interface LanguageServiceHost {
|
|||
* Return a list all the template files referenced by the project.
|
||||
*/
|
||||
getTemplateReferences(): string[];
|
||||
|
||||
/**
|
||||
* Return the AST for both HTML and template for the contextFile.
|
||||
*/
|
||||
getTemplateAst(template: TemplateSource, contextFile: string): AstResult;
|
||||
|
||||
/**
|
||||
* Return the template AST for the node that corresponds to the position.
|
||||
*/
|
||||
getTemplateAstAtPosition(fileName: string, position: number): TemplateInfo|undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,16 +6,18 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AotSummaryResolver, CompileMetadataResolver, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, JitSummaryResolver, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, analyzeNgModules, createOfflineCompileUrlResolver, isFormattedError} from '@angular/compiler';
|
||||
import {AotSummaryResolver, CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser, analyzeNgModules, createOfflineCompileUrlResolver, isFormattedError} from '@angular/compiler';
|
||||
import {CompilerOptions, getClassMembersFromDeclaration, getPipesTable, getSymbolQuery} from '@angular/compiler-cli/src/language_services';
|
||||
import {ViewEncapsulation, ɵConsole as Console} from '@angular/core';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AstResult, TemplateInfo} from './common';
|
||||
import {createLanguageService} from './language_service';
|
||||
import {ReflectorHost} from './reflector_host';
|
||||
import {Declaration, DeclarationError, Declarations, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, Symbol, SymbolQuery, TemplateSource, TemplateSources} from './types';
|
||||
import {Declaration, DeclarationError, Declarations, Diagnostic, DiagnosticKind, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, Symbol, SymbolQuery, TemplateSource, TemplateSources} from './types';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -25,7 +27,6 @@ export function createLanguageServiceFromTypescript(
|
|||
host: ts.LanguageServiceHost, service: ts.LanguageService): LanguageService {
|
||||
const ngHost = new TypeScriptServiceHost(host, service);
|
||||
const ngServer = createLanguageService(ngHost);
|
||||
ngHost.setSite(ngServer);
|
||||
return ngServer;
|
||||
}
|
||||
|
||||
|
@ -75,8 +76,6 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||
// TODO(issue/24571): remove '!'.
|
||||
private analyzedModules !: NgAnalyzedModules | null;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private service !: LanguageService;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private fileToComponent !: Map<string, StaticSymbol>| null;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private templateReferences !: string[] | null;
|
||||
|
@ -86,8 +85,6 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||
|
||||
constructor(private host: ts.LanguageServiceHost, private tsService: ts.LanguageService) {}
|
||||
|
||||
setSite(service: LanguageService) { this.service = service; }
|
||||
|
||||
/**
|
||||
* Angular LanguageServiceHost implementation
|
||||
*/
|
||||
|
@ -323,7 +320,11 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||
},
|
||||
get query() {
|
||||
if (!queryCache) {
|
||||
const pipes = t.service.getPipesAt(fileName, node.getStart());
|
||||
let pipes: CompilePipeSummary[] = [];
|
||||
const templateInfo = t.getTemplateAstAtPosition(fileName, node.getStart());
|
||||
if (templateInfo) {
|
||||
pipes = templateInfo.pipes;
|
||||
}
|
||||
queryCache = getSymbolQuery(
|
||||
t.program !, t.checker, sourceFile,
|
||||
() => getPipesTable(sourceFile, t.program !, t.checker, pipes));
|
||||
|
@ -590,8 +591,91 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||
|
||||
return find(sourceFile);
|
||||
}
|
||||
|
||||
getTemplateAstAtPosition(fileName: string, position: number): TemplateInfo|undefined {
|
||||
let template = this.getTemplateAt(fileName, position);
|
||||
if (template) {
|
||||
let astResult = this.getTemplateAst(template, fileName);
|
||||
if (astResult && astResult.htmlAst && astResult.templateAst && astResult.directive &&
|
||||
astResult.directives && astResult.pipes && astResult.expressionParser)
|
||||
return {
|
||||
position,
|
||||
fileName,
|
||||
template,
|
||||
htmlAst: astResult.htmlAst,
|
||||
directive: astResult.directive,
|
||||
directives: astResult.directives,
|
||||
pipes: astResult.pipes,
|
||||
templateAst: astResult.templateAst,
|
||||
expressionParser: astResult.expressionParser
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getTemplateAst(template: TemplateSource, contextFile: string): AstResult {
|
||||
let result: AstResult|undefined = undefined;
|
||||
try {
|
||||
const resolvedMetadata =
|
||||
this.resolver.getNonNormalizedDirectiveMetadata(template.type as any);
|
||||
const metadata = resolvedMetadata && resolvedMetadata.metadata;
|
||||
if (metadata) {
|
||||
const rawHtmlParser = new HtmlParser();
|
||||
const htmlParser = new I18NHtmlParser(rawHtmlParser);
|
||||
const expressionParser = new Parser(new Lexer());
|
||||
const config = new CompilerConfig();
|
||||
const parser = new TemplateParser(
|
||||
config, this.resolver.getReflector(), expressionParser, new DomElementSchemaRegistry(),
|
||||
htmlParser, null !, []);
|
||||
const htmlResult = htmlParser.parse(template.source, '', {tokenizeExpansionForms: true});
|
||||
const analyzedModules = this.getAnalyzedModules();
|
||||
let errors: Diagnostic[]|undefined = undefined;
|
||||
let ngModule = analyzedModules.ngModuleByPipeOrDirective.get(template.type);
|
||||
if (!ngModule) {
|
||||
// Reported by the the declaration diagnostics.
|
||||
ngModule = findSuitableDefaultModule(analyzedModules);
|
||||
}
|
||||
if (ngModule) {
|
||||
const directives =
|
||||
ngModule.transitiveModule.directives
|
||||
.map(d => this.resolver.getNonNormalizedDirectiveMetadata(d.reference))
|
||||
.filter(d => d)
|
||||
.map(d => d !.metadata.toSummary());
|
||||
const pipes = ngModule.transitiveModule.pipes.map(
|
||||
p => this.resolver.getOrLoadPipeMetadata(p.reference).toSummary());
|
||||
const schemas = ngModule.schemas;
|
||||
const parseResult = parser.tryParseHtml(htmlResult, metadata, directives, pipes, schemas);
|
||||
result = {
|
||||
htmlAst: htmlResult.rootNodes,
|
||||
templateAst: parseResult.templateAst,
|
||||
directive: metadata, directives, pipes,
|
||||
parseErrors: parseResult.errors, expressionParser, errors
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
let span = template.span;
|
||||
if (e.fileName == contextFile) {
|
||||
span = template.query.getSpanAt(e.line, e.column) || span;
|
||||
}
|
||||
result = {errors: [{kind: DiagnosticKind.Error, message: e.message, span}]};
|
||||
}
|
||||
return result || {};
|
||||
}
|
||||
}
|
||||
|
||||
function findSuitableDefaultModule(modules: NgAnalyzedModules): CompileNgModuleMetadata|undefined {
|
||||
let result: CompileNgModuleMetadata|undefined = undefined;
|
||||
let resultSize = 0;
|
||||
for (const module of modules.ngModules) {
|
||||
const moduleSize = module.transitiveModule.directives.length;
|
||||
if (moduleSize > resultSize) {
|
||||
result = module;
|
||||
resultSize = moduleSize;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function findTsConfig(fileName: string): string|undefined {
|
||||
let dir = path.dirname(fileName);
|
||||
|
|
|
@ -22,7 +22,6 @@ describe('completions', () => {
|
|||
let service = ts.createLanguageService(mockHost, documentRegistry);
|
||||
let ngHost = new TypeScriptServiceHost(mockHost, service);
|
||||
let ngService = createLanguageService(ngHost);
|
||||
ngHost.setSite(ngService);
|
||||
|
||||
it('should be able to get entity completions',
|
||||
() => { contains('/app/test.ng', 'entity-amp', '&', '>', '<', 'ι'); });
|
||||
|
|
|
@ -22,7 +22,6 @@ describe('definitions', () => {
|
|||
let service = ts.createLanguageService(mockHost, documentRegistry);
|
||||
let ngHost = new TypeScriptServiceHost(mockHost, service);
|
||||
let ngService = createLanguageService(ngHost);
|
||||
ngHost.setSite(ngService);
|
||||
|
||||
it('should be able to find field in an interpolation', () => {
|
||||
localReference(
|
||||
|
|
|
@ -26,7 +26,6 @@ describe('diagnostics', () => {
|
|||
const service = ts.createLanguageService(mockHost, documentRegistry);
|
||||
ngHost = new TypeScriptServiceHost(mockHost, service);
|
||||
ngService = createLanguageService(ngHost);
|
||||
ngHost.setSite(ngService);
|
||||
});
|
||||
|
||||
it('should be no diagnostics for test.ng',
|
||||
|
|
|
@ -23,7 +23,6 @@ describe('hover', () => {
|
|||
let service = ts.createLanguageService(mockHost, documentRegistry);
|
||||
let ngHost = new TypeScriptServiceHost(mockHost, service);
|
||||
let ngService = createLanguageService(ngHost);
|
||||
ngHost.setSite(ngService);
|
||||
|
||||
|
||||
it('should be able to find field in an interpolation', () => {
|
||||
|
|
|
@ -27,7 +27,6 @@ describe('references', () => {
|
|||
service = ts.createLanguageService(mockHost, documentRegistry);
|
||||
ngHost = new TypeScriptServiceHost(mockHost, service);
|
||||
ngService = createLanguageService(ngHost);
|
||||
ngHost.setSite(ngService);
|
||||
});
|
||||
|
||||
it('should be able to get template references',
|
||||
|
@ -53,4 +52,4 @@ describe('references', () => {
|
|||
expect(() => { ngService.getTemplateReferences(); }).not.toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue