diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index 0a01ebf5dd..dc0895c26e 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, AbsoluteSourceSpan, AstPath, AttrAst, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, Element, ElementAst, EmptyExpr, ExpressionBinding, HtmlAstPath, NAMED_ENTITIES, Node as HtmlAst, NullTemplateVisitor, ParseSpan, ReferenceAst, TagContentType, TemplateBinding, Text, VariableBinding, getHtmlTagDefinition} from '@angular/compiler'; +import {AbsoluteSourceSpan, AST, AstPath, AttrAst, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, Element, ElementAst, EmptyExpr, ExpressionBinding, getHtmlTagDefinition, HtmlAstPath, NAMED_ENTITIES, Node as HtmlAst, NullTemplateVisitor, ParseSpan, ReferenceAst, TagContentType, TemplateBinding, Text, VariableBinding} from '@angular/compiler'; import {$$, $_, isAsciiLetter, isDigit} from '@angular/compiler/src/chars'; import {AstResult} from './common'; @@ -216,7 +216,8 @@ export function getTemplateCompletions( const replacementSpan = getBoundedWordSpan(templateInfo, position); return result.map(entry => { return { - ...entry, replacementSpan, + ...entry, + replacementSpan, }; }); } @@ -331,7 +332,7 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C elemAst = parent; } } else if (templatePath.tail instanceof ElementAst) { - refAst = new ReferenceAst(htmlAttr.name, null !, htmlAttr.value, htmlAttr.valueSpan !); + refAst = new ReferenceAst(htmlAttr.name, null!, htmlAttr.value, htmlAttr.valueSpan!); elemAst = templatePath.tail; } if (refAst && elemAst) { @@ -340,7 +341,7 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C } else { // HtmlAst contains the `Attribute` node, however the corresponding `AttrAst` // node is missing from the TemplateAst. - const attrAst = new AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan !); + const attrAst = new AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan!); attrAst.visit(visitor, null); } return visitor.results; @@ -434,7 +435,9 @@ class ExpressionVisitor extends NullTemplateVisitor { super(); } - get results(): ng.CompletionEntry[] { return Array.from(this.completions.values()); } + get results(): ng.CompletionEntry[] { + return Array.from(this.completions.values()); + } visitDirectiveProperty(ast: BoundDirectivePropertyAst): void { this.processExpressionCompletions(ast.value); @@ -444,7 +447,9 @@ class ExpressionVisitor extends NullTemplateVisitor { this.processExpressionCompletions(ast.value); } - visitEvent(ast: BoundEventAst): void { this.processExpressionCompletions(ast.handler); } + visitEvent(ast: BoundEventAst): void { + this.processExpressionCompletions(ast.handler); + } visitElement(): void { // no-op for now @@ -577,7 +582,7 @@ class ExpressionVisitor extends NullTemplateVisitor { } } else if (binding instanceof ExpressionBinding) { if (inSpan(this.position, binding.value?.ast.sourceSpan)) { - this.processExpressionCompletions(binding.value !.ast); + this.processExpressionCompletions(binding.value!.ast); return; } else if (!binding.value && this.position > binding.key.span.end) { // No expression is defined for the value of the key expression binding, but the cursor is @@ -637,7 +642,7 @@ function angularAttributes(info: AstResult, elementName: string): AngularAttribu if (selector.element && selector.element !== elementName) { continue; } - const summary = selectorMap.get(selector) !; + const summary = selectorMap.get(selector)!; const hasTemplateRef = isStructuralDirective(summary.type); // attributes are listed in (attribute, value) pairs for (let i = 0; i < selector.attrs.length; i += 2) { diff --git a/packages/language-service/src/definitions.ts b/packages/language-service/src/definitions.ts index 17c14744d5..417df1f1e1 100644 --- a/packages/language-service/src/definitions.ts +++ b/packages/language-service/src/definitions.ts @@ -7,7 +7,7 @@ */ import * as path from 'path'; -import * as ts from 'typescript'; // used as value and is provided at runtime +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'; diff --git a/packages/language-service/src/diagnostic_messages.ts b/packages/language-service/src/diagnostic_messages.ts index 885d781bd2..749dceb8fd 100644 --- a/packages/language-service/src/diagnostic_messages.ts +++ b/packages/language-service/src/diagnostic_messages.ts @@ -14,15 +14,15 @@ export interface DiagnosticMessage { kind: keyof typeof ts.DiagnosticCategory; } -type DiagnosticName = 'directive_not_in_module' | 'missing_template_and_templateurl' | - 'both_template_and_templateurl' | 'invalid_templateurl' | 'template_context_missing_member' | - 'callable_expression_expected_method_call' | 'call_target_not_callable' | - 'expression_might_be_null' | 'expected_a_number_type' | 'expected_a_string_or_number_type' | - 'expected_operands_of_similar_type_or_any' | 'unrecognized_operator' | - 'unrecognized_primitive' | 'no_pipe_found' | 'unable_to_resolve_compatible_call_signature' | - 'unable_to_resolve_signature' | 'could_not_resolve_type' | 'identifier_not_callable' | - 'identifier_possibly_undefined' | 'identifier_not_defined_in_app_context' | - 'identifier_not_defined_on_receiver' | 'identifier_is_private'; +type DiagnosticName = 'directive_not_in_module'|'missing_template_and_templateurl'| + 'both_template_and_templateurl'|'invalid_templateurl'|'template_context_missing_member'| + 'callable_expression_expected_method_call'|'call_target_not_callable'| + 'expression_might_be_null'|'expected_a_number_type'|'expected_a_string_or_number_type'| + 'expected_operands_of_similar_type_or_any'|'unrecognized_operator'|'unrecognized_primitive'| + 'no_pipe_found'|'unable_to_resolve_compatible_call_signature'|'unable_to_resolve_signature'| + 'could_not_resolve_type'|'identifier_not_callable'|'identifier_possibly_undefined'| + 'identifier_not_defined_in_app_context'|'identifier_not_defined_on_receiver'| + 'identifier_is_private'; export const Diagnostic: Record = { directive_not_in_module: { @@ -156,6 +156,7 @@ export function createDiagnostic( dm.message.replace(/%(\d+)/g, (_, index: string) => formatArgs[+index - 1]); return { kind: ts.DiagnosticCategory[dm.kind], - message: formattedMessage, span, + message: formattedMessage, + span, }; } diff --git a/packages/language-service/src/diagnostics.ts b/packages/language-service/src/diagnostics.ts index d437a918ea..646086c5ef 100644 --- a/packages/language-service/src/diagnostics.ts +++ b/packages/language-service/src/diagnostics.ts @@ -11,7 +11,7 @@ import * as path from 'path'; import * as ts from 'typescript'; import {AstResult} from './common'; -import {Diagnostic, createDiagnostic} from './diagnostic_messages'; +import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {getTemplateExpressionDiagnostics} from './expression_diagnostics'; import * as ng from './types'; import {TypeScriptServiceHost} from './typescript_host'; @@ -193,7 +193,7 @@ function chainDiagnostics(chain: ng.DiagnosticMessageChain): ts.DiagnosticMessag * @param file */ export function ngDiagnosticToTsDiagnostic( - d: ng.Diagnostic, file: ts.SourceFile | undefined): ts.Diagnostic { + d: ng.Diagnostic, file: ts.SourceFile|undefined): ts.Diagnostic { return { file, start: d.span.start, diff --git a/packages/language-service/src/expression_diagnostics.ts b/packages/language-service/src/expression_diagnostics.ts index 0af26418be..61e62ec618 100644 --- a/packages/language-service/src/expression_diagnostics.ts +++ b/packages/language-service/src/expression_diagnostics.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, VariableAst, identifierName, templateVisitAll, tokenReference} from '@angular/compiler'; +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 {Diagnostic, createDiagnostic} from './diagnostic_messages'; +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'; @@ -44,7 +44,9 @@ function getReferences(info: DiagnosticTemplateInfo): SymbolDeclaration[] { name: reference.name, kind: 'reference', type: type || info.query.getBuiltinType(BuiltinType.Any), - get definition() { return getDefinitionOf(info, reference); } + get definition() { + return getDefinitionOf(info, reference); + } }); } } @@ -109,7 +111,10 @@ function getVarDeclarations( results.push({ name: variable.name, kind: 'variable', - type: symbol, get definition() { return getDefinitionOf(info, variable); }, + type: symbol, + get definition() { + return getDefinitionOf(info, variable); + }, }); } } @@ -296,7 +301,7 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { visitVariable(ast: VariableAst): void { const directive = this.directiveSummary; if (directive && ast.value) { - const context = this.info.query.getTemplateContext(directive.type.reference) !; + const context = this.info.query.getTemplateContext(directive.type.reference)!; if (context && !context.has(ast.value)) { const missingMember = ast.value === '$implicit' ? 'an implicit value' : `a member called '${ast.value}'`; @@ -322,7 +327,7 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { // Find directive that references this template this.directiveSummary = - ast.directives.map(d => d.directive).find(d => hasTemplateReference(d.type)) !; + ast.directives.map(d => d.directive).find(d => hasTemplateReference(d.type))!; // Process children super.visitEmbeddedTemplate(ast, context); @@ -350,9 +355,13 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { } } - private push(ast: TemplateAst) { this.path.push(ast); } + private push(ast: TemplateAst) { + this.path.push(ast); + } - private pop() { this.path.pop(); } + private pop() { + this.path.pop(); + } private absSpan(span: Span, additionalOffset: number = 0): Span { return { @@ -366,7 +375,7 @@ function hasTemplateReference(type: CompileTypeMetadata): boolean { if (type.diDeps) { for (let diDep of type.diDeps) { if (diDep.token && diDep.token.identifier && - identifierName(diDep.token !.identifier !) == 'TemplateRef') + identifierName(diDep.token!.identifier!) == 'TemplateRef') return true; } } diff --git a/packages/language-service/src/expression_type.ts b/packages/language-service/src/expression_type.ts index 5277ca3c55..8b2b5caeb2 100644 --- a/packages/language-service/src/expression_type.ts +++ b/packages/language-service/src/expression_type.ts @@ -8,11 +8,13 @@ import {AST, AstVisitor, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead} from '@angular/compiler'; -import {Diagnostic, createDiagnostic} from './diagnostic_messages'; +import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {BuiltinType, Signature, Symbol, SymbolQuery, SymbolTable} from './symbols'; import * as ng from './types'; -export interface ExpressionDiagnosticsContext { inEvent?: boolean; } +export interface ExpressionDiagnosticsContext { + inEvent?: boolean; +} // AstType calculatetype of the ast given AST element. export class AstType implements AstVisitor { @@ -22,7 +24,9 @@ export class AstType implements AstVisitor { private scope: SymbolTable, private query: SymbolQuery, private context: ExpressionDiagnosticsContext, private source: string) {} - getType(ast: AST): Symbol { return ast.visit(this); } + getType(ast: AST): Symbol { + return ast.visit(this); + } getDiagnostics(ast: AST): ng.Diagnostic[] { const type: Symbol = ast.visit(this); @@ -204,10 +208,10 @@ export class AstType implements AstVisitor { // support contextual typing of arguments so this is simpler than TypeScript's // version. const args = ast.args.map(arg => this.getType(arg)); - const target = this.getType(ast.target !); + const target = this.getType(ast.target!); if (!target || !target.callable) { this.diagnostics.push(createDiagnostic( - ast.span, Diagnostic.call_target_not_callable, this.sourceOf(ast.target !), target.name)); + ast.span, Diagnostic.call_target_not_callable, this.sourceOf(ast.target!), target.name)); return this.anyType; } const signature = target.selectSignature(args); @@ -237,11 +241,24 @@ export class AstType implements AstVisitor { public: true, definition: undefined, documentation: [], - members(): SymbolTable{return _this.scope;}, - signatures(): Signature[]{return [];}, - selectSignature(types): Signature | undefined{return undefined;}, - indexed(argument): Symbol | undefined{return undefined;}, - typeArguments(): Symbol[] | undefined{return undefined;}, + members(): SymbolTable { + return _this.scope; + }, + signatures(): Signature[] { + return []; + }, + selectSignature(types): Signature | + undefined { + return undefined; + }, + indexed(argument): Symbol | + undefined { + return undefined; + }, + typeArguments(): Symbol[] | + undefined { + return undefined; + }, }; } diff --git a/packages/language-service/src/expressions.ts b/packages/language-service/src/expressions.ts index 594a3c565b..bc33a1650a 100644 --- a/packages/language-service/src/expressions.ts +++ b/packages/language-service/src/expressions.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, ASTWithSource, AstPath as AstPathBase, RecursiveAstVisitor} from '@angular/compiler'; +import {AST, AstPath as AstPathBase, ASTWithSource, RecursiveAstVisitor} from '@angular/compiler'; + import {AstType} from './expression_type'; import {BuiltinType, Span, Symbol, SymbolTable, TemplateSource} from './types'; import {inSpan} from './utils'; @@ -41,7 +42,7 @@ export function getExpressionCompletions( undefined { const path = findAstAt(ast, position); if (path.empty) return undefined; - const tail = path.tail !; + const tail = path.tail!; let result: SymbolTable|undefined = scope; function getType(ast: AST): Symbol { @@ -57,7 +58,9 @@ export function getExpressionCompletions( visitConditional(ast) {}, visitFunctionCall(ast) {}, visitImplicitReceiver(ast) {}, - visitInterpolation(ast) { result = undefined; }, + visitInterpolation(ast) { + result = undefined; + }, visitKeyedRead(ast) {}, visitKeyedWrite(ast) {}, visitLiteralArray(ast) {}, @@ -111,7 +114,7 @@ export function getExpressionSymbol( templateInfo: TemplateSource): {symbol: Symbol, span: Span}|undefined { const path = findAstAt(ast, position, /* excludeEmpty */ true); if (path.empty) return undefined; - const tail = path.tail !; + const tail = path.tail!; function getType(ast: AST): Symbol { return new AstType(scope, templateInfo.query, {}, templateInfo.source).getType(ast); diff --git a/packages/language-service/src/hover.ts b/packages/language-service/src/hover.ts index 145fdfbc6b..9d60e13554 100644 --- a/packages/language-service/src/hover.ts +++ b/packages/language-service/src/hover.ts @@ -37,14 +37,15 @@ export function getTemplateHover( // The container is either the symbol's container (for example, 'AppComponent' // is the container of the symbol 'title' in its template) or the NgModule // that the directive belongs to (the container of AppComponent is AppModule). - let containerName: string|undefined = symbol.container ?.name; + let containerName: string|undefined = symbol.container?.name; if (!containerName && staticSymbol) { // If there is a static symbol then the target is a directive. const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol); - containerName = ngModule ?.type.reference.name; + containerName = ngModule?.type.reference.name; } - return createQuickInfo(symbol.name, symbol.kind, span, containerName, symbol.type?.name, symbol.documentation); + return createQuickInfo( + symbol.name, symbol.kind, span, containerName, symbol.type?.name, symbol.documentation); } /** @@ -63,7 +64,7 @@ export function getTsHover( const kind = metadata.isComponent ? 'component' : 'directive'; const textSpan = ts.createTextSpanFromBounds(declarationSpan.start, declarationSpan.end); const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol); - const moduleName = ngModule ?.type.reference.name; + const moduleName = ngModule?.type.reference.name; return createQuickInfo( directiveName, kind, textSpan, moduleName, ts.ScriptElementKind.classElement); } diff --git a/packages/language-service/src/html_info.ts b/packages/language-service/src/html_info.ts index b54243ba2f..dc5315c0c3 100644 --- a/packages/language-service/src/html_info.ts +++ b/packages/language-service/src/html_info.ts @@ -10,7 +10,7 @@ // This section defines the HTML elements and attribute surface of HTML 4 // which is derived from https://www.w3.org/TR/html4/strict.dtd -type attrType = string | string[]; +type attrType = string|string[]; type hash = { [name: string]: T }; @@ -104,7 +104,9 @@ const groups: hash[] = [ {class: 1, style: 1}, {hreflang: 2, rel: 1, rev: 1}, {ismap: 7}, - { defer: 25, event: 1, for : 1 } + { + defer: 25, event: 1, for: 1 + } ]; const elements: {[name: string]: number[]} = { @@ -193,7 +195,7 @@ export function elementNames(): string[] { return Object.keys(elements).sort().map(v => v.toLowerCase()); } -function compose(indexes: number[] | undefined): hash { +function compose(indexes: number[]|undefined): hash { const result: hash = {}; if (indexes) { for (let index of indexes) { @@ -415,7 +417,9 @@ export class SchemaInformation { }); } - allKnownElements(): string[] { return Object.keys(this.schema); } + allKnownElements(): string[] { + return Object.keys(this.schema); + } eventsOf(elementName: string): string[] { const elementType = this.schema[elementName.toLowerCase()] || {}; diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index 1f1cbc286f..fba5d1a812 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, VariableBinding, templateVisitAll, tokenReference} from '@angular/compiler'; +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'; @@ -77,7 +77,7 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): } if (result) { symbol = result.symbol; - span = offsetSpan(result.span, attribute.valueSpan !.start.offset); + span = offsetSpan(result.span, attribute.valueSpan!.start.offset); } return true; } @@ -121,7 +121,9 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): span = spanOf(ast); } }, - visitElementProperty(ast) { attributeValueSymbol(ast.value); }, + visitElementProperty(ast) { + attributeValueSymbol(ast.value); + }, visitAttr(ast) { const element = path.first(ElementAst); if (!element) return; @@ -188,7 +190,8 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): const {start, end} = offsetSpan(span, info.template.span.start); return { symbol, - span: tss.createTextSpanFromBounds(start, end), staticSymbol, + span: tss.createTextSpanFromBounds(start, end), + staticSymbol, }; } } @@ -216,7 +219,7 @@ function getSymbolInMicrosyntax(info: AstResult, path: TemplateAstPath, attribut if (inSpan(path.position, tb.value?.ast.sourceSpan)) { const dinfo = diagnosticInfoFromTemplateInfo(info); const scope = getExpressionScope(dinfo, path); - result = getExpressionSymbol(scope, tb.value !, path.position, info.template); + result = getExpressionSymbol(scope, tb.value!, path.position, info.template); } else if (inSpan(path.position, tb.sourceSpan)) { const template = path.first(EmbeddedTemplateAst); if (template) { @@ -277,7 +280,9 @@ function findParentOfBinding( } visitDirective(ast: DirectiveAst) { - const result = this.visitChildren(ast, visit => { visit(ast.inputs); }); + const result = this.visitChildren(ast, visit => { + visit(ast.inputs); + }); return result; } @@ -309,33 +314,63 @@ function findInputBinding(info: AstResult, name: string, directiveAst: Directive */ class OverrideKindSymbol implements Symbol { public readonly kind: DirectiveKind; - constructor(private sym: Symbol, kindOverride: DirectiveKind) { this.kind = kindOverride; } + constructor(private sym: Symbol, kindOverride: DirectiveKind) { + this.kind = kindOverride; + } - get name(): string { return this.sym.name; } + get name(): string { + return this.sym.name; + } - get language(): string { return this.sym.language; } + get language(): string { + return this.sym.language; + } - get type(): Symbol|undefined { return this.sym.type; } + get type(): Symbol|undefined { + return this.sym.type; + } - get container(): Symbol|undefined { return this.sym.container; } + get container(): Symbol|undefined { + return this.sym.container; + } - get public(): boolean { return this.sym.public; } + get public(): boolean { + return this.sym.public; + } - get callable(): boolean { return this.sym.callable; } + get callable(): boolean { + return this.sym.callable; + } - get nullable(): boolean { return this.sym.nullable; } + get nullable(): boolean { + return this.sym.nullable; + } - get definition(): Definition { return this.sym.definition; } + get definition(): Definition { + return this.sym.definition; + } - get documentation(): ts.SymbolDisplayPart[] { return this.sym.documentation; } + get documentation(): ts.SymbolDisplayPart[] { + return this.sym.documentation; + } - members() { return this.sym.members(); } + members() { + return this.sym.members(); + } - signatures() { return this.sym.signatures(); } + signatures() { + return this.sym.signatures(); + } - selectSignature(types: Symbol[]) { return this.sym.selectSignature(types); } + selectSignature(types: Symbol[]) { + return this.sym.selectSignature(types); + } - indexed(argument: Symbol) { return this.sym.indexed(argument); } + indexed(argument: Symbol) { + return this.sym.indexed(argument); + } - typeArguments(): Symbol[]|undefined { return this.sym.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.sym.typeArguments(); + } } diff --git a/packages/language-service/src/reflector_host.ts b/packages/language-service/src/reflector_host.ts index 13ba23a885..6a1b837932 100644 --- a/packages/language-service/src/reflector_host.ts +++ b/packages/language-service/src/reflector_host.ts @@ -7,7 +7,7 @@ */ import {StaticSymbolResolverHost} from '@angular/compiler'; -import {MetadataCollector, MetadataReaderHost, createMetadataReaderCache, readMetadata} from '@angular/compiler-cli/src/language_services'; +import {createMetadataReaderCache, MetadataCollector, MetadataReaderHost, readMetadata} from '@angular/compiler-cli/src/language_services'; import * as path from 'path'; import * as ts from 'typescript'; @@ -26,10 +26,10 @@ class ReflectorModuleModuleResolutionHost implements ts.ModuleResolutionHost, Me private readonly tsLSHost: ts.LanguageServiceHost, private readonly getProgram: () => ts.Program) { if (tsLSHost.directoryExists) { - this.directoryExists = directoryName => tsLSHost.directoryExists !(directoryName); + this.directoryExists = directoryName => tsLSHost.directoryExists!(directoryName); } if (tsLSHost.realpath) { - this.realpath = path => tsLSHost.realpath !(path); + this.realpath = path => tsLSHost.realpath!(path); } } @@ -53,14 +53,14 @@ class ReflectorModuleModuleResolutionHost implements ts.ModuleResolutionHost, Me // resolution, and it's used by Angular to read metadata.json during // metadata resolution. if (this.tsLSHost.readFile) { - return this.tsLSHost.readFile(fileName) !; + return this.tsLSHost.readFile(fileName)!; } // As a fallback, read the JSON files from the editor snapshot. const snapshot = this.tsLSHost.getScriptSnapshot(fileName); if (!snapshot) { // MetadataReaderHost readFile() declaration should be // `readFile(fileName: string): string | undefined` - return undefined !; + return undefined!; } return snapshot.getText(0, snapshot.getLength()); } @@ -120,5 +120,7 @@ export class ReflectorHost implements StaticSymbolResolverHost { return resolved ? resolved.resolvedFileName : null; } - getOutputName(filePath: string) { return filePath; } + getOutputName(filePath: string) { + return filePath; + } } diff --git a/packages/language-service/src/symbols.ts b/packages/language-service/src/symbols.ts index da3f851e24..f4eb514282 100644 --- a/packages/language-service/src/symbols.ts +++ b/packages/language-service/src/symbols.ts @@ -40,7 +40,7 @@ export interface Location { /** * A defnition location(s). */ -export type Definition = Location[] | undefined; +export type Definition = Location[]|undefined; /** * A symbol describing a language element that can be referenced by expressions @@ -235,8 +235,8 @@ export enum BuiltinType { * * @publicApi */ -export type DeclarationKind = 'attribute' | 'html attribute' | 'component' | 'element' | 'entity' | - 'key' | 'method' | 'pipe' | 'property' | 'type' | 'reference' | 'variable'; +export type DeclarationKind = 'attribute'|'html attribute'|'component'|'element'|'entity'|'key'| + 'method'|'pipe'|'property'|'type'|'reference'|'variable'; /** * Describes a symbol to type binding used to build a symbol table. @@ -287,7 +287,7 @@ export interface PipeInfo { * * @publicApi */ -export type Pipes = PipeInfo[] | undefined; +export type Pipes = PipeInfo[]|undefined; /** * Describes the language context in which an Angular expression is evaluated. diff --git a/packages/language-service/src/template.ts b/packages/language-service/src/template.ts index e882b1ca81..c5f3924bea 100644 --- a/packages/language-service/src/template.ts +++ b/packages/language-service/src/template.ts @@ -39,7 +39,9 @@ abstract class BaseTemplate implements ng.TemplateSource { /** * Return the Angular StaticSymbol for the class that contains this template. */ - get type() { return this.classSymbol; } + get type() { + return this.classSymbol; + } /** * Return a Map-like data structure that allows users to retrieve some or all diff --git a/packages/language-service/src/ts_plugin.ts b/packages/language-service/src/ts_plugin.ts index e2d4594cc9..d7774bf222 100644 --- a/packages/language-service/src/ts_plugin.ts +++ b/packages/language-service/src/ts_plugin.ts @@ -27,8 +27,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { const ngLS = createLanguageService(ngLSHost); function getCompletionsAtPosition( - fileName: string, position: number, - options: tss.GetCompletionsAtPositionOptions | undefined) { + fileName: string, position: number, options: tss.GetCompletionsAtPositionOptions|undefined) { if (!angularOnly) { const results = tsLS.getCompletionsAtPosition(fileName, position, options); if (results && results.entries.length) { @@ -93,8 +92,11 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { {}, tsLS, // Then override the methods supported by Angular language service { - getCompletionsAtPosition, getQuickInfoAtPosition, getSemanticDiagnostics, - getDefinitionAtPosition, getDefinitionAndBoundSpan, + getCompletionsAtPosition, + getQuickInfoAtPosition, + getSemanticDiagnostics, + getDefinitionAtPosition, + getDefinitionAndBoundSpan, }); return proxy; } diff --git a/packages/language-service/src/types.ts b/packages/language-service/src/types.ts index cb349eea4d..804a3fbc08 100644 --- a/packages/language-service/src/types.ts +++ b/packages/language-service/src/types.ts @@ -74,7 +74,7 @@ export interface TemplateSource { * * @publicApi */ -export type TemplateSources = TemplateSource[] | undefined; +export type TemplateSources = TemplateSource[]|undefined; /** * Error information found getting declaration information @@ -264,7 +264,7 @@ export enum CompletionKind { VARIABLE = 'variable', } -export type CompletionEntry = Omit& { +export type CompletionEntry = Omit&{ kind: CompletionKind, }; @@ -361,5 +361,6 @@ export interface Hover { * @publicApi */ export type LanguageService = Pick< - ts.LanguageService, 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'| - 'getQuickInfoAtPosition'|'getSemanticDiagnostics'>; + ts.LanguageService, + 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'|'getQuickInfoAtPosition'| + 'getSemanticDiagnostics'>; diff --git a/packages/language-service/src/typescript_host.ts b/packages/language-service/src/typescript_host.ts index e7a6e8d9ef..20602d028c 100644 --- a/packages/language-service/src/typescript_host.ts +++ b/packages/language-service/src/typescript_host.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotSummaryResolver, CompileDirectiveSummary, 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 {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 {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, InlineTemplate, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue} from './template'; +import {ExternalTemplate, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue, InlineTemplate} from './template'; import {Declaration, DeclarationError, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, TemplateSource} from './types'; import {findTightestNode, getDirectiveClassLike} from './utils'; @@ -35,14 +35,18 @@ export function createLanguageServiceFromTypescript( * syntactically incorrect templates. */ export class DummyHtmlParser extends HtmlParser { - parse(): ParseTreeResult { return new ParseTreeResult([], []); } + parse(): ParseTreeResult { + return new ParseTreeResult([], []); + } } /** * Avoid loading resources in the language servcie by using a dummy loader. */ export class DummyResourceLoader extends ResourceLoader { - get(url: string): Promise { return Promise.resolve(''); } + get(url: string): Promise { + return Promise.resolve(''); + } } /** @@ -74,10 +78,18 @@ export class TypeScriptServiceHost implements LanguageServiceHost { readonly tsLsHost: tss.LanguageServiceHost, private readonly tsLS: tss.LanguageService) { this.summaryResolver = new AotSummaryResolver( { - loadSummary(filePath: string) { return null; }, - isSourceFile(sourceFilePath: string) { return true; }, - toSummaryFileName(sourceFilePath: string) { return sourceFilePath; }, - fromSummaryFileName(filePath: string): string{return filePath;}, + loadSummary(filePath: string) { + return null; + }, + isSourceFile(sourceFilePath: string) { + return true; + }, + toSummaryFileName(sourceFilePath: string) { + return sourceFilePath; + }, + fromSummaryFileName(filePath: string): string { + return filePath; + }, }, this.staticSymbolCache); this.reflectorHost = new ReflectorHost(() => this.program, tsLsHost); @@ -159,7 +171,11 @@ export class TypeScriptServiceHost implements LanguageServiceHost { this.collectedErrors.clear(); this.resolver.clearCache(); - const analyzeHost = {isSourceFile(filePath: string) { return true; }}; + const analyzeHost = { + isSourceFile(filePath: string) { + return true; + } + }; const programFiles = this.program.getSourceFiles().map(sf => sf.fileName); this.analyzedModules = analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver); @@ -168,7 +184,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost { const urlResolver = createOfflineCompileUrlResolver(); for (const ngModule of this.analyzedModules.ngModules) { for (const directive of ngModule.declaredDirectives) { - const {metadata} = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference) !; + const {metadata} = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference)!; if (metadata.isComponent && metadata.template && metadata.template.templateUrl) { const templateName = urlResolver.resolve( this.reflector.componentModuleUrl(directive.reference), @@ -494,9 +510,9 @@ export class TypeScriptServiceHost implements LanguageServiceHost { const parser = new TemplateParser( new CompilerConfig(), this.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser, - null !, // console - [] // tranforms - ); + null!, // console + [] // tranforms + ); const htmlResult = htmlParser.parse(template.source, fileName, { tokenizeExpansionForms: true, preserveLineEndings: true, // do not convert CRLF to LF @@ -509,8 +525,12 @@ export class TypeScriptServiceHost implements LanguageServiceHost { return { htmlAst: htmlResult.rootNodes, templateAst: parseResult.templateAst, - directive: data.metadata, directives, pipes, - parseErrors: parseResult.errors, expressionParser, template, + directive: data.metadata, + directives, + pipes, + parseErrors: parseResult.errors, + expressionParser, + template, }; } @@ -574,7 +594,7 @@ function spanOf(node: tss.Node): Span { function spanAt(sourceFile: tss.SourceFile, line: number, column: number): Span|undefined { if (line != null && column != null) { const position = tss.getPositionOfLineAndCharacter(sourceFile, line, column); - const findChild = function findChild(node: tss.Node): tss.Node | undefined { + const findChild = function findChild(node: tss.Node): tss.Node|undefined { if (node.kind > tss.SyntaxKind.LastToken && node.pos <= position && node.end > position) { const betterNode = tss.forEachChild(node, findChild); return betterNode || node; diff --git a/packages/language-service/src/typescript_symbols.ts b/packages/language-service/src/typescript_symbols.ts index f018a092c6..19e5464c44 100644 --- a/packages/language-service/src/typescript_symbols.ts +++ b/packages/language-service/src/typescript_symbols.ts @@ -68,7 +68,7 @@ export function getClassFromStaticSymbol( return classDeclaration; } } - }) as(ts.ClassDeclaration | undefined); + }) as (ts.ClassDeclaration | undefined); } return undefined; @@ -123,7 +123,9 @@ class TypeScriptSymbolQuery implements SymbolQuery { return result || this.getBuiltinType(BuiltinType.Any); } - getArrayType(type: Symbol): Symbol { return this.getBuiltinType(BuiltinType.Any); } + getArrayType(type: Symbol): Symbol { + return this.getBuiltinType(BuiltinType.Any); + } getElementType(type: Symbol): Symbol|undefined { if (type instanceof TypeWrapper) { @@ -193,13 +195,13 @@ class TypeScriptSymbolQuery implements SymbolQuery { private getTemplateRefContextType(typeSymbol: ts.Symbol, context: TypeContext): Symbol|undefined { const type = this.checker.getTypeOfSymbolAtLocation(typeSymbol, this.source); const constructor = type.symbol && type.symbol.members && - getFromSymbolTable(type.symbol.members !, '__constructor'); + getFromSymbolTable(type.symbol.members!, '__constructor'); if (constructor) { - const constructorDeclaration = constructor.declarations ![0] as ts.ConstructorTypeNode; + const constructorDeclaration = constructor.declarations![0] as ts.ConstructorTypeNode; for (const parameter of constructorDeclaration.parameters) { - const type = this.checker.getTypeAtLocation(parameter.type !); - if (type.symbol !.name == 'TemplateRef' && isReferenceType(type)) { + const type = this.checker.getTypeAtLocation(parameter.type!); + if (type.symbol!.name == 'TemplateRef' && isReferenceType(type)) { const typeWrapper = new TypeWrapper(type, context); const typeArguments = typeWrapper.typeArguments(); if (typeArguments && typeArguments.length === 1) { @@ -237,7 +239,9 @@ class TypeWrapper implements Symbol { } } - get name(): string { return this.context.checker.typeToString(this.tsType); } + get name(): string { + return this.context.checker.typeToString(this.tsType); + } public readonly kind: DeclarationKind = 'type'; @@ -249,7 +253,9 @@ class TypeWrapper implements Symbol { public readonly public: boolean = true; - get callable(): boolean { return typeCallable(this.tsType); } + get callable(): boolean { + return typeCallable(this.tsType); + } get nullable(): boolean { return this.context.checker.getNonNullableType(this.tsType) != this.tsType; @@ -276,7 +282,9 @@ class TypeWrapper implements Symbol { return new SymbolTableWrapper(this.tsType.getApparentProperties(), this.context, this.tsType); } - signatures(): Signature[] { return signaturesOf(this.tsType, this.context); } + signatures(): Signature[] { + return signaturesOf(this.tsType, this.context); + } selectSignature(types: Symbol[]): Signature|undefined { return selectSignature(this.tsType, this.context, types); @@ -332,30 +340,44 @@ class SymbolWrapper implements Symbol { symbol: ts.Symbol, /** TypeScript type context of the symbol. */ private context: TypeContext, - /** Type of the TypeScript symbol, if known. If not provided, the type of the symbol - * will be determined dynamically; see `SymbolWrapper#tsType`. */ + /** + * Type of the TypeScript symbol, if known. If not provided, the type of the symbol + * will be determined dynamically; see `SymbolWrapper#tsType`. + */ private _tsType?: ts.Type) { this.symbol = symbol && context && (symbol.flags & ts.SymbolFlags.Alias) ? context.checker.getAliasedSymbol(symbol) : symbol; } - get name(): string { return this.symbol.name; } + get name(): string { + return this.symbol.name; + } - get kind(): DeclarationKind { return this.callable ? 'method' : 'property'; } + get kind(): DeclarationKind { + return this.callable ? 'method' : 'property'; + } - get type(): TypeWrapper { return new TypeWrapper(this.tsType, this.context); } + get type(): TypeWrapper { + return new TypeWrapper(this.tsType, this.context); + } - get container(): Symbol|undefined { return getContainerOf(this.symbol, this.context); } + get container(): Symbol|undefined { + return getContainerOf(this.symbol, this.context); + } get public(): boolean { // Symbols that are not explicitly made private are public. return !isSymbolPrivate(this.symbol); } - get callable(): boolean { return typeCallable(this.tsType); } + get callable(): boolean { + return typeCallable(this.tsType); + } - get definition(): Definition { return definitionFromTsSymbol(this.symbol); } + get definition(): Definition { + return definitionFromTsSymbol(this.symbol); + } get documentation(): ts.SymbolDisplayPart[] { return this.symbol.getDocumentationComment(this.context.checker); @@ -368,21 +390,27 @@ class SymbolWrapper implements Symbol { const typeWrapper = new TypeWrapper(declaredType, this.context); this._members = typeWrapper.members(); } else { - this._members = new SymbolTableWrapper(this.symbol.members !, this.context, this.tsType); + this._members = new SymbolTableWrapper(this.symbol.members!, this.context, this.tsType); } } return this._members; } - signatures(): Signature[] { return signaturesOf(this.tsType, this.context); } + signatures(): Signature[] { + return signaturesOf(this.tsType, this.context); + } selectSignature(types: Symbol[]): Signature|undefined { return selectSignature(this.tsType, this.context, types); } - indexed(argument: Symbol): Symbol|undefined { return undefined; } + indexed(argument: Symbol): Symbol|undefined { + return undefined; + } - typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.type.typeArguments(); + } private get tsType(): ts.Type { let type = this._tsType; @@ -403,29 +431,53 @@ class DeclaredSymbol implements Symbol { constructor(private declaration: SymbolDeclaration) {} - get name() { return this.declaration.name; } + get name() { + return this.declaration.name; + } - get kind() { return this.declaration.kind; } + get kind() { + return this.declaration.kind; + } - get container(): Symbol|undefined { return undefined; } + get container(): Symbol|undefined { + return undefined; + } - get type(): Symbol { return this.declaration.type; } + get type(): Symbol { + return this.declaration.type; + } - get callable(): boolean { return this.type.callable; } + get callable(): boolean { + return this.type.callable; + } - get definition(): Definition { return this.declaration.definition; } + get definition(): Definition { + return this.declaration.definition; + } - get documentation(): ts.SymbolDisplayPart[] { return this.declaration.type.documentation; } + get documentation(): ts.SymbolDisplayPart[] { + return this.declaration.type.documentation; + } - members(): SymbolTable { return this.type.members(); } + members(): SymbolTable { + return this.type.members(); + } - signatures(): Signature[] { return this.type.signatures(); } + signatures(): Signature[] { + return this.type.signatures(); + } - selectSignature(types: Symbol[]): Signature|undefined { return this.type.selectSignature(types); } + selectSignature(types: Symbol[]): Signature|undefined { + return this.type.selectSignature(types); + } - typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.type.typeArguments(); + } - indexed(argument: Symbol): Symbol|undefined { return undefined; } + indexed(argument: Symbol): Symbol|undefined { + return undefined; + } } class SignatureWrapper implements Signature { @@ -435,15 +487,21 @@ class SignatureWrapper implements Signature { return new SymbolTableWrapper(this.signature.getParameters(), this.context); } - get result(): Symbol { return new TypeWrapper(this.signature.getReturnType(), this.context); } + get result(): Symbol { + return new TypeWrapper(this.signature.getReturnType(), this.context); + } } class SignatureResultOverride implements Signature { constructor(private signature: Signature, private resultType: Symbol) {} - get arguments(): SymbolTable { return this.signature.arguments; } + get arguments(): SymbolTable { + return this.signature.arguments; + } - get result(): Symbol { return this.resultType; } + get result(): Symbol { + return this.resultType; + } } export function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { @@ -456,7 +514,7 @@ export function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { return result as ts.SymbolTable; } -function toSymbols(symbolTable: ts.SymbolTable | undefined): ts.Symbol[] { +function toSymbols(symbolTable: ts.SymbolTable|undefined): ts.Symbol[] { if (!symbolTable) return []; const table = symbolTable as any; @@ -507,7 +565,9 @@ class SymbolTableWrapper implements SymbolTable { } } - get size(): number { return this.symbols.length; } + get size(): number { + return this.symbols.length; + } get(key: string): Symbol|undefined { const symbol = getFromSymbolTable(this.symbolTable, key); @@ -535,20 +595,26 @@ class SymbolTableWrapper implements SymbolTable { this.stringIndexType !== undefined; } - values(): Symbol[] { return this.symbols.map(s => new SymbolWrapper(s, this.context)); } + values(): Symbol[] { + return this.symbols.map(s => new SymbolWrapper(s, this.context)); + } } class MapSymbolTable implements SymbolTable { private map = new Map(); private _values: Symbol[] = []; - get size(): number { return this.map.size; } + get size(): number { + return this.map.size; + } - get(key: string): Symbol|undefined { return this.map.get(key); } + get(key: string): Symbol|undefined { + return this.map.get(key); + } add(symbol: Symbol) { if (this.map.has(symbol.name)) { - const previous = this.map.get(symbol.name) !; + const previous = this.map.get(symbol.name)!; this._values[this._values.indexOf(previous)] = symbol; } this.map.set(symbol.name, symbol); @@ -561,7 +627,9 @@ class MapSymbolTable implements SymbolTable { } } - has(key: string): boolean { return this.map.has(key); } + has(key: string): boolean { + return this.map.has(key); + } values(): Symbol[] { // Switch to this.map.values once iterables are supported by the target language. @@ -572,7 +640,9 @@ class MapSymbolTable implements SymbolTable { class PipesTable implements SymbolTable { constructor(private pipes: CompilePipeSummary[], private context: TypeContext) {} - get size() { return this.pipes.length; } + get size() { + return this.pipes.length; + } get(key: string): Symbol|undefined { const pipe = this.pipes.find(pipe => pipe.name == key); @@ -581,9 +651,13 @@ class PipesTable implements SymbolTable { } } - has(key: string): boolean { return this.pipes.find(pipe => pipe.name == key) != null; } + has(key: string): boolean { + return this.pipes.find(pipe => pipe.name == key) != null; + } - values(): Symbol[] { return this.pipes.map(pipe => new PipeSymbol(pipe, this.context)); } + values(): Symbol[] { + return this.pipes.map(pipe => new PipeSymbol(pipe, this.context)); + } } // This matches .d.ts files that look like "...//.d.ts", @@ -600,9 +674,13 @@ class PipeSymbol implements Symbol { constructor(private pipe: CompilePipeSummary, private context: TypeContext) {} - get name(): string { return this.pipe.name; } + get name(): string { + return this.pipe.name; + } - get type(): TypeWrapper { return new TypeWrapper(this.tsType, this.context); } + get type(): TypeWrapper { + return new TypeWrapper(this.tsType, this.context); + } get definition(): Definition|undefined { const symbol = this.tsType.getSymbol(); @@ -617,12 +695,16 @@ class PipeSymbol implements Symbol { return symbol.getDocumentationComment(this.context.checker); } - members(): SymbolTable { return EmptyTable.instance; } + members(): SymbolTable { + return EmptyTable.instance; + } - signatures(): Signature[] { return signaturesOf(this.tsType, this.context); } + signatures(): Signature[] { + return signaturesOf(this.tsType, this.context); + } selectSignature(types: Symbol[]): Signature|undefined { - let signature = selectSignature(this.tsType, this.context, types) !; + let signature = selectSignature(this.tsType, this.context, types)!; if (types.length > 0) { const parameterType = types[0]; let resultType: Symbol|undefined = undefined; @@ -645,16 +727,20 @@ class PipeSymbol implements Symbol { return signature; } - indexed(argument: Symbol): Symbol|undefined { return undefined; } + indexed(argument: Symbol): Symbol|undefined { + return undefined; + } - typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.type.typeArguments(); + } private get tsType(): ts.Type { let type = this._tsType; if (!type) { const classSymbol = this.findClassSymbol(this.pipe.type.reference); if (classSymbol) { - type = this._tsType = this.findTransformMethodType(classSymbol) !; + type = this._tsType = this.findTransformMethodType(classSymbol)!; } if (!type) { type = this._tsType = getTsTypeFromBuiltinType(BuiltinType.Any, this.context); @@ -700,9 +786,15 @@ function findClassSymbolInContext(type: StaticSymbol, context: TypeContext): ts. class EmptyTable implements SymbolTable { public readonly size: number = 0; - get(key: string): Symbol|undefined { return undefined; } - has(key: string): boolean { return false; } - values(): Symbol[] { return []; } + get(key: string): Symbol|undefined { + return undefined; + } + has(key: string): boolean { + return false; + } + values(): Symbol[] { + return []; + } static instance = new EmptyTable(); } @@ -743,7 +835,7 @@ function getTsTypeFromBuiltinType(builtinType: BuiltinType, ctx: TypeContext): t function spanAt(sourceFile: ts.SourceFile, line: number, column: number): Span|undefined { if (line != null && column != null) { const position = ts.getPositionOfLineAndCharacter(sourceFile, line, column); - const findChild = function findChild(node: ts.Node): ts.Node | undefined { + const findChild = function findChild(node: ts.Node): ts.Node|undefined { if (node.kind > ts.SyntaxKind.LastToken && node.pos <= position && node.end > position) { const betterNode = ts.forEachChild(node, findChild); return betterNode || node; @@ -779,7 +871,7 @@ function parentDeclarationOf(node: ts.Node): ts.Node|undefined { case ts.SyntaxKind.SourceFile: return undefined; } - node = node.parent !; + node = node.parent!; } } @@ -797,7 +889,7 @@ function getContainerOf(symbol: ts.Symbol, context: TypeContext): Symbol|undefin } } -function typeKindOf(type: ts.Type | undefined): BuiltinType { +function typeKindOf(type: ts.Type|undefined): BuiltinType { if (type) { if (type.flags & ts.TypeFlags.Any) { return BuiltinType.Any; diff --git a/packages/language-service/src/utils.ts b/packages/language-service/src/utils.ts index 6d00eace56..e2f9de8bab 100644 --- a/packages/language-service/src/utils.ts +++ b/packages/language-service/src/utils.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, identifierName, templateVisitAll, visitAll} from '@angular/compiler'; +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'; @@ -25,8 +25,8 @@ export function isParseSourceSpan(value: any): value is ParseSourceSpan { export function spanOf(span: SpanHolder): Span; export function spanOf(span: ParseSourceSpan): Span; -export function spanOf(span: SpanHolder | ParseSourceSpan | undefined): Span|undefined; -export function spanOf(span?: SpanHolder | ParseSourceSpan): Span|undefined { +export function spanOf(span: SpanHolder|ParseSourceSpan|undefined): Span|undefined; +export function spanOf(span?: SpanHolder|ParseSourceSpan): Span|undefined { if (!span) return undefined; if (isParseSourceSpan(span)) { return {start: span.start.offset, end: span.end.offset}; @@ -36,7 +36,7 @@ export function spanOf(span?: SpanHolder | ParseSourceSpan): Span|undefined { } else if (span.children && span.children.length) { return { start: span.sourceSpan.start.offset, - end: spanOf(span.children[span.children.length - 1]) !.end + end: spanOf(span.children[span.children.length - 1])!.end }; } return {start: span.sourceSpan.start.offset, end: span.sourceSpan.end.offset}; @@ -44,8 +44,9 @@ export function spanOf(span?: SpanHolder | ParseSourceSpan): Span|undefined { } export function inSpan(position: number, span?: Span, exclusive?: boolean): boolean { - return span != null && (exclusive ? position >= span.start && position < span.end : - position >= span.start && position <= span.end); + return span != null && + (exclusive ? position >= span.start && position < span.end : + position >= span.start && position <= span.end); } export function offsetSpan(span: Span, amount: number): Span { @@ -71,7 +72,7 @@ export function getSelectors(info: AstResult): SelectorInfo { const map = new Map(); const results: CssSelector[] = []; for (const directive of info.directives) { - const selectors: CssSelector[] = CssSelector.parse(directive.selector !); + const selectors: CssSelector[] = CssSelector.parse(directive.selector!); for (const selector of selectors) { results.push(selector); map.set(selector, directive); @@ -141,7 +142,9 @@ export function findTemplateAstAt(ast: TemplateAst[], position: number): Templat visitDirective(ast: DirectiveAst, context: any): any { // Ignore the host properties of a directive - const result = this.visitChildren(context, visit => { visit(ast.inputs); }); + const result = this.visitChildren(context, visit => { + visit(ast.inputs); + }); // We never care about the diretive itself, just its inputs. if (path[path.length - 1] === ast) { path.pop(); diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts index ed8f3e081f..9e12a5db67 100644 --- a/packages/language-service/test/completions_spec.ts +++ b/packages/language-service/test/completions_spec.ts @@ -25,7 +25,9 @@ describe('completions', () => { const ngHost = new TypeScriptServiceHost(mockHost, tsLS); const ngLS = createLanguageService(ngHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should be able to get entity completions', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'entity-amp'); @@ -102,7 +104,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h2-hero'); const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expect(completions).toBeDefined(); - const internal = completions !.entries.find(e => e.name === 'internal'); + const internal = completions!.entries.find(e => e.name === 'internal'); expect(internal).toBeUndefined(); }); @@ -202,7 +204,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - expect(completions !.entries).toContain(jasmine.objectContaining({ + expect(completions!.entries).toContain(jasmine.objectContaining({ name: 'myClick', kind: CompletionKind.METHOD as any, insertText: 'myClick()', @@ -214,7 +216,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'pipe-method'); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - expect(completions !.entries).toContain(jasmine.objectContaining({ + expect(completions!.entries).toContain(jasmine.objectContaining({ name: 'lowercase', kind: CompletionKind.PIPE as any, insertText: 'lowercase', @@ -234,7 +236,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, location); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - const {entries} = completions !; + const {entries} = completions!; expect(entries).not.toContain(jasmine.objectContaining({name: 'div'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'h1'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'h2'})); @@ -257,7 +259,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'h1-after-space'); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - const {entries} = completions !; + const {entries} = completions!; expect(entries).not.toContain(jasmine.objectContaining({name: 'class'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'id'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'onclick'})); @@ -536,9 +538,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'key') !; + const completion = completions.entries.find(entry => entry.name === 'key')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('property'); expect(completion.replacementSpan).toBeUndefined(); @@ -553,9 +555,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'start'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'acronym') !; + const completion = completions.entries.find(entry => entry.name === 'acronym')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('html element'); expect(completion.replacementSpan).toEqual({start: location.start, length: 3}); @@ -570,9 +572,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'end'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'acronym') !; + const completion = completions.entries.find(entry => entry.name === 'acronym')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('html element'); expect(completion.replacementSpan).toEqual({start: location.start - 4, length: 4}); @@ -591,9 +593,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'key') !; + const completion = completions.entries.find(entry => entry.name === 'key')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('property'); expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 5}); @@ -612,9 +614,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'field'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === '$title_1') !; + const completion = completions.entries.find(entry => entry.name === '$title_1')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('property'); expect(completion.replacementSpan).toEqual({start: location.start, length: 8}); @@ -631,9 +633,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'click'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'click') !; + const completion = completions.entries.find(entry => entry.name === 'click')!; expect(completion).toBeDefined(); expect(completion.kind).toBe(CompletionKind.ATTRIBUTE); expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); @@ -652,9 +654,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'handleClick'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'handleClick') !; + const completion = completions.entries.find(entry => entry.name === 'handleClick')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('method'); expect(completion.replacementSpan).toEqual({start: location.start - 3, length: 3}); @@ -671,9 +673,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'div'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'div') !; + const completion = completions.entries.find(entry => entry.name === 'div')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('html element'); expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); @@ -690,9 +692,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'model'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'ngModel') !; + const completion = completions.entries.find(entry => entry.name === 'ngModel')!; expect(completion).toBeDefined(); expect(completion.kind).toBe(CompletionKind.ATTRIBUTE); expect(completion.replacementSpan).toEqual({start: location.start - 5, length: 5}); @@ -741,14 +743,14 @@ describe('completions', () => { it('should be able to get the completions (ref- prefix)', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference'); - const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !; + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start)!; expectContain(completions, CompletionKind.REFERENCE, ['ngForm']); }); it('should be able to get the completions (# prefix)', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference'); - const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !; + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start)!; expectContain(completions, CompletionKind.REFERENCE, ['ngForm']); }); }); @@ -789,9 +791,9 @@ describe('completions', () => { }); function expectContain( - completions: ts.CompletionInfo | undefined, kind: CompletionKind, names: string[]) { + completions: ts.CompletionInfo|undefined, kind: CompletionKind, names: string[]) { expect(completions).toBeDefined(); for (const name of names) { - expect(completions !.entries).toContain(jasmine.objectContaining({ name, kind } as any)); + expect(completions!.entries).toContain(jasmine.objectContaining({name, kind} as any)); } } diff --git a/packages/language-service/test/definitions_spec.ts b/packages/language-service/test/definitions_spec.ts index 69d34a2f38..dcf5f25bea 100644 --- a/packages/language-service/test/definitions_spec.ts +++ b/packages/language-service/test/definitions_spec.ts @@ -22,7 +22,9 @@ describe('definitions', () => { const ngHost = new TypeScriptServiceHost(mockHost, service); const ngService = createLanguageService(ngHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should be able to find field in an interpolation', () => { const fileName = mockHost.addCode(` @@ -36,12 +38,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('name'); @@ -55,20 +57,20 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(PARSING_CASES); expect(def.name).toBe('title'); expect(def.kind).toBe('property'); const fileContent = mockHost.readFile(def.fileName); - expect(fileContent !.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) + expect(fileContent!.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) .toEqual(`title = 'Some title';`); }); @@ -84,12 +86,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'myClick'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(mockHost.getLocationMarkerFor(fileName, 'my')); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('myClick'); @@ -109,12 +111,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'include'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('include'); @@ -134,7 +136,7 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above. const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); @@ -142,14 +144,14 @@ describe('definitions', () => { // There should be exactly 1 definition expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; const refFileName = '/app/parsing-cases.ts'; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('TestComponent'); expect(def.kind).toBe('component'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; const begin = '/*BeginTestComponent*/ '; const start = content.indexOf(begin) + begin.length; const end = content.indexOf(' /*EndTestComponent*/'); @@ -171,7 +173,7 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); @@ -179,14 +181,14 @@ describe('definitions', () => { // There should be exactly 1 definition expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; const refFileName = '/app/parsing-cases.ts'; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('testEvent'); expect(def.kind).toBe('event'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; const ref = `@Output('test') testEvent = new EventEmitter();`; expect(def.textSpan).toEqual({ start: content.indexOf(ref), @@ -208,7 +210,7 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); @@ -216,14 +218,14 @@ describe('definitions', () => { // There should be exactly 1 definition expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; const refFileName = '/app/parsing-cases.ts'; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('name'); expect(def.kind).toBe('property'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; const ref = `@Input('tcName') name = 'test';`; expect(def.textSpan).toEqual({ start: content.indexOf(ref), @@ -245,14 +247,14 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(4); + expect(definitions!.length).toBe(4); const refFileName = '/node_modules/@angular/common/common.d.ts'; - for (const def of definitions !) { + for (const def of definitions!) { expect(def.fileName).toBe(refFileName); expect(def.name).toBe('async'); expect(def.kind).toBe('pipe'); @@ -268,14 +270,14 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); + expect(definitions!.length).toBe(1); const refFileName = '/node_modules/@angular/common/common.d.ts'; - for (const def of definitions !) { + for (const def of definitions!) { expect(def.fileName).toBe(refFileName); expect(def.name).toBe('date'); expect(def.kind).toBe('pipe'); @@ -292,17 +294,17 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); expect(textSpan).toEqual(boundedText); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); + expect(definitions!.length).toBe(1); const refFileName = '/node_modules/@angular/common/common.d.ts'; - const def = definitions ![0]; + const def = definitions![0]; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('NgForOf'); expect(def.kind).toBe('directive'); @@ -317,17 +319,17 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); // The two definitions are setter and getter of 'ngForTrackBy'. - expect(definitions !.length).toBe(2); + expect(definitions!.length).toBe(2); const refFileName = '/node_modules/@angular/common/common.d.ts'; - definitions !.forEach(def => { + definitions!.forEach(def => { expect(def.fileName).toBe(refFileName); expect(def.name).toBe('ngForTrackBy'); expect(def.kind).toBe('method'); @@ -343,19 +345,19 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); + expect(definitions!.length).toBe(1); const refFileName = '/app/parsing-cases.ts'; - const def = definitions ![0]; + const def = definitions![0]; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('heroes'); expect(def.kind).toBe('property'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; expect(content.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) .toEqual(`heroes: Hero[] = [this.hero];`); }); @@ -370,28 +372,28 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); expect(textSpan).toEqual(boundedText); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(2); - const [def1, def2] = definitions !; + expect(definitions!.length).toBe(2); + const [def1, def2] = definitions!; const refFileName = '/app/parsing-cases.ts'; expect(def1.fileName).toBe(refFileName); expect(def1.name).toBe('model'); expect(def1.kind).toBe('property'); - let content = mockHost.readFile(refFileName) !; + let content = mockHost.readFile(refFileName)!; expect(content.substring(def1.textSpan.start, def1.textSpan.start + def1.textSpan.length)) .toEqual(`@Input() model: string = 'model';`); expect(def2.fileName).toBe(refFileName); expect(def2.name).toBe('modelChange'); expect(def2.kind).toBe('event'); - content = mockHost.readFile(refFileName) !; + content = mockHost.readFile(refFileName)!; expect(content.substring(def2.textSpan.start, def2.textSpan.start + def2.textSpan.length)) .toEqual(`@Output() modelChange: EventEmitter = new EventEmitter();`); }); @@ -407,13 +409,13 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual({start: marker.start - 2, length: 9}); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const [def] = definitions !; + expect(definitions!.length).toBe(1); + const [def] = definitions!; expect(def.fileName).toBe('/app/test.ng'); expect(def.textSpan).toEqual({start: 0, length: 0}); }); @@ -430,13 +432,13 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual({start: marker.start - 2, length: 10}); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const [def] = definitions !; + expect(definitions!.length).toBe(1); + const [def] = definitions!; expect(def.fileName).toBe('/app/test.css'); expect(def.textSpan).toEqual({start: 0, length: 0}); }); @@ -453,12 +455,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('name'); diff --git a/packages/language-service/test/diagnostic_messages_spec.ts b/packages/language-service/test/diagnostic_messages_spec.ts index a4dd95e6ec..cc44671fa0 100644 --- a/packages/language-service/test/diagnostic_messages_spec.ts +++ b/packages/language-service/test/diagnostic_messages_spec.ts @@ -7,7 +7,8 @@ */ import * as ts from 'typescript'; -import {DiagnosticMessage, createDiagnostic} from '../src/diagnostic_messages'; + +import {createDiagnostic, DiagnosticMessage} from '../src/diagnostic_messages'; describe('create diagnostic', () => { it('should format and create diagnostics correctly', () => { diff --git a/packages/language-service/test/diagnostics_spec.ts b/packages/language-service/test/diagnostics_spec.ts index dd51b1d13f..6f2aa589c0 100644 --- a/packages/language-service/test/diagnostics_spec.ts +++ b/packages/language-service/test/diagnostics_spec.ts @@ -34,7 +34,9 @@ describe('diagnostics', () => { const ngHost = new TypeScriptServiceHost(mockHost, tsLS); const ngLS = createLanguageService(ngHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should produce no diagnostics for test.ng', () => { // there should not be any errors on existing external template @@ -300,7 +302,8 @@ describe('diagnostics', () => { expect(messageText) .toBe( `The template context of 'CounterDirective' does not define an implicit value.\n` + - `If the context type is a base type or 'any', consider refining it to a more specific type.`, ); + `If the context type is a base type or 'any', consider refining it to a more specific type.`, + ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); @@ -337,7 +340,8 @@ describe('diagnostics', () => { expect(category).toBe(ts.DiagnosticCategory.Error); expect(messageText) .toBe( - `Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`, ); + `Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`, + ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); expect(length).toBe(span.length); @@ -355,7 +359,8 @@ describe('diagnostics', () => { expect(category).toBe(ts.DiagnosticCategory.Error); expect(messageText) .toBe( - `Identifier 'missingField' is not defined. 'Person' does not contain such a member`, ); + `Identifier 'missingField' is not defined. 'Person' does not contain such a member`, + ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); expect(length).toBe(span.length); @@ -396,7 +401,7 @@ describe('diagnostics', () => { it('should reject it when not in an event binding', () => { const content = mockHost.override(TEST_TEMPLATE, '
'); - const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !; + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE)!; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) @@ -410,7 +415,7 @@ describe('diagnostics', () => { it('should reject invalid properties on an event type', () => { const content = mockHost.override( TEST_TEMPLATE, '
'); - const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !; + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE)!; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) @@ -436,14 +441,14 @@ describe('diagnostics', () => { template: '
' }) export class MyComponent {}`); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) .toBe( `Component 'MyComponent' is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration.`); - const content = mockHost.readFile(fileName) !; - expect(content.substring(start !, start ! + length !)).toBe('MyComponent'); + const content = mockHost.readFile(fileName)!; + expect(content.substring(start!, start! + length!)).toBe('MyComponent'); }); @@ -495,7 +500,7 @@ describe('diagnostics', () => { }`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT)!; expect(ngDiags.length).toBe(1); const {messageText, start, length} = ngDiags[0]; const keyword = `() => 'foo'`; @@ -504,9 +509,9 @@ describe('diagnostics', () => { // messageText is a three-part chain const firstPart = messageText as ts.DiagnosticMessageChain; expect(firstPart.messageText).toBe(`Error during template compile of 'AppComponent'`); - const secondPart = firstPart.next !; + const secondPart = firstPart.next!; expect(secondPart[0].messageText).toBe('Function expressions are not supported in decorators'); - const thirdPart = secondPart[0].next !; + const thirdPart = secondPart[0].next!; expect(thirdPart[0].messageText) .toBe('Consider changing the function expression into an exported function'); expect(thirdPart[0].next).toBeFalsy(); @@ -568,7 +573,7 @@ describe('diagnostics', () => { export class AppComponent { onClick() { } }`); - const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; + const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT)!; const {messageText, start, length} = diagnostics[0]; expect(messageText).toBe('Unexpected callable expression. Expected a method call'); const keyword = `"onClick"`; @@ -682,7 +687,7 @@ describe('diagnostics', () => { .toBe( 'Invalid providers for "AppComponent in /app/app.component.ts" - only instances of Provider and Type are allowed, got: [?null?]'); // TODO: Looks like this is the wrong span. Should point to 'null' instead. - expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); + expect(content.substring(start!, start! + length!)).toBe('AppComponent'); }); // Issue #15768 @@ -815,12 +820,12 @@ describe('diagnostics', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile'); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeDefined(); - const {start, length} = urlDiagnostic !; + const {start, length} = urlDiagnostic!; expect(start).toBe(marker.start); expect(length).toBe(marker.length); }); @@ -832,7 +837,7 @@ describe('diagnostics', () => { }) export class MyComponent {}`); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeUndefined(); @@ -849,9 +854,9 @@ describe('diagnostics', () => { const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(diags.length).toBe(1); const {file, messageText, start, length} = diags[0]; - expect(file !.fileName).toBe(APP_COMPONENT); + expect(file!.fileName).toBe(APP_COMPONENT); expect(messageText).toBe(`Component 'AppComponent' must have a template or templateUrl`); - expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); + expect(content.substring(start!, start! + length!)).toBe('AppComponent'); }); it('should report diagnostic for both template and templateUrl', () => { @@ -867,10 +872,10 @@ describe('diagnostics', () => { const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(diags.length).toBe(1); const {file, messageText, start, length} = diags[0]; - expect(file !.fileName).toBe(APP_COMPONENT); + expect(file!.fileName).toBe(APP_COMPONENT); expect(messageText) .toBe(`Component 'AppComponent' must not have both template and templateUrl`); - expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); + expect(content.substring(start!, start! + length!)).toBe('AppComponent'); }); it('should report errors for invalid styleUrls', () => { @@ -882,12 +887,12 @@ describe('diagnostics', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile'); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeDefined(); - const {start, length} = urlDiagnostic !; + const {start, length} = urlDiagnostic!; expect(start).toBe(marker.start); expect(length).toBe(marker.length); }); @@ -902,7 +907,7 @@ describe('diagnostics', () => { }) export class AppComponent {}`); - const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; + const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT)!; expect(diagnostics.length).toBe(0); }); }); @@ -926,14 +931,14 @@ describe('diagnostics', () => { `element references do not contain such a member`); // Assert that the span is actually highlight the bounded text. The span // would be off if CRLF endings are not handled properly. - expect(content.substring(start !, start ! + length !)).toBe(`line${i}`); + expect(content.substring(start!, start! + length!)).toBe(`line${i}`); } }); it('should work correctly with CRLF endings in inline template', () => { const fileName = mockHost.addCode( '\n@Component({template:`\r\n\r\n{{line}}`})export class ComponentCRLF {}'); - const content = mockHost.readFile(fileName) !; + const content = mockHost.readFile(fileName)!; const ngDiags = ngLS.getSemanticDiagnostics(fileName); expect(ngDiags.length).toBeGreaterThan(0); const {messageText, start, length} = ngDiags[0]; @@ -942,7 +947,7 @@ describe('diagnostics', () => { `Identifier 'line' is not defined. ` + `The component declaration, template variable declarations, and ` + `element references do not contain such a member`); - expect(content.substring(start !, start ! + length !)).toBe('line'); + expect(content.substring(start!, start! + length!)).toBe('line'); }); it('should not produce diagnostics for non-exported directives', () => { @@ -972,8 +977,7 @@ describe('diagnostics', () => { `Consider using the safe navigation operator (optional?.toLowerCase) ` + `or non-null assertion operator (optional!.toLowerCase).`); expect(category).toBe(ts.DiagnosticCategory.Suggestion); - expect(content.substring(start !, start ! + length !)).toBe('optional.toLowerCase()'); - + expect(content.substring(start!, start! + length!)).toBe('optional.toLowerCase()'); }); it('should suggest ? or ! operator if property receiver is nullable', () => { @@ -987,7 +991,7 @@ describe('diagnostics', () => { `Consider using the safe navigation operator (optional?.length) ` + `or non-null assertion operator (optional!.length).`); expect(category).toBe(ts.DiagnosticCategory.Suggestion); - expect(content.substring(start !, start ! + length !)).toBe('optional.length'); + expect(content.substring(start!, start! + length!)).toBe('optional.length'); }); it('should report error if method is not found on non-nullable receiver', () => { @@ -1003,7 +1007,7 @@ describe('diagnostics', () => { expect(messageText) .toBe(`Identifier 'someMethod' is not defined. 'string' does not contain such a member`); expect(category).toBe(ts.DiagnosticCategory.Error); - expect(content.substring(start !, start ! + length !)).toBe(expression); + expect(content.substring(start!, start! + length!)).toBe(expression); } }); @@ -1020,7 +1024,7 @@ describe('diagnostics', () => { expect(messageText) .toBe(`Identifier 'someProp' is not defined. 'string' does not contain such a member`); expect(category).toBe(ts.DiagnosticCategory.Error); - expect(content.substring(start !, start ! + length !)).toBe(expression); + expect(content.substring(start!, start! + length!)).toBe(expression); } }); @@ -1030,12 +1034,12 @@ describe('diagnostics', () => {

{{myClick()()}}

`); - const content = mockHost.readFile(TEST_TEMPLATE) !; + const content = mockHost.readFile(TEST_TEMPLATE)!; const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); - const {messageText, start, length} = diags[0] !; + const {messageText, start, length} = diags[0]!; expect(messageText).toBe(`Call target 'myClick()' has non-callable type 'void'.`); - expect(content.substring(start !, start ! + length !)).toBe('myClick()()'); + expect(content.substring(start!, start! + length!)).toBe('myClick()()'); }); }); }); diff --git a/packages/language-service/test/expression_diagnostics_spec.ts b/packages/language-service/test/expression_diagnostics_spec.ts index 8bc33a2a70..43640d2443 100644 --- a/packages/language-service/test/expression_diagnostics_spec.ts +++ b/packages/language-service/test/expression_diagnostics_spec.ts @@ -13,7 +13,7 @@ import * as ts from 'typescript'; import {getTemplateExpressionDiagnostics} from '../src/expression_diagnostics'; -import {DiagnosticContext, MockLanguageServiceHost, getDiagnosticTemplateInfo} from './mocks'; +import {DiagnosticContext, getDiagnosticTemplateInfo, MockLanguageServiceHost} from './mocks'; describe('expression diagnostics', () => { let registry: ts.DocumentRegistry; @@ -27,15 +27,15 @@ describe('expression diagnostics', () => { registry = ts.createDocumentRegistry(false, '/src'); host = new MockLanguageServiceHost(['app/app.component.ts'], FILES, '/src'); service = ts.createLanguageService(host, registry); - const program = service.getProgram() !; + const program = service.getProgram()!; const checker = program.getTypeChecker(); - const symbolResolverHost = new ReflectorHost(() => program !, host); - context = new DiagnosticContext(service, program !, checker, symbolResolverHost); + const symbolResolverHost = new ReflectorHost(() => program!, host); + context = new DiagnosticContext(service, program!, checker, symbolResolverHost); type = context.getStaticSymbol('app/app.component.ts', 'AppComponent'); }); it('should have no diagnostics in default app', () => { - function messageToString(messageText: string | ts.DiagnosticMessageChain): string { + function messageToString(messageText: string|ts.DiagnosticMessageChain): string { if (typeof messageText == 'string') { return messageText; } else { @@ -107,13 +107,14 @@ describe('expression diagnostics', () => { {{p.name.first}} {{p.name.last}} `)); - it('should reject misspelled field in *ngFor', () => reject( - ` + it('should reject misspelled field in *ngFor', + () => reject( + `
{{p.names.first}} {{p.name.last}}
`, - 'Identifier \'names\' is not defined')); + 'Identifier \'names\' is not defined')); it('should accept an async expression', () => accept('{{(promised_person | async)?.name.first || ""}}')); it('should reject an async misspelled field', @@ -124,25 +125,27 @@ describe('expression diagnostics', () => { {{p.name.first}} {{p.name.last}} `)); - it('should reject misspelled field an async *ngFor', () => reject( - ` + it('should reject misspelled field an async *ngFor', + () => reject( + `
{{p.name.first}} {{p.nume.last}}
`, - 'Identifier \'nume\' is not defined')); + 'Identifier \'nume\' is not defined')); it('should accept an async *ngIf', () => accept(`
{{p.name.first}} {{p.name.last}}
`)); - it('should reject misspelled field in async *ngIf', () => reject( - ` + it('should reject misspelled field in async *ngIf', + () => reject( + `
{{p.name.first}} {{p.nume.last}}
`, - 'Identifier \'nume\' is not defined')); + 'Identifier \'nume\' is not defined')); it('should reject access to potentially undefined field', () => reject( `
{{maybe_person.name.first}}`, diff --git a/packages/language-service/test/global_symbols_spec.ts b/packages/language-service/test/global_symbols_spec.ts index f85241bb42..bb0aee8a77 100644 --- a/packages/language-service/test/global_symbols_spec.ts +++ b/packages/language-service/test/global_symbols_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript/lib/tsserverlibrary'; -import {EMPTY_SYMBOL_TABLE, createGlobalSymbolTable} from '../src/global_symbols'; +import {createGlobalSymbolTable, EMPTY_SYMBOL_TABLE} from '../src/global_symbols'; import {getSymbolQuery} from '../src/typescript_symbols'; import {MockTypescriptHost} from './test_utils'; @@ -18,7 +18,7 @@ describe('GlobalSymbolTable', () => { const tsLS = ts.createLanguageService(mockHost); it(`contains $any()`, () => { - const program = tsLS.getProgram() !; + const program = tsLS.getProgram()!; const typeChecker = program.getTypeChecker(); const source = ts.createSourceFile('foo.ts', '', ts.ScriptTarget.ES2015); const query = getSymbolQuery(program, typeChecker, source, () => EMPTY_SYMBOL_TABLE); diff --git a/packages/language-service/test/hover_spec.ts b/packages/language-service/test/hover_spec.ts index 9a22801c06..425d9078f4 100644 --- a/packages/language-service/test/hover_spec.ts +++ b/packages/language-service/test/hover_spec.ts @@ -22,7 +22,9 @@ describe('hover', () => { const ngLSHost = new TypeScriptServiceHost(mockHost, tsLS); const ngLS = createLanguageService(ngLSHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); describe('location of hover', () => { it('should find members in a text interpolation', () => { @@ -30,7 +32,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -40,7 +42,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -50,7 +52,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -60,7 +62,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -70,7 +72,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -80,7 +82,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'anyValue'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.anyValue: any'); }); @@ -92,7 +94,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const documentation = toText(quickInfo !.documentation); + const documentation = toText(quickInfo!.documentation); expect(documentation).toBe('This is the title of the `TemplateReference` Component.'); }); @@ -102,7 +104,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -112,7 +114,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(variable) hero: Hero'); }); @@ -123,7 +125,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(variable) hero: Readonly'); }); @@ -133,7 +135,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'name'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(variable) name: { readonly name: "name"; }'); }); @@ -144,7 +146,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'myClick'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(method) TemplateReference.myClick: (event: any) => void'); }); @@ -154,7 +156,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'trackBy'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(method) NgForOf.ngForTrackBy: TrackByFunction'); }); @@ -164,7 +166,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'heroes'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.heroes: Hero[]'); }); @@ -175,7 +177,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'date'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)) .toBe( @@ -187,7 +189,7 @@ describe('hover', () => { const position = content.indexOf('$any'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, position); expect(quickInfo).toBeDefined(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual({ start: position, length: '$any(title)'.length, @@ -202,7 +204,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const documentation = toText(quickInfo !.documentation); + const documentation = toText(quickInfo!.documentation); expect(documentation).toBe('This Component provides the `test-comp` selector.'); }); @@ -211,7 +213,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const {displayParts, documentation} = quickInfo !; + const {displayParts, documentation} = quickInfo!; expect(toText(displayParts)) .toBe('(component) AppModule.TestComponent: typeof TestComponent'); expect(toText(documentation)).toBe('This Component provides the `test-comp` selector.'); @@ -222,7 +224,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const {displayParts, textSpan} = quickInfo !; + const {displayParts, textSpan} = quickInfo!; expect(toText(displayParts)).toBe('(directive) AppModule.StringModel: typeof StringModel'); expect(content.substring(textSpan.start, textSpan.start + textSpan.length)) .toBe('string-model'); @@ -233,7 +235,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'test'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(event) TestComponent.testEvent: EventEmitter'); }); @@ -243,7 +245,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'tcName'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TestComponent.name: string'); }); @@ -254,7 +256,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'model'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) StringModel.model: string'); }); @@ -264,7 +266,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'ngFor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(directive) NgForOf: typeof NgForOf'); }); @@ -272,12 +274,12 @@ describe('hover', () => { describe('hovering on TypeScript nodes', () => { it('should work for component TypeScript declarations', () => { - const content = mockHost.readFile(PARSING_CASES) !; + const content = mockHost.readFile(PARSING_CASES)!; const position = content.indexOf('TemplateReference'); expect(position).toBeGreaterThan(0); const quickInfo = ngLS.getQuickInfoAtPosition(PARSING_CASES, position); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual({ start: position, length: 'TemplateReference'.length, @@ -286,12 +288,12 @@ describe('hover', () => { }); it('should work for directive TypeScript declarations', () => { - const content = mockHost.readFile(PARSING_CASES) !; + const content = mockHost.readFile(PARSING_CASES)!; const position = content.indexOf('StringModel'); expect(position).toBeGreaterThan(0); const quickInfo = ngLS.getQuickInfoAtPosition(PARSING_CASES, position); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual({ start: position, length: 'StringModel'.length, @@ -313,7 +315,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); diff --git a/packages/language-service/test/html_info_spec.ts b/packages/language-service/test/html_info_spec.ts index 62cefdbfc2..3781eb3f73 100644 --- a/packages/language-service/test/html_info_spec.ts +++ b/packages/language-service/test/html_info_spec.ts @@ -32,7 +32,6 @@ describe('html_info', () => { } } }); - }); function uniqueElements(a: T[], b: T[]): T[] { diff --git a/packages/language-service/test/language_service_spec.ts b/packages/language-service/test/language_service_spec.ts index a271928230..3fd10de9cd 100644 --- a/packages/language-service/test/language_service_spec.ts +++ b/packages/language-service/test/language_service_spec.ts @@ -21,20 +21,25 @@ describe('service without angular', () => { const fileName = '/app/test.ng'; const position = mockHost.getLocationMarkerFor(fileName, 'h1-content').start; - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); - it('should not crash a get diagnostics', - () => { expect(() => ngService.getSemanticDiagnostics(fileName)).not.toThrow(); }); + it('should not crash a get diagnostics', () => { + expect(() => ngService.getSemanticDiagnostics(fileName)).not.toThrow(); + }); - it('should not crash a completion', - () => { expect(() => ngService.getCompletionsAtPosition(fileName, position)).not.toThrow(); }); + it('should not crash a completion', () => { + expect(() => ngService.getCompletionsAtPosition(fileName, position)).not.toThrow(); + }); it('should not crash a get definition', () => { expect(() => ngService.getDefinitionAndBoundSpan(fileName, position)).not.toThrow(); }); - it('should not crash a hover', - () => { expect(() => ngService.getQuickInfoAtPosition(fileName, position)).not.toThrow(); }); + it('should not crash a hover', () => { + expect(() => ngService.getQuickInfoAtPosition(fileName, position)).not.toThrow(); + }); it('should not crash with an incomplete class', () => { mockHost.addCode('\nexport class'); diff --git a/packages/language-service/test/mocks.ts b/packages/language-service/test/mocks.ts index b58ea15651..4fdcc66d12 100644 --- a/packages/language-service/test/mocks.ts +++ b/packages/language-service/test/mocks.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotSummaryResolver, CompileMetadataResolver, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, TemplateParser, analyzeNgModules, createOfflineCompileUrlResolver} from '@angular/compiler'; +import {analyzeNgModules, AotSummaryResolver, CompileMetadataResolver, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, TemplateParser} from '@angular/compiler'; import {Directory, MockAotContext} from '@angular/compiler-cli/test/mocks'; import {setup} from '@angular/compiler-cli/test/test_support'; import {ViewEncapsulation, ɵConsole as Console} from '@angular/core'; @@ -45,11 +45,17 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { this.context = new MockAotContext(currentDirectory, files); } - getCompilationSettings(): ts.CompilerOptions { return this.options; } + getCompilationSettings(): ts.CompilerOptions { + return this.options; + } - getScriptFileNames(): string[] { return this.scripts; } + getScriptFileNames(): string[] { + return this.scripts; + } - getScriptVersion(fileName: string): string { return '0'; } + getScriptVersion(fileName: string): string { + return '0'; + } getScriptSnapshot(fileName: string): ts.IScriptSnapshot|undefined { const content = this.internalReadFile(fileName); @@ -58,15 +64,25 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { } } - getCurrentDirectory(): string { return this.context.currentDirectory; } + getCurrentDirectory(): string { + return this.context.currentDirectory; + } - getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return 'lib.d.ts'; + } - readFile(fileName: string): string { return this.internalReadFile(fileName) as string; } + readFile(fileName: string): string { + return this.internalReadFile(fileName) as string; + } - readResource(fileName: string): Promise { return Promise.resolve(''); } + readResource(fileName: string): Promise { + return Promise.resolve(''); + } - assumeFileExists(fileName: string): void { this.assumedExist.add(fileName); } + assumeFileExists(fileName: string): void { + this.assumedExist.add(fileName); + } fileExists(fileName: string): boolean { return this.assumedExist.has(fileName) || this.internalReadFile(fileName) != null; @@ -99,10 +115,18 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { const staticSymbolCache = new StaticSymbolCache(); const summaryResolver = new AotSummaryResolver( { - loadSummary(filePath: string) { return null; }, - isSourceFile(sourceFilePath: string) { return true; }, - toSummaryFileName(sourceFilePath: string) { return sourceFilePath; }, - fromSummaryFileName(filePath: string): string{return filePath;}, + loadSummary(filePath: string) { + return null; + }, + isSourceFile(sourceFilePath: string) { + return true; + }, + toSummaryFileName(sourceFilePath: string) { + return sourceFilePath; + }, + fromSummaryFileName(filePath: string): string { + return filePath; + }, }, staticSymbolCache); @@ -117,7 +141,9 @@ export class DiagnosticContext { public service: ts.LanguageService, public program: ts.Program, public checker: ts.TypeChecker, public host: StaticSymbolResolverHost) {} - private collectError(e: any, path?: string) { this._errors.push({e, path}); } + private collectError(e: any, path?: string) { + this._errors.push({e, path}); + } private get staticSymbolResolver(): StaticSymbolResolver { let result = this._staticSymbolResolver; @@ -133,7 +159,7 @@ export class DiagnosticContext { if (!this._reflector) { const ssr = this.staticSymbolResolver; const result = this._reflector = new StaticReflector( - summaryResolver, ssr, [], [], (e, filePath) => this.collectError(e, filePath !)); + summaryResolver, ssr, [], [], (e, filePath) => this.collectError(e, filePath!)); this._reflector = result; return result; } @@ -148,11 +174,15 @@ export class DiagnosticContext { const pipeResolver = new PipeResolver(this.reflector); const elementSchemaRegistry = new DomElementSchemaRegistry(); const resourceLoader = new class extends ResourceLoader { - get(url: string): Promise { return Promise.resolve(''); } + get(url: string): Promise { + return Promise.resolve(''); + } }; const urlResolver = createOfflineCompileUrlResolver(); const htmlParser = new class extends HtmlParser { - parse(): ParseTreeResult { return new ParseTreeResult([], []); } + parse(): ParseTreeResult { + return new ParseTreeResult([], []); + } }; // This tracks the CompileConfig in codegen.ts. Currently these options @@ -174,7 +204,11 @@ export class DiagnosticContext { get analyzedModules(): NgAnalyzedModules { let analyzedModules = this._analyzedModules; if (!analyzedModules) { - const analyzeHost = {isSourceFile(filePath: string) { return true; }}; + const analyzeHost = { + isSourceFile(filePath: string) { + return true; + } + }; const programFiles = this.program.getSourceFiles().map(sf => sf.fileName); analyzedModules = this._analyzedModules = analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver); @@ -198,7 +232,7 @@ function compileTemplate(context: DiagnosticContext, type: StaticSymbol, templat const config = new CompilerConfig(); const parser = new TemplateParser( config, context.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser, - null !, []); + null!, []); const htmlResult = htmlParser.parse(template, '', {tokenizeExpansionForms: true}); const analyzedModules = context.analyzedModules; // let errors: Diagnostic[]|undefined = undefined; @@ -214,8 +248,11 @@ function compileTemplate(context: DiagnosticContext, type: StaticSymbol, templat return { htmlAst: htmlResult.rootNodes, templateAst: parseResult.templateAst, - directive: metadata, directives, pipes, - parseErrors: parseResult.errors, expressionParser + directive: metadata, + directives, + pipes, + parseErrors: parseResult.errors, + expressionParser }; } } @@ -236,7 +273,9 @@ export function getDiagnosticTemplateInfo( sourceFile, context.program, context.checker, compiledTemplate.pipes)); return { fileName: templateFile, - offset: 0, query, members, + offset: 0, + query, + members, htmlAst: compiledTemplate.htmlAst, templateAst: compiledTemplate.templateAst, source: sourceFile.text, @@ -246,6 +285,6 @@ export function getDiagnosticTemplateInfo( } } -function removeMissing(values: (T | null | undefined)[]): T[] { +function removeMissing(values: (T|null|undefined)[]): T[] { return values.filter(e => !!e) as T[]; } diff --git a/packages/language-service/test/reflector_host_spec.ts b/packages/language-service/test/reflector_host_spec.ts index 717c91e536..39aa4cc922 100644 --- a/packages/language-service/test/reflector_host_spec.ts +++ b/packages/language-service/test/reflector_host_spec.ts @@ -15,7 +15,6 @@ import {TypeScriptServiceHost} from '../src/typescript_host'; import {MockTypescriptHost} from './test_utils'; describe('reflector_host_spec', () => { - // Regression #21811 it('should be able to find angular under windows', () => { const originalJoin = path.join; @@ -24,15 +23,16 @@ describe('reflector_host_spec', () => { new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], 'node_modules', { ...path, join: (...args: string[]) => originalJoin.apply(path, args), - posix: - {...path.posix, join: (...args: string[]) => originalPosixJoin.apply(path, args)} + posix: {...path.posix, join: (...args: string[]) => originalPosixJoin.apply(path, args)} }); const reflectorHost = new ReflectorHost(() => undefined as any, mockHost); if (process.platform !== 'win32') { // If we call this in Windows it will cause a 'Maximum call stack size exceeded error' // Because we are spying on the same function that we are call faking - spyOn(path, 'join').and.callFake((...args: string[]) => { return path.win32.join(...args); }); + spyOn(path, 'join').and.callFake((...args: string[]) => { + return path.win32.join(...args); + }); } const result = reflectorHost.moduleNameToFileName('@angular/core'); diff --git a/packages/language-service/test/template_spec.ts b/packages/language-service/test/template_spec.ts index 7617e2779b..1574e3ef34 100644 --- a/packages/language-service/test/template_spec.ts +++ b/packages/language-service/test/template_spec.ts @@ -11,7 +11,6 @@ import {getClassDeclFromDecoratorProp} from '../src/template'; import {MockTypescriptHost} from './test_utils'; describe('getClassDeclFromTemplateNode', () => { - it('should find class declaration in syntax-only mode', () => { const sourceFile = ts.createSourceFile( 'foo.ts', ` @@ -28,24 +27,24 @@ describe('getClassDeclFromTemplateNode', () => { } const classDecl = sourceFile.forEachChild(visit); expect(classDecl).toBeTruthy(); - expect(classDecl !.kind).toBe(ts.SyntaxKind.ClassDeclaration); - expect((classDecl as ts.ClassDeclaration).name !.text).toBe('MyComponent'); + expect(classDecl!.kind).toBe(ts.SyntaxKind.ClassDeclaration); + expect((classDecl as ts.ClassDeclaration).name!.text).toBe('MyComponent'); }); it('should return class declaration for AppComponent', () => { const host = new MockTypescriptHost(['/app/app.component.ts']); const tsLS = ts.createLanguageService(host); - const sourceFile = tsLS.getProgram() !.getSourceFile('/app/app.component.ts'); + const sourceFile = tsLS.getProgram()!.getSourceFile('/app/app.component.ts'); expect(sourceFile).toBeTruthy(); - const classDecl = sourceFile !.forEachChild(function visit(node): ts.Node | undefined { + const classDecl = sourceFile!.forEachChild(function visit(node): ts.Node|undefined { if (ts.isPropertyAssignment(node)) { return getClassDeclFromDecoratorProp(node); } return node.forEachChild(visit); }); expect(classDecl).toBeTruthy(); - expect(ts.isClassDeclaration(classDecl !)).toBe(true); - expect((classDecl as ts.ClassDeclaration).name !.text).toBe('AppComponent'); + expect(ts.isClassDeclaration(classDecl!)).toBe(true); + expect((classDecl as ts.ClassDeclaration).name!.text).toBe('AppComponent'); }); }); diff --git a/packages/language-service/test/test_utils.ts b/packages/language-service/test/test_utils.ts index 7973e2e37b..c58e76ee6f 100644 --- a/packages/language-service/test/test_utils.ts +++ b/packages/language-service/test/test_utils.ts @@ -57,11 +57,11 @@ function isFile(path: string) { function loadTourOfHeroes(): ReadonlyMap { const {TEST_SRCDIR} = process.env; const root = - path.join(TEST_SRCDIR !, 'angular', 'packages', 'language-service', 'test', 'project'); + path.join(TEST_SRCDIR!, 'angular', 'packages', 'language-service', 'test', 'project'); const dirs = [root]; const files = new Map(); while (dirs.length) { - const dirPath = dirs.pop() !; + const dirPath = dirs.pop()!; for (const filePath of fs.readdirSync(dirPath)) { const absPath = path.join(dirPath, filePath); if (isFile(absPath)) { @@ -140,11 +140,17 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { this.projectVersion++; } - getCompilationSettings(): ts.CompilerOptions { return {...this.options}; } + getCompilationSettings(): ts.CompilerOptions { + return {...this.options}; + } - getProjectVersion(): string { return this.projectVersion.toString(); } + getProjectVersion(): string { + return this.projectVersion.toString(); + } - getScriptFileNames(): string[] { return this.scriptNames; } + getScriptFileNames(): string[] { + return this.scriptNames; + } getScriptVersion(fileName: string): string { return (this.scriptVersion.get(fileName) || 0).toString(); @@ -156,9 +162,13 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { return undefined; } - getCurrentDirectory(): string { return '/'; } + getCurrentDirectory(): string { + return '/'; + } - getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return 'lib.d.ts'; + } directoryExists(directoryName: string): boolean { if (this.overrideDirectory.has(directoryName)) return true; @@ -172,7 +182,9 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { return this.pathExists(effectiveName); } - fileExists(fileName: string): boolean { return this.getRawFileContent(fileName) != null; } + fileExists(fileName: string): boolean { + return this.getRawFileContent(fileName) != null; + } readFile(fileName: string): string|undefined { const content = this.getRawFileContent(fileName); @@ -242,7 +254,7 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { private pathExists(path: string): boolean { if (this.existsCache.has(path)) { - return this.existsCache.get(path) !; + return this.existsCache.get(path)!; } const exists = fs.existsSync(path); @@ -411,8 +423,9 @@ function getReferenceMarkers(value: string): ReferenceResult { let adjustment = 0; const text = value.replace( - referenceMarker, (match: string, text: string, reference: string, _: string, - definition: string, definitionName: string, index: number): string => { + referenceMarker, + (match: string, text: string, reference: string, _: string, definition: string, + definitionName: string, index: number): string => { const result = reference ? text : text.replace(/ᐱ/g, ''); const span: Span = {start: index - adjustment, end: index - adjustment + result.length}; const markers = reference ? references : definitions; diff --git a/packages/language-service/test/ts_plugin_spec.ts b/packages/language-service/test/ts_plugin_spec.ts index 37c373d398..97d93a253c 100644 --- a/packages/language-service/test/ts_plugin_spec.ts +++ b/packages/language-service/test/ts_plugin_spec.ts @@ -26,7 +26,7 @@ const mockProject = { describe('plugin', () => { const mockHost = new MockTypescriptHost(['/app/main.ts']); const tsLS = ts.createLanguageService(mockHost); - const program = tsLS.getProgram() !; + const program = tsLS.getProgram()!; const plugin = create({ languageService: tsLS, languageServiceHost: mockHost, @@ -35,7 +35,9 @@ describe('plugin', () => { config: {}, }); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should produce TypeScript diagnostics', () => { const fileName = '/foo.ts'; @@ -117,7 +119,7 @@ describe('plugin', () => { const marker = mockHost.getLocationMarkerFor(MY_COMPONENT, 'tree'); const completions = plugin.getCompletionsAtPosition(MY_COMPONENT, marker.start, undefined); expect(completions).toBeDefined(); - expect(completions !.entries).toEqual([ + expect(completions!.entries).toEqual([ { name: 'children', kind: CompletionKind.PROPERTY as any, diff --git a/packages/language-service/test/typescript_host_spec.ts b/packages/language-service/test/typescript_host_spec.ts index dadf9e9e7c..7d383c46d6 100644 --- a/packages/language-service/test/typescript_host_spec.ts +++ b/packages/language-service/test/typescript_host_spec.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {TypeScriptServiceHost} from '../src/typescript_host'; -import {MockTypescriptHost, findDirectiveMetadataByName} from './test_utils'; +import {findDirectiveMetadataByName, MockTypescriptHost} from './test_utils'; describe('TypeScriptServiceHost', () => { @@ -62,7 +62,7 @@ describe('TypeScriptServiceHost', () => { expect(oldModules.ngModules).toEqual([]); // Now add a script, this would change the program const fileName = '/app/main.ts'; - const content = tsLSHost.readFile(fileName) !; + const content = tsLSHost.readFile(fileName)!; tsLSHost.addScript(fileName, content); // If the caches are not cleared, we would get back an empty array. // But if the caches are cleared then the analyzed modules will be non-empty. @@ -121,8 +121,8 @@ describe('TypeScriptServiceHost', () => { expect(oldModules.symbolsMissingModule).toEqual([]); // Expect to find AppComponent in the old modules const oldFile = oldModules.files.find(f => f.fileName === fileName); - expect(oldFile !.directives.length).toBe(1); - const appComp = oldFile !.directives[0]; + expect(oldFile!.directives.length).toBe(1); + const appComp = oldFile!.directives[0]; expect(appComp.name).toBe('AppComponent'); expect(oldModules.ngModuleByPipeOrDirective.has(appComp)).toBe(true); @@ -154,8 +154,8 @@ describe('TypeScriptServiceHost', () => { expect(newModules.symbolsMissingModule).toEqual([]); // Expect to find HelloComponent in the new modules const newFile = newModules.files.find(f => f.fileName === fileName); - expect(newFile !.directives.length).toBe(1); - const helloComp = newFile !.directives[0]; + expect(newFile!.directives.length).toBe(1); + const helloComp = newFile!.directives[0]; expect(helloComp.name).toBe('HelloComponent'); expect(newModules.ngModuleByPipeOrDirective.has(helloComp)).toBe(true); expect(newModules.ngModuleByPipeOrDirective.has(appComp)).toBe(false); diff --git a/packages/language-service/test/typescript_symbols_spec.ts b/packages/language-service/test/typescript_symbols_spec.ts index aa4064949b..058d49a0dc 100644 --- a/packages/language-service/test/typescript_symbols_spec.ts +++ b/packages/language-service/test/typescript_symbols_spec.ts @@ -18,9 +18,15 @@ import {DiagnosticContext, MockLanguageServiceHost} from './mocks'; function emptyPipes(): SymbolTable { return { size: 0, - get(key: string) { return undefined; }, - has(key: string) { return false; }, - values(): Symbol[]{return [];} + get(key: string) { + return undefined; + }, + has(key: string) { + return false; + }, + values(): Symbol[] { + return []; + } }; } @@ -35,9 +41,9 @@ describe('symbol query', () => { const host = new MockLanguageServiceHost( ['/quickstart/app/app.component.ts'], QUICKSTART, '/quickstart'); const service = ts.createLanguageService(host, registry); - program = service.getProgram() !; + program = service.getProgram()!; checker = program.getTypeChecker(); - sourceFile = program.getSourceFile('/quickstart/app/app.component.ts') !; + sourceFile = program.getSourceFile('/quickstart/app/app.component.ts')!; const symbolResolverHost = new ReflectorHost(() => program, host); context = new DiagnosticContext(service, program, checker, symbolResolverHost); query = getSymbolQuery(program, checker, sourceFile, emptyPipes); @@ -67,7 +73,7 @@ describe('symbol query', () => { } else { const symbol = query.getBuiltinType(builtinType); const got: ts.TypeFlags = (symbol as any).tsType.flags; - expect(got).toBe(want !); + expect(got).toBe(want!); } } }); @@ -75,8 +81,8 @@ describe('symbol query', () => { describe('toSymbolTableFactory(tsVersion)', () => { it('should return a Map for versions of TypeScript >= 2.2', () => { - const a = { name: 'a' } as ts.Symbol; - const b = { name: 'b' } as ts.Symbol; + const a = {name: 'a'} as ts.Symbol; + const b = {name: 'b'} as ts.Symbol; expect(toSymbolTableFactory([a, b]) instanceof Map).toEqual(true); }); }); diff --git a/packages/language-service/test/utils_spec.ts b/packages/language-service/test/utils_spec.ts index ce50568219..3d940c36da 100644 --- a/packages/language-service/test/utils_spec.ts +++ b/packages/language-service/test/utils_spec.ts @@ -28,7 +28,7 @@ describe('getDirectiveClassLike', () => { } }); expect(result).toBeTruthy(); - const {decoratorId, classId} = result !; + const {decoratorId, classId} = result!; expect(decoratorId.kind).toBe(ts.SyntaxKind.Identifier); expect(decoratorId.text).toBe('NgModule'); expect(classId.text).toBe('AppModule');