refactor(compiler-cli): track a dependency on a default import on `WrappedNodeExpr` (#41557)
Previously, the `DefaultImportRecorder` interface was used as follows: 1. During the analysis phase, the default import declaration of an identifier was recorded. 2. During the emit phase each emitted identifier would be recorded. The information from step 1 would then be used to determine the default import declaration of the identifier which would be registered as used. 3. A TypeScript transform would taint all default imports that were registered as used in step 2 such that the imports are not elided by TypeScript. In incremental compilations, a file may have to be emitted even if its analysis data has been reused from the prior compilation. This would mean that step 1 is not executed, resulting in a mismatch in step 2 and ultimately in incorrectly eliding the default. This was mitigated by storing the mapping from identifier to import declaration on the `ts.SourceFile` instead of a member of `DefaultImportTracker` such that it would also be visible to the `DefaultImportRecorder` of subsequent compiles even if step 1 had not been executed. Ultimately however, the information that is being recorded into the `DefaultImportRecorder` has a longer lifetime than a single `DefaultImportRecorder` instance, as that is only valid during a single compilation whereas the identifier to import declaration mapping outlives a single compilation. This commit replaces the registration of this mapping by attaching the default import declaration on the output AST node that captures the identifier. This enables the removal of all of the `DefaultImportRecorder` usages throughout the analysis phase together with the `DefaultImportRecorder` interface itself. PR Close #41557
This commit is contained in:
parent
7f1651574e
commit
1381301afe
|
@ -14,7 +14,7 @@ import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecorato
|
||||||
import {CycleAnalyzer, CycleHandlingStrategy, ImportGraph} from '../../../src/ngtsc/cycles';
|
import {CycleAnalyzer, CycleHandlingStrategy, ImportGraph} from '../../../src/ngtsc/cycles';
|
||||||
import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics';
|
import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics';
|
||||||
import {absoluteFromSourceFile, LogicalFileSystem, ReadonlyFileSystem} from '../../../src/ngtsc/file_system';
|
import {absoluteFromSourceFile, LogicalFileSystem, ReadonlyFileSystem} from '../../../src/ngtsc/file_system';
|
||||||
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, PrivateExportAliasingHost, Reexport, ReferenceEmitter} from '../../../src/ngtsc/imports';
|
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, PrivateExportAliasingHost, Reexport, ReferenceEmitter} from '../../../src/ngtsc/imports';
|
||||||
import {SemanticSymbol} from '../../../src/ngtsc/incremental/semantic_graph';
|
import {SemanticSymbol} from '../../../src/ngtsc/incremental/semantic_graph';
|
||||||
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';
|
||||||
|
@ -107,8 +107,8 @@ export class DecorationAnalyzer {
|
||||||
/* 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,
|
||||||
CycleHandlingStrategy.UseRemoteScoping, this.refEmitter, NOOP_DEFAULT_IMPORT_RECORDER,
|
CycleHandlingStrategy.UseRemoteScoping, this.refEmitter, NOOP_DEPENDENCY_TRACKER,
|
||||||
NOOP_DEPENDENCY_TRACKER, this.injectableRegistry,
|
this.injectableRegistry,
|
||||||
/* semanticDepGraphUpdater */ null, !!this.compilerOptions.annotateForClosureCompiler,
|
/* semanticDepGraphUpdater */ null, !!this.compilerOptions.annotateForClosureCompiler,
|
||||||
NOOP_PERF_RECORDER),
|
NOOP_PERF_RECORDER),
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ export class DecorationAnalyzer {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
new DirectiveDecoratorHandler(
|
new DirectiveDecoratorHandler(
|
||||||
this.reflectionHost, this.evaluator, this.fullRegistry, this.scopeRegistry,
|
this.reflectionHost, this.evaluator, this.fullRegistry, this.scopeRegistry,
|
||||||
this.fullMetaReader, NOOP_DEFAULT_IMPORT_RECORDER, this.injectableRegistry, this.isCore,
|
this.fullMetaReader, this.injectableRegistry, this.isCore,
|
||||||
/* semanticDepGraphUpdater */ null,
|
/* semanticDepGraphUpdater */ null,
|
||||||
!!this.compilerOptions.annotateForClosureCompiler,
|
!!this.compilerOptions.annotateForClosureCompiler,
|
||||||
// In ngcc we want to compile undecorated classes with Angular features. As of
|
// In ngcc we want to compile undecorated classes with Angular features. As of
|
||||||
|
@ -131,18 +131,17 @@ export class DecorationAnalyzer {
|
||||||
// before injectable factories (so injectable factories can delegate to them)
|
// before injectable factories (so injectable factories can delegate to them)
|
||||||
new PipeDecoratorHandler(
|
new PipeDecoratorHandler(
|
||||||
this.reflectionHost, this.evaluator, this.metaRegistry, this.scopeRegistry,
|
this.reflectionHost, this.evaluator, this.metaRegistry, this.scopeRegistry,
|
||||||
NOOP_DEFAULT_IMPORT_RECORDER, this.injectableRegistry, this.isCore, NOOP_PERF_RECORDER),
|
this.injectableRegistry, this.isCore, NOOP_PERF_RECORDER),
|
||||||
new InjectableDecoratorHandler(
|
new InjectableDecoratorHandler(
|
||||||
this.reflectionHost, NOOP_DEFAULT_IMPORT_RECORDER, this.isCore,
|
this.reflectionHost, this.isCore,
|
||||||
/* strictCtorDeps */ false, this.injectableRegistry, NOOP_PERF_RECORDER,
|
/* strictCtorDeps */ false, this.injectableRegistry, NOOP_PERF_RECORDER,
|
||||||
/* errorOnDuplicateProv */ false),
|
/* errorOnDuplicateProv */ false),
|
||||||
new NgModuleDecoratorHandler(
|
new NgModuleDecoratorHandler(
|
||||||
this.reflectionHost, this.evaluator, this.fullMetaReader, this.fullRegistry,
|
this.reflectionHost, this.evaluator, this.fullMetaReader, this.fullRegistry,
|
||||||
this.scopeRegistry, this.referencesRegistry, this.isCore, /* routeAnalyzer */ null,
|
this.scopeRegistry, this.referencesRegistry, this.isCore, /* routeAnalyzer */ null,
|
||||||
this.refEmitter,
|
this.refEmitter,
|
||||||
/* factoryTracker */ null, NOOP_DEFAULT_IMPORT_RECORDER,
|
/* factoryTracker */ null, !!this.compilerOptions.annotateForClosureCompiler,
|
||||||
!!this.compilerOptions.annotateForClosureCompiler, this.injectableRegistry,
|
this.injectableRegistry, NOOP_PERF_RECORDER),
|
||||||
NOOP_PERF_RECORDER),
|
|
||||||
];
|
];
|
||||||
compiler = new NgccTraitCompiler(this.handlers, this.reflectionHost);
|
compiler = new NgccTraitCompiler(this.handlers, this.reflectionHost);
|
||||||
migrations: Migration[] = [
|
migrations: Migration[] = [
|
||||||
|
|
|
@ -12,7 +12,7 @@ import * as ts from 'typescript';
|
||||||
import {Cycle, CycleAnalyzer, CycleHandlingStrategy} from '../../cycles';
|
import {Cycle, CycleAnalyzer, CycleHandlingStrategy} from '../../cycles';
|
||||||
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../diagnostics';
|
||||||
import {absoluteFrom, relative} from '../../file_system';
|
import {absoluteFrom, relative} from '../../file_system';
|
||||||
import {DefaultImportRecorder, ImportedFile, ModuleResolver, Reference, ReferenceEmitter} from '../../imports';
|
import {ImportedFile, ModuleResolver, Reference, ReferenceEmitter} from '../../imports';
|
||||||
import {DependencyTracker} from '../../incremental/api';
|
import {DependencyTracker} from '../../incremental/api';
|
||||||
import {extractSemanticTypeParameters, isArrayEqual, isReferenceEqual, SemanticDepGraphUpdater, SemanticReference, SemanticSymbol} from '../../incremental/semantic_graph';
|
import {extractSemanticTypeParameters, isArrayEqual, isReferenceEqual, SemanticDepGraphUpdater, SemanticReference, SemanticSymbol} from '../../incremental/semantic_graph';
|
||||||
import {IndexingContext} from '../../indexer';
|
import {IndexingContext} from '../../indexer';
|
||||||
|
@ -205,7 +205,6 @@ export class ComponentDecoratorHandler implements
|
||||||
private i18nNormalizeLineEndingsInICUs: boolean|undefined,
|
private i18nNormalizeLineEndingsInICUs: boolean|undefined,
|
||||||
private moduleResolver: ModuleResolver, private cycleAnalyzer: CycleAnalyzer,
|
private moduleResolver: ModuleResolver, private cycleAnalyzer: CycleAnalyzer,
|
||||||
private cycleHandlingStrategy: CycleHandlingStrategy, private refEmitter: ReferenceEmitter,
|
private cycleHandlingStrategy: CycleHandlingStrategy, private refEmitter: ReferenceEmitter,
|
||||||
private defaultImportRecorder: DefaultImportRecorder,
|
|
||||||
private depTracker: DependencyTracker|null,
|
private depTracker: DependencyTracker|null,
|
||||||
private injectableRegistry: InjectableClassRegistry,
|
private injectableRegistry: InjectableClassRegistry,
|
||||||
private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
|
private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
|
||||||
|
@ -326,8 +325,8 @@ export class ComponentDecoratorHandler implements
|
||||||
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
|
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
|
||||||
// on it.
|
// on it.
|
||||||
const directiveResult = extractDirectiveMetadata(
|
const directiveResult = extractDirectiveMetadata(
|
||||||
node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore,
|
node, decorator, this.reflector, this.evaluator, this.isCore, flags,
|
||||||
flags, this.annotateForClosureCompiler,
|
this.annotateForClosureCompiler,
|
||||||
this.elementSchemaRegistry.getDefaultComponentElementName());
|
this.elementSchemaRegistry.getDefaultComponentElementName());
|
||||||
if (directiveResult === undefined) {
|
if (directiveResult === undefined) {
|
||||||
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this
|
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this
|
||||||
|
@ -490,8 +489,7 @@ export class ComponentDecoratorHandler implements
|
||||||
},
|
},
|
||||||
typeCheckMeta: extractDirectiveTypeCheckMeta(node, inputs, this.reflector),
|
typeCheckMeta: extractDirectiveTypeCheckMeta(node, inputs, this.reflector),
|
||||||
classMetadata: extractClassMetadata(
|
classMetadata: extractClassMetadata(
|
||||||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
||||||
this.annotateForClosureCompiler),
|
|
||||||
template,
|
template,
|
||||||
providersRequiringFactory,
|
providersRequiringFactory,
|
||||||
viewProvidersRequiringFactory,
|
viewProvidersRequiringFactory,
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {emitDistinctChangesOnlyDefaultValue} from '@angular/compiler/src/core';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {DefaultImportRecorder, Reference} from '../../imports';
|
import {Reference} from '../../imports';
|
||||||
import {areTypeParametersEqual, extractSemanticTypeParameters, isArrayEqual, isSetEqual, isSymbolEqual, SemanticDepGraphUpdater, SemanticSymbol, SemanticTypeParameter} from '../../incremental/semantic_graph';
|
import {areTypeParametersEqual, extractSemanticTypeParameters, isArrayEqual, isSetEqual, isSymbolEqual, SemanticDepGraphUpdater, SemanticSymbol, SemanticTypeParameter} from '../../incremental/semantic_graph';
|
||||||
import {BindingPropertyName, ClassPropertyMapping, ClassPropertyName, DirectiveTypeCheckMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry, TemplateGuardMeta} from '../../metadata';
|
import {BindingPropertyName, ClassPropertyMapping, ClassPropertyName, DirectiveTypeCheckMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry, TemplateGuardMeta} from '../../metadata';
|
||||||
import {extractDirectiveTypeCheckMeta} from '../../metadata/src/util';
|
import {extractDirectiveTypeCheckMeta} from '../../metadata/src/util';
|
||||||
|
@ -177,9 +177,8 @@ export class DirectiveDecoratorHandler implements
|
||||||
constructor(
|
constructor(
|
||||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
|
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
|
||||||
private metaReader: MetadataReader, private defaultImportRecorder: DefaultImportRecorder,
|
private metaReader: MetadataReader, private injectableRegistry: InjectableClassRegistry,
|
||||||
private injectableRegistry: InjectableClassRegistry, private isCore: boolean,
|
private isCore: boolean, private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
|
||||||
private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
|
|
||||||
private annotateForClosureCompiler: boolean,
|
private annotateForClosureCompiler: boolean,
|
||||||
private compileUndecoratedClassesWithAngularFeatures: boolean, private perf: PerfRecorder) {}
|
private compileUndecoratedClassesWithAngularFeatures: boolean, private perf: PerfRecorder) {}
|
||||||
|
|
||||||
|
@ -215,8 +214,8 @@ export class DirectiveDecoratorHandler implements
|
||||||
this.perf.eventCount(PerfEvent.AnalyzeDirective);
|
this.perf.eventCount(PerfEvent.AnalyzeDirective);
|
||||||
|
|
||||||
const directiveResult = extractDirectiveMetadata(
|
const directiveResult = extractDirectiveMetadata(
|
||||||
node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore,
|
node, decorator, this.reflector, this.evaluator, this.isCore, flags,
|
||||||
flags, this.annotateForClosureCompiler);
|
this.annotateForClosureCompiler);
|
||||||
if (directiveResult === undefined) {
|
if (directiveResult === undefined) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -234,8 +233,7 @@ export class DirectiveDecoratorHandler implements
|
||||||
outputs: directiveResult.outputs,
|
outputs: directiveResult.outputs,
|
||||||
meta: analysis,
|
meta: analysis,
|
||||||
classMetadata: extractClassMetadata(
|
classMetadata: extractClassMetadata(
|
||||||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
||||||
this.annotateForClosureCompiler),
|
|
||||||
baseClass: readBaseClass(node, this.reflector, this.evaluator),
|
baseClass: readBaseClass(node, this.reflector, this.evaluator),
|
||||||
typeCheckMeta: extractDirectiveTypeCheckMeta(node, directiveResult.inputs, this.reflector),
|
typeCheckMeta: extractDirectiveTypeCheckMeta(node, directiveResult.inputs, this.reflector),
|
||||||
providersRequiringFactory,
|
providersRequiringFactory,
|
||||||
|
@ -351,9 +349,8 @@ export class DirectiveDecoratorHandler implements
|
||||||
*/
|
*/
|
||||||
export function extractDirectiveMetadata(
|
export function extractDirectiveMetadata(
|
||||||
clazz: ClassDeclaration, decorator: Readonly<Decorator|null>, reflector: ReflectionHost,
|
clazz: ClassDeclaration, decorator: Readonly<Decorator|null>, reflector: ReflectionHost,
|
||||||
evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
evaluator: PartialEvaluator, isCore: boolean, flags: HandlerFlags,
|
||||||
flags: HandlerFlags, annotateForClosureCompiler: boolean,
|
annotateForClosureCompiler: boolean, defaultSelector: string|null = null): {
|
||||||
defaultSelector: string|null = null): {
|
|
||||||
decorator: Map<string, ts.Expression>,
|
decorator: Map<string, ts.Expression>,
|
||||||
metadata: R3DirectiveMetadata,
|
metadata: R3DirectiveMetadata,
|
||||||
inputs: ClassPropertyMapping,
|
inputs: ClassPropertyMapping,
|
||||||
|
@ -473,7 +470,7 @@ export function extractDirectiveMetadata(
|
||||||
exportAs = resolved.split(',').map(part => part.trim());
|
exportAs = resolved.split(',').map(part => part.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawCtorDeps = getConstructorDependencies(clazz, reflector, defaultImportRecorder, isCore);
|
const rawCtorDeps = getConstructorDependencies(clazz, reflector, isCore);
|
||||||
|
|
||||||
// Non-abstract directives (those with a selector) require valid constructor dependencies, whereas
|
// Non-abstract directives (those with a selector) require valid constructor dependencies, whereas
|
||||||
// abstract directives are allowed to have invalid dependencies, given that a subclass may call
|
// abstract directives are allowed to have invalid dependencies, given that a subclass may call
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {compileClassMetadata, CompileClassMetadataFn, compileDeclareClassMetadat
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {DefaultImportRecorder} from '../../imports';
|
|
||||||
import {InjectableClassRegistry} from '../../metadata';
|
import {InjectableClassRegistry} from '../../metadata';
|
||||||
import {PerfEvent, PerfRecorder} from '../../perf';
|
import {PerfEvent, PerfRecorder} from '../../perf';
|
||||||
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||||
|
@ -33,8 +32,7 @@ export interface InjectableHandlerData {
|
||||||
export class InjectableDecoratorHandler implements
|
export class InjectableDecoratorHandler implements
|
||||||
DecoratorHandler<Decorator, InjectableHandlerData, null, unknown> {
|
DecoratorHandler<Decorator, InjectableHandlerData, null, unknown> {
|
||||||
constructor(
|
constructor(
|
||||||
private reflector: ReflectionHost, private defaultImportRecorder: DefaultImportRecorder,
|
private reflector: ReflectionHost, private isCore: boolean, private strictCtorDeps: boolean,
|
||||||
private isCore: boolean, private strictCtorDeps: boolean,
|
|
||||||
private injectableRegistry: InjectableClassRegistry, private perf: PerfRecorder,
|
private injectableRegistry: InjectableClassRegistry, private perf: PerfRecorder,
|
||||||
/**
|
/**
|
||||||
* What to do if the injectable already contains a ɵprov property.
|
* What to do if the injectable already contains a ɵprov property.
|
||||||
|
@ -74,10 +72,8 @@ export class InjectableDecoratorHandler implements
|
||||||
analysis: {
|
analysis: {
|
||||||
meta,
|
meta,
|
||||||
ctorDeps: extractInjectableCtorDeps(
|
ctorDeps: extractInjectableCtorDeps(
|
||||||
node, meta, decorator, this.reflector, this.defaultImportRecorder, this.isCore,
|
node, meta, decorator, this.reflector, this.isCore, this.strictCtorDeps),
|
||||||
this.strictCtorDeps),
|
classMetadata: extractClassMetadata(node, this.reflector, this.isCore),
|
||||||
classMetadata:
|
|
||||||
extractClassMetadata(node, this.reflector, this.defaultImportRecorder, this.isCore),
|
|
||||||
// Avoid generating multiple factories if a class has
|
// Avoid generating multiple factories if a class has
|
||||||
// more Angular decorators, apart from Injectable.
|
// more Angular decorators, apart from Injectable.
|
||||||
needsFactory: !decorators ||
|
needsFactory: !decorators ||
|
||||||
|
@ -232,8 +228,7 @@ function getProviderExpression(
|
||||||
|
|
||||||
function extractInjectableCtorDeps(
|
function extractInjectableCtorDeps(
|
||||||
clazz: ClassDeclaration, meta: R3InjectableMetadata, decorator: Decorator,
|
clazz: ClassDeclaration, meta: R3InjectableMetadata, decorator: Decorator,
|
||||||
reflector: ReflectionHost, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
reflector: ReflectionHost, isCore: boolean, strictCtorDeps: boolean) {
|
||||||
strictCtorDeps: boolean) {
|
|
||||||
if (decorator.args === null) {
|
if (decorator.args === null) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.DECORATOR_NOT_CALLED, Decorator.nodeForError(decorator),
|
ErrorCode.DECORATOR_NOT_CALLED, Decorator.nodeForError(decorator),
|
||||||
|
@ -252,15 +247,15 @@ function extractInjectableCtorDeps(
|
||||||
// constructor signature does not work for DI then a factory definition (ɵfac) that throws is
|
// constructor signature does not work for DI then a factory definition (ɵfac) that throws is
|
||||||
// generated.
|
// generated.
|
||||||
if (strictCtorDeps) {
|
if (strictCtorDeps) {
|
||||||
ctorDeps = getValidConstructorDependencies(clazz, reflector, defaultImportRecorder, isCore);
|
ctorDeps = getValidConstructorDependencies(clazz, reflector, isCore);
|
||||||
} else {
|
} else {
|
||||||
ctorDeps = unwrapConstructorDependencies(
|
ctorDeps =
|
||||||
getConstructorDependencies(clazz, reflector, defaultImportRecorder, isCore));
|
unwrapConstructorDependencies(getConstructorDependencies(clazz, reflector, isCore));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctorDeps;
|
return ctorDeps;
|
||||||
} else if (decorator.args.length === 1) {
|
} else if (decorator.args.length === 1) {
|
||||||
const rawCtorDeps = getConstructorDependencies(clazz, reflector, defaultImportRecorder, isCore);
|
const rawCtorDeps = getConstructorDependencies(clazz, reflector, isCore);
|
||||||
|
|
||||||
if (strictCtorDeps && meta.useValue === undefined && meta.useExisting === undefined &&
|
if (strictCtorDeps && meta.useValue === undefined && meta.useExisting === undefined &&
|
||||||
meta.useClass === undefined && meta.useFactory === undefined) {
|
meta.useClass === undefined && meta.useFactory === undefined) {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
import {Expression, FunctionExpr, LiteralArrayExpr, LiteralExpr, literalMap, R3ClassMetadata, ReturnStatement, WrappedNodeExpr} from '@angular/compiler';
|
import {Expression, FunctionExpr, LiteralArrayExpr, LiteralExpr, literalMap, R3ClassMetadata, ReturnStatement, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {DefaultImportRecorder} from '../../imports';
|
|
||||||
import {CtorParameter, DeclarationNode, Decorator, ReflectionHost, TypeValueReferenceKind} from '../../reflection';
|
import {CtorParameter, DeclarationNode, Decorator, ReflectionHost, TypeValueReferenceKind} from '../../reflection';
|
||||||
|
|
||||||
import {valueReferenceToExpression, wrapFunctionExpressionsInParens} from './util';
|
import {valueReferenceToExpression, wrapFunctionExpressionsInParens} from './util';
|
||||||
|
@ -23,8 +22,7 @@ import {valueReferenceToExpression, wrapFunctionExpressionsInParens} from './uti
|
||||||
* as a `Statement` for inclusion along with the class.
|
* as a `Statement` for inclusion along with the class.
|
||||||
*/
|
*/
|
||||||
export function extractClassMetadata(
|
export function extractClassMetadata(
|
||||||
clazz: DeclarationNode, reflection: ReflectionHost,
|
clazz: DeclarationNode, reflection: ReflectionHost, isCore: boolean,
|
||||||
defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
|
||||||
annotateForClosureCompiler?: boolean): R3ClassMetadata|null {
|
annotateForClosureCompiler?: boolean): R3ClassMetadata|null {
|
||||||
if (!reflection.isClass(clazz)) {
|
if (!reflection.isClass(clazz)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -55,8 +53,7 @@ export function extractClassMetadata(
|
||||||
let metaCtorParameters: Expression|null = null;
|
let metaCtorParameters: Expression|null = null;
|
||||||
const classCtorParameters = reflection.getConstructorParameters(clazz);
|
const classCtorParameters = reflection.getConstructorParameters(clazz);
|
||||||
if (classCtorParameters !== null) {
|
if (classCtorParameters !== null) {
|
||||||
const ctorParameters = classCtorParameters.map(
|
const ctorParameters = classCtorParameters.map(param => ctorParameterToMetadata(param, isCore));
|
||||||
param => ctorParameterToMetadata(param, defaultImportRecorder, isCore));
|
|
||||||
metaCtorParameters = new FunctionExpr([], [
|
metaCtorParameters = new FunctionExpr([], [
|
||||||
new ReturnStatement(new LiteralArrayExpr(ctorParameters)),
|
new ReturnStatement(new LiteralArrayExpr(ctorParameters)),
|
||||||
]);
|
]);
|
||||||
|
@ -93,13 +90,11 @@ export function extractClassMetadata(
|
||||||
/**
|
/**
|
||||||
* Convert a reflected constructor parameter to metadata.
|
* Convert a reflected constructor parameter to metadata.
|
||||||
*/
|
*/
|
||||||
function ctorParameterToMetadata(
|
function ctorParameterToMetadata(param: CtorParameter, isCore: boolean): Expression {
|
||||||
param: CtorParameter, defaultImportRecorder: DefaultImportRecorder,
|
|
||||||
isCore: boolean): Expression {
|
|
||||||
// Parameters sometimes have a type that can be referenced. If so, then use it, otherwise
|
// Parameters sometimes have a type that can be referenced. If so, then use it, otherwise
|
||||||
// its type is undefined.
|
// its type is undefined.
|
||||||
const type = param.typeValueReference.kind !== TypeValueReferenceKind.UNAVAILABLE ?
|
const type = param.typeValueReference.kind !== TypeValueReferenceKind.UNAVAILABLE ?
|
||||||
valueReferenceToExpression(param.typeValueReference, defaultImportRecorder) :
|
valueReferenceToExpression(param.typeValueReference) :
|
||||||
new LiteralExpr(undefined);
|
new LiteralExpr(undefined);
|
||||||
|
|
||||||
const mapEntries: {key: string, value: Expression, quoted: false}[] = [
|
const mapEntries: {key: string, value: Expression, quoted: false}[] = [
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {compileClassMetadata, compileDeclareClassMetadata, compileDeclareInjecto
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../diagnostics';
|
||||||
import {DefaultImportRecorder, Reference, ReferenceEmitter} from '../../imports';
|
import {Reference, ReferenceEmitter} from '../../imports';
|
||||||
import {isArrayEqual, isReferenceEqual, isSymbolEqual, SemanticReference, SemanticSymbol} from '../../incremental/semantic_graph';
|
import {isArrayEqual, isReferenceEqual, isSymbolEqual, SemanticReference, SemanticSymbol} from '../../incremental/semantic_graph';
|
||||||
import {InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
|
import {InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator';
|
import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator';
|
||||||
|
@ -130,9 +130,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
private scopeRegistry: LocalModuleScopeRegistry,
|
private scopeRegistry: LocalModuleScopeRegistry,
|
||||||
private referencesRegistry: ReferencesRegistry, private isCore: boolean,
|
private referencesRegistry: ReferencesRegistry, private isCore: boolean,
|
||||||
private routeAnalyzer: NgModuleRouteAnalyzer|null, private refEmitter: ReferenceEmitter,
|
private routeAnalyzer: NgModuleRouteAnalyzer|null, private refEmitter: ReferenceEmitter,
|
||||||
private factoryTracker: FactoryTracker|null,
|
private factoryTracker: FactoryTracker|null, private annotateForClosureCompiler: boolean,
|
||||||
private defaultImportRecorder: DefaultImportRecorder,
|
|
||||||
private annotateForClosureCompiler: boolean,
|
|
||||||
private injectableRegistry: InjectableClassRegistry, private perf: PerfRecorder,
|
private injectableRegistry: InjectableClassRegistry, private perf: PerfRecorder,
|
||||||
private localeId?: string) {}
|
private localeId?: string) {}
|
||||||
|
|
||||||
|
@ -350,8 +348,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
type,
|
type,
|
||||||
internalType,
|
internalType,
|
||||||
typeArgumentCount: 0,
|
typeArgumentCount: 0,
|
||||||
deps: getValidConstructorDependencies(
|
deps: getValidConstructorDependencies(node, this.reflector, this.isCore),
|
||||||
node, this.reflector, this.defaultImportRecorder, this.isCore),
|
|
||||||
target: FactoryTarget.NgModule,
|
target: FactoryTarget.NgModule,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -371,8 +368,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
resolveProvidersRequiringFactory(rawProviders, this.reflector, this.evaluator) :
|
resolveProvidersRequiringFactory(rawProviders, this.reflector, this.evaluator) :
|
||||||
null,
|
null,
|
||||||
classMetadata: extractClassMetadata(
|
classMetadata: extractClassMetadata(
|
||||||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
||||||
this.annotateForClosureCompiler),
|
|
||||||
factorySymbolName: node.name.text,
|
factorySymbolName: node.name.text,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {compileClassMetadata, compileDeclareClassMetadata, compileDeclarePipeFro
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {DefaultImportRecorder, Reference} from '../../imports';
|
import {Reference} from '../../imports';
|
||||||
import {SemanticSymbol} from '../../incremental/semantic_graph';
|
import {SemanticSymbol} from '../../incremental/semantic_graph';
|
||||||
import {InjectableClassRegistry, MetadataRegistry} from '../../metadata';
|
import {InjectableClassRegistry, MetadataRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
|
@ -55,7 +55,6 @@ export class PipeDecoratorHandler implements
|
||||||
constructor(
|
constructor(
|
||||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||||
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
|
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
|
||||||
private defaultImportRecorder: DefaultImportRecorder,
|
|
||||||
private injectableRegistry: InjectableClassRegistry, private isCore: boolean,
|
private injectableRegistry: InjectableClassRegistry, private isCore: boolean,
|
||||||
private perf: PerfRecorder) {}
|
private perf: PerfRecorder) {}
|
||||||
|
|
||||||
|
@ -131,12 +130,10 @@ export class PipeDecoratorHandler implements
|
||||||
internalType,
|
internalType,
|
||||||
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0,
|
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0,
|
||||||
pipeName,
|
pipeName,
|
||||||
deps: getValidConstructorDependencies(
|
deps: getValidConstructorDependencies(clazz, this.reflector, this.isCore),
|
||||||
clazz, this.reflector, this.defaultImportRecorder, this.isCore),
|
|
||||||
pure,
|
pure,
|
||||||
},
|
},
|
||||||
classMetadata:
|
classMetadata: extractClassMetadata(clazz, this.reflector, this.isCore),
|
||||||
extractClassMetadata(clazz, this.reflector, this.defaultImportRecorder, this.isCore),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ import {FactoryTarget} from '@angular/compiler/src/render3/partial/api';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../diagnostics';
|
||||||
import {DefaultImportRecorder, ImportFlags, Reference, ReferenceEmitter} from '../../imports';
|
import {ImportFlags, Reference, ReferenceEmitter} from '../../imports';
|
||||||
|
import {attachDefaultImportDeclaration} from '../../imports/src/default';
|
||||||
import {ForeignFunctionResolver, PartialEvaluator} from '../../partial_evaluator';
|
import {ForeignFunctionResolver, PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {ClassDeclaration, CtorParameter, Decorator, Import, ImportedTypeValueReference, isNamedClassDeclaration, LocalTypeValueReference, ReflectionHost, TypeValueReference, TypeValueReferenceKind, UnavailableValue, ValueUnavailableKind} from '../../reflection';
|
import {ClassDeclaration, CtorParameter, Decorator, Import, ImportedTypeValueReference, isNamedClassDeclaration, LocalTypeValueReference, ReflectionHost, TypeValueReference, TypeValueReferenceKind, UnavailableValue, ValueUnavailableKind} from '../../reflection';
|
||||||
import {DeclarationData} from '../../scope';
|
import {DeclarationData} from '../../scope';
|
||||||
|
@ -32,8 +33,7 @@ export interface ConstructorDepError {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConstructorDependencies(
|
export function getConstructorDependencies(
|
||||||
clazz: ClassDeclaration, reflector: ReflectionHost,
|
clazz: ClassDeclaration, reflector: ReflectionHost, isCore: boolean): ConstructorDeps|null {
|
||||||
defaultImportRecorder: DefaultImportRecorder, isCore: boolean): ConstructorDeps|null {
|
|
||||||
const deps: R3DependencyMetadata[] = [];
|
const deps: R3DependencyMetadata[] = [];
|
||||||
const errors: ConstructorDepError[] = [];
|
const errors: ConstructorDepError[] = [];
|
||||||
let ctorParams = reflector.getConstructorParameters(clazz);
|
let ctorParams = reflector.getConstructorParameters(clazz);
|
||||||
|
@ -45,7 +45,7 @@ export function getConstructorDependencies(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctorParams.forEach((param, idx) => {
|
ctorParams.forEach((param, idx) => {
|
||||||
let token = valueReferenceToExpression(param.typeValueReference, defaultImportRecorder);
|
let token = valueReferenceToExpression(param.typeValueReference);
|
||||||
let attributeNameType: Expression|null = null;
|
let attributeNameType: Expression|null = null;
|
||||||
let optional = false, self = false, skipSelf = false, host = false;
|
let optional = false, self = false, skipSelf = false, host = false;
|
||||||
|
|
||||||
|
@ -115,22 +115,18 @@ export function getConstructorDependencies(
|
||||||
* references are converted to an `ExternalExpr`. Note that this is only valid in the context of the
|
* references are converted to an `ExternalExpr`. Note that this is only valid in the context of the
|
||||||
* file in which the `TypeValueReference` originated.
|
* file in which the `TypeValueReference` originated.
|
||||||
*/
|
*/
|
||||||
export function valueReferenceToExpression(
|
export function valueReferenceToExpression(valueRef: LocalTypeValueReference|
|
||||||
valueRef: LocalTypeValueReference|ImportedTypeValueReference,
|
ImportedTypeValueReference): Expression;
|
||||||
defaultImportRecorder: DefaultImportRecorder): Expression;
|
export function valueReferenceToExpression(valueRef: TypeValueReference): Expression|null;
|
||||||
export function valueReferenceToExpression(
|
export function valueReferenceToExpression(valueRef: TypeValueReference): Expression|null {
|
||||||
valueRef: TypeValueReference, defaultImportRecorder: DefaultImportRecorder): Expression|null;
|
|
||||||
export function valueReferenceToExpression(
|
|
||||||
valueRef: TypeValueReference, defaultImportRecorder: DefaultImportRecorder): Expression|null {
|
|
||||||
if (valueRef.kind === TypeValueReferenceKind.UNAVAILABLE) {
|
if (valueRef.kind === TypeValueReferenceKind.UNAVAILABLE) {
|
||||||
return null;
|
return null;
|
||||||
} else if (valueRef.kind === TypeValueReferenceKind.LOCAL) {
|
} else if (valueRef.kind === TypeValueReferenceKind.LOCAL) {
|
||||||
if (defaultImportRecorder !== null && valueRef.defaultImportStatement !== null &&
|
const expr = new WrappedNodeExpr(valueRef.expression);
|
||||||
ts.isIdentifier(valueRef.expression)) {
|
if (valueRef.defaultImportStatement !== null) {
|
||||||
defaultImportRecorder.recordImportedIdentifier(
|
attachDefaultImportDeclaration(expr, valueRef.defaultImportStatement);
|
||||||
valueRef.expression, valueRef.defaultImportStatement);
|
|
||||||
}
|
}
|
||||||
return new WrappedNodeExpr(valueRef.expression);
|
return expr;
|
||||||
} else {
|
} else {
|
||||||
let importExpr: Expression =
|
let importExpr: Expression =
|
||||||
new ExternalExpr({moduleName: valueRef.moduleName, name: valueRef.importedName});
|
new ExternalExpr({moduleName: valueRef.moduleName, name: valueRef.importedName});
|
||||||
|
@ -163,10 +159,10 @@ export function unwrapConstructorDependencies(deps: ConstructorDeps|null): R3Dep
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getValidConstructorDependencies(
|
export function getValidConstructorDependencies(
|
||||||
clazz: ClassDeclaration, reflector: ReflectionHost,
|
clazz: ClassDeclaration, reflector: ReflectionHost, isCore: boolean): R3DependencyMetadata[]|
|
||||||
defaultImportRecorder: DefaultImportRecorder, isCore: boolean): R3DependencyMetadata[]|null {
|
null {
|
||||||
return validateConstructorDependencies(
|
return validateConstructorDependencies(
|
||||||
clazz, getConstructorDependencies(clazz, reflector, defaultImportRecorder, isCore));
|
clazz, getConstructorDependencies(clazz, reflector, isCore));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {CycleAnalyzer, CycleHandlingStrategy, ImportGraph} from '../../cycles';
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
import {absoluteFrom} from '../../file_system';
|
import {absoluteFrom} from '../../file_system';
|
||||||
import {runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
import {ModuleResolver, ReferenceEmitter} from '../../imports';
|
||||||
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 {NOOP_PERF_RECORDER} from '../../perf';
|
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||||
|
@ -81,7 +81,6 @@ function setup(program: ts.Program, options: ts.CompilerOptions, host: ts.Compil
|
||||||
cycleAnalyzer,
|
cycleAnalyzer,
|
||||||
CycleHandlingStrategy.UseRemoteScoping,
|
CycleHandlingStrategy.UseRemoteScoping,
|
||||||
refEmitter,
|
refEmitter,
|
||||||
NOOP_DEFAULT_IMPORT_RECORDER,
|
|
||||||
/* depTracker */ null,
|
/* depTracker */ null,
|
||||||
injectableRegistry,
|
injectableRegistry,
|
||||||
/* semanticDepGraphUpdater */ null,
|
/* semanticDepGraphUpdater */ null,
|
||||||
|
|
|
@ -10,7 +10,7 @@ import * as ts from 'typescript';
|
||||||
|
|
||||||
import {absoluteFrom} from '../../file_system';
|
import {absoluteFrom} from '../../file_system';
|
||||||
import {runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
import {ReferenceEmitter} from '../../imports';
|
||||||
import {DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
import {DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {NOOP_PERF_RECORDER} from '../../perf';
|
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||||
|
@ -168,8 +168,8 @@ runInEachFileSystem(() => {
|
||||||
null);
|
null);
|
||||||
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
||||||
const handler = new DirectiveDecoratorHandler(
|
const handler = new DirectiveDecoratorHandler(
|
||||||
reflectionHost, evaluator, scopeRegistry, scopeRegistry, metaReader,
|
reflectionHost, evaluator, scopeRegistry, scopeRegistry, metaReader, injectableRegistry,
|
||||||
NOOP_DEFAULT_IMPORT_RECORDER, injectableRegistry, /*isCore*/ false,
|
/*isCore*/ false,
|
||||||
/*semanticDepGraphUpdater*/ null,
|
/*semanticDepGraphUpdater*/ null,
|
||||||
/*annotateForClosureCompiler*/ false,
|
/*annotateForClosureCompiler*/ false,
|
||||||
/*detectUndecoratedClassesWithAngularFeatures*/ false, NOOP_PERF_RECORDER);
|
/*detectUndecoratedClassesWithAngularFeatures*/ false, NOOP_PERF_RECORDER);
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
import {ErrorCode, FatalDiagnosticError, ngErrorCode} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError, ngErrorCode} from '../../diagnostics';
|
||||||
import {absoluteFrom} from '../../file_system';
|
import {absoluteFrom} from '../../file_system';
|
||||||
import {runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../imports';
|
|
||||||
import {InjectableClassRegistry} from '../../metadata';
|
import {InjectableClassRegistry} from '../../metadata';
|
||||||
import {NOOP_PERF_RECORDER} from '../../perf';
|
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||||
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
|
@ -70,7 +69,7 @@ function setupHandler(errorOnDuplicateProv: boolean) {
|
||||||
const reflectionHost = new TypeScriptReflectionHost(checker);
|
const reflectionHost = new TypeScriptReflectionHost(checker);
|
||||||
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
||||||
const handler = new InjectableDecoratorHandler(
|
const handler = new InjectableDecoratorHandler(
|
||||||
reflectionHost, NOOP_DEFAULT_IMPORT_RECORDER, /* isCore */ false,
|
reflectionHost, /* isCore */ false,
|
||||||
/* strictCtorDeps */ false, injectableRegistry, NOOP_PERF_RECORDER, errorOnDuplicateProv);
|
/* strictCtorDeps */ false, injectableRegistry, NOOP_PERF_RECORDER, errorOnDuplicateProv);
|
||||||
const TestClass = getDeclaration(program, ENTRY_FILE, 'TestClass', isNamedClassDeclaration);
|
const TestClass = getDeclaration(program, ENTRY_FILE, 'TestClass', isNamedClassDeclaration);
|
||||||
const ɵprov = reflectionHost.getMembersOfClass(TestClass).find(member => member.name === 'ɵprov');
|
const ɵprov = reflectionHost.getMembersOfClass(TestClass).find(member => member.name === 'ɵprov');
|
||||||
|
|
|
@ -10,7 +10,7 @@ import * as ts from 'typescript';
|
||||||
|
|
||||||
import {absoluteFrom, getSourceFileOrError} from '../../file_system';
|
import {absoluteFrom, getSourceFileOrError} from '../../file_system';
|
||||||
import {runInEachFileSystem, TestFile} from '../../file_system/testing';
|
import {runInEachFileSystem, TestFile} from '../../file_system/testing';
|
||||||
import {NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports';
|
import {NoopImportRewriter} from '../../imports';
|
||||||
import {TypeScriptReflectionHost} from '../../reflection';
|
import {TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
import {ImportManager, translateStatement} from '../../translator';
|
import {ImportManager, translateStatement} from '../../translator';
|
||||||
|
@ -128,7 +128,7 @@ runInEachFileSystem(() => {
|
||||||
{target: ts.ScriptTarget.ES2015});
|
{target: ts.ScriptTarget.ES2015});
|
||||||
const host = new TypeScriptReflectionHost(program.getTypeChecker());
|
const host = new TypeScriptReflectionHost(program.getTypeChecker());
|
||||||
const target = getDeclaration(program, _('/index.ts'), 'Target', ts.isClassDeclaration);
|
const target = getDeclaration(program, _('/index.ts'), 'Target', ts.isClassDeclaration);
|
||||||
const call = extractClassMetadata(target, host, NOOP_DEFAULT_IMPORT_RECORDER, false);
|
const call = extractClassMetadata(target, host, false);
|
||||||
if (call === null) {
|
if (call === null) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import * as ts from 'typescript';
|
||||||
|
|
||||||
import {absoluteFrom} from '../../file_system';
|
import {absoluteFrom} from '../../file_system';
|
||||||
import {runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {LocalIdentifierStrategy, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
import {LocalIdentifierStrategy, ReferenceEmitter} from '../../imports';
|
||||||
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {NOOP_PERF_RECORDER} from '../../perf';
|
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||||
|
@ -72,8 +72,7 @@ runInEachFileSystem(() => {
|
||||||
const handler = new NgModuleDecoratorHandler(
|
const handler = new NgModuleDecoratorHandler(
|
||||||
reflectionHost, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry,
|
reflectionHost, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry,
|
||||||
/* isCore */ false, /* routeAnalyzer */ null, refEmitter, /* factoryTracker */ null,
|
/* isCore */ false, /* routeAnalyzer */ null, refEmitter, /* factoryTracker */ null,
|
||||||
NOOP_DEFAULT_IMPORT_RECORDER, /* annotateForClosureCompiler */ false, injectableRegistry,
|
/* annotateForClosureCompiler */ false, injectableRegistry, NOOP_PERF_RECORDER);
|
||||||
NOOP_PERF_RECORDER);
|
|
||||||
const TestModule =
|
const TestModule =
|
||||||
getDeclaration(program, _('/entry.ts'), 'TestModule', isNamedClassDeclaration);
|
getDeclaration(program, _('/entry.ts'), 'TestModule', isNamedClassDeclaration);
|
||||||
const detected =
|
const detected =
|
||||||
|
|
|
@ -52,7 +52,6 @@ interface LazyCompilationState {
|
||||||
routeAnalyzer: NgModuleRouteAnalyzer;
|
routeAnalyzer: NgModuleRouteAnalyzer;
|
||||||
dtsTransforms: DtsTransformRegistry;
|
dtsTransforms: DtsTransformRegistry;
|
||||||
mwpScanner: ModuleWithProvidersScanner;
|
mwpScanner: ModuleWithProvidersScanner;
|
||||||
defaultImportTracker: DefaultImportTracker;
|
|
||||||
aliasingHost: AliasingHost|null;
|
aliasingHost: AliasingHost|null;
|
||||||
refEmitter: ReferenceEmitter;
|
refEmitter: ReferenceEmitter;
|
||||||
templateTypeChecker: TemplateTypeChecker;
|
templateTypeChecker: TemplateTypeChecker;
|
||||||
|
@ -613,13 +612,14 @@ export class NgCompiler {
|
||||||
importRewriter = new NoopImportRewriter();
|
importRewriter = new NoopImportRewriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultImportTracker = new DefaultImportTracker();
|
||||||
|
|
||||||
const before = [
|
const before = [
|
||||||
ivyTransformFactory(
|
ivyTransformFactory(
|
||||||
compilation.traitCompiler, compilation.reflector, importRewriter,
|
compilation.traitCompiler, compilation.reflector, importRewriter, defaultImportTracker,
|
||||||
compilation.defaultImportTracker, this.delegatingPerfRecorder, compilation.isCore,
|
this.delegatingPerfRecorder, compilation.isCore, this.closureCompilerEnabled),
|
||||||
this.closureCompilerEnabled),
|
|
||||||
aliasTransformFactory(compilation.traitCompiler.exportStatements),
|
aliasTransformFactory(compilation.traitCompiler.exportStatements),
|
||||||
compilation.defaultImportTracker.importPreservingTransformer(),
|
defaultImportTracker.importPreservingTransformer(),
|
||||||
];
|
];
|
||||||
|
|
||||||
const afterDeclarations: ts.TransformerFactory<ts.SourceFile>[] = [];
|
const afterDeclarations: ts.TransformerFactory<ts.SourceFile>[] = [];
|
||||||
|
@ -971,7 +971,6 @@ export class NgCompiler {
|
||||||
|
|
||||||
const isCore = isAngularCorePackage(this.inputProgram);
|
const isCore = isAngularCorePackage(this.inputProgram);
|
||||||
|
|
||||||
const defaultImportTracker = new DefaultImportTracker();
|
|
||||||
const resourceRegistry = new ResourceRegistry();
|
const resourceRegistry = new ResourceRegistry();
|
||||||
|
|
||||||
const compilationMode =
|
const compilationMode =
|
||||||
|
@ -993,16 +992,15 @@ export class NgCompiler {
|
||||||
this.options.i18nUseExternalIds !== 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,
|
||||||
cycleHandlingStrategy, refEmitter, defaultImportTracker, this.incrementalDriver.depGraph,
|
cycleHandlingStrategy, refEmitter, this.incrementalDriver.depGraph, injectableRegistry,
|
||||||
injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled,
|
semanticDepGraphUpdater, this.closureCompilerEnabled, this.delegatingPerfRecorder),
|
||||||
this.delegatingPerfRecorder),
|
|
||||||
|
|
||||||
// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
|
// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
|
||||||
// not being assignable to `unknown` when wrapped in `Readonly`).
|
// not being assignable to `unknown` when wrapped in `Readonly`).
|
||||||
// clang-format off
|
// clang-format off
|
||||||
new DirectiveDecoratorHandler(
|
new DirectiveDecoratorHandler(
|
||||||
reflector, evaluator, metaRegistry, scopeRegistry, metaReader,
|
reflector, evaluator, metaRegistry, scopeRegistry, metaReader,
|
||||||
defaultImportTracker, injectableRegistry, isCore, semanticDepGraphUpdater,
|
injectableRegistry, isCore, semanticDepGraphUpdater,
|
||||||
this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures,
|
this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures,
|
||||||
this.delegatingPerfRecorder,
|
this.delegatingPerfRecorder,
|
||||||
) as Readonly<DecoratorHandler<unknown, unknown, SemanticSymbol | null,unknown>>,
|
) as Readonly<DecoratorHandler<unknown, unknown, SemanticSymbol | null,unknown>>,
|
||||||
|
@ -1010,16 +1008,15 @@ export class NgCompiler {
|
||||||
// Pipe handler must be before injectable handler in list so pipe factories are printed
|
// Pipe handler must be before injectable handler in list so pipe factories are printed
|
||||||
// before injectable factories (so injectable factories can delegate to them)
|
// before injectable factories (so injectable factories can delegate to them)
|
||||||
new PipeDecoratorHandler(
|
new PipeDecoratorHandler(
|
||||||
reflector, evaluator, metaRegistry, scopeRegistry, defaultImportTracker,
|
reflector, evaluator, metaRegistry, scopeRegistry, injectableRegistry, isCore,
|
||||||
injectableRegistry, isCore, this.delegatingPerfRecorder),
|
this.delegatingPerfRecorder),
|
||||||
new InjectableDecoratorHandler(
|
new InjectableDecoratorHandler(
|
||||||
reflector, defaultImportTracker, isCore, this.options.strictInjectionParameters || false,
|
reflector, isCore, this.options.strictInjectionParameters || false, injectableRegistry,
|
||||||
injectableRegistry, this.delegatingPerfRecorder),
|
this.delegatingPerfRecorder),
|
||||||
new NgModuleDecoratorHandler(
|
new NgModuleDecoratorHandler(
|
||||||
reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore,
|
reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore,
|
||||||
routeAnalyzer, refEmitter, this.adapter.factoryTracker, defaultImportTracker,
|
routeAnalyzer, refEmitter, this.adapter.factoryTracker, this.closureCompilerEnabled,
|
||||||
this.closureCompilerEnabled, injectableRegistry, this.delegatingPerfRecorder,
|
injectableRegistry, this.delegatingPerfRecorder, this.options.i18nInLocale),
|
||||||
this.options.i18nInLocale),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const traitCompiler = new TraitCompiler(
|
const traitCompiler = new TraitCompiler(
|
||||||
|
@ -1051,7 +1048,6 @@ export class NgCompiler {
|
||||||
mwpScanner,
|
mwpScanner,
|
||||||
metaReader,
|
metaReader,
|
||||||
typeCheckScopeRegistry,
|
typeCheckScopeRegistry,
|
||||||
defaultImportTracker,
|
|
||||||
aliasingHost,
|
aliasingHost,
|
||||||
refEmitter,
|
refEmitter,
|
||||||
templateTypeChecker,
|
templateTypeChecker,
|
||||||
|
|
|
@ -167,8 +167,6 @@ It consists of two mechanisms:
|
||||||
|
|
||||||
1. A `DefaultImportTracker`, which records information about both default imports encountered in the program as well as usages of those imports added during compilation.
|
1. A `DefaultImportTracker`, which records information about both default imports encountered in the program as well as usages of those imports added during compilation.
|
||||||
|
|
||||||
A `DefaultImportRecorder` interface is used to allow for a noop implementation in cases (like ngcc) where this tracking isn't necessary.
|
|
||||||
|
|
||||||
2. A TypeScript transformer which processes default import statements and can preserve those which are actually used.
|
2. A TypeScript transformer which processes default import statements and can preserve those which are actually used.
|
||||||
|
|
||||||
This is accessed via `DefaultImportTracker.importPreservingTransformer`.
|
This is accessed via `DefaultImportTracker.importPreservingTransformer`.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
export {AliasingHost, AliasStrategy, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias';
|
export {AliasingHost, AliasStrategy, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias';
|
||||||
export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core';
|
export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core';
|
||||||
export {DefaultImportRecorder, DefaultImportTracker, NOOP_DEFAULT_IMPORT_RECORDER} from './src/default';
|
export {DefaultImportTracker} from './src/default';
|
||||||
export {AbsoluteModuleStrategy, EmittedReference, ImportedFile, ImportFlags, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesStrategy} from './src/emitter';
|
export {AbsoluteModuleStrategy, EmittedReference, ImportedFile, ImportFlags, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesStrategy} from './src/emitter';
|
||||||
export {Reexport} from './src/reexport';
|
export {Reexport} from './src/reexport';
|
||||||
export {OwningModule, Reference} from './src/references';
|
export {OwningModule, Reference} from './src/references';
|
||||||
|
|
|
@ -6,52 +6,33 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {getSourceFile} from '../../util/src/typescript';
|
import {getSourceFile} from '../../util/src/typescript';
|
||||||
|
|
||||||
/**
|
const DefaultImportDeclaration = Symbol('DefaultImportDeclaration');
|
||||||
* Registers and records usages of `ts.Identifer`s that came from default import statements.
|
|
||||||
*
|
|
||||||
* See `DefaultImportTracker` for details.
|
|
||||||
*/
|
|
||||||
export interface DefaultImportRecorder {
|
|
||||||
/**
|
|
||||||
* Record an association between a `ts.Identifier` which might be emitted and the
|
|
||||||
* `ts.ImportDeclaration` from which it came.
|
|
||||||
*
|
|
||||||
* Alone, this method has no effect as the `ts.Identifier` might not be used in the output.
|
|
||||||
* The identifier must later be marked as used with `recordUsedIdentifier` in order for its
|
|
||||||
* import to be preserved.
|
|
||||||
*/
|
|
||||||
recordImportedIdentifier(id: ts.Identifier, decl: ts.ImportDeclaration): void;
|
|
||||||
|
|
||||||
/**
|
interface WithDefaultImportDeclaration {
|
||||||
* Record the fact that the given `ts.Identifer` will be emitted, and thus its
|
[DefaultImportDeclaration]?: ts.ImportDeclaration;
|
||||||
* `ts.ImportDeclaration`, if it was a previously registered default import, must be preserved.
|
|
||||||
*
|
|
||||||
* This method can be called safely for any `ts.Identifer`, regardless of its origin. It will only
|
|
||||||
* have an effect if the identifier came from a `ts.ImportDeclaration` default import which was
|
|
||||||
* previously registered with `recordImportedIdentifier`.
|
|
||||||
*/
|
|
||||||
recordUsedIdentifier(id: ts.Identifier): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of `DefaultImportRecorder` which does nothing.
|
* Attaches a default import declaration to `expr` to indicate the dependency of `expr` on the
|
||||||
*
|
* default import.
|
||||||
* This is useful when default import tracking isn't required, such as when emitting .d.ts code
|
|
||||||
* or for ngcc.
|
|
||||||
*/
|
*/
|
||||||
export const NOOP_DEFAULT_IMPORT_RECORDER: DefaultImportRecorder = {
|
export function attachDefaultImportDeclaration(
|
||||||
recordImportedIdentifier: (id: ts.Identifier) => void{},
|
expr: WrappedNodeExpr<unknown>, importDecl: ts.ImportDeclaration): void {
|
||||||
recordUsedIdentifier: (id: ts.Identifier) => void{},
|
(expr as WithDefaultImportDeclaration)[DefaultImportDeclaration] = importDecl;
|
||||||
};
|
}
|
||||||
|
|
||||||
const ImportDeclarationMapping = Symbol('ImportDeclarationMapping');
|
/**
|
||||||
|
* Obtains the default import declaration that `expr` depends on, or `null` if there is no such
|
||||||
interface SourceFileWithImportDeclarationMapping extends ts.SourceFile {
|
* dependency.
|
||||||
[ImportDeclarationMapping]?: Map<ts.Identifier, ts.ImportDeclaration>;
|
*/
|
||||||
|
export function getDefaultImportDeclaration(expr: WrappedNodeExpr<unknown>): ts.ImportDeclaration|
|
||||||
|
null {
|
||||||
|
return (expr as WithDefaultImportDeclaration)[DefaultImportDeclaration] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,45 +65,28 @@ interface SourceFileWithImportDeclarationMapping extends ts.SourceFile {
|
||||||
* This problem does not exist for non-default imports as the compiler can easily insert
|
* This problem does not exist for non-default imports as the compiler can easily insert
|
||||||
* "import * as X" style imports for those, and the "X" identifier survives transformation.
|
* "import * as X" style imports for those, and the "X" identifier survives transformation.
|
||||||
*/
|
*/
|
||||||
export class DefaultImportTracker implements DefaultImportRecorder {
|
export class DefaultImportTracker {
|
||||||
/**
|
/**
|
||||||
* A `Map` which tracks the `Set` of `ts.ImportDeclaration`s for default imports that were used in
|
* A `Map` which tracks the `Set` of `ts.ImportDeclaration`s for default imports that were used in
|
||||||
* a given `ts.SourceFile` and need to be preserved.
|
* a given `ts.SourceFile` and need to be preserved.
|
||||||
*/
|
*/
|
||||||
private sourceFileToUsedImports = new Map<ts.SourceFile, Set<ts.ImportDeclaration>>();
|
private sourceFileToUsedImports = new Map<ts.SourceFile, Set<ts.ImportDeclaration>>();
|
||||||
recordImportedIdentifier(id: ts.Identifier, decl: ts.ImportDeclaration): void {
|
|
||||||
const sf = getSourceFile(id) as SourceFileWithImportDeclarationMapping;
|
|
||||||
if (sf[ImportDeclarationMapping] === undefined) {
|
|
||||||
sf[ImportDeclarationMapping] = new Map<ts.Identifier, ts.ImportDeclaration>();
|
|
||||||
}
|
|
||||||
sf[ImportDeclarationMapping]!.set(id, decl);
|
|
||||||
}
|
|
||||||
|
|
||||||
recordUsedIdentifier(id: ts.Identifier): void {
|
recordUsedImport(importDecl: ts.ImportDeclaration): void {
|
||||||
const sf = getSourceFile(id) as SourceFileWithImportDeclarationMapping;
|
const sf = getSourceFile(importDecl);
|
||||||
const identifierToDeclaration = sf[ImportDeclarationMapping];
|
|
||||||
if (identifierToDeclaration === undefined) {
|
|
||||||
// The identifier's source file has no registered default imports at all.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!identifierToDeclaration.has(id)) {
|
|
||||||
// The identifier isn't from a registered default import.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const decl = identifierToDeclaration.get(id)!;
|
|
||||||
|
|
||||||
// Add the default import declaration to the set of used import declarations for the file.
|
// Add the default import declaration to the set of used import declarations for the file.
|
||||||
if (!this.sourceFileToUsedImports.has(sf)) {
|
if (!this.sourceFileToUsedImports.has(sf)) {
|
||||||
this.sourceFileToUsedImports.set(sf, new Set<ts.ImportDeclaration>());
|
this.sourceFileToUsedImports.set(sf, new Set<ts.ImportDeclaration>());
|
||||||
}
|
}
|
||||||
this.sourceFileToUsedImports.get(sf)!.add(decl);
|
this.sourceFileToUsedImports.get(sf)!.add(importDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a `ts.TransformerFactory` which will preserve default imports that were previously marked
|
* Get a `ts.TransformerFactory` which will preserve default imports that were previously marked
|
||||||
* as used.
|
* as used.
|
||||||
*
|
*
|
||||||
* This transformer must run after any other transformers which call `recordUsedIdentifier`.
|
* This transformer must run after any other transformers which call `recordUsedImport`.
|
||||||
*/
|
*/
|
||||||
importPreservingTransformer(): ts.TransformerFactory<ts.SourceFile> {
|
importPreservingTransformer(): ts.TransformerFactory<ts.SourceFile> {
|
||||||
return (context: ts.TransformationContext) => {
|
return (context: ts.TransformationContext) => {
|
||||||
|
|
|
@ -39,12 +39,10 @@ runInEachFileSystem(() => {
|
||||||
module: ts.ModuleKind.ES2015,
|
module: ts.ModuleKind.ES2015,
|
||||||
});
|
});
|
||||||
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
||||||
const fooId = fooClause.name!;
|
|
||||||
const fooDecl = fooClause.parent;
|
const fooDecl = fooClause.parent;
|
||||||
|
|
||||||
const tracker = new DefaultImportTracker();
|
const tracker = new DefaultImportTracker();
|
||||||
tracker.recordImportedIdentifier(fooId, fooDecl);
|
tracker.recordUsedImport(fooDecl);
|
||||||
tracker.recordUsedIdentifier(fooId);
|
|
||||||
program.emit(undefined, undefined, undefined, undefined, {
|
program.emit(undefined, undefined, undefined, undefined, {
|
||||||
before: [tracker.importPreservingTransformer()],
|
before: [tracker.importPreservingTransformer()],
|
||||||
});
|
});
|
||||||
|
@ -73,8 +71,7 @@ runInEachFileSystem(() => {
|
||||||
const fooDecl = fooClause.parent;
|
const fooDecl = fooClause.parent;
|
||||||
|
|
||||||
const tracker = new DefaultImportTracker();
|
const tracker = new DefaultImportTracker();
|
||||||
tracker.recordImportedIdentifier(fooId, fooDecl);
|
tracker.recordUsedImport(fooDecl);
|
||||||
tracker.recordUsedIdentifier(fooId);
|
|
||||||
program.emit(undefined, undefined, undefined, undefined, {
|
program.emit(undefined, undefined, undefined, undefined, {
|
||||||
before: [
|
before: [
|
||||||
addReferenceTransformer(fooId),
|
addReferenceTransformer(fooId),
|
||||||
|
|
|
@ -9,10 +9,11 @@
|
||||||
import {ConstantPool} from '@angular/compiler';
|
import {ConstantPool} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {DefaultImportRecorder, ImportRewriter} from '../../imports';
|
import {DefaultImportTracker, ImportRewriter} from '../../imports';
|
||||||
|
import {getDefaultImportDeclaration} from '../../imports/src/default';
|
||||||
import {PerfPhase, PerfRecorder} from '../../perf';
|
import {PerfPhase, PerfRecorder} from '../../perf';
|
||||||
import {Decorator, ReflectionHost} from '../../reflection';
|
import {Decorator, ReflectionHost} from '../../reflection';
|
||||||
import {ImportManager, RecordWrappedNodeExprFn, translateExpression, translateStatement, TranslatorOptions} from '../../translator';
|
import {ImportManager, RecordWrappedNodeFn, translateExpression, translateStatement, TranslatorOptions} from '../../translator';
|
||||||
import {visit, VisitListEntryResult, Visitor} from '../../util/src/visitor';
|
import {visit, VisitListEntryResult, Visitor} from '../../util/src/visitor';
|
||||||
|
|
||||||
import {CompileResult} from './api';
|
import {CompileResult} from './api';
|
||||||
|
@ -34,16 +35,16 @@ interface FileOverviewMeta {
|
||||||
|
|
||||||
export function ivyTransformFactory(
|
export function ivyTransformFactory(
|
||||||
compilation: TraitCompiler, reflector: ReflectionHost, importRewriter: ImportRewriter,
|
compilation: TraitCompiler, reflector: ReflectionHost, importRewriter: ImportRewriter,
|
||||||
defaultImportRecorder: DefaultImportRecorder, perf: PerfRecorder, isCore: boolean,
|
defaultImportTracker: DefaultImportTracker, perf: PerfRecorder, isCore: boolean,
|
||||||
isClosureCompilerEnabled: boolean): ts.TransformerFactory<ts.SourceFile> {
|
isClosureCompilerEnabled: boolean): ts.TransformerFactory<ts.SourceFile> {
|
||||||
const recordWrappedNodeExpr = createRecorderFn(defaultImportRecorder);
|
const recordWrappedNode = createRecorderFn(defaultImportTracker);
|
||||||
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
|
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
|
||||||
return (file: ts.SourceFile): ts.SourceFile => {
|
return (file: ts.SourceFile): ts.SourceFile => {
|
||||||
return perf.inPhase(
|
return perf.inPhase(
|
||||||
PerfPhase.Compile,
|
PerfPhase.Compile,
|
||||||
() => transformIvySourceFile(
|
() => transformIvySourceFile(
|
||||||
compilation, context, reflector, importRewriter, file, isCore,
|
compilation, context, reflector, importRewriter, file, isCore,
|
||||||
isClosureCompilerEnabled, recordWrappedNodeExpr));
|
isClosureCompilerEnabled, recordWrappedNode));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -81,7 +82,7 @@ class IvyTransformationVisitor extends Visitor {
|
||||||
private compilation: TraitCompiler,
|
private compilation: TraitCompiler,
|
||||||
private classCompilationMap: Map<ts.ClassDeclaration, CompileResult[]>,
|
private classCompilationMap: Map<ts.ClassDeclaration, CompileResult[]>,
|
||||||
private reflector: ReflectionHost, private importManager: ImportManager,
|
private reflector: ReflectionHost, private importManager: ImportManager,
|
||||||
private recordWrappedNodeExpr: RecordWrappedNodeExprFn<ts.Expression>,
|
private recordWrappedNodeExpr: RecordWrappedNodeFn<ts.Expression>,
|
||||||
private isClosureCompilerEnabled: boolean, private isCore: boolean) {
|
private isClosureCompilerEnabled: boolean, private isCore: boolean) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ class IvyTransformationVisitor extends Visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
const translateOptions: TranslatorOptions<ts.Expression> = {
|
const translateOptions: TranslatorOptions<ts.Expression> = {
|
||||||
recordWrappedNodeExpr: this.recordWrappedNodeExpr,
|
recordWrappedNode: this.recordWrappedNodeExpr,
|
||||||
annotateForClosureCompiler: this.isClosureCompilerEnabled,
|
annotateForClosureCompiler: this.isClosureCompilerEnabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -252,7 +253,7 @@ function transformIvySourceFile(
|
||||||
compilation: TraitCompiler, context: ts.TransformationContext, reflector: ReflectionHost,
|
compilation: TraitCompiler, context: ts.TransformationContext, reflector: ReflectionHost,
|
||||||
importRewriter: ImportRewriter, file: ts.SourceFile, isCore: boolean,
|
importRewriter: ImportRewriter, file: ts.SourceFile, isCore: boolean,
|
||||||
isClosureCompilerEnabled: boolean,
|
isClosureCompilerEnabled: boolean,
|
||||||
recordWrappedNodeExpr: RecordWrappedNodeExprFn<ts.Expression>): ts.SourceFile {
|
recordWrappedNode: RecordWrappedNodeFn<ts.Expression>): ts.SourceFile {
|
||||||
const constantPool = new ConstantPool(isClosureCompilerEnabled);
|
const constantPool = new ConstantPool(isClosureCompilerEnabled);
|
||||||
const importManager = new ImportManager(importRewriter);
|
const importManager = new ImportManager(importRewriter);
|
||||||
|
|
||||||
|
@ -274,7 +275,7 @@ function transformIvySourceFile(
|
||||||
// results obtained at Step 1.
|
// results obtained at Step 1.
|
||||||
const transformationVisitor = new IvyTransformationVisitor(
|
const transformationVisitor = new IvyTransformationVisitor(
|
||||||
compilation, compilationVisitor.classCompilationMap, reflector, importManager,
|
compilation, compilationVisitor.classCompilationMap, reflector, importManager,
|
||||||
recordWrappedNodeExpr, isClosureCompilerEnabled, isCore);
|
recordWrappedNode, isClosureCompilerEnabled, isCore);
|
||||||
let sf = visit(file, transformationVisitor, context);
|
let sf = visit(file, transformationVisitor, context);
|
||||||
|
|
||||||
// Generate the constant statements first, as they may involve adding additional imports
|
// Generate the constant statements first, as they may involve adding additional imports
|
||||||
|
@ -282,7 +283,7 @@ function transformIvySourceFile(
|
||||||
const downlevelTranslatedCode = getLocalizeCompileTarget(context) < ts.ScriptTarget.ES2015;
|
const downlevelTranslatedCode = getLocalizeCompileTarget(context) < ts.ScriptTarget.ES2015;
|
||||||
const constants =
|
const constants =
|
||||||
constantPool.statements.map(stmt => translateStatement(stmt, importManager, {
|
constantPool.statements.map(stmt => translateStatement(stmt, importManager, {
|
||||||
recordWrappedNodeExpr,
|
recordWrappedNode,
|
||||||
downlevelTaggedTemplates: downlevelTranslatedCode,
|
downlevelTaggedTemplates: downlevelTranslatedCode,
|
||||||
downlevelVariableDeclarations: downlevelTranslatedCode,
|
downlevelVariableDeclarations: downlevelTranslatedCode,
|
||||||
annotateForClosureCompiler: isClosureCompilerEnabled,
|
annotateForClosureCompiler: isClosureCompilerEnabled,
|
||||||
|
@ -370,11 +371,12 @@ function isFromAngularCore(decorator: Decorator): boolean {
|
||||||
return decorator.import !== null && decorator.import.from === '@angular/core';
|
return decorator.import !== null && decorator.import.from === '@angular/core';
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRecorderFn(defaultImportRecorder: DefaultImportRecorder):
|
function createRecorderFn(defaultImportTracker: DefaultImportTracker):
|
||||||
RecordWrappedNodeExprFn<ts.Expression> {
|
RecordWrappedNodeFn<ts.Expression> {
|
||||||
return expr => {
|
return node => {
|
||||||
if (ts.isIdentifier(expr)) {
|
const importDecl = getDefaultImportDeclaration(node);
|
||||||
defaultImportRecorder.recordUsedIdentifier(expr);
|
if (importDecl !== null) {
|
||||||
|
defaultImportTracker.recordUsedImport(importDecl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ export {AstFactory, BinaryOperator, LeadingComment, ObjectLiteralProperty, Sourc
|
||||||
export {ImportGenerator, NamedImport} from './src/api/import_generator';
|
export {ImportGenerator, NamedImport} from './src/api/import_generator';
|
||||||
export {Context} from './src/context';
|
export {Context} from './src/context';
|
||||||
export {Import, ImportManager} from './src/import_manager';
|
export {Import, ImportManager} from './src/import_manager';
|
||||||
export {ExpressionTranslatorVisitor, RecordWrappedNodeExprFn, TranslatorOptions} from './src/translator';
|
export {ExpressionTranslatorVisitor, RecordWrappedNodeFn, TranslatorOptions} from './src/translator';
|
||||||
export {translateType} from './src/type_translator';
|
export {translateType} from './src/type_translator';
|
||||||
export {attachComments, createTemplateMiddle, createTemplateTail, TypeScriptAstFactory} from './src/typescript_ast_factory';
|
export {attachComments, createTemplateMiddle, createTemplateTail, TypeScriptAstFactory} from './src/typescript_ast_factory';
|
||||||
export {translateExpression, translateStatement} from './src/typescript_translator';
|
export {translateExpression, translateStatement} from './src/typescript_translator';
|
||||||
|
|
|
@ -37,12 +37,12 @@ const BINARY_OPERATORS = new Map<o.BinaryOperator, BinaryOperator>([
|
||||||
[o.BinaryOperator.NullishCoalesce, '??'],
|
[o.BinaryOperator.NullishCoalesce, '??'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export type RecordWrappedNodeExprFn<TExpression> = (expr: TExpression) => void;
|
export type RecordWrappedNodeFn<TExpression> = (node: o.WrappedNodeExpr<TExpression>) => void;
|
||||||
|
|
||||||
export interface TranslatorOptions<TExpression> {
|
export interface TranslatorOptions<TExpression> {
|
||||||
downlevelTaggedTemplates?: boolean;
|
downlevelTaggedTemplates?: boolean;
|
||||||
downlevelVariableDeclarations?: boolean;
|
downlevelVariableDeclarations?: boolean;
|
||||||
recordWrappedNodeExpr?: RecordWrappedNodeExprFn<TExpression>;
|
recordWrappedNode?: RecordWrappedNodeFn<TExpression>;
|
||||||
annotateForClosureCompiler?: boolean;
|
annotateForClosureCompiler?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,14 +50,14 @@ export class ExpressionTranslatorVisitor<TStatement, TExpression> implements o.E
|
||||||
o.StatementVisitor {
|
o.StatementVisitor {
|
||||||
private downlevelTaggedTemplates: boolean;
|
private downlevelTaggedTemplates: boolean;
|
||||||
private downlevelVariableDeclarations: boolean;
|
private downlevelVariableDeclarations: boolean;
|
||||||
private recordWrappedNodeExpr: RecordWrappedNodeExprFn<TExpression>;
|
private recordWrappedNode: RecordWrappedNodeFn<TExpression>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private factory: AstFactory<TStatement, TExpression>,
|
private factory: AstFactory<TStatement, TExpression>,
|
||||||
private imports: ImportGenerator<TExpression>, options: TranslatorOptions<TExpression>) {
|
private imports: ImportGenerator<TExpression>, options: TranslatorOptions<TExpression>) {
|
||||||
this.downlevelTaggedTemplates = options.downlevelTaggedTemplates === true;
|
this.downlevelTaggedTemplates = options.downlevelTaggedTemplates === true;
|
||||||
this.downlevelVariableDeclarations = options.downlevelVariableDeclarations === true;
|
this.downlevelVariableDeclarations = options.downlevelVariableDeclarations === true;
|
||||||
this.recordWrappedNodeExpr = options.recordWrappedNodeExpr || (() => {});
|
this.recordWrappedNode = options.recordWrappedNode || (() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, context: Context): TStatement {
|
visitDeclareVarStmt(stmt: o.DeclareVarStmt, context: Context): TStatement {
|
||||||
|
@ -382,7 +382,7 @@ export class ExpressionTranslatorVisitor<TStatement, TExpression> implements o.E
|
||||||
}
|
}
|
||||||
|
|
||||||
visitWrappedNodeExpr(ast: o.WrappedNodeExpr<any>, _context: Context): any {
|
visitWrappedNodeExpr(ast: o.WrappedNodeExpr<any>, _context: Context): any {
|
||||||
this.recordWrappedNodeExpr(ast.node);
|
this.recordWrappedNode(ast);
|
||||||
return ast.node;
|
return ast.node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue