fix(language-service): do not throw for invalid metadata (#13261)
Fixes #13255
This commit is contained in:
parent
16efb13dd1
commit
4a09c81724
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, Directive, Host, Inject, Injectable, ModuleWithProviders, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
|
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, Directive, Host, Inject, Injectable, ModuleWithProviders, OpaqueToken, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {StaticSymbol} from './aot/static_symbol';
|
import {StaticSymbol} from './aot/static_symbol';
|
||||||
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
||||||
|
@ -25,7 +25,8 @@ import {SummaryResolver} from './summary_resolver';
|
||||||
import {getUrlScheme} from './url_resolver';
|
import {getUrlScheme} from './url_resolver';
|
||||||
import {MODULE_SUFFIX, SyncAsyncResult, ValueTransformer, visitValue} from './util';
|
import {MODULE_SUFFIX, SyncAsyncResult, ValueTransformer, visitValue} from './util';
|
||||||
|
|
||||||
|
export type ErrorCollector = (error: any, type?: any) => void;
|
||||||
|
export const ERROR_COLLECTOR_TOKEN = new OpaqueToken('ErrorCollector');
|
||||||
|
|
||||||
// Design notes:
|
// Design notes:
|
||||||
// - don't lazily create metadata:
|
// - don't lazily create metadata:
|
||||||
|
@ -47,7 +48,8 @@ export class CompileMetadataResolver {
|
||||||
private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver,
|
private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver,
|
||||||
private _schemaRegistry: ElementSchemaRegistry,
|
private _schemaRegistry: ElementSchemaRegistry,
|
||||||
private _directiveNormalizer: DirectiveNormalizer,
|
private _directiveNormalizer: DirectiveNormalizer,
|
||||||
private _reflector: ReflectorReader = reflector) {}
|
private _reflector: ReflectorReader = reflector,
|
||||||
|
@Optional() @Inject(ERROR_COLLECTOR_TOKEN) private _errorCollector?: ErrorCollector) {}
|
||||||
|
|
||||||
clearCacheFor(type: Type<any>) {
|
clearCacheFor(type: Type<any>) {
|
||||||
const dirMeta = this._directiveCache.get(type);
|
const dirMeta = this._directiveCache.get(type);
|
||||||
|
@ -182,7 +184,8 @@ export class CompileMetadataResolver {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
if (isSync) {
|
if (isSync) {
|
||||||
throw new ComponentStillLoadingError(directiveType);
|
this._reportError(new ComponentStillLoadingError(directiveType), directiveType);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return templateMeta.asyncResult.then(createDirectiveMetadata);
|
return templateMeta.asyncResult.then(createDirectiveMetadata);
|
||||||
}
|
}
|
||||||
|
@ -234,7 +237,7 @@ export class CompileMetadataResolver {
|
||||||
if (dirMeta.viewProviders) {
|
if (dirMeta.viewProviders) {
|
||||||
viewProviders = this._getProvidersMetadata(
|
viewProviders = this._getProvidersMetadata(
|
||||||
dirMeta.viewProviders, entryComponentMetadata,
|
dirMeta.viewProviders, entryComponentMetadata,
|
||||||
`viewProviders for "${stringify(directiveType)}"`);
|
`viewProviders for "${stringify(directiveType)}"`, [], directiveType);
|
||||||
}
|
}
|
||||||
if (dirMeta.entryComponents) {
|
if (dirMeta.entryComponents) {
|
||||||
entryComponentMetadata = flattenAndDedupeArray(dirMeta.entryComponents)
|
entryComponentMetadata = flattenAndDedupeArray(dirMeta.entryComponents)
|
||||||
|
@ -247,14 +250,18 @@ export class CompileMetadataResolver {
|
||||||
} else {
|
} else {
|
||||||
// Directive
|
// Directive
|
||||||
if (!selector) {
|
if (!selector) {
|
||||||
throw new Error(`Directive ${stringify(directiveType)} has no selector, please add it!`);
|
this._reportError(
|
||||||
|
new Error(`Directive ${stringify(directiveType)} has no selector, please add it!`),
|
||||||
|
directiveType);
|
||||||
|
selector = 'error';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let providers: cpl.CompileProviderMetadata[] = [];
|
let providers: cpl.CompileProviderMetadata[] = [];
|
||||||
if (isPresent(dirMeta.providers)) {
|
if (isPresent(dirMeta.providers)) {
|
||||||
providers = this._getProvidersMetadata(
|
providers = this._getProvidersMetadata(
|
||||||
dirMeta.providers, entryComponentMetadata, `providers for "${stringify(directiveType)}"`);
|
dirMeta.providers, entryComponentMetadata, `providers for "${stringify(directiveType)}"`,
|
||||||
|
[], directiveType);
|
||||||
}
|
}
|
||||||
let queries: cpl.CompileQueryMetadata[] = [];
|
let queries: cpl.CompileQueryMetadata[] = [];
|
||||||
let viewQueries: cpl.CompileQueryMetadata[] = [];
|
let viewQueries: cpl.CompileQueryMetadata[] = [];
|
||||||
|
@ -289,8 +296,10 @@ export class CompileMetadataResolver {
|
||||||
getDirectiveMetadata(directiveType: any): cpl.CompileDirectiveMetadata {
|
getDirectiveMetadata(directiveType: any): cpl.CompileDirectiveMetadata {
|
||||||
const dirMeta = this._directiveCache.get(directiveType);
|
const dirMeta = this._directiveCache.get(directiveType);
|
||||||
if (!dirMeta) {
|
if (!dirMeta) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleMetadata for a module that declares it. Directive ${stringify(directiveType)}.`);
|
new Error(
|
||||||
|
`Illegal state: getDirectiveMetadata can only be called after loadNgModuleMetadata for a module that declares it. Directive ${stringify(directiveType)}.`),
|
||||||
|
directiveType);
|
||||||
}
|
}
|
||||||
return dirMeta;
|
return dirMeta;
|
||||||
}
|
}
|
||||||
|
@ -299,8 +308,10 @@ export class CompileMetadataResolver {
|
||||||
const dirSummary =
|
const dirSummary =
|
||||||
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
|
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
|
||||||
if (!dirSummary) {
|
if (!dirSummary) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Illegal state: Could not load the summary for directive ${stringify(dirType)}.`);
|
new Error(
|
||||||
|
`Illegal state: Could not load the summary for directive ${stringify(dirType)}.`),
|
||||||
|
dirType);
|
||||||
}
|
}
|
||||||
return dirSummary;
|
return dirSummary;
|
||||||
}
|
}
|
||||||
|
@ -372,20 +383,26 @@ export class CompileMetadataResolver {
|
||||||
if (moduleWithProviders.providers) {
|
if (moduleWithProviders.providers) {
|
||||||
providers.push(...this._getProvidersMetadata(
|
providers.push(...this._getProvidersMetadata(
|
||||||
moduleWithProviders.providers, entryComponents,
|
moduleWithProviders.providers, entryComponents,
|
||||||
`provider for the NgModule '${stringify(importedModuleType)}'`));
|
`provider for the NgModule '${stringify(importedModuleType)}'`, [], importedType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (importedModuleType) {
|
if (importedModuleType) {
|
||||||
const importedModuleSummary = this.getNgModuleSummary(importedModuleType);
|
const importedModuleSummary = this.getNgModuleSummary(importedModuleType);
|
||||||
if (!importedModuleSummary) {
|
if (!importedModuleSummary) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Unexpected ${this._getTypeDescriptor(importedType)} '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
|
new Error(
|
||||||
|
`Unexpected ${this._getTypeDescriptor(importedType)} '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`),
|
||||||
|
moduleType);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
importedModules.push(importedModuleSummary);
|
importedModules.push(importedModuleSummary);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
|
new Error(
|
||||||
|
`Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`),
|
||||||
|
moduleType);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -393,8 +410,11 @@ export class CompileMetadataResolver {
|
||||||
if (meta.exports) {
|
if (meta.exports) {
|
||||||
flattenAndDedupeArray(meta.exports).forEach((exportedType) => {
|
flattenAndDedupeArray(meta.exports).forEach((exportedType) => {
|
||||||
if (!isValidType(exportedType)) {
|
if (!isValidType(exportedType)) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
|
new Error(
|
||||||
|
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`),
|
||||||
|
moduleType);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const exportedModuleSummary = this.getNgModuleSummary(exportedType);
|
const exportedModuleSummary = this.getNgModuleSummary(exportedType);
|
||||||
if (exportedModuleSummary) {
|
if (exportedModuleSummary) {
|
||||||
|
@ -411,8 +431,11 @@ export class CompileMetadataResolver {
|
||||||
if (meta.declarations) {
|
if (meta.declarations) {
|
||||||
flattenAndDedupeArray(meta.declarations).forEach((declaredType) => {
|
flattenAndDedupeArray(meta.declarations).forEach((declaredType) => {
|
||||||
if (!isValidType(declaredType)) {
|
if (!isValidType(declaredType)) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
|
new Error(
|
||||||
|
`Unexpected value '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`),
|
||||||
|
moduleType);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const declaredIdentifier = this._getIdentifierMetadata(declaredType);
|
const declaredIdentifier = this._getIdentifierMetadata(declaredType);
|
||||||
if (this._directiveResolver.isDirective(declaredType)) {
|
if (this._directiveResolver.isDirective(declaredType)) {
|
||||||
|
@ -425,8 +448,11 @@ export class CompileMetadataResolver {
|
||||||
declaredPipes.push(declaredIdentifier);
|
declaredPipes.push(declaredIdentifier);
|
||||||
this._addTypeToModule(declaredType, moduleType);
|
this._addTypeToModule(declaredType, moduleType);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`);
|
new Error(
|
||||||
|
`Unexpected ${this._getTypeDescriptor(declaredType)} '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`),
|
||||||
|
moduleType);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -441,8 +467,10 @@ export class CompileMetadataResolver {
|
||||||
exportedPipes.push(exportedId);
|
exportedPipes.push(exportedId);
|
||||||
transitiveModule.addExportedPipe(exportedId);
|
transitiveModule.addExportedPipe(exportedId);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringify(exportedId.reference)} from ${stringify(moduleType)} as it was neither declared nor imported!`);
|
new Error(
|
||||||
|
`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringify(exportedId.reference)} from ${stringify(moduleType)} as it was neither declared nor imported!`),
|
||||||
|
moduleType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -450,7 +478,8 @@ export class CompileMetadataResolver {
|
||||||
// so that they overwrite any other provider we already added.
|
// so that they overwrite any other provider we already added.
|
||||||
if (meta.providers) {
|
if (meta.providers) {
|
||||||
providers.push(...this._getProvidersMetadata(
|
providers.push(...this._getProvidersMetadata(
|
||||||
meta.providers, entryComponents, `provider for the NgModule '${stringify(moduleType)}'`));
|
meta.providers, entryComponents, `provider for the NgModule '${stringify(moduleType)}'`,
|
||||||
|
[], moduleType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta.entryComponents) {
|
if (meta.entryComponents) {
|
||||||
|
@ -459,14 +488,16 @@ export class CompileMetadataResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta.bootstrap) {
|
if (meta.bootstrap) {
|
||||||
const typeMetadata = flattenAndDedupeArray(meta.bootstrap).map(type => {
|
flattenAndDedupeArray(meta.bootstrap).forEach(type => {
|
||||||
if (!isValidType(type)) {
|
if (!isValidType(type)) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Unexpected value '${stringify(type)}' used in the bootstrap property of module '${stringify(moduleType)}'`);
|
new Error(
|
||||||
|
`Unexpected value '${stringify(type)}' used in the bootstrap property of module '${stringify(moduleType)}'`),
|
||||||
|
moduleType);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return this._getTypeMetadata(type);
|
bootstrapComponents.push(this._getTypeMetadata(type));
|
||||||
});
|
});
|
||||||
bootstrapComponents.push(...typeMetadata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entryComponents.push(...bootstrapComponents);
|
entryComponents.push(...bootstrapComponents);
|
||||||
|
@ -522,10 +553,12 @@ export class CompileMetadataResolver {
|
||||||
private _addTypeToModule(type: Type<any>, moduleType: Type<any>) {
|
private _addTypeToModule(type: Type<any>, moduleType: Type<any>) {
|
||||||
const oldModule = this._ngModuleOfTypes.get(type);
|
const oldModule = this._ngModuleOfTypes.get(type);
|
||||||
if (oldModule && oldModule !== moduleType) {
|
if (oldModule && oldModule !== moduleType) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Type ${stringify(type)} is part of the declarations of 2 modules: ${stringify(oldModule)} and ${stringify(moduleType)}! ` +
|
new Error(
|
||||||
`Please consider moving ${stringify(type)} to a higher module that imports ${stringify(oldModule)} and ${stringify(moduleType)}. ` +
|
`Type ${stringify(type)} is part of the declarations of 2 modules: ${stringify(oldModule)} and ${stringify(moduleType)}! ` +
|
||||||
`You can also create a new NgModule that exports and includes ${stringify(type)} then import that NgModule in ${stringify(oldModule)} and ${stringify(moduleType)}.`);
|
`Please consider moving ${stringify(type)} to a higher module that imports ${stringify(oldModule)} and ${stringify(moduleType)}. ` +
|
||||||
|
`You can also create a new NgModule that exports and includes ${stringify(type)} then import that NgModule in ${stringify(oldModule)} and ${stringify(moduleType)}.`),
|
||||||
|
moduleType);
|
||||||
}
|
}
|
||||||
this._ngModuleOfTypes.set(type, moduleType);
|
this._ngModuleOfTypes.set(type, moduleType);
|
||||||
}
|
}
|
||||||
|
@ -596,8 +629,10 @@ export class CompileMetadataResolver {
|
||||||
getPipeMetadata(pipeType: any): cpl.CompilePipeMetadata {
|
getPipeMetadata(pipeType: any): cpl.CompilePipeMetadata {
|
||||||
const pipeMeta = this._pipeCache.get(pipeType);
|
const pipeMeta = this._pipeCache.get(pipeType);
|
||||||
if (!pipeMeta) {
|
if (!pipeMeta) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Illegal state: getPipeMetadata can only be called after loadNgModuleMetadata for a module that declares it. Pipe ${stringify(pipeType)}.`);
|
new Error(
|
||||||
|
`Illegal state: getPipeMetadata can only be called after loadNgModuleMetadata for a module that declares it. Pipe ${stringify(pipeType)}.`),
|
||||||
|
pipeType);
|
||||||
}
|
}
|
||||||
return pipeMeta;
|
return pipeMeta;
|
||||||
}
|
}
|
||||||
|
@ -606,7 +641,9 @@ export class CompileMetadataResolver {
|
||||||
const pipeSummary =
|
const pipeSummary =
|
||||||
<cpl.CompilePipeSummary>this._loadSummary(pipeType, cpl.CompileSummaryKind.Pipe);
|
<cpl.CompilePipeSummary>this._loadSummary(pipeType, cpl.CompileSummaryKind.Pipe);
|
||||||
if (!pipeSummary) {
|
if (!pipeSummary) {
|
||||||
throw new Error(`Illegal state: Could not load the summary for pipe ${stringify(pipeType)}.`);
|
this._reportError(
|
||||||
|
new Error(`Illegal state: Could not load the summary for pipe ${stringify(pipeType)}.`),
|
||||||
|
pipeType);
|
||||||
}
|
}
|
||||||
return pipeSummary;
|
return pipeSummary;
|
||||||
}
|
}
|
||||||
|
@ -686,8 +723,9 @@ export class CompileMetadataResolver {
|
||||||
if (hasUnknownDeps) {
|
if (hasUnknownDeps) {
|
||||||
const depsTokens =
|
const depsTokens =
|
||||||
dependenciesMetadata.map((dep) => dep ? stringify(dep.token) : '?').join(', ');
|
dependenciesMetadata.map((dep) => dep ? stringify(dep.token) : '?').join(', ');
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Can't resolve all parameters for ${stringify(typeOrFunc)}: (${depsTokens}).`);
|
new Error(`Can't resolve all parameters for ${stringify(typeOrFunc)}: (${depsTokens}).`),
|
||||||
|
typeOrFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dependenciesMetadata;
|
return dependenciesMetadata;
|
||||||
|
@ -706,8 +744,8 @@ export class CompileMetadataResolver {
|
||||||
|
|
||||||
private _getProvidersMetadata(
|
private _getProvidersMetadata(
|
||||||
providers: Provider[], targetEntryComponents: cpl.CompileIdentifierMetadata[],
|
providers: Provider[], targetEntryComponents: cpl.CompileIdentifierMetadata[],
|
||||||
debugInfo?: string,
|
debugInfo?: string, compileProviders: cpl.CompileProviderMetadata[] = [],
|
||||||
compileProviders: cpl.CompileProviderMetadata[] = []): cpl.CompileProviderMetadata[] {
|
type?: any): cpl.CompileProviderMetadata[] {
|
||||||
providers.forEach((provider: any, providerIdx: number) => {
|
providers.forEach((provider: any, providerIdx: number) => {
|
||||||
if (Array.isArray(provider)) {
|
if (Array.isArray(provider)) {
|
||||||
this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
|
this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders);
|
||||||
|
@ -733,11 +771,13 @@ export class CompileMetadataResolver {
|
||||||
},
|
},
|
||||||
[]))
|
[]))
|
||||||
.join(', ');
|
.join(', ');
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`);
|
new Error(
|
||||||
|
`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`),
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
if (providerMeta.token === resolveIdentifier(Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS)) {
|
if (providerMeta.token === resolveIdentifier(Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS)) {
|
||||||
targetEntryComponents.push(...this._getEntryComponentsFromProvider(providerMeta));
|
targetEntryComponents.push(...this._getEntryComponentsFromProvider(providerMeta, type));
|
||||||
} else {
|
} else {
|
||||||
compileProviders.push(this.getProviderMetadata(providerMeta));
|
compileProviders.push(this.getProviderMetadata(providerMeta));
|
||||||
}
|
}
|
||||||
|
@ -746,17 +786,21 @@ export class CompileMetadataResolver {
|
||||||
return compileProviders;
|
return compileProviders;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getEntryComponentsFromProvider(provider: cpl.ProviderMeta):
|
private _getEntryComponentsFromProvider(provider: cpl.ProviderMeta, type?: any):
|
||||||
cpl.CompileIdentifierMetadata[] {
|
cpl.CompileIdentifierMetadata[] {
|
||||||
const components: cpl.CompileIdentifierMetadata[] = [];
|
const components: cpl.CompileIdentifierMetadata[] = [];
|
||||||
const collectedIdentifiers: cpl.CompileIdentifierMetadata[] = [];
|
const collectedIdentifiers: cpl.CompileIdentifierMetadata[] = [];
|
||||||
|
|
||||||
if (provider.useFactory || provider.useExisting || provider.useClass) {
|
if (provider.useFactory || provider.useExisting || provider.useClass) {
|
||||||
throw new Error(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!`);
|
this._reportError(
|
||||||
|
new Error(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports useValue!`), type);
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!provider.multi) {
|
if (!provider.multi) {
|
||||||
throw new Error(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!`);
|
this._reportError(
|
||||||
|
new Error(`The ANALYZE_FOR_ENTRY_COMPONENTS token only supports 'multi = true'!`), type);
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
extractIdentifiers(provider.useValue, collectedIdentifiers);
|
||||||
|
@ -822,8 +866,10 @@ export class CompileMetadataResolver {
|
||||||
this._queryVarBindings(q.selector).map(varName => this._getTokenMetadata(varName));
|
this._queryVarBindings(q.selector).map(varName => this._getTokenMetadata(varName));
|
||||||
} else {
|
} else {
|
||||||
if (!q.selector) {
|
if (!q.selector) {
|
||||||
throw new Error(
|
this._reportError(
|
||||||
`Can't construct a query for the property "${propertyName}" of "${stringify(typeOrFunc)}" since the query selector wasn't defined.`);
|
new Error(
|
||||||
|
`Can't construct a query for the property "${propertyName}" of "${stringify(typeOrFunc)}" since the query selector wasn't defined.`),
|
||||||
|
typeOrFunc);
|
||||||
}
|
}
|
||||||
selectors = [this._getTokenMetadata(q.selector)];
|
selectors = [this._getTokenMetadata(q.selector)];
|
||||||
}
|
}
|
||||||
|
@ -835,6 +881,17 @@ export class CompileMetadataResolver {
|
||||||
read: q.read ? this._getTokenMetadata(q.read) : null
|
read: q.read ? this._getTokenMetadata(q.read) : null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _reportError(error: any, type?: any, otherType?: any) {
|
||||||
|
if (this._errorCollector) {
|
||||||
|
this._errorCollector(error, type);
|
||||||
|
if (otherType) {
|
||||||
|
this._errorCollector(error, otherType);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function flattenArray(tree: any[], out: Array<any> = []): Array<any> {
|
function flattenArray(tree: any[], out: Array<any> = []): Array<any> {
|
||||||
|
|
|
@ -120,7 +120,8 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
|
|
||||||
result = this._resolver = new CompileMetadataResolver(
|
result = this._resolver = new CompileMetadataResolver(
|
||||||
moduleResolver, directiveResolver, pipeResolver, new SummaryResolver(),
|
moduleResolver, directiveResolver, pipeResolver, new SummaryResolver(),
|
||||||
elementSchemaRegistry, directiveNormalizer, this.reflector);
|
elementSchemaRegistry, directiveNormalizer, this.reflector,
|
||||||
|
(error, type) => this.collectError(error, type && type.filePath));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {createLanguageService} from '../src/language_service';
|
import {createLanguageService} from '../src/language_service';
|
||||||
import {Completions, Diagnostic, Diagnostics} from '../src/types';
|
import {Completions, Diagnostic, Diagnostics, LanguageService} from '../src/types';
|
||||||
import {TypeScriptServiceHost} from '../src/typescript_host';
|
import {TypeScriptServiceHost} from '../src/typescript_host';
|
||||||
|
|
||||||
import {toh} from './test_data';
|
import {toh} from './test_data';
|
||||||
|
@ -17,16 +17,42 @@ import {MockTypescriptHost} from './test_utils';
|
||||||
|
|
||||||
describe('references', () => {
|
describe('references', () => {
|
||||||
let documentRegistry = ts.createDocumentRegistry();
|
let documentRegistry = ts.createDocumentRegistry();
|
||||||
let mockHost = new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], toh);
|
let mockHost: MockTypescriptHost;
|
||||||
let service = ts.createLanguageService(mockHost, documentRegistry);
|
let service: ts.LanguageService;
|
||||||
let program = service.getProgram();
|
let program: ts.Program;
|
||||||
let ngHost = new TypeScriptServiceHost(mockHost, service);
|
let ngHost: TypeScriptServiceHost;
|
||||||
let ngService = createLanguageService(ngHost);
|
let ngService: LanguageService = createLanguageService(ngHost);
|
||||||
ngHost.setSite(ngService);
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockHost = new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], toh);
|
||||||
|
service = ts.createLanguageService(mockHost, documentRegistry);
|
||||||
|
program = service.getProgram();
|
||||||
|
ngHost = new TypeScriptServiceHost(mockHost, service);
|
||||||
|
ngService = createLanguageService(ngHost);
|
||||||
|
ngHost.setSite(ngService);
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to get template references',
|
it('should be able to get template references',
|
||||||
() => { expect(() => ngService.getTemplateReferences()).not.toThrow(); });
|
() => { expect(() => ngService.getTemplateReferences()).not.toThrow(); });
|
||||||
|
|
||||||
it('should be able to determine that test.ng is a template reference',
|
it('should be able to determine that test.ng is a template reference',
|
||||||
() => { expect(ngService.getTemplateReferences()).toContain('/app/test.ng'); });
|
() => { expect(ngService.getTemplateReferences()).toContain('/app/test.ng'); });
|
||||||
|
|
||||||
|
it('should be able to get template references for an invalid project', () => {
|
||||||
|
const moduleCode = `
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {NewClass} from './test.component';
|
||||||
|
|
||||||
|
@NgModule({declarations: [NewClass]}) export class TestModule {}`;
|
||||||
|
const classCode = `
|
||||||
|
export class NewClass {}
|
||||||
|
|
||||||
|
@Component({})
|
||||||
|
export class SomeComponent {}
|
||||||
|
`;
|
||||||
|
mockHost.addScript('/app/test.module.ts', moduleCode);
|
||||||
|
mockHost.addScript('/app/test.component.ts', classCode);
|
||||||
|
expect(() => { ngService.getTemplateReferences(); }).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
|
@ -91,6 +91,12 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addScript(fileName: string, content: string) {
|
||||||
|
this.projectVersion++;
|
||||||
|
this.overrides.set(fileName, content);
|
||||||
|
this.scriptNames.push(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
getCompilationSettings(): ts.CompilerOptions {
|
getCompilationSettings(): ts.CompilerOptions {
|
||||||
return {
|
return {
|
||||||
target: ts.ScriptTarget.ES5,
|
target: ts.ScriptTarget.ES5,
|
||||||
|
|
Loading…
Reference in New Issue