From 9dae85c3d32a6313e072b06e37740c8264acd626 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 8 Apr 2020 20:05:32 -0700 Subject: [PATCH 1/2] refactor(language-service): clean up and exports and consolidate types --- packages/language-service/language-service.ts | 3 +- packages/language-service/src/common.ts | 27 --- packages/language-service/src/completions.ts | 26 +-- packages/language-service/src/definitions.ts | 7 +- packages/language-service/src/diagnostics.ts | 5 +- .../src/expression_diagnostics.ts | 42 +---- .../language-service/src/expression_type.ts | 10 +- packages/language-service/src/expressions.ts | 58 +++---- packages/language-service/src/hover.ts | 4 +- packages/language-service/src/html_info.ts | 4 - .../language-service/src/language_service.ts | 2 +- .../language-service/src/locate_symbol.ts | 21 +-- packages/language-service/src/template.ts | 59 ------- packages/language-service/src/types.ts | 156 +++++------------- .../language-service/src/typescript_host.ts | 17 +- .../src/typescript_symbols.ts | 35 ++-- packages/language-service/src/utils.ts | 84 ++++++++-- packages/language-service/src/version.ts | 17 -- packages/language-service/test/BUILD.bazel | 1 - packages/language-service/test/mocks.ts | 2 +- .../language-service/test/template_spec.ts | 50 ------ .../test/typescript_symbols_spec.ts | 10 +- packages/language-service/test/utils_spec.ts | 42 ++++- 23 files changed, 252 insertions(+), 430 deletions(-) delete mode 100644 packages/language-service/src/common.ts delete mode 100644 packages/language-service/src/version.ts delete mode 100644 packages/language-service/test/template_spec.ts diff --git a/packages/language-service/language-service.ts b/packages/language-service/language-service.ts index 1fa65563fca4b..3ddd039a9b365 100644 --- a/packages/language-service/language-service.ts +++ b/packages/language-service/language-service.ts @@ -15,6 +15,5 @@ */ export {createLanguageService} from './src/language_service'; export * from './src/ts_plugin'; -export {Completion, Completions, Declaration, Declarations, Definition, Diagnostic, Diagnostics, Hover, HoverTextSection, LanguageService, LanguageServiceHost, Location, Span, TemplateSource, TemplateSources} from './src/types'; +export {Declaration, Definition, Diagnostic, LanguageService, LanguageServiceHost, Span, TemplateSource} from './src/types'; export {TypeScriptServiceHost, createLanguageServiceFromTypescript} from './src/typescript_host'; -export {VERSION} from './src/version'; diff --git a/packages/language-service/src/common.ts b/packages/language-service/src/common.ts deleted file mode 100644 index 9da46502e5b0b..0000000000000 --- a/packages/language-service/src/common.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CssSelector, Node as HtmlAst, ParseError, Parser, TemplateAst} from '@angular/compiler'; - -import {TemplateSource} from './types'; - -export interface AstResult { - htmlAst: HtmlAst[]; - templateAst: TemplateAst[]; - directive: CompileDirectiveMetadata; - directives: CompileDirectiveSummary[]; - pipes: CompilePipeSummary[]; - parseErrors?: ParseError[]; - expressionParser: Parser; - template: TemplateSource; -} - -export type SelectorInfo = { - selectors: CssSelector[], - map: Map -}; diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index 8c139042dbb81..a637eba1da54b 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -10,13 +10,12 @@ import {AbsoluteSourceSpan, AST, AstPath, AttrAst, Attribute, BoundDirectiveProp import {$$, $_, isAsciiLetter, isDigit} from '@angular/compiler/src/chars'; import {ATTR, getBindingDescriptor} from './binding_utils'; -import {AstResult} from './common'; -import {diagnosticInfoFromTemplateInfo, getExpressionScope} from './expression_diagnostics'; +import {getExpressionScope} from './expression_diagnostics'; import {getExpressionCompletions} from './expressions'; import {attributeNames, elementNames, eventNames, propertyNames} from './html_info'; import {InlineTemplate} from './template'; import * as ng from './types'; -import {findTemplateAstAt, getPathToNodeAtPosition, getSelectors, inSpan, isStructuralDirective, spanOf} from './utils'; +import {diagnosticInfoFromTemplateInfo, findTemplateAstAt, getPathToNodeAtPosition, getSelectors, inSpan, isStructuralDirective, spanOf} from './utils'; const HIDDEN_HTML_ELEMENTS: ReadonlySet = new Set(['html', 'script', 'noscript', 'base', 'body', 'title', 'head', 'link']); @@ -56,7 +55,7 @@ function isIdentifierPart(code: number) { * `position`, nothing is returned. */ function getBoundedWordSpan( - templateInfo: AstResult, position: number, ast: HtmlAst|undefined): ts.TextSpan|undefined { + templateInfo: ng.AstResult, position: number, ast: HtmlAst|undefined): ts.TextSpan|undefined { const {template} = templateInfo; const templateSrc = template.source; @@ -127,7 +126,7 @@ function getBoundedWordSpan( } export function getTemplateCompletions( - templateInfo: AstResult, position: number): ng.CompletionEntry[] { + templateInfo: ng.AstResult, position: number): ng.CompletionEntry[] { let result: ng.CompletionEntry[] = []; const {htmlAst, template} = templateInfo; // The templateNode starts at the delimiter character so we add 1 to skip it. @@ -204,7 +203,7 @@ export function getTemplateCompletions( }); } -function attributeCompletions(info: AstResult, path: AstPath): ng.CompletionEntry[] { +function attributeCompletions(info: ng.AstResult, path: AstPath): ng.CompletionEntry[] { const attr = path.tail; const elem = path.parentOf(attr); if (!(attr instanceof Attribute) || !(elem instanceof Element)) { @@ -258,7 +257,7 @@ function attributeCompletions(info: AstResult, path: AstPath): ng.Compl } function attributeCompletionsForElement( - info: AstResult, elementName: string): ng.CompletionEntry[] { + info: ng.AstResult, elementName: string): ng.CompletionEntry[] { const results: ng.CompletionEntry[] = []; if (info.template instanceof InlineTemplate) { @@ -292,7 +291,8 @@ function attributeCompletionsForElement( * @param info Object that contains the template AST * @param htmlPath Path to the HTML node */ -function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.CompletionEntry[] { +function attributeValueCompletions( + info: ng.AstResult, htmlPath: HtmlAstPath): ng.CompletionEntry[] { // Find the corresponding Template AST path. const templatePath = findTemplateAstAt(info.templateAst, htmlPath.position); const visitor = new ExpressionVisitor(info, htmlPath.position, () => { @@ -334,7 +334,7 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C return visitor.results; } -function elementCompletions(info: AstResult): ng.CompletionEntry[] { +function elementCompletions(info: ng.AstResult): ng.CompletionEntry[] { const results: ng.CompletionEntry[] = [...ANGULAR_ELEMENTS]; if (info.template instanceof InlineTemplate) { @@ -380,7 +380,7 @@ function entityCompletions(value: string, position: number): ng.CompletionEntry[ return result; } -function interpolationCompletions(info: AstResult, position: number): ng.CompletionEntry[] { +function interpolationCompletions(info: ng.AstResult, position: number): ng.CompletionEntry[] { // Look for an interpolation in at the position. const templatePath = findTemplateAstAt(info.templateAst, position); if (!templatePath.tail) { @@ -399,7 +399,7 @@ function interpolationCompletions(info: AstResult, position: number): ng.Complet // code checks for this case and returns element completions if it is detected or undefined // if it is not. function voidElementAttributeCompletions( - info: AstResult, path: AstPath): ng.CompletionEntry[] { + info: ng.AstResult, path: AstPath): ng.CompletionEntry[] { const tail = path.tail; if (tail instanceof Text) { const match = tail.value.match(/<(\w(\w|\d|-)*:)?(\w(\w|\d|-)*)\s/); @@ -417,7 +417,7 @@ class ExpressionVisitor extends NullTemplateVisitor { private readonly completions = new Map(); constructor( - private readonly info: AstResult, private readonly position: number, + private readonly info: ng.AstResult, private readonly position: number, private readonly getExpressionScope: () => ng.SymbolTable) { super(); } @@ -619,7 +619,7 @@ interface AngularAttributes { * @param info * @param elementName */ -function angularAttributes(info: AstResult, elementName: string): AngularAttributes { +function angularAttributes(info: ng.AstResult, elementName: string): AngularAttributes { const {selectors, map: selectorMap} = getSelectors(info); const templateRefs = new Set(); const inputs = new Set(); diff --git a/packages/language-service/src/definitions.ts b/packages/language-service/src/definitions.ts index 417df1f1e1e1d..0164ce2b248e0 100644 --- a/packages/language-service/src/definitions.ts +++ b/packages/language-service/src/definitions.ts @@ -8,11 +8,10 @@ import * as path from 'path'; import * as ts from 'typescript'; // used as value and is provided at runtime -import {AstResult} from './common'; + import {locateSymbols} from './locate_symbol'; -import {getPropertyAssignmentFromValue, isClassDecoratorProperty} from './template'; -import {Span} from './types'; -import {findTightestNode} from './utils'; +import {AstResult, Span} from './types'; +import {findTightestNode, getPropertyAssignmentFromValue, isClassDecoratorProperty} from './utils'; /** * Convert Angular Span to TypeScript TextSpan. Angular Span has 'start' and diff --git a/packages/language-service/src/diagnostics.ts b/packages/language-service/src/diagnostics.ts index 646086c5ef0ce..f5c55ecd82884 100644 --- a/packages/language-service/src/diagnostics.ts +++ b/packages/language-service/src/diagnostics.ts @@ -10,20 +10,17 @@ import {NgAnalyzedModules} from '@angular/compiler'; import * as path from 'path'; import * as ts from 'typescript'; -import {AstResult} from './common'; import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {getTemplateExpressionDiagnostics} from './expression_diagnostics'; import * as ng from './types'; import {TypeScriptServiceHost} from './typescript_host'; import {findPropertyValueOfType, findTightestNode, offsetSpan, spanOf} from './utils'; - - /** * Return diagnostic information for the parsed AST of the template. * @param ast contains HTML and template AST */ -export function getTemplateDiagnostics(ast: AstResult): ng.Diagnostic[] { +export function getTemplateDiagnostics(ast: ng.AstResult): ng.Diagnostic[] { const {parseErrors, templateAst, htmlAst, template} = ast; if (parseErrors && parseErrors.length) { return parseErrors.map(e => { diff --git a/packages/language-service/src/expression_diagnostics.ts b/packages/language-service/src/expression_diagnostics.ts index 81950b5798946..1baa12c50ba21 100644 --- a/packages/language-service/src/expression_diagnostics.ts +++ b/packages/language-service/src/expression_diagnostics.ts @@ -6,33 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, identifierName, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableAst} from '@angular/compiler'; +import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, identifierName, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableAst} from '@angular/compiler'; -import {AstResult} from './common'; import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {AstType} from './expression_type'; import {BuiltinType, Definition, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; import * as ng from './types'; import {findOutputBinding, getPathToNodeAtPosition} from './utils'; -export interface DiagnosticTemplateInfo { - fileName?: string; - offset: number; - query: SymbolQuery; - members: SymbolTable; - htmlAst: Node[]; - templateAst: TemplateAst[]; - source: string; -} - -export function getTemplateExpressionDiagnostics(info: DiagnosticTemplateInfo): ng.Diagnostic[] { +export function getTemplateExpressionDiagnostics(info: ng.DiagnosticTemplateInfo): ng.Diagnostic[] { const visitor = new ExpressionDiagnosticsVisitor( info, (path: TemplateAstPath) => getExpressionScope(info, path)); templateVisitAll(visitor, info.templateAst); return visitor.diagnostics; } -function getReferences(info: DiagnosticTemplateInfo): SymbolDeclaration[] { +function getReferences(info: ng.DiagnosticTemplateInfo): SymbolDeclaration[] { const result: SymbolDeclaration[] = []; function processReferences(references: ReferenceAst[]) { @@ -68,7 +57,7 @@ function getReferences(info: DiagnosticTemplateInfo): SymbolDeclaration[] { return result; } -function getDefinitionOf(info: DiagnosticTemplateInfo, ast: TemplateAst): Definition|undefined { +function getDefinitionOf(info: ng.DiagnosticTemplateInfo, ast: TemplateAst): Definition|undefined { if (info.fileName) { const templateOffset = info.offset; return [{ @@ -88,7 +77,7 @@ function getDefinitionOf(info: DiagnosticTemplateInfo, ast: TemplateAst): Defini * @param path template AST path */ function getVarDeclarations( - info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration[] { + info: ng.DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration[] { const results: SymbolDeclaration[] = []; for (let current = path.head; current; current = path.childOf(current)) { if (!(current instanceof EmbeddedTemplateAst)) { @@ -154,7 +143,7 @@ function getVariableTypeFromDirectiveContext( * @param templateElement */ function refinedVariableType( - value: string, mergedTable: SymbolTable, info: DiagnosticTemplateInfo, + value: string, mergedTable: SymbolTable, info: ng.DiagnosticTemplateInfo, templateElement: EmbeddedTemplateAst): Symbol { if (value === '$implicit') { // Special case: ngFor directive @@ -206,7 +195,7 @@ function refinedVariableType( } function getEventDeclaration( - info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration|undefined { + info: ng.DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration|undefined { const event = path.tail; if (!(event instanceof BoundEventAst)) { // No event available in this context. @@ -241,7 +230,7 @@ function getEventDeclaration( * derived for. */ export function getExpressionScope( - info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolTable { + info: ng.DiagnosticTemplateInfo, path: TemplateAstPath): SymbolTable { let result = info.members; const references = getReferences(info); const variables = getVarDeclarations(info, path); @@ -262,7 +251,7 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { diagnostics: ng.Diagnostic[] = []; constructor( - private info: DiagnosticTemplateInfo, + private info: ng.DiagnosticTemplateInfo, private getExpressionScope: (path: TemplateAstPath, includeEvent: boolean) => SymbolTable) { super(); this.path = new AstPath([]); @@ -386,16 +375,3 @@ function hasTemplateReference(type: CompileTypeMetadata): boolean { function spanOf(sourceSpan: ParseSourceSpan): Span { return {start: sourceSpan.start.offset, end: sourceSpan.end.offset}; } - - -export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTemplateInfo { - return { - fileName: info.template.fileName, - offset: info.template.span.start, - query: info.template.query, - members: info.template.members, - htmlAst: info.htmlAst, - templateAst: info.templateAst, - source: info.template.source, - }; -} diff --git a/packages/language-service/src/expression_type.ts b/packages/language-service/src/expression_type.ts index 8b2b5caeb2a6e..9364d07c52162 100644 --- a/packages/language-service/src/expression_type.ts +++ b/packages/language-service/src/expression_type.ts @@ -12,7 +12,7 @@ import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {BuiltinType, Signature, Symbol, SymbolQuery, SymbolTable} from './symbols'; import * as ng from './types'; -export interface ExpressionDiagnosticsContext { +interface ExpressionDiagnosticsContext { inEvent?: boolean; } @@ -225,7 +225,7 @@ export class AstType implements AstVisitor { return this.anyType; } - visitImplicitReceiver(ast: ImplicitReceiver): Symbol { + visitImplicitReceiver(_ast: ImplicitReceiver): Symbol { const _this = this; // Return a pseudo-symbol for the implicit receiver. // The members of the implicit receiver are what is defined by the @@ -247,11 +247,11 @@ export class AstType implements AstVisitor { signatures(): Signature[] { return []; }, - selectSignature(types): Signature | + selectSignature(_types): Signature | undefined { return undefined; }, - indexed(argument): Symbol | + indexed(_argument): Symbol | undefined { return undefined; }, @@ -366,7 +366,7 @@ export class AstType implements AstVisitor { return this.getType(ast.value); } - visitQuote(ast: Quote) { + visitQuote(_ast: Quote) { // The type of a quoted expression is any. return this.query.getBuiltinType(BuiltinType.Any); } diff --git a/packages/language-service/src/expressions.ts b/packages/language-service/src/expressions.ts index bc33a1650a3ec..1d27b209ab95f 100644 --- a/packages/language-service/src/expressions.ts +++ b/packages/language-service/src/expressions.ts @@ -53,20 +53,20 @@ export function getExpressionCompletions( // (that is the scope of the implicit receiver) is the right scope as the user is typing the // beginning of an expression. tail.visit({ - visitBinary(ast) {}, - visitChain(ast) {}, - visitConditional(ast) {}, - visitFunctionCall(ast) {}, - visitImplicitReceiver(ast) {}, - visitInterpolation(ast) { + visitBinary(_ast) {}, + visitChain(_ast) {}, + visitConditional(_ast) {}, + visitFunctionCall(_ast) {}, + visitImplicitReceiver(_ast) {}, + visitInterpolation(_ast) { result = undefined; }, - visitKeyedRead(ast) {}, - visitKeyedWrite(ast) {}, - visitLiteralArray(ast) {}, - visitLiteralMap(ast) {}, - visitLiteralPrimitive(ast) {}, - visitMethodCall(ast) {}, + visitKeyedRead(_ast) {}, + visitKeyedWrite(_ast) {}, + visitLiteralArray(_ast) {}, + visitLiteralMap(_ast) {}, + visitLiteralPrimitive(_ast) {}, + visitMethodCall(_ast) {}, visitPipe(ast) { if (position >= ast.exp.span.end && (!ast.args || !ast.args.length || position < (ast.args[0]).span.start)) { @@ -74,8 +74,8 @@ export function getExpressionCompletions( result = templateInfo.query.getPipes(); } }, - visitPrefixNot(ast) {}, - visitNonNullAssert(ast) {}, + visitPrefixNot(_ast) {}, + visitNonNullAssert(_ast) {}, visitPropertyRead(ast) { const receiverType = getType(ast.receiver); result = receiverType ? receiverType.members() : scope; @@ -84,7 +84,7 @@ export function getExpressionCompletions( const receiverType = getType(ast.receiver); result = receiverType ? receiverType.members() : scope; }, - visitQuote(ast) { + visitQuote(_ast) { // For a quote, return the members of any (if there are any). result = templateInfo.query.getBuiltinType(BuiltinType.Any).members(); }, @@ -127,17 +127,17 @@ export function getExpressionSymbol( // (that is the scope of the implicit receiver) is the right scope as the user is typing the // beginning of an expression. tail.visit({ - visitBinary(ast) {}, - visitChain(ast) {}, - visitConditional(ast) {}, - visitFunctionCall(ast) {}, - visitImplicitReceiver(ast) {}, - visitInterpolation(ast) {}, - visitKeyedRead(ast) {}, - visitKeyedWrite(ast) {}, - visitLiteralArray(ast) {}, - visitLiteralMap(ast) {}, - visitLiteralPrimitive(ast) {}, + visitBinary(_ast) {}, + visitChain(_ast) {}, + visitConditional(_ast) {}, + visitFunctionCall(_ast) {}, + visitImplicitReceiver(_ast) {}, + visitInterpolation(_ast) {}, + visitKeyedRead(_ast) {}, + visitKeyedWrite(_ast) {}, + visitLiteralArray(_ast) {}, + visitLiteralMap(_ast) {}, + visitLiteralPrimitive(_ast) {}, visitMethodCall(ast) { const receiverType = getType(ast.receiver); symbol = receiverType && receiverType.members().get(ast.name); @@ -159,8 +159,8 @@ export function getExpressionSymbol( }; } }, - visitPrefixNot(ast) {}, - visitNonNullAssert(ast) {}, + visitPrefixNot(_ast) {}, + visitNonNullAssert(_ast) {}, visitPropertyRead(ast) { const receiverType = getType(ast.receiver); symbol = receiverType && receiverType.members().get(ast.name); @@ -177,7 +177,7 @@ export function getExpressionSymbol( // ^^^^^^ value; visited separately as a nested AST span = {start, end: start + ast.name.length}; }, - visitQuote(ast) {}, + visitQuote(_ast) {}, visitSafeMethodCall(ast) { const receiverType = getType(ast.receiver); symbol = receiverType && receiverType.members().get(ast.name); diff --git a/packages/language-service/src/hover.ts b/packages/language-service/src/hover.ts index 9d60e13554947..9e30ac861478b 100644 --- a/packages/language-service/src/hover.ts +++ b/packages/language-service/src/hover.ts @@ -8,7 +8,6 @@ import {NgAnalyzedModules} from '@angular/compiler'; import * as ts from 'typescript'; -import {AstResult} from './common'; import {locateSymbols} from './locate_symbol'; import * as ng from './types'; import {inSpan} from './utils'; @@ -27,7 +26,8 @@ const SYMBOL_INTERFACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.inter * @param analyzedModules all NgModules in the program. */ export function getTemplateHover( - info: AstResult, position: number, analyzedModules: NgAnalyzedModules): ts.QuickInfo|undefined { + info: ng.AstResult, position: number, analyzedModules: NgAnalyzedModules): ts.QuickInfo| + undefined { const symbolInfo = locateSymbols(info, position)[0]; if (!symbolInfo) { return; diff --git a/packages/language-service/src/html_info.ts b/packages/language-service/src/html_info.ts index dc5315c0c3aca..934c9889813f0 100644 --- a/packages/language-service/src/html_info.ts +++ b/packages/language-service/src/html_info.ts @@ -453,7 +453,3 @@ export function eventNames(elementName: string): string[] { export function propertyNames(elementName: string): string[] { return SchemaInformation.instance.propertiesOf(elementName); } - -export function propertyType(elementName: string, propertyName: string): string { - return SchemaInformation.instance.typeOf(elementName, propertyName); -} diff --git a/packages/language-service/src/language_service.ts b/packages/language-service/src/language_service.ts index c6d1faacfec0b..375a6f39d0abe 100644 --- a/packages/language-service/src/language_service.ts +++ b/packages/language-service/src/language_service.ts @@ -49,7 +49,7 @@ class LanguageServiceImpl implements ng.LanguageService { getCompletionsAtPosition( fileName: string, position: number, - options?: tss.GetCompletionsAtPositionOptions): tss.CompletionInfo|undefined { + _options?: tss.GetCompletionsAtPositionOptions): tss.CompletionInfo|undefined { this.host.getAnalyzedModules(); // same role as 'synchronizeHostData' const ast = this.host.getTemplateAstAtPosition(fileName, position); if (!ast) { diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index 97475ab27bd90..3b6e4024dc55f 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -9,17 +9,10 @@ import {AST, Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableBinding} from '@angular/compiler'; import * as tss from 'typescript/lib/tsserverlibrary'; -import {AstResult} from './common'; -import {diagnosticInfoFromTemplateInfo, getExpressionScope} from './expression_diagnostics'; +import {getExpressionScope} from './expression_diagnostics'; import {getExpressionSymbol} from './expressions'; -import {Definition, DirectiveKind, Span, Symbol} from './types'; -import {findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils'; - -export interface SymbolInfo { - symbol: Symbol; - span: tss.TextSpan; - staticSymbol?: StaticSymbol; -} +import {AstResult, Definition, DirectiveKind, Span, Symbol, SymbolInfo} from './types'; +import {diagnosticInfoFromTemplateInfo, findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils'; /** * Traverses a template AST and locates symbol(s) at a specified position. @@ -86,8 +79,8 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): }; ast.visit( { - visitNgContent(ast) {}, - visitEmbeddedTemplate(ast) {}, + visitNgContent(_ast) {}, + visitEmbeddedTemplate(_ast) {}, visitElement(ast) { const component = ast.directives.find(d => d.directive.isComponent); if (component) { @@ -113,7 +106,7 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): symbol = ast.value && info.template.query.getTypeSymbol(tokenReference(ast.value)); span = spanOf(ast); }, - visitVariable(ast) {}, + visitVariable(_ast) {}, visitEvent(ast) { if (!attributeValueSymbol(ast.handler)) { symbol = findOutputBinding(ast, path, info.template.query); @@ -158,7 +151,7 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): } } }, - visitText(ast) {}, + visitText(_ast) {}, visitDirective(ast) { // Need to cast because 'reference' is typed as any staticSymbol = ast.directive.type.reference as StaticSymbol; diff --git a/packages/language-service/src/template.ts b/packages/language-service/src/template.ts index c5f3924bead0b..5e88bf97243d4 100644 --- a/packages/language-service/src/template.ts +++ b/packages/language-service/src/template.ts @@ -132,62 +132,3 @@ export class ExternalTemplate extends BaseTemplate { }; } } - -/** - * Returns a property assignment from the assignment value, or `undefined` if there is no - * assignment. - */ -export function getPropertyAssignmentFromValue(value: ts.Node): ts.PropertyAssignment|undefined { - if (!value.parent || !ts.isPropertyAssignment(value.parent)) { - return; - } - return value.parent; -} - -/** - * Given a decorator property assignment, return the ClassDeclaration node that corresponds to the - * directive class the property applies to. - * If the property assignment is not on a class decorator, no declaration is returned. - * - * For example, - * - * @Component({ - * template: '
' - * ^^^^^^^^^^^^^^^^^^^^^^^---- property assignment - * }) - * class AppComponent {} - * ^---- class declaration node - * - * @param propAsgn property assignment - */ -export function getClassDeclFromDecoratorProp(propAsgnNode: ts.PropertyAssignment): - ts.ClassDeclaration|undefined { - if (!propAsgnNode.parent || !ts.isObjectLiteralExpression(propAsgnNode.parent)) { - return; - } - const objLitExprNode = propAsgnNode.parent; - if (!objLitExprNode.parent || !ts.isCallExpression(objLitExprNode.parent)) { - return; - } - const callExprNode = objLitExprNode.parent; - if (!callExprNode.parent || !ts.isDecorator(callExprNode.parent)) { - return; - } - const decorator = callExprNode.parent; - if (!decorator.parent || !ts.isClassDeclaration(decorator.parent)) { - return; - } - const classDeclNode = decorator.parent; - return classDeclNode; -} - -/** - * Determines if a property assignment is on a class decorator. - * See `getClassDeclFromDecoratorProperty`, which gets the class the decorator is applied to, for - * more details. - * - * @param prop property assignment - */ -export function isClassDecoratorProperty(propAsgn: ts.PropertyAssignment): boolean { - return !!getClassDeclFromDecoratorProp(propAsgn); -} diff --git a/packages/language-service/src/types.ts b/packages/language-service/src/types.ts index 804a3fbc08d85..c76d83a373815 100644 --- a/packages/language-service/src/types.ts +++ b/packages/language-service/src/types.ts @@ -6,26 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileDirectiveMetadata, NgAnalyzedModules, StaticSymbol} from '@angular/compiler'; +import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CssSelector, NgAnalyzedModules, Node as HtmlAst, ParseError, Parser, StaticSymbol, TemplateAst} from '@angular/compiler'; import * as ts from 'typescript'; -import {AstResult} from './common'; -import {BuiltinType, DeclarationKind, Definition, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; - -export { - BuiltinType, - DeclarationKind, - Definition, - PipeInfo, - Pipes, - Signature, - Span, - StaticSymbol, - Symbol, - SymbolDeclaration, - SymbolQuery, - SymbolTable -}; +import {Span, Symbol, SymbolQuery, SymbolTable} from './symbols'; + +export {StaticSymbol} from '@angular/compiler'; +export {BuiltinType, Definition, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; /** * The information `LanguageService` needs from the `LanguageServiceHost` to describe the content of @@ -67,15 +54,6 @@ export interface TemplateSource { readonly fileName: string; } -/** - * A sequence of template sources. - * - * A host type; see `LanguageServiceHost`. - * - * @publicApi - */ -export type TemplateSources = TemplateSource[]|undefined; - /** * Error information found getting declaration information * @@ -132,15 +110,6 @@ export interface Declaration { readonly errors: DeclarationError[]; } -/** - * A sequence of declarations. - * - * A host type; see `LanguageServiceHost`. - * - * @publicApi - */ -export type Declarations = Declaration[]; - /** * The host for a `LanguageService`. This provides all the `LanguageService` requires to respond * to the `LanguageService` requests. @@ -178,7 +147,7 @@ export interface LanguageServiceHost { /** * Returns the Angular declarations in the given file. */ - getDeclarations(fileName: string): Declarations; + getDeclarations(fileName: string): Declaration[]; /** * Return a summary of all Angular modules in the project. @@ -196,45 +165,6 @@ export interface LanguageServiceHost { getTemplateAstAtPosition(fileName: string, position: number): AstResult|undefined; } -/** - * An item of the completion result to be displayed by an editor. - * - * A `LanguageService` interface. - * - * @publicApi - */ -export interface Completion { - /** - * The kind of completion. - */ - kind: DeclarationKind; - - /** - * The name of the completion to be displayed - */ - name: string; - - /** - * The key to use to sort the completions for display. - */ - sort: string; -} - -/** - * A sequence of completions. - * - * @deprecated - */ -export type Completions = Completion[]; - -/** - * A file and span. - */ -export interface Location { - fileName: string; - span: Span; -} - /** * The type of Angular directive. Used for QuickInfo in template. */ @@ -312,45 +242,6 @@ export interface Diagnostic { message: string|DiagnosticMessageChain; } -/** - * A sequence of diagnostic message. - * - * @deprecated - */ -export type Diagnostics = Diagnostic[]; - -/** - * A section of hover text. If the text is code then language should be provided. - * Otherwise the text is assumed to be Markdown text that will be sanitized. - */ -export interface HoverTextSection { - /** - * Source code or markdown text describing the symbol a the hover location. - */ - readonly text: string; - - /** - * The language of the source if `text` is a source code fragment. - */ - readonly language?: string; -} - -/** - * Hover information for a symbol at the hover location. - */ -export interface Hover { - /** - * The hover text to display for the symbol at the hover location. If the text includes - * source code, the section will specify which language it should be interpreted as. - */ - readonly text: HoverTextSection[]; - - /** - * The span of source the hover covers. - */ - readonly span: Span; -} - /** * An instance of an Angular language service created by `createLanguageService()`. * @@ -364,3 +255,38 @@ export type LanguageService = Pick< ts.LanguageService, 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'|'getQuickInfoAtPosition'| 'getSemanticDiagnostics'>; + +/** Information about an Angular template AST. */ +export interface AstResult { + htmlAst: HtmlAst[]; + templateAst: TemplateAst[]; + directive: CompileDirectiveMetadata; + directives: CompileDirectiveSummary[]; + pipes: CompilePipeSummary[]; + parseErrors?: ParseError[]; + expressionParser: Parser; + template: TemplateSource; +} + +/** Information about a directive's selectors. */ +export type SelectorInfo = { + selectors: CssSelector[], + map: Map +}; + +export interface SymbolInfo { + symbol: Symbol; + span: ts.TextSpan; + staticSymbol?: StaticSymbol; +} + +/** TODO: this should probably be merged with AstResult */ +export interface DiagnosticTemplateInfo { + fileName?: string; + offset: number; + query: SymbolQuery; + members: SymbolTable; + htmlAst: HtmlAst[]; + templateAst: TemplateAst[]; + source: string; +} diff --git a/packages/language-service/src/typescript_host.ts b/packages/language-service/src/typescript_host.ts index 20602d028cef9..836b8cc9569b8 100644 --- a/packages/language-service/src/typescript_host.ts +++ b/packages/language-service/src/typescript_host.ts @@ -6,16 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {analyzeNgModules, AotSummaryResolver, CompileDirectiveSummary, CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, I18NHtmlParser, isFormattedError, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser} from '@angular/compiler'; +import {analyzeNgModules, AotSummaryResolver, CompileDirectiveSummary, CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, isFormattedError, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser} from '@angular/compiler'; import {SchemaMetadata, ViewEncapsulation, ɵConsole as Console} from '@angular/core'; import * as tss from 'typescript/lib/tsserverlibrary'; -import {AstResult} from './common'; import {createLanguageService} from './language_service'; import {ReflectorHost} from './reflector_host'; -import {ExternalTemplate, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue, InlineTemplate} from './template'; -import {Declaration, DeclarationError, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, TemplateSource} from './types'; -import {findTightestNode, getDirectiveClassLike} from './utils'; +import {ExternalTemplate, InlineTemplate} from './template'; +import {AstResult, Declaration, DeclarationError, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, TemplateSource} from './types'; +import {findTightestNode, getClassDeclFromDecoratorProp, getDirectiveClassLike, getPropertyAssignmentFromValue} from './utils'; /** @@ -44,7 +43,7 @@ export class DummyHtmlParser extends HtmlParser { * Avoid loading resources in the language servcie by using a dummy loader. */ export class DummyResourceLoader extends ResourceLoader { - get(url: string): Promise { + get(_url: string): Promise { return Promise.resolve(''); } } @@ -78,10 +77,10 @@ export class TypeScriptServiceHost implements LanguageServiceHost { readonly tsLsHost: tss.LanguageServiceHost, private readonly tsLS: tss.LanguageService) { this.summaryResolver = new AotSummaryResolver( { - loadSummary(filePath: string) { + loadSummary(_filePath: string) { return null; }, - isSourceFile(sourceFilePath: string) { + isSourceFile(_sourceFilePath: string) { return true; }, toSummaryFileName(sourceFilePath: string) { @@ -172,7 +171,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost { this.resolver.clearCache(); const analyzeHost = { - isSourceFile(filePath: string) { + isSourceFile(_filePath: string) { return true; } }; diff --git a/packages/language-service/src/typescript_symbols.ts b/packages/language-service/src/typescript_symbols.ts index 19e5464c444bf..b09cbb8bc79cf 100644 --- a/packages/language-service/src/typescript_symbols.ts +++ b/packages/language-service/src/typescript_symbols.ts @@ -57,8 +57,14 @@ export function getClassMembersFromDeclaration( return new TypeWrapper(type, {node: source, program, checker}).members(); } -export function getClassFromStaticSymbol( - program: ts.Program, type: StaticSymbol): ts.ClassDeclaration|undefined { +export function getPipesTable( + source: ts.SourceFile, program: ts.Program, checker: ts.TypeChecker, + pipes: CompilePipeSummary[]): SymbolTable { + return new PipesTable(pipes, {program, checker, node: source}); +} + +function getClassFromStaticSymbol(program: ts.Program, type: StaticSymbol): ts.ClassDeclaration| + undefined { const source = program.getSourceFile(type.filePath); if (source) { return ts.forEachChild(source, child => { @@ -74,12 +80,6 @@ export function getClassFromStaticSymbol( return undefined; } -export function getPipesTable( - source: ts.SourceFile, program: ts.Program, checker: ts.TypeChecker, - pipes: CompilePipeSummary[]): SymbolTable { - return new PipesTable(pipes, {program, checker, node: source}); -} - class TypeScriptSymbolQuery implements SymbolQuery { private typeCache = new Map(); private pipesCache: SymbolTable|undefined; @@ -123,7 +123,7 @@ class TypeScriptSymbolQuery implements SymbolQuery { return result || this.getBuiltinType(BuiltinType.Any); } - getArrayType(type: Symbol): Symbol { + getArrayType(_type: Symbol): Symbol { return this.getBuiltinType(BuiltinType.Any); } @@ -222,7 +222,7 @@ function signaturesOf(type: ts.Type, context: TypeContext): Signature[] { return type.getCallSignatures().map(s => new SignatureWrapper(s, context)); } -function selectSignature(type: ts.Type, context: TypeContext, types: Symbol[]): Signature| +function selectSignature(type: ts.Type, context: TypeContext, _types: Symbol[]): Signature| undefined { // TODO: Do a better job of selecting the right signature. TypeScript does not currently support a // Type Relationship API (see https://github.com/angular/vscode-ng-language-service/issues/143). @@ -404,7 +404,7 @@ class SymbolWrapper implements Symbol { return selectSignature(this.tsType, this.context, types); } - indexed(argument: Symbol): Symbol|undefined { + indexed(_argument: Symbol): Symbol|undefined { return undefined; } @@ -475,7 +475,7 @@ class DeclaredSymbol implements Symbol { return this.type.typeArguments(); } - indexed(argument: Symbol): Symbol|undefined { + indexed(_argument: Symbol): Symbol|undefined { return undefined; } } @@ -504,7 +504,7 @@ class SignatureResultOverride implements Signature { } } -export function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { +function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { // ∀ Typescript version >= 2.2, `SymbolTable` is implemented as an ES6 `Map` const result = new Map(); for (const symbol of symbols) { @@ -548,8 +548,7 @@ class SymbolTableWrapper implements SymbolTable { * @param context program context * @param type original TypeScript type of entity owning the symbols, if known */ - constructor( - symbols: ts.SymbolTable|ts.Symbol[], private context: TypeContext, private type?: ts.Type) { + constructor(symbols: ts.SymbolTable|ts.Symbol[], private context: TypeContext, type?: ts.Type) { symbols = symbols || []; if (Array.isArray(symbols)) { @@ -727,7 +726,7 @@ class PipeSymbol implements Symbol { return signature; } - indexed(argument: Symbol): Symbol|undefined { + indexed(_argument: Symbol): Symbol|undefined { return undefined; } @@ -786,10 +785,10 @@ function findClassSymbolInContext(type: StaticSymbol, context: TypeContext): ts. class EmptyTable implements SymbolTable { public readonly size: number = 0; - get(key: string): Symbol|undefined { + get(_key: string): Symbol|undefined { return undefined; } - has(key: string): boolean { + has(_key: string): boolean { return false; } values(): Symbol[] { diff --git a/packages/language-service/src/utils.ts b/packages/language-service/src/utils.ts index 36fa25c71ccc4..a73fac69a6bb7 100644 --- a/packages/language-service/src/utils.ts +++ b/packages/language-service/src/utils.ts @@ -9,16 +9,15 @@ import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, identifierName, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, templateVisitAll, visitAll} from '@angular/compiler'; import * as ts from 'typescript'; -import {AstResult, SelectorInfo} from './common'; -import {Span, Symbol, SymbolQuery} from './types'; +import {AstResult, DiagnosticTemplateInfo, SelectorInfo, Span, Symbol, SymbolQuery} from './types'; -export interface SpanHolder { +interface SpanHolder { sourceSpan: ParseSourceSpan; endSourceSpan?: ParseSourceSpan|null; children?: SpanHolder[]; } -export function isParseSourceSpan(value: any): value is ParseSourceSpan { +function isParseSourceSpan(value: any): value is ParseSourceSpan { return value && !!value.start; } @@ -80,14 +79,16 @@ export function getSelectors(info: AstResult): SelectorInfo { return {selectors: results, map}; } -export function isTypescriptVersion(low: string, high?: string) { - const version = ts.version; - - if (version.substring(0, low.length) < low) return false; - - if (high && (version.substring(0, high.length) > high)) return false; - - return true; +export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTemplateInfo { + return { + fileName: info.template.fileName, + offset: info.template.span.start, + query: info.template.query, + members: info.template.members, + htmlAst: info.htmlAst, + templateAst: info.templateAst, + source: info.template.source, + }; } export function findTemplateAstAt(ast: TemplateAst[], position: number): TemplateAstPath { @@ -276,3 +277,62 @@ export function findOutputBinding( } } } + +/** + * Returns a property assignment from the assignment value, or `undefined` if there is no + * assignment. + */ +export function getPropertyAssignmentFromValue(value: ts.Node): ts.PropertyAssignment|undefined { + if (!value.parent || !ts.isPropertyAssignment(value.parent)) { + return; + } + return value.parent; +} + +/** + * Given a decorator property assignment, return the ClassDeclaration node that corresponds to the + * directive class the property applies to. + * If the property assignment is not on a class decorator, no declaration is returned. + * + * For example, + * + * @Component({ + * template: '
' + * ^^^^^^^^^^^^^^^^^^^^^^^---- property assignment + * }) + * class AppComponent {} + * ^---- class declaration node + * + * @param propAsgn property assignment + */ +export function getClassDeclFromDecoratorProp(propAsgnNode: ts.PropertyAssignment): + ts.ClassDeclaration|undefined { + if (!propAsgnNode.parent || !ts.isObjectLiteralExpression(propAsgnNode.parent)) { + return; + } + const objLitExprNode = propAsgnNode.parent; + if (!objLitExprNode.parent || !ts.isCallExpression(objLitExprNode.parent)) { + return; + } + const callExprNode = objLitExprNode.parent; + if (!callExprNode.parent || !ts.isDecorator(callExprNode.parent)) { + return; + } + const decorator = callExprNode.parent; + if (!decorator.parent || !ts.isClassDeclaration(decorator.parent)) { + return; + } + const classDeclNode = decorator.parent; + return classDeclNode; +} + +/** + * Determines if a property assignment is on a class decorator. + * See `getClassDeclFromDecoratorProperty`, which gets the class the decorator is applied to, for + * more details. + * + * @param prop property assignment + */ +export function isClassDecoratorProperty(propAsgn: ts.PropertyAssignment): boolean { + return !!getClassDeclFromDecoratorProp(propAsgn); +} diff --git a/packages/language-service/src/version.ts b/packages/language-service/src/version.ts deleted file mode 100644 index af66f0fa278a8..0000000000000 --- a/packages/language-service/src/version.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * @module - * @description - * Entry point for all public APIs of the common package. - */ - -import {Version} from '@angular/core'; - -export const VERSION = new Version('0.0.0-PLACEHOLDER'); diff --git a/packages/language-service/test/BUILD.bazel b/packages/language-service/test/BUILD.bazel index c033a2006701c..4dcdc45adb1e5 100644 --- a/packages/language-service/test/BUILD.bazel +++ b/packages/language-service/test/BUILD.bazel @@ -47,7 +47,6 @@ ts_library( "html_info_spec.ts", "language_service_spec.ts", "reflector_host_spec.ts", - "template_spec.ts", "ts_plugin_spec.ts", "typescript_host_spec.ts", "utils_spec.ts", diff --git a/packages/language-service/test/mocks.ts b/packages/language-service/test/mocks.ts index 4fdcc66d12151..4046ae37ad3b9 100644 --- a/packages/language-service/test/mocks.ts +++ b/packages/language-service/test/mocks.ts @@ -14,7 +14,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; -import {DiagnosticTemplateInfo} from '../src/expression_diagnostics'; +import {DiagnosticTemplateInfo} from '../src/types'; import {getClassMembers, getPipesTable, getSymbolQuery} from '../src/typescript_symbols'; const realFiles = new Map(); diff --git a/packages/language-service/test/template_spec.ts b/packages/language-service/test/template_spec.ts deleted file mode 100644 index 1574e3ef34248..0000000000000 --- a/packages/language-service/test/template_spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as ts from 'typescript'; -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', ` - @Component({ - template: '
' - }) - class MyComponent {}`, - ts.ScriptTarget.ES2015, true /* setParentNodes */); - function visit(node: ts.Node): ts.ClassDeclaration|undefined { - if (ts.isPropertyAssignment(node)) { - return getClassDeclFromDecoratorProp(node); - } - return node.forEachChild(visit); - } - const classDecl = sourceFile.forEachChild(visit); - expect(classDecl).toBeTruthy(); - 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'); - expect(sourceFile).toBeTruthy(); - 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'); - }); -}); diff --git a/packages/language-service/test/typescript_symbols_spec.ts b/packages/language-service/test/typescript_symbols_spec.ts index 058d49a0dc3f6..7c901f9edaea6 100644 --- a/packages/language-service/test/typescript_symbols_spec.ts +++ b/packages/language-service/test/typescript_symbols_spec.ts @@ -11,7 +11,7 @@ import {ReflectorHost} from '@angular/language-service/src/reflector_host'; import * as ts from 'typescript'; import {BuiltinType, Symbol, SymbolQuery, SymbolTable} from '../src/symbols'; -import {getSymbolQuery, toSymbolTableFactory} from '../src/typescript_symbols'; +import {getSymbolQuery} from '../src/typescript_symbols'; import {DiagnosticContext, MockLanguageServiceHost} from './mocks'; @@ -79,14 +79,6 @@ 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; - expect(toSymbolTableFactory([a, b]) instanceof Map).toEqual(true); - }); -}); - function appComponentSource(template: string): string { return ` import {Component} from '@angular/core'; diff --git a/packages/language-service/test/utils_spec.ts b/packages/language-service/test/utils_spec.ts index 3d940c36dab93..c4d2159a99df3 100644 --- a/packages/language-service/test/utils_spec.ts +++ b/packages/language-service/test/utils_spec.ts @@ -9,7 +9,8 @@ import * as ng from '@angular/compiler'; import * as ts from 'typescript'; -import {getDirectiveClassLike, getPathToNodeAtPosition} from '../src/utils'; +import {getClassDeclFromDecoratorProp, getDirectiveClassLike, getPathToNodeAtPosition} from '../src/utils'; +import {MockTypescriptHost} from './test_utils'; describe('getDirectiveClassLike', () => { it('should return a directive class', () => { @@ -80,3 +81,42 @@ describe('getPathToNodeAtPosition', () => { expect(path.tail instanceof ng.Attribute).toBe(true); }); }); + +describe('getClassDeclFromTemplateNode', () => { + it('should find class declaration in syntax-only mode', () => { + const sourceFile = ts.createSourceFile( + 'foo.ts', ` + @Component({ + template: '
' + }) + class MyComponent {}`, + ts.ScriptTarget.ES2015, true /* setParentNodes */); + function visit(node: ts.Node): ts.ClassDeclaration|undefined { + if (ts.isPropertyAssignment(node)) { + return getClassDeclFromDecoratorProp(node); + } + return node.forEachChild(visit); + } + const classDecl = sourceFile.forEachChild(visit); + expect(classDecl).toBeTruthy(); + 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'); + expect(sourceFile).toBeTruthy(); + 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'); + }); +}); From fdc6dcd05dee13bc535d946b123fcf659b943492 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 13 Apr 2020 12:45:21 -0700 Subject: [PATCH 2/2] fixup! refactor(language-service): clean up and exports and consolidate types --- goldens/packages-circular-deps.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/goldens/packages-circular-deps.json b/goldens/packages-circular-deps.json index 92e8e0aabda3a..aed337abef890 100644 --- a/goldens/packages-circular-deps.json +++ b/goldens/packages-circular-deps.json @@ -1956,10 +1956,6 @@ "packages/forms/src/directives/validators.ts", "packages/forms/src/validators.ts" ], - [ - "packages/language-service/src/common.ts", - "packages/language-service/src/types.ts" - ], [ "packages/language-service/src/completions.ts", "packages/language-service/src/template.ts",