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 {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics';
|
||||
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 {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, ResourceRegistry} from '../../../src/ngtsc/metadata';
|
||||
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
|
||||
|
@ -107,8 +107,8 @@ export class DecorationAnalyzer {
|
|||
/* i18nUseExternalIds */ true, this.bundle.enableI18nLegacyMessageIdFormat,
|
||||
/* usePoisonedData */ false,
|
||||
/* i18nNormalizeLineEndingsInICUs */ false, this.moduleResolver, this.cycleAnalyzer,
|
||||
CycleHandlingStrategy.UseRemoteScoping, this.refEmitter, NOOP_DEFAULT_IMPORT_RECORDER,
|
||||
NOOP_DEPENDENCY_TRACKER, this.injectableRegistry,
|
||||
CycleHandlingStrategy.UseRemoteScoping, this.refEmitter, NOOP_DEPENDENCY_TRACKER,
|
||||
this.injectableRegistry,
|
||||
/* semanticDepGraphUpdater */ null, !!this.compilerOptions.annotateForClosureCompiler,
|
||||
NOOP_PERF_RECORDER),
|
||||
|
||||
|
@ -116,7 +116,7 @@ export class DecorationAnalyzer {
|
|||
// clang-format off
|
||||
new DirectiveDecoratorHandler(
|
||||
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,
|
||||
!!this.compilerOptions.annotateForClosureCompiler,
|
||||
// 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)
|
||||
new PipeDecoratorHandler(
|
||||
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(
|
||||
this.reflectionHost, NOOP_DEFAULT_IMPORT_RECORDER, this.isCore,
|
||||
this.reflectionHost, this.isCore,
|
||||
/* strictCtorDeps */ false, this.injectableRegistry, NOOP_PERF_RECORDER,
|
||||
/* errorOnDuplicateProv */ false),
|
||||
new NgModuleDecoratorHandler(
|
||||
this.reflectionHost, this.evaluator, this.fullMetaReader, this.fullRegistry,
|
||||
this.scopeRegistry, this.referencesRegistry, this.isCore, /* routeAnalyzer */ null,
|
||||
this.refEmitter,
|
||||
/* factoryTracker */ null, NOOP_DEFAULT_IMPORT_RECORDER,
|
||||
!!this.compilerOptions.annotateForClosureCompiler, this.injectableRegistry,
|
||||
NOOP_PERF_RECORDER),
|
||||
/* factoryTracker */ null, !!this.compilerOptions.annotateForClosureCompiler,
|
||||
this.injectableRegistry, NOOP_PERF_RECORDER),
|
||||
];
|
||||
compiler = new NgccTraitCompiler(this.handlers, this.reflectionHost);
|
||||
migrations: Migration[] = [
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as ts from 'typescript';
|
|||
import {Cycle, CycleAnalyzer, CycleHandlingStrategy} from '../../cycles';
|
||||
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../diagnostics';
|
||||
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 {extractSemanticTypeParameters, isArrayEqual, isReferenceEqual, SemanticDepGraphUpdater, SemanticReference, SemanticSymbol} from '../../incremental/semantic_graph';
|
||||
import {IndexingContext} from '../../indexer';
|
||||
|
@ -205,7 +205,6 @@ export class ComponentDecoratorHandler implements
|
|||
private i18nNormalizeLineEndingsInICUs: boolean|undefined,
|
||||
private moduleResolver: ModuleResolver, private cycleAnalyzer: CycleAnalyzer,
|
||||
private cycleHandlingStrategy: CycleHandlingStrategy, private refEmitter: ReferenceEmitter,
|
||||
private defaultImportRecorder: DefaultImportRecorder,
|
||||
private depTracker: DependencyTracker|null,
|
||||
private injectableRegistry: InjectableClassRegistry,
|
||||
private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
|
||||
|
@ -326,8 +325,8 @@ export class ComponentDecoratorHandler implements
|
|||
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
|
||||
// on it.
|
||||
const directiveResult = extractDirectiveMetadata(
|
||||
node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore,
|
||||
flags, this.annotateForClosureCompiler,
|
||||
node, decorator, this.reflector, this.evaluator, this.isCore, flags,
|
||||
this.annotateForClosureCompiler,
|
||||
this.elementSchemaRegistry.getDefaultComponentElementName());
|
||||
if (directiveResult === undefined) {
|
||||
// `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),
|
||||
classMetadata: extractClassMetadata(
|
||||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
||||
this.annotateForClosureCompiler),
|
||||
node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
||||
template,
|
||||
providersRequiringFactory,
|
||||
viewProvidersRequiringFactory,
|
||||
|
|
|
@ -11,7 +11,7 @@ import {emitDistinctChangesOnlyDefaultValue} from '@angular/compiler/src/core';
|
|||
import * as ts from 'typescript';
|
||||
|
||||
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 {BindingPropertyName, ClassPropertyMapping, ClassPropertyName, DirectiveTypeCheckMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry, TemplateGuardMeta} from '../../metadata';
|
||||
import {extractDirectiveTypeCheckMeta} from '../../metadata/src/util';
|
||||
|
@ -177,9 +177,8 @@ export class DirectiveDecoratorHandler implements
|
|||
constructor(
|
||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
|
||||
private metaReader: MetadataReader, private defaultImportRecorder: DefaultImportRecorder,
|
||||
private injectableRegistry: InjectableClassRegistry, private isCore: boolean,
|
||||
private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
|
||||
private metaReader: MetadataReader, private injectableRegistry: InjectableClassRegistry,
|
||||
private isCore: boolean, private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
|
||||
private annotateForClosureCompiler: boolean,
|
||||
private compileUndecoratedClassesWithAngularFeatures: boolean, private perf: PerfRecorder) {}
|
||||
|
||||
|
@ -215,8 +214,8 @@ export class DirectiveDecoratorHandler implements
|
|||
this.perf.eventCount(PerfEvent.AnalyzeDirective);
|
||||
|
||||
const directiveResult = extractDirectiveMetadata(
|
||||
node, decorator, this.reflector, this.evaluator, this.defaultImportRecorder, this.isCore,
|
||||
flags, this.annotateForClosureCompiler);
|
||||
node, decorator, this.reflector, this.evaluator, this.isCore, flags,
|
||||
this.annotateForClosureCompiler);
|
||||
if (directiveResult === undefined) {
|
||||
return {};
|
||||
}
|
||||
|
@ -234,8 +233,7 @@ export class DirectiveDecoratorHandler implements
|
|||
outputs: directiveResult.outputs,
|
||||
meta: analysis,
|
||||
classMetadata: extractClassMetadata(
|
||||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
||||
this.annotateForClosureCompiler),
|
||||
node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
||||
baseClass: readBaseClass(node, this.reflector, this.evaluator),
|
||||
typeCheckMeta: extractDirectiveTypeCheckMeta(node, directiveResult.inputs, this.reflector),
|
||||
providersRequiringFactory,
|
||||
|
@ -351,9 +349,8 @@ export class DirectiveDecoratorHandler implements
|
|||
*/
|
||||
export function extractDirectiveMetadata(
|
||||
clazz: ClassDeclaration, decorator: Readonly<Decorator|null>, reflector: ReflectionHost,
|
||||
evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
||||
flags: HandlerFlags, annotateForClosureCompiler: boolean,
|
||||
defaultSelector: string|null = null): {
|
||||
evaluator: PartialEvaluator, isCore: boolean, flags: HandlerFlags,
|
||||
annotateForClosureCompiler: boolean, defaultSelector: string|null = null): {
|
||||
decorator: Map<string, ts.Expression>,
|
||||
metadata: R3DirectiveMetadata,
|
||||
inputs: ClassPropertyMapping,
|
||||
|
@ -473,7 +470,7 @@ export function extractDirectiveMetadata(
|
|||
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
|
||||
// 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 {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
import {DefaultImportRecorder} from '../../imports';
|
||||
import {InjectableClassRegistry} from '../../metadata';
|
||||
import {PerfEvent, PerfRecorder} from '../../perf';
|
||||
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||
|
@ -33,8 +32,7 @@ export interface InjectableHandlerData {
|
|||
export class InjectableDecoratorHandler implements
|
||||
DecoratorHandler<Decorator, InjectableHandlerData, null, unknown> {
|
||||
constructor(
|
||||
private reflector: ReflectionHost, private defaultImportRecorder: DefaultImportRecorder,
|
||||
private isCore: boolean, private strictCtorDeps: boolean,
|
||||
private reflector: ReflectionHost, private isCore: boolean, private strictCtorDeps: boolean,
|
||||
private injectableRegistry: InjectableClassRegistry, private perf: PerfRecorder,
|
||||
/**
|
||||
* What to do if the injectable already contains a ɵprov property.
|
||||
|
@ -74,10 +72,8 @@ export class InjectableDecoratorHandler implements
|
|||
analysis: {
|
||||
meta,
|
||||
ctorDeps: extractInjectableCtorDeps(
|
||||
node, meta, decorator, this.reflector, this.defaultImportRecorder, this.isCore,
|
||||
this.strictCtorDeps),
|
||||
classMetadata:
|
||||
extractClassMetadata(node, this.reflector, this.defaultImportRecorder, this.isCore),
|
||||
node, meta, decorator, this.reflector, this.isCore, this.strictCtorDeps),
|
||||
classMetadata: extractClassMetadata(node, this.reflector, this.isCore),
|
||||
// Avoid generating multiple factories if a class has
|
||||
// more Angular decorators, apart from Injectable.
|
||||
needsFactory: !decorators ||
|
||||
|
@ -232,8 +228,7 @@ function getProviderExpression(
|
|||
|
||||
function extractInjectableCtorDeps(
|
||||
clazz: ClassDeclaration, meta: R3InjectableMetadata, decorator: Decorator,
|
||||
reflector: ReflectionHost, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
||||
strictCtorDeps: boolean) {
|
||||
reflector: ReflectionHost, isCore: boolean, strictCtorDeps: boolean) {
|
||||
if (decorator.args === null) {
|
||||
throw new FatalDiagnosticError(
|
||||
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
|
||||
// generated.
|
||||
if (strictCtorDeps) {
|
||||
ctorDeps = getValidConstructorDependencies(clazz, reflector, defaultImportRecorder, isCore);
|
||||
ctorDeps = getValidConstructorDependencies(clazz, reflector, isCore);
|
||||
} else {
|
||||
ctorDeps = unwrapConstructorDependencies(
|
||||
getConstructorDependencies(clazz, reflector, defaultImportRecorder, isCore));
|
||||
ctorDeps =
|
||||
unwrapConstructorDependencies(getConstructorDependencies(clazz, reflector, isCore));
|
||||
}
|
||||
|
||||
return ctorDeps;
|
||||
} 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 &&
|
||||
meta.useClass === undefined && meta.useFactory === undefined) {
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
import {Expression, FunctionExpr, LiteralArrayExpr, LiteralExpr, literalMap, R3ClassMetadata, ReturnStatement, WrappedNodeExpr} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {DefaultImportRecorder} from '../../imports';
|
||||
import {CtorParameter, DeclarationNode, Decorator, ReflectionHost, TypeValueReferenceKind} from '../../reflection';
|
||||
|
||||
import {valueReferenceToExpression, wrapFunctionExpressionsInParens} from './util';
|
||||
|
@ -23,8 +22,7 @@ import {valueReferenceToExpression, wrapFunctionExpressionsInParens} from './uti
|
|||
* as a `Statement` for inclusion along with the class.
|
||||
*/
|
||||
export function extractClassMetadata(
|
||||
clazz: DeclarationNode, reflection: ReflectionHost,
|
||||
defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
||||
clazz: DeclarationNode, reflection: ReflectionHost, isCore: boolean,
|
||||
annotateForClosureCompiler?: boolean): R3ClassMetadata|null {
|
||||
if (!reflection.isClass(clazz)) {
|
||||
return null;
|
||||
|
@ -55,8 +53,7 @@ export function extractClassMetadata(
|
|||
let metaCtorParameters: Expression|null = null;
|
||||
const classCtorParameters = reflection.getConstructorParameters(clazz);
|
||||
if (classCtorParameters !== null) {
|
||||
const ctorParameters = classCtorParameters.map(
|
||||
param => ctorParameterToMetadata(param, defaultImportRecorder, isCore));
|
||||
const ctorParameters = classCtorParameters.map(param => ctorParameterToMetadata(param, isCore));
|
||||
metaCtorParameters = new FunctionExpr([], [
|
||||
new ReturnStatement(new LiteralArrayExpr(ctorParameters)),
|
||||
]);
|
||||
|
@ -93,13 +90,11 @@ export function extractClassMetadata(
|
|||
/**
|
||||
* Convert a reflected constructor parameter to metadata.
|
||||
*/
|
||||
function ctorParameterToMetadata(
|
||||
param: CtorParameter, defaultImportRecorder: DefaultImportRecorder,
|
||||
isCore: boolean): Expression {
|
||||
function ctorParameterToMetadata(param: CtorParameter, isCore: boolean): Expression {
|
||||
// Parameters sometimes have a type that can be referenced. If so, then use it, otherwise
|
||||
// its type is undefined.
|
||||
const type = param.typeValueReference.kind !== TypeValueReferenceKind.UNAVAILABLE ?
|
||||
valueReferenceToExpression(param.typeValueReference, defaultImportRecorder) :
|
||||
valueReferenceToExpression(param.typeValueReference) :
|
||||
new LiteralExpr(undefined);
|
||||
|
||||
const mapEntries: {key: string, value: Expression, quoted: false}[] = [
|
||||
|
|
|
@ -10,7 +10,7 @@ import {compileClassMetadata, compileDeclareClassMetadata, compileDeclareInjecto
|
|||
import * as ts from 'typescript';
|
||||
|
||||
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 {InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
|
||||
import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator';
|
||||
|
@ -130,9 +130,7 @@ export class NgModuleDecoratorHandler implements
|
|||
private scopeRegistry: LocalModuleScopeRegistry,
|
||||
private referencesRegistry: ReferencesRegistry, private isCore: boolean,
|
||||
private routeAnalyzer: NgModuleRouteAnalyzer|null, private refEmitter: ReferenceEmitter,
|
||||
private factoryTracker: FactoryTracker|null,
|
||||
private defaultImportRecorder: DefaultImportRecorder,
|
||||
private annotateForClosureCompiler: boolean,
|
||||
private factoryTracker: FactoryTracker|null, private annotateForClosureCompiler: boolean,
|
||||
private injectableRegistry: InjectableClassRegistry, private perf: PerfRecorder,
|
||||
private localeId?: string) {}
|
||||
|
||||
|
@ -350,8 +348,7 @@ export class NgModuleDecoratorHandler implements
|
|||
type,
|
||||
internalType,
|
||||
typeArgumentCount: 0,
|
||||
deps: getValidConstructorDependencies(
|
||||
node, this.reflector, this.defaultImportRecorder, this.isCore),
|
||||
deps: getValidConstructorDependencies(node, this.reflector, this.isCore),
|
||||
target: FactoryTarget.NgModule,
|
||||
};
|
||||
|
||||
|
@ -371,8 +368,7 @@ export class NgModuleDecoratorHandler implements
|
|||
resolveProvidersRequiringFactory(rawProviders, this.reflector, this.evaluator) :
|
||||
null,
|
||||
classMetadata: extractClassMetadata(
|
||||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
||||
this.annotateForClosureCompiler),
|
||||
node, this.reflector, this.isCore, this.annotateForClosureCompiler),
|
||||
factorySymbolName: node.name.text,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import {compileClassMetadata, compileDeclareClassMetadata, compileDeclarePipeFro
|
|||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
import {DefaultImportRecorder, Reference} from '../../imports';
|
||||
import {Reference} from '../../imports';
|
||||
import {SemanticSymbol} from '../../incremental/semantic_graph';
|
||||
import {InjectableClassRegistry, MetadataRegistry} from '../../metadata';
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
|
@ -55,7 +55,6 @@ export class PipeDecoratorHandler implements
|
|||
constructor(
|
||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
|
||||
private defaultImportRecorder: DefaultImportRecorder,
|
||||
private injectableRegistry: InjectableClassRegistry, private isCore: boolean,
|
||||
private perf: PerfRecorder) {}
|
||||
|
||||
|
@ -131,12 +130,10 @@ export class PipeDecoratorHandler implements
|
|||
internalType,
|
||||
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0,
|
||||
pipeName,
|
||||
deps: getValidConstructorDependencies(
|
||||
clazz, this.reflector, this.defaultImportRecorder, this.isCore),
|
||||
deps: getValidConstructorDependencies(clazz, this.reflector, this.isCore),
|
||||
pure,
|
||||
},
|
||||
classMetadata:
|
||||
extractClassMetadata(clazz, this.reflector, this.defaultImportRecorder, this.isCore),
|
||||
classMetadata: extractClassMetadata(clazz, this.reflector, this.isCore),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ import {FactoryTarget} from '@angular/compiler/src/render3/partial/api';
|
|||
import * as ts from 'typescript';
|
||||
|
||||
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 {ClassDeclaration, CtorParameter, Decorator, Import, ImportedTypeValueReference, isNamedClassDeclaration, LocalTypeValueReference, ReflectionHost, TypeValueReference, TypeValueReferenceKind, UnavailableValue, ValueUnavailableKind} from '../../reflection';
|
||||
import {DeclarationData} from '../../scope';
|
||||
|
@ -32,8 +33,7 @@ export interface ConstructorDepError {
|
|||
}
|
||||
|
||||
export function getConstructorDependencies(
|
||||
clazz: ClassDeclaration, reflector: ReflectionHost,
|
||||
defaultImportRecorder: DefaultImportRecorder, isCore: boolean): ConstructorDeps|null {
|
||||
clazz: ClassDeclaration, reflector: ReflectionHost, isCore: boolean): ConstructorDeps|null {
|
||||
const deps: R3DependencyMetadata[] = [];
|
||||
const errors: ConstructorDepError[] = [];
|
||||
let ctorParams = reflector.getConstructorParameters(clazz);
|
||||
|
@ -45,7 +45,7 @@ export function getConstructorDependencies(
|
|||
}
|
||||
}
|
||||
ctorParams.forEach((param, idx) => {
|
||||
let token = valueReferenceToExpression(param.typeValueReference, defaultImportRecorder);
|
||||
let token = valueReferenceToExpression(param.typeValueReference);
|
||||
let attributeNameType: Expression|null = null;
|
||||
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
|
||||
* file in which the `TypeValueReference` originated.
|
||||
*/
|
||||
export function valueReferenceToExpression(
|
||||
valueRef: LocalTypeValueReference|ImportedTypeValueReference,
|
||||
defaultImportRecorder: DefaultImportRecorder): Expression;
|
||||
export function valueReferenceToExpression(
|
||||
valueRef: TypeValueReference, defaultImportRecorder: DefaultImportRecorder): Expression|null;
|
||||
export function valueReferenceToExpression(
|
||||
valueRef: TypeValueReference, defaultImportRecorder: DefaultImportRecorder): Expression|null {
|
||||
export function valueReferenceToExpression(valueRef: LocalTypeValueReference|
|
||||
ImportedTypeValueReference): Expression;
|
||||
export function valueReferenceToExpression(valueRef: TypeValueReference): Expression|null;
|
||||
export function valueReferenceToExpression(valueRef: TypeValueReference): Expression|null {
|
||||
if (valueRef.kind === TypeValueReferenceKind.UNAVAILABLE) {
|
||||
return null;
|
||||
} else if (valueRef.kind === TypeValueReferenceKind.LOCAL) {
|
||||
if (defaultImportRecorder !== null && valueRef.defaultImportStatement !== null &&
|
||||
ts.isIdentifier(valueRef.expression)) {
|
||||
defaultImportRecorder.recordImportedIdentifier(
|
||||
valueRef.expression, valueRef.defaultImportStatement);
|
||||
const expr = new WrappedNodeExpr(valueRef.expression);
|
||||
if (valueRef.defaultImportStatement !== null) {
|
||||
attachDefaultImportDeclaration(expr, valueRef.defaultImportStatement);
|
||||
}
|
||||
return new WrappedNodeExpr(valueRef.expression);
|
||||
return expr;
|
||||
} else {
|
||||
let importExpr: Expression =
|
||||
new ExternalExpr({moduleName: valueRef.moduleName, name: valueRef.importedName});
|
||||
|
@ -163,10 +159,10 @@ export function unwrapConstructorDependencies(deps: ConstructorDeps|null): R3Dep
|
|||
}
|
||||
|
||||
export function getValidConstructorDependencies(
|
||||
clazz: ClassDeclaration, reflector: ReflectionHost,
|
||||
defaultImportRecorder: DefaultImportRecorder, isCore: boolean): R3DependencyMetadata[]|null {
|
||||
clazz: ClassDeclaration, reflector: ReflectionHost, isCore: boolean): R3DependencyMetadata[]|
|
||||
null {
|
||||
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 {absoluteFrom} from '../../file_system';
|
||||
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 {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||
|
@ -81,7 +81,6 @@ function setup(program: ts.Program, options: ts.CompilerOptions, host: ts.Compil
|
|||
cycleAnalyzer,
|
||||
CycleHandlingStrategy.UseRemoteScoping,
|
||||
refEmitter,
|
||||
NOOP_DEFAULT_IMPORT_RECORDER,
|
||||
/* depTracker */ null,
|
||||
injectableRegistry,
|
||||
/* semanticDepGraphUpdater */ null,
|
||||
|
|
|
@ -10,7 +10,7 @@ import * as ts from 'typescript';
|
|||
|
||||
import {absoluteFrom} from '../../file_system';
|
||||
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 {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||
|
@ -168,8 +168,8 @@ runInEachFileSystem(() => {
|
|||
null);
|
||||
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
||||
const handler = new DirectiveDecoratorHandler(
|
||||
reflectionHost, evaluator, scopeRegistry, scopeRegistry, metaReader,
|
||||
NOOP_DEFAULT_IMPORT_RECORDER, injectableRegistry, /*isCore*/ false,
|
||||
reflectionHost, evaluator, scopeRegistry, scopeRegistry, metaReader, injectableRegistry,
|
||||
/*isCore*/ false,
|
||||
/*semanticDepGraphUpdater*/ null,
|
||||
/*annotateForClosureCompiler*/ false,
|
||||
/*detectUndecoratedClassesWithAngularFeatures*/ false, NOOP_PERF_RECORDER);
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import {ErrorCode, FatalDiagnosticError, ngErrorCode} from '../../diagnostics';
|
||||
import {absoluteFrom} from '../../file_system';
|
||||
import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../imports';
|
||||
import {InjectableClassRegistry} from '../../metadata';
|
||||
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||
|
@ -70,7 +69,7 @@ function setupHandler(errorOnDuplicateProv: boolean) {
|
|||
const reflectionHost = new TypeScriptReflectionHost(checker);
|
||||
const injectableRegistry = new InjectableClassRegistry(reflectionHost);
|
||||
const handler = new InjectableDecoratorHandler(
|
||||
reflectionHost, NOOP_DEFAULT_IMPORT_RECORDER, /* isCore */ false,
|
||||
reflectionHost, /* isCore */ false,
|
||||
/* strictCtorDeps */ false, injectableRegistry, NOOP_PERF_RECORDER, errorOnDuplicateProv);
|
||||
const TestClass = getDeclaration(program, ENTRY_FILE, 'TestClass', isNamedClassDeclaration);
|
||||
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 {runInEachFileSystem, TestFile} from '../../file_system/testing';
|
||||
import {NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports';
|
||||
import {NoopImportRewriter} from '../../imports';
|
||||
import {TypeScriptReflectionHost} from '../../reflection';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {ImportManager, translateStatement} from '../../translator';
|
||||
|
@ -128,7 +128,7 @@ runInEachFileSystem(() => {
|
|||
{target: ts.ScriptTarget.ES2015});
|
||||
const host = new TypeScriptReflectionHost(program.getTypeChecker());
|
||||
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) {
|
||||
return '';
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import * as ts from 'typescript';
|
|||
|
||||
import {absoluteFrom} from '../../file_system';
|
||||
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 {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {NOOP_PERF_RECORDER} from '../../perf';
|
||||
|
@ -72,8 +72,7 @@ runInEachFileSystem(() => {
|
|||
const handler = new NgModuleDecoratorHandler(
|
||||
reflectionHost, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry,
|
||||
/* isCore */ false, /* routeAnalyzer */ null, refEmitter, /* factoryTracker */ null,
|
||||
NOOP_DEFAULT_IMPORT_RECORDER, /* annotateForClosureCompiler */ false, injectableRegistry,
|
||||
NOOP_PERF_RECORDER);
|
||||
/* annotateForClosureCompiler */ false, injectableRegistry, NOOP_PERF_RECORDER);
|
||||
const TestModule =
|
||||
getDeclaration(program, _('/entry.ts'), 'TestModule', isNamedClassDeclaration);
|
||||
const detected =
|
||||
|
|
|
@ -52,7 +52,6 @@ interface LazyCompilationState {
|
|||
routeAnalyzer: NgModuleRouteAnalyzer;
|
||||
dtsTransforms: DtsTransformRegistry;
|
||||
mwpScanner: ModuleWithProvidersScanner;
|
||||
defaultImportTracker: DefaultImportTracker;
|
||||
aliasingHost: AliasingHost|null;
|
||||
refEmitter: ReferenceEmitter;
|
||||
templateTypeChecker: TemplateTypeChecker;
|
||||
|
@ -613,13 +612,14 @@ export class NgCompiler {
|
|||
importRewriter = new NoopImportRewriter();
|
||||
}
|
||||
|
||||
const defaultImportTracker = new DefaultImportTracker();
|
||||
|
||||
const before = [
|
||||
ivyTransformFactory(
|
||||
compilation.traitCompiler, compilation.reflector, importRewriter,
|
||||
compilation.defaultImportTracker, this.delegatingPerfRecorder, compilation.isCore,
|
||||
this.closureCompilerEnabled),
|
||||
compilation.traitCompiler, compilation.reflector, importRewriter, defaultImportTracker,
|
||||
this.delegatingPerfRecorder, compilation.isCore, this.closureCompilerEnabled),
|
||||
aliasTransformFactory(compilation.traitCompiler.exportStatements),
|
||||
compilation.defaultImportTracker.importPreservingTransformer(),
|
||||
defaultImportTracker.importPreservingTransformer(),
|
||||
];
|
||||
|
||||
const afterDeclarations: ts.TransformerFactory<ts.SourceFile>[] = [];
|
||||
|
@ -971,7 +971,6 @@ export class NgCompiler {
|
|||
|
||||
const isCore = isAngularCorePackage(this.inputProgram);
|
||||
|
||||
const defaultImportTracker = new DefaultImportTracker();
|
||||
const resourceRegistry = new ResourceRegistry();
|
||||
|
||||
const compilationMode =
|
||||
|
@ -993,16 +992,15 @@ export class NgCompiler {
|
|||
this.options.i18nUseExternalIds !== false,
|
||||
this.options.enableI18nLegacyMessageIdFormat !== false, this.usePoisonedData,
|
||||
this.options.i18nNormalizeLineEndingsInICUs, this.moduleResolver, this.cycleAnalyzer,
|
||||
cycleHandlingStrategy, refEmitter, defaultImportTracker, this.incrementalDriver.depGraph,
|
||||
injectableRegistry, semanticDepGraphUpdater, this.closureCompilerEnabled,
|
||||
this.delegatingPerfRecorder),
|
||||
cycleHandlingStrategy, refEmitter, this.incrementalDriver.depGraph, injectableRegistry,
|
||||
semanticDepGraphUpdater, this.closureCompilerEnabled, this.delegatingPerfRecorder),
|
||||
|
||||
// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
|
||||
// not being assignable to `unknown` when wrapped in `Readonly`).
|
||||
// clang-format off
|
||||
new DirectiveDecoratorHandler(
|
||||
reflector, evaluator, metaRegistry, scopeRegistry, metaReader,
|
||||
defaultImportTracker, injectableRegistry, isCore, semanticDepGraphUpdater,
|
||||
injectableRegistry, isCore, semanticDepGraphUpdater,
|
||||
this.closureCompilerEnabled, compileUndecoratedClassesWithAngularFeatures,
|
||||
this.delegatingPerfRecorder,
|
||||
) 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
|
||||
// before injectable factories (so injectable factories can delegate to them)
|
||||
new PipeDecoratorHandler(
|
||||
reflector, evaluator, metaRegistry, scopeRegistry, defaultImportTracker,
|
||||
injectableRegistry, isCore, this.delegatingPerfRecorder),
|
||||
reflector, evaluator, metaRegistry, scopeRegistry, injectableRegistry, isCore,
|
||||
this.delegatingPerfRecorder),
|
||||
new InjectableDecoratorHandler(
|
||||
reflector, defaultImportTracker, isCore, this.options.strictInjectionParameters || false,
|
||||
injectableRegistry, this.delegatingPerfRecorder),
|
||||
reflector, isCore, this.options.strictInjectionParameters || false, injectableRegistry,
|
||||
this.delegatingPerfRecorder),
|
||||
new NgModuleDecoratorHandler(
|
||||
reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore,
|
||||
routeAnalyzer, refEmitter, this.adapter.factoryTracker, defaultImportTracker,
|
||||
this.closureCompilerEnabled, injectableRegistry, this.delegatingPerfRecorder,
|
||||
this.options.i18nInLocale),
|
||||
routeAnalyzer, refEmitter, this.adapter.factoryTracker, this.closureCompilerEnabled,
|
||||
injectableRegistry, this.delegatingPerfRecorder, this.options.i18nInLocale),
|
||||
];
|
||||
|
||||
const traitCompiler = new TraitCompiler(
|
||||
|
@ -1051,7 +1048,6 @@ export class NgCompiler {
|
|||
mwpScanner,
|
||||
metaReader,
|
||||
typeCheckScopeRegistry,
|
||||
defaultImportTracker,
|
||||
aliasingHost,
|
||||
refEmitter,
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
This is accessed via `DefaultImportTracker.importPreservingTransformer`.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
export {AliasingHost, AliasStrategy, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias';
|
||||
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 {Reexport} from './src/reexport';
|
||||
export {OwningModule, Reference} from './src/references';
|
||||
|
|
|
@ -6,52 +6,33 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {WrappedNodeExpr} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {getSourceFile} from '../../util/src/typescript';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
const DefaultImportDeclaration = Symbol('DefaultImportDeclaration');
|
||||
|
||||
/**
|
||||
* Record the fact that the given `ts.Identifer` will be emitted, and thus its
|
||||
* `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;
|
||||
interface WithDefaultImportDeclaration {
|
||||
[DefaultImportDeclaration]?: ts.ImportDeclaration;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of `DefaultImportRecorder` which does nothing.
|
||||
*
|
||||
* This is useful when default import tracking isn't required, such as when emitting .d.ts code
|
||||
* or for ngcc.
|
||||
* Attaches a default import declaration to `expr` to indicate the dependency of `expr` on the
|
||||
* default import.
|
||||
*/
|
||||
export const NOOP_DEFAULT_IMPORT_RECORDER: DefaultImportRecorder = {
|
||||
recordImportedIdentifier: (id: ts.Identifier) => void{},
|
||||
recordUsedIdentifier: (id: ts.Identifier) => void{},
|
||||
};
|
||||
export function attachDefaultImportDeclaration(
|
||||
expr: WrappedNodeExpr<unknown>, importDecl: ts.ImportDeclaration): void {
|
||||
(expr as WithDefaultImportDeclaration)[DefaultImportDeclaration] = importDecl;
|
||||
}
|
||||
|
||||
const ImportDeclarationMapping = Symbol('ImportDeclarationMapping');
|
||||
|
||||
interface SourceFileWithImportDeclarationMapping extends ts.SourceFile {
|
||||
[ImportDeclarationMapping]?: Map<ts.Identifier, ts.ImportDeclaration>;
|
||||
/**
|
||||
* Obtains the default import declaration that `expr` depends on, or `null` if there is no such
|
||||
* dependency.
|
||||
*/
|
||||
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
|
||||
* "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 given `ts.SourceFile` and need to be preserved.
|
||||
*/
|
||||
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 {
|
||||
const sf = getSourceFile(id) as SourceFileWithImportDeclarationMapping;
|
||||
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)!;
|
||||
recordUsedImport(importDecl: ts.ImportDeclaration): void {
|
||||
const sf = getSourceFile(importDecl);
|
||||
|
||||
// Add the default import declaration to the set of used import declarations for the file.
|
||||
if (!this.sourceFileToUsedImports.has(sf)) {
|
||||
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
|
||||
* 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> {
|
||||
return (context: ts.TransformationContext) => {
|
||||
|
|
|
@ -39,12 +39,10 @@ runInEachFileSystem(() => {
|
|||
module: ts.ModuleKind.ES2015,
|
||||
});
|
||||
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
||||
const fooId = fooClause.name!;
|
||||
const fooDecl = fooClause.parent;
|
||||
|
||||
const tracker = new DefaultImportTracker();
|
||||
tracker.recordImportedIdentifier(fooId, fooDecl);
|
||||
tracker.recordUsedIdentifier(fooId);
|
||||
tracker.recordUsedImport(fooDecl);
|
||||
program.emit(undefined, undefined, undefined, undefined, {
|
||||
before: [tracker.importPreservingTransformer()],
|
||||
});
|
||||
|
@ -73,8 +71,7 @@ runInEachFileSystem(() => {
|
|||
const fooDecl = fooClause.parent;
|
||||
|
||||
const tracker = new DefaultImportTracker();
|
||||
tracker.recordImportedIdentifier(fooId, fooDecl);
|
||||
tracker.recordUsedIdentifier(fooId);
|
||||
tracker.recordUsedImport(fooDecl);
|
||||
program.emit(undefined, undefined, undefined, undefined, {
|
||||
before: [
|
||||
addReferenceTransformer(fooId),
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
import {ConstantPool} from '@angular/compiler';
|
||||
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 {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 {CompileResult} from './api';
|
||||
|
@ -34,16 +35,16 @@ interface FileOverviewMeta {
|
|||
|
||||
export function ivyTransformFactory(
|
||||
compilation: TraitCompiler, reflector: ReflectionHost, importRewriter: ImportRewriter,
|
||||
defaultImportRecorder: DefaultImportRecorder, perf: PerfRecorder, isCore: boolean,
|
||||
defaultImportTracker: DefaultImportTracker, perf: PerfRecorder, isCore: boolean,
|
||||
isClosureCompilerEnabled: boolean): ts.TransformerFactory<ts.SourceFile> {
|
||||
const recordWrappedNodeExpr = createRecorderFn(defaultImportRecorder);
|
||||
const recordWrappedNode = createRecorderFn(defaultImportTracker);
|
||||
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
|
||||
return (file: ts.SourceFile): ts.SourceFile => {
|
||||
return perf.inPhase(
|
||||
PerfPhase.Compile,
|
||||
() => transformIvySourceFile(
|
||||
compilation, context, reflector, importRewriter, file, isCore,
|
||||
isClosureCompilerEnabled, recordWrappedNodeExpr));
|
||||
isClosureCompilerEnabled, recordWrappedNode));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -81,7 +82,7 @@ class IvyTransformationVisitor extends Visitor {
|
|||
private compilation: TraitCompiler,
|
||||
private classCompilationMap: Map<ts.ClassDeclaration, CompileResult[]>,
|
||||
private reflector: ReflectionHost, private importManager: ImportManager,
|
||||
private recordWrappedNodeExpr: RecordWrappedNodeExprFn<ts.Expression>,
|
||||
private recordWrappedNodeExpr: RecordWrappedNodeFn<ts.Expression>,
|
||||
private isClosureCompilerEnabled: boolean, private isCore: boolean) {
|
||||
super();
|
||||
}
|
||||
|
@ -95,7 +96,7 @@ class IvyTransformationVisitor extends Visitor {
|
|||
}
|
||||
|
||||
const translateOptions: TranslatorOptions<ts.Expression> = {
|
||||
recordWrappedNodeExpr: this.recordWrappedNodeExpr,
|
||||
recordWrappedNode: this.recordWrappedNodeExpr,
|
||||
annotateForClosureCompiler: this.isClosureCompilerEnabled,
|
||||
};
|
||||
|
||||
|
@ -252,7 +253,7 @@ function transformIvySourceFile(
|
|||
compilation: TraitCompiler, context: ts.TransformationContext, reflector: ReflectionHost,
|
||||
importRewriter: ImportRewriter, file: ts.SourceFile, isCore: boolean,
|
||||
isClosureCompilerEnabled: boolean,
|
||||
recordWrappedNodeExpr: RecordWrappedNodeExprFn<ts.Expression>): ts.SourceFile {
|
||||
recordWrappedNode: RecordWrappedNodeFn<ts.Expression>): ts.SourceFile {
|
||||
const constantPool = new ConstantPool(isClosureCompilerEnabled);
|
||||
const importManager = new ImportManager(importRewriter);
|
||||
|
||||
|
@ -274,7 +275,7 @@ function transformIvySourceFile(
|
|||
// results obtained at Step 1.
|
||||
const transformationVisitor = new IvyTransformationVisitor(
|
||||
compilation, compilationVisitor.classCompilationMap, reflector, importManager,
|
||||
recordWrappedNodeExpr, isClosureCompilerEnabled, isCore);
|
||||
recordWrappedNode, isClosureCompilerEnabled, isCore);
|
||||
let sf = visit(file, transformationVisitor, context);
|
||||
|
||||
// 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 constants =
|
||||
constantPool.statements.map(stmt => translateStatement(stmt, importManager, {
|
||||
recordWrappedNodeExpr,
|
||||
recordWrappedNode,
|
||||
downlevelTaggedTemplates: downlevelTranslatedCode,
|
||||
downlevelVariableDeclarations: downlevelTranslatedCode,
|
||||
annotateForClosureCompiler: isClosureCompilerEnabled,
|
||||
|
@ -370,11 +371,12 @@ function isFromAngularCore(decorator: Decorator): boolean {
|
|||
return decorator.import !== null && decorator.import.from === '@angular/core';
|
||||
}
|
||||
|
||||
function createRecorderFn(defaultImportRecorder: DefaultImportRecorder):
|
||||
RecordWrappedNodeExprFn<ts.Expression> {
|
||||
return expr => {
|
||||
if (ts.isIdentifier(expr)) {
|
||||
defaultImportRecorder.recordUsedIdentifier(expr);
|
||||
function createRecorderFn(defaultImportTracker: DefaultImportTracker):
|
||||
RecordWrappedNodeFn<ts.Expression> {
|
||||
return node => {
|
||||
const importDecl = getDefaultImportDeclaration(node);
|
||||
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 {Context} from './src/context';
|
||||
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 {attachComments, createTemplateMiddle, createTemplateTail, TypeScriptAstFactory} from './src/typescript_ast_factory';
|
||||
export {translateExpression, translateStatement} from './src/typescript_translator';
|
||||
|
|
|
@ -37,12 +37,12 @@ const BINARY_OPERATORS = new Map<o.BinaryOperator, BinaryOperator>([
|
|||
[o.BinaryOperator.NullishCoalesce, '??'],
|
||||
]);
|
||||
|
||||
export type RecordWrappedNodeExprFn<TExpression> = (expr: TExpression) => void;
|
||||
export type RecordWrappedNodeFn<TExpression> = (node: o.WrappedNodeExpr<TExpression>) => void;
|
||||
|
||||
export interface TranslatorOptions<TExpression> {
|
||||
downlevelTaggedTemplates?: boolean;
|
||||
downlevelVariableDeclarations?: boolean;
|
||||
recordWrappedNodeExpr?: RecordWrappedNodeExprFn<TExpression>;
|
||||
recordWrappedNode?: RecordWrappedNodeFn<TExpression>;
|
||||
annotateForClosureCompiler?: boolean;
|
||||
}
|
||||
|
||||
|
@ -50,14 +50,14 @@ export class ExpressionTranslatorVisitor<TStatement, TExpression> implements o.E
|
|||
o.StatementVisitor {
|
||||
private downlevelTaggedTemplates: boolean;
|
||||
private downlevelVariableDeclarations: boolean;
|
||||
private recordWrappedNodeExpr: RecordWrappedNodeExprFn<TExpression>;
|
||||
private recordWrappedNode: RecordWrappedNodeFn<TExpression>;
|
||||
|
||||
constructor(
|
||||
private factory: AstFactory<TStatement, TExpression>,
|
||||
private imports: ImportGenerator<TExpression>, options: TranslatorOptions<TExpression>) {
|
||||
this.downlevelTaggedTemplates = options.downlevelTaggedTemplates === true;
|
||||
this.downlevelVariableDeclarations = options.downlevelVariableDeclarations === true;
|
||||
this.recordWrappedNodeExpr = options.recordWrappedNodeExpr || (() => {});
|
||||
this.recordWrappedNode = options.recordWrappedNode || (() => {});
|
||||
}
|
||||
|
||||
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 {
|
||||
this.recordWrappedNodeExpr(ast.node);
|
||||
this.recordWrappedNode(ast);
|
||||
return ast.node;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue