feat(ivy): register references from NgModule annotations (#26906)

The `NgModuleDecoratorHandler` can now register all the references that
it finds in the `NgModule` metadata, such as `declarations`, `imports`,
`exports` etc.

This information can then be used by ngcc to work out if any of these
references are internal only and need to be manually exported from a
library's entry-point.

PR Close #26906
This commit is contained in:
Pete Bacon Darwin 2018-11-13 14:40:54 +00:00 committed by Igor Minar
parent b93c1dffa1
commit 4a70b669be
12 changed files with 191 additions and 20 deletions

View File

@ -9,9 +9,8 @@ import {ConstantPool} from '@angular/compiler';
import * as fs from 'fs'; import * as fs from 'fs';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from '../../../ngtsc/annotations'; import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader, SelectorScopeRegistry} from '../../../ngtsc/annotations';
import {CompileResult, DecoratorHandler} from '../../../ngtsc/transform'; import {CompileResult, DecoratorHandler} from '../../../ngtsc/transform';
import {DecoratedClass} from '../host/decorated_class'; import {DecoratedClass} from '../host/decorated_class';
import {NgccReflectionHost} from '../host/ngcc_host'; import {NgccReflectionHost} from '../host/ngcc_host';
import {isDefined} from '../utils'; import {isDefined} from '../utils';
@ -63,13 +62,15 @@ export class DecorationAnalyzer {
this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true), this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true),
new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
new InjectableDecoratorHandler(this.host, this.isCore), new InjectableDecoratorHandler(this.host, this.isCore),
new NgModuleDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), new NgModuleDecoratorHandler(
this.typeChecker, this.host, this.scopeRegistry, this.referencesRegistry, this.isCore),
new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore),
]; ];
constructor( constructor(
private typeChecker: ts.TypeChecker, private host: NgccReflectionHost, private typeChecker: ts.TypeChecker, private host: NgccReflectionHost,
private rootDirs: string[], private isCore: boolean) {} private referencesRegistry: ReferencesRegistry, private rootDirs: string[],
private isCore: boolean) {}
/** /**
* Analyze a program to find all the decorated files should be transformed. * Analyze a program to find all the decorated files should be transformed.

View File

@ -0,0 +1,49 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import {ReferencesRegistry} from '../../../ngtsc/annotations';
import {Declaration, ReflectionHost} from '../../../ngtsc/host';
import {Reference, ResolvedReference} from '../../../ngtsc/metadata';
import {hasNameIdentifier} from '../utils';
/**
* This is a place for DecoratorHandlers to register references that they
* find in their analysis of the code.
*
* This registry is used to ensure that these references are publicly exported
* from libraries that are compiled by ngcc.
*/
export class NgccReferencesRegistry implements ReferencesRegistry {
private map = new Map<ts.Identifier, Declaration>();
constructor(private host: ReflectionHost) {}
/**
* Register one or more references in the registry.
* Only `ResolveReference` references are stored. Other types are ignored.
* @param references A collection of references to register.
*/
add(...references: Reference<ts.Declaration>[]): void {
references.forEach(ref => {
// Only store resolved references. We are not interested in literals.
if (ref instanceof ResolvedReference && hasNameIdentifier(ref.node)) {
const declaration = this.host.getDeclarationOfIdentifier(ref.node.name);
if (declaration && hasNameIdentifier(declaration.node)) {
this.map.set(declaration.node.name, declaration);
}
}
});
}
/**
* Create and return a mapping for the registered resolved references.
* @returns A map of reference identifiers to reference declarations.
*/
getDeclarationMap(): Map<ts.Identifier, Declaration> { return this.map; }
}

View File

@ -62,7 +62,7 @@ interface EntryPointPackageJson {
* @param packageJsonPath the absolute path to the package.json file. * @param packageJsonPath the absolute path to the package.json file.
* @returns JSON from the package.json file if it is valid, `null` otherwise. * @returns JSON from the package.json file if it is valid, `null` otherwise.
*/ */
function loadEntryPointPackage(packageJsonPath: string): {[key: string]: any}|null { function loadEntryPointPackage(packageJsonPath: string): EntryPointPackageJson|null {
try { try {
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
} catch (e) { } catch (e) {
@ -109,7 +109,8 @@ export function getEntryPointInfo(packagePath: string, entryPointPath: string):
} }
// Also there must exist a `metadata.json` file next to the typings entry-point. // Also there must exist a `metadata.json` file next to the typings entry-point.
const metadataPath = path.resolve(entryPointPath, typings.replace(/\.d\.ts$/, '') + '.metadata.json'); const metadataPath =
path.resolve(entryPointPath, typings.replace(/\.d\.ts$/, '') + '.metadata.json');
if (!fs.existsSync(metadataPath)) { if (!fs.existsSync(metadataPath)) {
return null; return null;
} }

View File

@ -11,6 +11,7 @@ import {mkdir, mv} from 'shelljs';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {DecorationAnalyzer} from '../analysis/decoration_analyzer'; import {DecorationAnalyzer} from '../analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../analysis/ngcc_references_registry';
import {SwitchMarkerAnalyzer} from '../analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../analysis/switch_marker_analyzer';
import {Esm2015ReflectionHost} from '../host/esm2015_host'; import {Esm2015ReflectionHost} from '../host/esm2015_host';
import {Esm5ReflectionHost} from '../host/esm5_host'; import {Esm5ReflectionHost} from '../host/esm5_host';
@ -156,8 +157,10 @@ export class Transformer {
analyzeProgram( analyzeProgram(
program: ts.Program, reflectionHost: NgccReflectionHost, rootDirs: string[], program: ts.Program, reflectionHost: NgccReflectionHost, rootDirs: string[],
isCore: boolean) { isCore: boolean) {
const typeChecker = bundle.program.getTypeChecker();
const referencesRegistry = new NgccReferencesRegistry(reflectionHost);
const decorationAnalyzer = const decorationAnalyzer =
new DecorationAnalyzer(program.getTypeChecker(), reflectionHost, rootDirs, isCore); new DecorationAnalyzer(typeChecker, reflectionHost, referencesRegistry, rootDirs, isCore);
const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost); const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost);
return { return {
decorationAnalyses: decorationAnalyzer.analyzeProgram(program), decorationAnalyses: decorationAnalyzer.analyzeProgram(program),

View File

@ -40,3 +40,13 @@ export function findAll<T>(node: ts.Node, test: (node: ts.Node) => node is ts.No
} }
} }
} }
/**
* Does the given declaration have a name which is an identifier?
* @param declaration The declaration to test.
* @returns true if the declaration has an identifer for a name.
*/
export function hasNameIdentifier(declaration: ts.Declaration): declaration is ts.Declaration&
{name: ts.Identifier} {
return ts.isIdentifier((declaration as any).name);
}

View File

@ -10,6 +10,7 @@ import * as ts from 'typescript';
import {Decorator} from '../../../ngtsc/host'; import {Decorator} from '../../../ngtsc/host';
import {DecoratorHandler} from '../../../ngtsc/transform'; import {DecoratorHandler} from '../../../ngtsc/transform';
import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {makeProgram} from '../helpers/utils'; import {makeProgram} from '../helpers/utils';
@ -84,9 +85,10 @@ describe('DecorationAnalyzer', () => {
beforeEach(() => { beforeEach(() => {
program = makeProgram(TEST_PROGRAM); program = makeProgram(TEST_PROGRAM);
const analyzer = new DecorationAnalyzer( const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
program.getTypeChecker(), new Esm2015ReflectionHost(false, program.getTypeChecker()), const referencesRegistry = new NgccReferencesRegistry(host);
[''], false); const analyzer =
new DecorationAnalyzer(program.getTypeChecker(), host, referencesRegistry, [''], false);
testHandler = createTestHandler(); testHandler = createTestHandler();
analyzer.handlers = [testHandler]; analyzer.handlers = [testHandler];
result = analyzer.analyzeProgram(program); result = analyzer.analyzeProgram(program);
@ -126,9 +128,10 @@ describe('DecorationAnalyzer', () => {
it('should analyze an internally imported component, which is not publicly exported from the entry-point', it('should analyze an internally imported component, which is not publicly exported from the entry-point',
() => { () => {
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM); const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const referencesRegistry = new NgccReferencesRegistry(host);
const analyzer = new DecorationAnalyzer( const analyzer = new DecorationAnalyzer(
program.getTypeChecker(), new Esm2015ReflectionHost(false, program.getTypeChecker()), program.getTypeChecker(), host, referencesRegistry, [''], false);
[''], false);
const testHandler = createTestHandler(); const testHandler = createTestHandler();
analyzer.handlers = [testHandler]; analyzer.handlers = [testHandler];
const result = analyzer.analyzeProgram(program); const result = analyzer.analyzeProgram(program);
@ -142,9 +145,10 @@ describe('DecorationAnalyzer', () => {
it('should analyze an internally defined component, which is not exported at all', () => { it('should analyze an internally defined component, which is not exported at all', () => {
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM); const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM);
const analyzer = new DecorationAnalyzer( const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
program.getTypeChecker(), new Esm2015ReflectionHost(false, program.getTypeChecker()), const referencesRegistry = new NgccReferencesRegistry(host);
[''], false); const analyzer =
new DecorationAnalyzer(program.getTypeChecker(), host, referencesRegistry, [''], false);
const testHandler = createTestHandler(); const testHandler = createTestHandler();
analyzer.handlers = [testHandler]; analyzer.handlers = [testHandler];
const result = analyzer.analyzeProgram(program); const result = analyzer.analyzeProgram(program);

View File

@ -0,0 +1,52 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import {Reference, TypeScriptReflectionHost, staticallyResolve} from '../../../ngtsc/metadata';
import {getDeclaration, makeProgram} from '../../../ngtsc/testing/in_memory_typescript';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
describe('NgccReferencesRegistry', () => {
it('should return a mapping from resolved reference identifiers to their declarations', () => {
const {program} = makeProgram([{
name: 'index.ts',
contents: `
export class SomeClass {}
export function someFunction() {}
export const someVariable = 42;
export const testArray = [SomeClass, someFunction, someVariable];
`
}]);
const checker = program.getTypeChecker();
const testArrayDeclaration =
getDeclaration(program, 'index.ts', 'testArray', ts.isVariableDeclaration);
const someClassDecl = getDeclaration(program, 'index.ts', 'SomeClass', ts.isClassDeclaration);
const someFunctionDecl =
getDeclaration(program, 'index.ts', 'someFunction', ts.isFunctionDeclaration);
const someVariableDecl =
getDeclaration(program, 'index.ts', 'someVariable', ts.isVariableDeclaration);
const testArrayExpression = testArrayDeclaration.initializer !;
const host = new TypeScriptReflectionHost(checker);
const registry = new NgccReferencesRegistry(host);
const references =
staticallyResolve(testArrayExpression, host, checker) as Reference<ts.Declaration>[];
registry.add(...references);
const map = registry.getDeclarationMap();
expect(map.size).toEqual(2);
expect(map.get(someClassDecl.name !) !.node).toBe(someClassDecl);
expect(map.get(someFunctionDecl.name !) !.node).toBe(someFunctionDecl);
expect(map.has(someVariableDecl.name as ts.Identifier)).toBe(false);
});
});

View File

@ -12,6 +12,7 @@ import MagicString from 'magic-string';
import {fromObject, generateMapFileComment} from 'convert-source-map'; import {fromObject, generateMapFileComment} from 'convert-source-map';
import {makeProgram} from '../helpers/utils'; import {makeProgram} from '../helpers/utils';
import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {BundleInfo, createBundleInfo} from '../../src/packages/bundle'; import {BundleInfo, createBundleInfo} from '../../src/packages/bundle';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
@ -46,8 +47,10 @@ function createTestRenderer(
options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null; options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null;
const bundle = createBundleInfo(options.isCore || false, rewriteCoreImportsTo, null); const bundle = createBundleInfo(options.isCore || false, rewriteCoreImportsTo, null);
const host = new Esm2015ReflectionHost(bundle.isCore, program.getTypeChecker()); const host = new Esm2015ReflectionHost(bundle.isCore, program.getTypeChecker());
const referencesRegistry = new NgccReferencesRegistry(host);
const decorationAnalyses = const decorationAnalyses =
new DecorationAnalyzer(program.getTypeChecker(), host, [''], bundle.isCore) new DecorationAnalyzer(
program.getTypeChecker(), host, referencesRegistry, [''], bundle.isCore)
.analyzeProgram(program); .analyzeProgram(program);
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
const renderer = new TestRenderer(host, bundle); const renderer = new TestRenderer(host, bundle);

View File

@ -15,4 +15,5 @@ export {DirectiveDecoratorHandler} from './src/directive';
export {InjectableDecoratorHandler} from './src/injectable'; export {InjectableDecoratorHandler} from './src/injectable';
export {NgModuleDecoratorHandler} from './src/ng_module'; export {NgModuleDecoratorHandler} from './src/ng_module';
export {PipeDecoratorHandler} from './src/pipe'; export {PipeDecoratorHandler} from './src/pipe';
export {NoopReferencesRegistry, ReferencesRegistry} from './src/references_registry';
export {CompilationScope, SelectorScopeRegistry} from './src/selector_scope'; export {CompilationScope, SelectorScopeRegistry} from './src/selector_scope';

View File

@ -15,6 +15,7 @@ import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, stati
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {generateSetClassMetadataCall} from './metadata'; import {generateSetClassMetadataCall} from './metadata';
import {ReferencesRegistry} from './references_registry';
import {SelectorScopeRegistry} from './selector_scope'; import {SelectorScopeRegistry} from './selector_scope';
import {getConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util'; import {getConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util';
@ -32,7 +33,8 @@ export interface NgModuleAnalysis {
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> { export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
constructor( constructor(
private checker: ts.TypeChecker, private reflector: ReflectionHost, private checker: ts.TypeChecker, private reflector: ReflectionHost,
private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {} private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry,
private isCore: boolean) {}
detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined {
if (!decorators) { if (!decorators) {
@ -72,6 +74,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
const expr = ngModule.get('declarations') !; const expr = ngModule.get('declarations') !;
const declarationMeta = staticallyResolve(expr, this.reflector, this.checker); const declarationMeta = staticallyResolve(expr, this.reflector, this.checker);
declarations = this.resolveTypeList(expr, declarationMeta, 'declarations'); declarations = this.resolveTypeList(expr, declarationMeta, 'declarations');
this.referencesRegistry.add(...declarations);
} }
let imports: Reference<ts.Declaration>[] = []; let imports: Reference<ts.Declaration>[] = [];
if (ngModule.has('imports')) { if (ngModule.has('imports')) {
@ -80,6 +83,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
expr, this.reflector, this.checker, expr, this.reflector, this.checker,
ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
imports = this.resolveTypeList(expr, importsMeta, 'imports'); imports = this.resolveTypeList(expr, importsMeta, 'imports');
this.referencesRegistry.add(...imports);
} }
let exports: Reference<ts.Declaration>[] = []; let exports: Reference<ts.Declaration>[] = [];
if (ngModule.has('exports')) { if (ngModule.has('exports')) {
@ -88,12 +92,14 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
expr, this.reflector, this.checker, expr, this.reflector, this.checker,
ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); ref => this._extractModuleFromModuleWithProvidersFn(ref.node));
exports = this.resolveTypeList(expr, exportsMeta, 'exports'); exports = this.resolveTypeList(expr, exportsMeta, 'exports');
this.referencesRegistry.add(...exports);
} }
let bootstrap: Reference<ts.Declaration>[] = []; let bootstrap: Reference<ts.Declaration>[] = [];
if (ngModule.has('bootstrap')) { if (ngModule.has('bootstrap')) {
const expr = ngModule.get('bootstrap') !; const expr = ngModule.get('bootstrap') !;
const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker); const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker);
bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap'); bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap');
this.referencesRegistry.add(...bootstrap);
} }
// Register this module's information with the SelectorScopeRegistry. This ensures that during // Register this module's information with the SelectorScopeRegistry. This ensures that during

View File

@ -0,0 +1,39 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import {Declaration} from '../../host';
import {Reference} from '../../metadata';
/**
* Implement this interface if you want DecoratorHandlers to register
* references that they find in their analysis of the code.
*/
export interface ReferencesRegistry {
/**
* Register one or more references in the registry.
* Only `ResolveReference` references are stored. Other types are ignored.
* @param references A collection of references to register.
*/
add(...references: Reference<ts.Declaration>[]): void;
/**
* Create and return a mapping for the registered resolved references.
* @returns A map of reference identifiers to reference declarations.
*/
getDeclarationMap(): Map<ts.Identifier, Declaration>;
}
/**
* This registry does nothing, since ngtsc does not currently need
* this functionality.
* The ngcc tool implements a working version for its purposes.
*/
export class NoopReferencesRegistry implements ReferencesRegistry {
add(...references: Reference<ts.Declaration>[]): void {}
getDeclarationMap(): Map<ts.Identifier, Declaration> { return new Map(); }
}

View File

@ -13,7 +13,7 @@ import * as ts from 'typescript';
import * as api from '../transformers/api'; import * as api from '../transformers/api';
import {nocollapseHack} from '../transformers/nocollapse_hack'; import {nocollapseHack} from '../transformers/nocollapse_hack';
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations'; import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations';
import {BaseDefDecoratorHandler} from './annotations/src/base_def'; import {BaseDefDecoratorHandler} from './annotations/src/base_def';
import {TypeScriptReflectionHost} from './metadata'; import {TypeScriptReflectionHost} from './metadata';
import {FileResourceLoader, HostResourceLoader} from './resource_loader'; import {FileResourceLoader, HostResourceLoader} from './resource_loader';
@ -214,6 +214,7 @@ export class NgtscProgram implements api.Program {
private makeCompilation(): IvyCompilation { private makeCompilation(): IvyCompilation {
const checker = this.tsProgram.getTypeChecker(); const checker = this.tsProgram.getTypeChecker();
const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector); const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector);
const referencesRegistry = new NoopReferencesRegistry();
// Set up the IvyCompilation, which manages state for the Ivy transformer. // Set up the IvyCompilation, which manages state for the Ivy transformer.
const handlers = [ const handlers = [
@ -223,7 +224,8 @@ export class NgtscProgram implements api.Program {
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false), this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false),
new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
new InjectableDecoratorHandler(this.reflector, this.isCore), new InjectableDecoratorHandler(this.reflector, this.isCore),
new NgModuleDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), new NgModuleDecoratorHandler(
checker, this.reflector, scopeRegistry, referencesRegistry, this.isCore),
new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore),
]; ];