refactor(compiler-cli): make `TypeCheckingScopeRegistry` a general utility (#40032)
The `annotations` package in the compiler previously contained a registry which tracks NgModule scopes for template type-checking, including unifying all type-checking metadata across class inheritance lines. This commit generalizes this utility and prepares it for use in the `TemplateTypeChecker` as well, to back APIs used by the language service. PR Close #40032
This commit is contained in:
parent
e42250f139
commit
a543e69497
|
@ -16,7 +16,7 @@ import {absoluteFrom, absoluteFromSourceFile, dirname, FileSystem, LogicalFileSy
|
||||||
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, PrivateExportAliasingHost, Reexport, ReferenceEmitter} from '../../../src/ngtsc/imports';
|
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, PrivateExportAliasingHost, Reexport, ReferenceEmitter} from '../../../src/ngtsc/imports';
|
||||||
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, ResourceRegistry} from '../../../src/ngtsc/metadata';
|
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, ResourceRegistry} from '../../../src/ngtsc/metadata';
|
||||||
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
|
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
|
||||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../../src/ngtsc/scope';
|
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver, TypeCheckScopeRegistry} from '../../../src/ngtsc/scope';
|
||||||
import {DecoratorHandler} from '../../../src/ngtsc/transform';
|
import {DecoratorHandler} from '../../../src/ngtsc/transform';
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {Migration} from '../migrations/migration';
|
import {Migration} from '../migrations/migration';
|
||||||
|
@ -91,11 +91,13 @@ export class DecorationAnalyzer {
|
||||||
importGraph = new ImportGraph(this.moduleResolver);
|
importGraph = new ImportGraph(this.moduleResolver);
|
||||||
cycleAnalyzer = new CycleAnalyzer(this.importGraph);
|
cycleAnalyzer = new CycleAnalyzer(this.importGraph);
|
||||||
injectableRegistry = new InjectableClassRegistry(this.reflectionHost);
|
injectableRegistry = new InjectableClassRegistry(this.reflectionHost);
|
||||||
|
typeCheckScopeRegistry = new TypeCheckScopeRegistry(this.scopeRegistry, this.fullMetaReader);
|
||||||
handlers: DecoratorHandler<unknown, unknown, unknown>[] = [
|
handlers: DecoratorHandler<unknown, unknown, unknown>[] = [
|
||||||
new ComponentDecoratorHandler(
|
new ComponentDecoratorHandler(
|
||||||
this.reflectionHost, this.evaluator, this.fullRegistry, this.fullMetaReader,
|
this.reflectionHost, this.evaluator, this.fullRegistry, this.fullMetaReader,
|
||||||
this.scopeRegistry, this.scopeRegistry, new ResourceRegistry(), this.isCore,
|
this.scopeRegistry, this.scopeRegistry, this.typeCheckScopeRegistry, new ResourceRegistry(),
|
||||||
this.resourceManager, this.rootDirs, !!this.compilerOptions.preserveWhitespaces,
|
this.isCore, this.resourceManager, this.rootDirs,
|
||||||
|
!!this.compilerOptions.preserveWhitespaces,
|
||||||
/* i18nUseExternalIds */ true, this.bundle.enableI18nLegacyMessageIdFormat,
|
/* i18nUseExternalIds */ true, this.bundle.enableI18nLegacyMessageIdFormat,
|
||||||
/* usePoisonedData */ false,
|
/* usePoisonedData */ false,
|
||||||
/* i18nNormalizeLineEndingsInICUs */ false, this.moduleResolver, this.cycleAnalyzer,
|
/* i18nNormalizeLineEndingsInICUs */ false, this.moduleResolver, this.cycleAnalyzer,
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {IndexingContext} from '../../indexer';
|
||||||
import {ClassPropertyMapping, ComponentResources, DirectiveMeta, DirectiveTypeCheckMeta, extractDirectiveTypeCheckMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry, Resource, ResourceRegistry} from '../../metadata';
|
import {ClassPropertyMapping, ComponentResources, DirectiveMeta, DirectiveTypeCheckMeta, extractDirectiveTypeCheckMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry, Resource, ResourceRegistry} from '../../metadata';
|
||||||
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {ClassDeclaration, DeclarationNode, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
import {ClassDeclaration, DeclarationNode, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||||
import {ComponentScopeReader, LocalModuleScopeRegistry} from '../../scope';
|
import {ComponentScopeReader, LocalModuleScopeRegistry, TypeCheckScopeRegistry} from '../../scope';
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFlags, HandlerPrecedence, ResolveResult} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFlags, HandlerPrecedence, ResolveResult} from '../../transform';
|
||||||
import {TemplateSourceMapping, TypeCheckContext} from '../../typecheck/api';
|
import {TemplateSourceMapping, TypeCheckContext} from '../../typecheck/api';
|
||||||
import {getTemplateId, makeTemplateDiagnostic} from '../../typecheck/diagnostics';
|
import {getTemplateId, makeTemplateDiagnostic} from '../../typecheck/diagnostics';
|
||||||
|
@ -30,7 +30,6 @@ import {createValueHasWrongTypeError, getDirectiveDiagnostics, getProviderDiagno
|
||||||
import {extractDirectiveMetadata, parseFieldArrayValue} from './directive';
|
import {extractDirectiveMetadata, parseFieldArrayValue} from './directive';
|
||||||
import {compileNgFactoryDefField} from './factory';
|
import {compileNgFactoryDefField} from './factory';
|
||||||
import {generateSetClassMetadataCall} from './metadata';
|
import {generateSetClassMetadataCall} from './metadata';
|
||||||
import {TypeCheckScopes} from './typecheck_scopes';
|
|
||||||
import {findAngularDecorator, isAngularCoreReference, isExpressionForwardReference, readBaseClass, resolveProvidersRequiringFactory, unwrapExpression, wrapFunctionExpressionsInParens} from './util';
|
import {findAngularDecorator, isAngularCoreReference, isExpressionForwardReference, readBaseClass, resolveProvidersRequiringFactory, unwrapExpression, wrapFunctionExpressionsInParens} from './util';
|
||||||
|
|
||||||
const EMPTY_MAP = new Map<string, Expression>();
|
const EMPTY_MAP = new Map<string, Expression>();
|
||||||
|
@ -87,6 +86,7 @@ export class ComponentDecoratorHandler implements
|
||||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private metaRegistry: MetadataRegistry, private metaReader: MetadataReader,
|
private metaRegistry: MetadataRegistry, private metaReader: MetadataReader,
|
||||||
private scopeReader: ComponentScopeReader, private scopeRegistry: LocalModuleScopeRegistry,
|
private scopeReader: ComponentScopeReader, private scopeRegistry: LocalModuleScopeRegistry,
|
||||||
|
private typeCheckScopeRegistry: TypeCheckScopeRegistry,
|
||||||
private resourceRegistry: ResourceRegistry, private isCore: boolean,
|
private resourceRegistry: ResourceRegistry, private isCore: boolean,
|
||||||
private resourceLoader: ResourceLoader, private rootDirs: ReadonlyArray<string>,
|
private resourceLoader: ResourceLoader, private rootDirs: ReadonlyArray<string>,
|
||||||
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean,
|
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean,
|
||||||
|
@ -100,7 +100,6 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
private literalCache = new Map<Decorator, ts.ObjectLiteralExpression>();
|
private literalCache = new Map<Decorator, ts.ObjectLiteralExpression>();
|
||||||
private elementSchemaRegistry = new DomElementSchemaRegistry();
|
private elementSchemaRegistry = new DomElementSchemaRegistry();
|
||||||
private typeCheckScopes = new TypeCheckScopes(this.scopeReader, this.metaReader);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* During the asynchronous preanalyze phase, it's necessary to parse the template to extract
|
* During the asynchronous preanalyze phase, it's necessary to parse the template to extract
|
||||||
|
@ -440,15 +439,14 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
typeCheck(ctx: TypeCheckContext, node: ClassDeclaration, meta: Readonly<ComponentAnalysisData>):
|
typeCheck(ctx: TypeCheckContext, node: ClassDeclaration, meta: Readonly<ComponentAnalysisData>):
|
||||||
void {
|
void {
|
||||||
if (!ts.isClassDeclaration(node)) {
|
if (this.typeCheckScopeRegistry === null || !ts.isClassDeclaration(node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta.isPoisoned && !this.usePoisonedData) {
|
if (meta.isPoisoned && !this.usePoisonedData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const scope = this.typeCheckScopeRegistry.getTypeCheckScope(node);
|
||||||
const scope = this.typeCheckScopes.getTypeCheckScope(node);
|
|
||||||
if (scope.isPoisoned && !this.usePoisonedData) {
|
if (scope.isPoisoned && !this.usePoisonedData) {
|
||||||
// Don't type-check components that had errors in their scopes, unless requested.
|
// Don't type-check components that had errors in their scopes, unless requested.
|
||||||
return;
|
return;
|
||||||
|
@ -492,17 +490,17 @@ export class ComponentDecoratorHandler implements
|
||||||
// Determining this is challenging, because the TemplateDefinitionBuilder is responsible for
|
// Determining this is challenging, because the TemplateDefinitionBuilder is responsible for
|
||||||
// matching directives and pipes in the template; however, that doesn't run until the actual
|
// matching directives and pipes in the template; however, that doesn't run until the actual
|
||||||
// compile() step. It's not possible to run template compilation sooner as it requires the
|
// compile() step. It's not possible to run template compilation sooner as it requires the
|
||||||
// ConstantPool for the overall file being compiled (which isn't available until the transform
|
// ConstantPool for the overall file being compiled (which isn't available until the
|
||||||
// step).
|
// transform step).
|
||||||
//
|
//
|
||||||
// Instead, directives/pipes are matched independently here, using the R3TargetBinder. This is
|
// Instead, directives/pipes are matched independently here, using the R3TargetBinder. This
|
||||||
// an alternative implementation of template matching which is used for template type-checking
|
// is an alternative implementation of template matching which is used for template
|
||||||
// and will eventually replace matching in the TemplateDefinitionBuilder.
|
// type-checking and will eventually replace matching in the TemplateDefinitionBuilder.
|
||||||
|
|
||||||
|
|
||||||
// Set up the R3TargetBinder, as well as a 'directives' array and a 'pipes' map that are later
|
// Set up the R3TargetBinder, as well as a 'directives' array and a 'pipes' map that are
|
||||||
// fed to the TemplateDefinitionBuilder. First, a SelectorMatcher is constructed to match
|
// later fed to the TemplateDefinitionBuilder. First, a SelectorMatcher is constructed to
|
||||||
// directives that are in scope.
|
// match directives that are in scope.
|
||||||
type MatchedDirective = DirectiveMeta&{selector: string};
|
type MatchedDirective = DirectiveMeta&{selector: string};
|
||||||
const matcher = new SelectorMatcher<MatchedDirective>();
|
const matcher = new SelectorMatcher<MatchedDirective>();
|
||||||
|
|
||||||
|
@ -563,8 +561,8 @@ export class ComponentDecoratorHandler implements
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the directive/pipe arrays in ɵcmp need to be wrapped in closures.
|
// Check whether the directive/pipe arrays in ɵcmp need to be wrapped in closures.
|
||||||
// This is required if any directive/pipe reference is to a declaration in the same file but
|
// This is required if any directive/pipe reference is to a declaration in the same file
|
||||||
// declared after this component.
|
// but declared after this component.
|
||||||
const wrapDirectivesAndPipesInClosure =
|
const wrapDirectivesAndPipesInClosure =
|
||||||
usedDirectives.some(
|
usedDirectives.some(
|
||||||
dir => isExpressionForwardReference(dir.type, node.name, context)) ||
|
dir => isExpressionForwardReference(dir.type, node.name, context)) ||
|
||||||
|
@ -890,8 +888,8 @@ export class ComponentDecoratorHandler implements
|
||||||
// 2. By default, the template parser strips leading trivia characters (like spaces, tabs, and
|
// 2. By default, the template parser strips leading trivia characters (like spaces, tabs, and
|
||||||
// newlines). This also destroys source mapping information.
|
// newlines). This also destroys source mapping information.
|
||||||
//
|
//
|
||||||
// In order to guarantee the correctness of diagnostics, templates are parsed a second time with
|
// In order to guarantee the correctness of diagnostics, templates are parsed a second time
|
||||||
// the above options set to preserve source mappings.
|
// with the above options set to preserve source mappings.
|
||||||
|
|
||||||
const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, {
|
const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, {
|
||||||
preserveWhitespaces: true,
|
preserveWhitespaces: true,
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CycleAnalyzer, ImportGraph} from '../../cycles';
|
import {CycleAnalyzer, ImportGraph} from '../../cycles';
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {absoluteFrom} from '../../file_system';
|
import {absoluteFrom} from '../../file_system';
|
||||||
|
@ -13,7 +16,7 @@ import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '..
|
||||||
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, ResourceRegistry} from '../../metadata';
|
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, ResourceRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver, TypeCheckScopeRegistry} from '../../scope';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
import {ResourceLoader} from '../src/api';
|
import {ResourceLoader} from '../src/api';
|
||||||
import {ComponentDecoratorHandler} from '../src/component';
|
import {ComponentDecoratorHandler} from '../src/component';
|
||||||
|
@ -48,17 +51,33 @@ function setup(program: ts.Program, options: ts.CompilerOptions, host: ts.Compil
|
||||||
const refEmitter = new ReferenceEmitter([]);
|
const refEmitter = new ReferenceEmitter([]);
|
||||||
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
||||||
const resourceRegistry = new ResourceRegistry();
|
const resourceRegistry = new ResourceRegistry();
|
||||||
|
const typeCheckScopeRegistry = new TypeCheckScopeRegistry(scopeRegistry, metaReader);
|
||||||
|
|
||||||
const handler = new ComponentDecoratorHandler(
|
const handler = new ComponentDecoratorHandler(
|
||||||
reflectionHost, evaluator, metaRegistry, metaReader, scopeRegistry, scopeRegistry,
|
reflectionHost,
|
||||||
|
evaluator,
|
||||||
|
metaRegistry,
|
||||||
|
metaReader,
|
||||||
|
scopeRegistry,
|
||||||
|
scopeRegistry,
|
||||||
|
typeCheckScopeRegistry,
|
||||||
resourceRegistry,
|
resourceRegistry,
|
||||||
/* isCore */ false, new StubResourceLoader(), /* rootDirs */['/'],
|
/* isCore */ false,
|
||||||
/* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true,
|
new StubResourceLoader(),
|
||||||
|
/* rootDirs */['/'],
|
||||||
|
/* defaultPreserveWhitespaces */ false,
|
||||||
|
/* i18nUseExternalIds */ true,
|
||||||
/* enableI18nLegacyMessageIdFormat */ false,
|
/* enableI18nLegacyMessageIdFormat */ false,
|
||||||
/* usePoisonedData */ false,
|
/* usePoisonedData */ false,
|
||||||
/* i18nNormalizeLineEndingsInICUs */ undefined, moduleResolver, cycleAnalyzer, refEmitter,
|
/* i18nNormalizeLineEndingsInICUs */ undefined,
|
||||||
NOOP_DEFAULT_IMPORT_RECORDER, /* depTracker */ null, injectableRegistry,
|
moduleResolver,
|
||||||
/* annotateForClosureCompiler */ false);
|
cycleAnalyzer,
|
||||||
|
refEmitter,
|
||||||
|
NOOP_DEFAULT_IMPORT_RECORDER,
|
||||||
|
/* depTracker */ null,
|
||||||
|
injectableRegistry,
|
||||||
|
/* annotateForClosureCompiler */ false,
|
||||||
|
);
|
||||||
return {reflectionHost, handler};
|
return {reflectionHost, handler};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {NOOP_PERF_RECORDER, PerfRecorder} from '../../perf';
|
||||||
import {DeclarationNode, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
import {DeclarationNode, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {AdapterResourceLoader} from '../../resource';
|
import {AdapterResourceLoader} from '../../resource';
|
||||||
import {entryPointKeyFor, NgModuleRouteAnalyzer} from '../../routing';
|
import {entryPointKeyFor, NgModuleRouteAnalyzer} from '../../routing';
|
||||||
import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver, TypeCheckScopeRegistry} from '../../scope';
|
||||||
import {generatedFactoryTransform} from '../../shims';
|
import {generatedFactoryTransform} from '../../shims';
|
||||||
import {ivySwitchTransform} from '../../switch';
|
import {ivySwitchTransform} from '../../switch';
|
||||||
import {aliasTransformFactory, CompilationMode, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform';
|
import {aliasTransformFactory, CompilationMode, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform';
|
||||||
|
@ -44,6 +44,7 @@ interface LazyCompilationState {
|
||||||
reflector: TypeScriptReflectionHost;
|
reflector: TypeScriptReflectionHost;
|
||||||
metaReader: MetadataReader;
|
metaReader: MetadataReader;
|
||||||
scopeRegistry: LocalModuleScopeRegistry;
|
scopeRegistry: LocalModuleScopeRegistry;
|
||||||
|
typeCheckScopeRegistry: TypeCheckScopeRegistry;
|
||||||
exportReferenceGraph: ReferenceGraph|null;
|
exportReferenceGraph: ReferenceGraph|null;
|
||||||
routeAnalyzer: NgModuleRouteAnalyzer;
|
routeAnalyzer: NgModuleRouteAnalyzer;
|
||||||
dtsTransforms: DtsTransformRegistry;
|
dtsTransforms: DtsTransformRegistry;
|
||||||
|
@ -732,6 +733,7 @@ export class NgCompiler {
|
||||||
const injectableRegistry = new InjectableClassRegistry(reflector);
|
const injectableRegistry = new InjectableClassRegistry(reflector);
|
||||||
|
|
||||||
const metaReader = new CompoundMetadataReader([localMetaReader, dtsReader]);
|
const metaReader = new CompoundMetadataReader([localMetaReader, dtsReader]);
|
||||||
|
const typeCheckScopeRegistry = new TypeCheckScopeRegistry(scopeReader, metaReader);
|
||||||
|
|
||||||
|
|
||||||
// If a flat module entrypoint was specified, then track references via a `ReferenceGraph` in
|
// If a flat module entrypoint was specified, then track references via a `ReferenceGraph` in
|
||||||
|
@ -761,8 +763,9 @@ export class NgCompiler {
|
||||||
const handlers: DecoratorHandler<unknown, unknown, unknown>[] = [
|
const handlers: DecoratorHandler<unknown, unknown, unknown>[] = [
|
||||||
new ComponentDecoratorHandler(
|
new ComponentDecoratorHandler(
|
||||||
reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry,
|
reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry,
|
||||||
resourceRegistry, isCore, this.resourceManager, this.adapter.rootDirs,
|
typeCheckScopeRegistry, resourceRegistry, isCore, this.resourceManager,
|
||||||
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false,
|
this.adapter.rootDirs, this.options.preserveWhitespaces || false,
|
||||||
|
this.options.i18nUseExternalIds !== false,
|
||||||
this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData,
|
this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData,
|
||||||
this.options.i18nNormalizeLineEndingsInICUs, this.moduleResolver, this.cycleAnalyzer,
|
this.options.i18nNormalizeLineEndingsInICUs, this.moduleResolver, this.cycleAnalyzer,
|
||||||
refEmitter, defaultImportTracker, this.incrementalDriver.depGraph, injectableRegistry,
|
refEmitter, defaultImportTracker, this.incrementalDriver.depGraph, injectableRegistry,
|
||||||
|
@ -814,6 +817,7 @@ export class NgCompiler {
|
||||||
routeAnalyzer,
|
routeAnalyzer,
|
||||||
mwpScanner,
|
mwpScanner,
|
||||||
metaReader,
|
metaReader,
|
||||||
|
typeCheckScopeRegistry,
|
||||||
defaultImportTracker,
|
defaultImportTracker,
|
||||||
aliasingHost,
|
aliasingHost,
|
||||||
refEmitter,
|
refEmitter,
|
||||||
|
|
|
@ -10,3 +10,4 @@ export {ExportScope, ScopeData} from './src/api';
|
||||||
export {ComponentScopeReader, CompoundComponentScopeReader} from './src/component_scope';
|
export {ComponentScopeReader, CompoundComponentScopeReader} from './src/component_scope';
|
||||||
export {DtsModuleScopeResolver, MetadataDtsModuleScopeResolver} from './src/dependency';
|
export {DtsModuleScopeResolver, MetadataDtsModuleScopeResolver} from './src/dependency';
|
||||||
export {DeclarationData, LocalModuleScope, LocalModuleScopeRegistry, LocalNgModuleData} from './src/local';
|
export {DeclarationData, LocalModuleScope, LocalModuleScopeRegistry, LocalNgModuleData} from './src/local';
|
||||||
|
export {TypeCheckScope, TypeCheckScopeRegistry} from './src/typecheck';
|
|
@ -12,7 +12,8 @@ import * as ts from 'typescript';
|
||||||
import {Reference} from '../../imports';
|
import {Reference} from '../../imports';
|
||||||
import {DirectiveMeta, flattenInheritedDirectiveMetadata, MetadataReader} from '../../metadata';
|
import {DirectiveMeta, flattenInheritedDirectiveMetadata, MetadataReader} from '../../metadata';
|
||||||
import {ClassDeclaration} from '../../reflection';
|
import {ClassDeclaration} from '../../reflection';
|
||||||
import {ComponentScopeReader} from '../../scope';
|
|
||||||
|
import {ComponentScopeReader} from './component_scope';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The scope that is used for type-check code generation of a component template.
|
* The scope that is used for type-check code generation of a component template.
|
||||||
|
@ -24,6 +25,11 @@ export interface TypeCheckScope {
|
||||||
*/
|
*/
|
||||||
matcher: SelectorMatcher<DirectiveMeta>;
|
matcher: SelectorMatcher<DirectiveMeta>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All of the directives available in the compilation scope of the declaring NgModule.
|
||||||
|
*/
|
||||||
|
directives: DirectiveMeta[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The pipes that are available in the compilation scope.
|
* The pipes that are available in the compilation scope.
|
||||||
*/
|
*/
|
||||||
|
@ -44,7 +50,7 @@ export interface TypeCheckScope {
|
||||||
/**
|
/**
|
||||||
* Computes scope information to be used in template type checking.
|
* Computes scope information to be used in template type checking.
|
||||||
*/
|
*/
|
||||||
export class TypeCheckScopes {
|
export class TypeCheckScopeRegistry {
|
||||||
/**
|
/**
|
||||||
* Cache of flattened directive metadata. Because flattened metadata is scope-invariant it's
|
* Cache of flattened directive metadata. Because flattened metadata is scope-invariant it's
|
||||||
* cached individually, such that all scopes refer to the same flattened metadata.
|
* cached individually, such that all scopes refer to the same flattened metadata.
|
||||||
|
@ -65,12 +71,14 @@ export class TypeCheckScopes {
|
||||||
*/
|
*/
|
||||||
getTypeCheckScope(node: ClassDeclaration): TypeCheckScope {
|
getTypeCheckScope(node: ClassDeclaration): TypeCheckScope {
|
||||||
const matcher = new SelectorMatcher<DirectiveMeta>();
|
const matcher = new SelectorMatcher<DirectiveMeta>();
|
||||||
|
const directives: DirectiveMeta[] = [];
|
||||||
const pipes = new Map<string, Reference<ClassDeclaration<ts.ClassDeclaration>>>();
|
const pipes = new Map<string, Reference<ClassDeclaration<ts.ClassDeclaration>>>();
|
||||||
|
|
||||||
const scope = this.scopeReader.getScopeForComponent(node);
|
const scope = this.scopeReader.getScopeForComponent(node);
|
||||||
if (scope === null) {
|
if (scope === null) {
|
||||||
return {
|
return {
|
||||||
matcher,
|
matcher,
|
||||||
|
directives,
|
||||||
pipes,
|
pipes,
|
||||||
schemas: [],
|
schemas: [],
|
||||||
isPoisoned: false,
|
isPoisoned: false,
|
||||||
|
@ -83,8 +91,9 @@ export class TypeCheckScopes {
|
||||||
|
|
||||||
for (const meta of scope.compilation.directives) {
|
for (const meta of scope.compilation.directives) {
|
||||||
if (meta.selector !== null) {
|
if (meta.selector !== null) {
|
||||||
const extMeta = this.getInheritedDirectiveMetadata(meta.ref);
|
const extMeta = this.getTypeCheckDirectiveMetadata(meta.ref);
|
||||||
matcher.addSelectables(CssSelector.parse(meta.selector), extMeta);
|
matcher.addSelectables(CssSelector.parse(meta.selector), extMeta);
|
||||||
|
directives.push(extMeta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +107,7 @@ export class TypeCheckScopes {
|
||||||
|
|
||||||
const typeCheckScope: TypeCheckScope = {
|
const typeCheckScope: TypeCheckScope = {
|
||||||
matcher,
|
matcher,
|
||||||
|
directives,
|
||||||
pipes,
|
pipes,
|
||||||
schemas: scope.schemas,
|
schemas: scope.schemas,
|
||||||
isPoisoned: scope.compilation.isPoisoned || scope.exported.isPoisoned,
|
isPoisoned: scope.compilation.isPoisoned || scope.exported.isPoisoned,
|
||||||
|
@ -106,7 +116,7 @@ export class TypeCheckScopes {
|
||||||
return typeCheckScope;
|
return typeCheckScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getInheritedDirectiveMetadata(ref: Reference<ClassDeclaration>): DirectiveMeta {
|
getTypeCheckDirectiveMetadata(ref: Reference<ClassDeclaration>): DirectiveMeta {
|
||||||
const clazz = ref.node;
|
const clazz = ref.node;
|
||||||
if (this.flattenedDirectiveMetaCache.has(clazz)) {
|
if (this.flattenedDirectiveMetaCache.has(clazz)) {
|
||||||
return this.flattenedDirectiveMetaCache.get(clazz)!;
|
return this.flattenedDirectiveMetaCache.get(clazz)!;
|
Loading…
Reference in New Issue