diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index e2387792c7..cd2311c11a 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -235,6 +235,34 @@ runInEachFileSystem(() => { `TestClass.ɵprov = ɵngcc0.ɵɵdefineInjectable({`); }); + it('should use the correct type name in typings files when an export has a different name in source files', + () => { + // We need to make sure that changes to the typings files use the correct name + // static ɵprov: ɵngcc0.ɵɵInjectableDef<ɵangular_packages_common_common_a>; + mainNgcc({ + basePath: '/node_modules', + targetEntryPointPath: '@angular/common', + propertiesToConsider: ['esm2015'] + }); + + // In `@angular/common` the `NgClassR3Impl` class gets exported as something like + // `ɵangular_packages_common_common_a`. + const jsContents = fs.readFile(_(`/node_modules/@angular/common/fesm2015/common.js`)); + const exportedNameMatch = jsContents.match(/export.* NgClassR3Impl as ([^ ,}]+)/); + if (exportedNameMatch === null) { + return fail( + 'Expected `/node_modules/@angular/common/fesm2015/common.js` to export `NgClassR3Impl` via an alias'); + } + const exportedName = exportedNameMatch[1]; + + // We need to make sure that the flat typings file exports this directly + const dtsContents = fs.readFile(_('/node_modules/@angular/common/common.d.ts')); + expect(dtsContents) + .toContain(`export declare class ${exportedName} implements ɵNgClassImpl`); + // And that ngcc's modifications to that class use the correct (exported) name + expect(dtsContents).toContain(`static ɵprov: ɵngcc0.ɵɵInjectableDef<${exportedName}>`); + }); + it('should add generic type for ModuleWithProviders and generate exports for private modules', () => { compileIntoApf('test-package', { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index 64bf416728..77f1918fb0 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -20,7 +20,7 @@ import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFl import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; -import {findAngularDecorator, getConstructorDependencies, isAngularDecorator, makeDuplicateDeclarationError, readBaseClass, unwrapConstructorDependencies, unwrapExpression, unwrapForwardRef, validateConstructorDependencies, wrapFunctionExpressionsInParens} from './util'; +import {findAngularDecorator, getConstructorDependencies, isAngularDecorator, makeDuplicateDeclarationError, readBaseClass, unwrapConstructorDependencies, unwrapExpression, unwrapForwardRef, validateConstructorDependencies, wrapFunctionExpressionsInParens, wrapTypeReference} from './util'; const EMPTY_OBJECT: {[key: string]: string} = {}; const FIELD_DECORATORS = [ @@ -292,6 +292,9 @@ export function extractDirectiveMetadata( // Detect if the component inherits from another class const usesInheritance = reflector.hasBaseClass(clazz); + const type = wrapTypeReference(reflector, clazz); + const internalType = new WrappedNodeExpr(reflector.getInternalNameOfClass(clazz)); + const metadata: R3DirectiveMetadata = { name: clazz.name.text, deps: ctorDeps, host, @@ -300,9 +303,7 @@ export function extractDirectiveMetadata( }, inputs: {...inputsFromMeta, ...inputsFromFields}, outputs: {...outputsFromMeta, ...outputsFromFields}, queries, viewQueries, selector, - fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE), - type: new WrappedNodeExpr(clazz.name), - internalType: new WrappedNodeExpr(reflector.getInternalNameOfClass(clazz)), + fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE), type, internalType, typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0, typeSourceSpan: EMPTY_SOURCE_SPAN, usesInheritance, exportAs, providers }; diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index aba230e092..93717607b5 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -16,7 +16,7 @@ import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPr import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; -import {findAngularDecorator, getConstructorDependencies, getValidConstructorDependencies, isAngularCore, unwrapConstructorDependencies, unwrapForwardRef, validateConstructorDependencies} from './util'; +import {findAngularDecorator, getConstructorDependencies, getValidConstructorDependencies, isAngularCore, unwrapConstructorDependencies, unwrapForwardRef, validateConstructorDependencies, wrapTypeReference} from './util'; export interface InjectableHandlerData { meta: R3InjectableMetadata; @@ -130,7 +130,7 @@ function extractInjectableMetadata( clazz: ClassDeclaration, decorator: Decorator, reflector: ReflectionHost): R3InjectableMetadata { const name = clazz.name.text; - const type = new WrappedNodeExpr(clazz.name); + const type = wrapTypeReference(reflector, clazz); const internalType = new WrappedNodeExpr(reflector.getInternalNameOfClass(clazz)); const typeArgumentCount = reflector.getGenericArityOfClass(clazz) || 0; if (decorator.args === null) { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts index 9ba2c1186e..7e43c198ee 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts @@ -22,7 +22,7 @@ import {getSourceFile} from '../../util/src/typescript'; import {generateSetClassMetadataCall} from './metadata'; import {ReferencesRegistry} from './references_registry'; -import {combineResolvers, findAngularDecorator, forwardRefResolver, getReferenceOriginForDiagnostics, getValidConstructorDependencies, isExpressionForwardReference, toR3Reference, unwrapExpression, wrapFunctionExpressionsInParens} from './util'; +import {combineResolvers, findAngularDecorator, forwardRefResolver, getReferenceOriginForDiagnostics, getValidConstructorDependencies, isExpressionForwardReference, toR3Reference, unwrapExpression, wrapFunctionExpressionsInParens, wrapTypeReference} from './util'; export interface NgModuleAnalysis { mod: R3NgModuleMetadata; @@ -220,10 +220,14 @@ export class NgModuleDecoratorHandler implements declarations.some(isForwardReference) || imports.some(isForwardReference) || exports.some(isForwardReference); + const type = wrapTypeReference(this.reflector, node); + const internalType = new WrappedNodeExpr(this.reflector.getInternalNameOfClass(node)); + const adjacentType = new WrappedNodeExpr(this.reflector.getAdjacentNameOfClass(node)); + const ngModuleDef: R3NgModuleMetadata = { - type: new WrappedNodeExpr(node.name), - internalType: new WrappedNodeExpr(this.reflector.getInternalNameOfClass(node)), - adjacentType: new WrappedNodeExpr(this.reflector.getAdjacentNameOfClass(node)), + type, + internalType, + adjacentType, bootstrap, declarations, exports, @@ -256,8 +260,8 @@ export class NgModuleDecoratorHandler implements const ngInjectorDef: R3InjectorMetadata = { name, - type: new WrappedNodeExpr(node.name), - internalType: new WrappedNodeExpr(this.reflector.getInternalNameOfClass(node)), + type, + internalType, deps: getValidConstructorDependencies( node, this.reflector, this.defaultImportRecorder, this.isCore), providers, diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts index fa3b831d0b..0210aba663 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts @@ -19,7 +19,7 @@ import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPr import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; -import {findAngularDecorator, getValidConstructorDependencies, makeDuplicateDeclarationError, unwrapExpression} from './util'; +import {findAngularDecorator, getValidConstructorDependencies, makeDuplicateDeclarationError, unwrapExpression, wrapTypeReference} from './util'; export interface PipeHandlerData { meta: R3PipeMetadata; @@ -53,8 +53,9 @@ export class PipeDecoratorHandler implements DecoratorHandler): AnalysisOutput { const name = clazz.name.text; - const type = new WrappedNodeExpr(clazz.name); + const type = wrapTypeReference(this.reflector, clazz); const internalType = new WrappedNodeExpr(this.reflector.getInternalNameOfClass(clazz)); + if (decorator.args === null) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_NOT_CALLED, Decorator.nodeForError(decorator), diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts index d10ff5f2c1..989275dfbf 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts @@ -435,3 +435,18 @@ export function makeDuplicateDeclarationError( ErrorCode.NGMODULE_DECLARATION_NOT_UNIQUE, node.name, `The ${kind} '${node.name.text}' is declared by more than one NgModule.`, context); } + +/** + * Create an R3Reference for a class. + * + * The `value` is the exported declaration of the class from its source file. + * The `type` is an expression that would be used by ngcc in the typings (.d.ts) files. + */ +export function wrapTypeReference(reflector: ReflectionHost, clazz: ClassDeclaration): R3Reference { + const dtsClass = reflector.getDtsDeclaration(clazz); + const value = new WrappedNodeExpr(clazz.name); + const type = dtsClass !== null && isNamedClassDeclaration(dtsClass) ? + new WrappedNodeExpr(dtsClass.name) : + value; + return {value, type}; +} diff --git a/packages/compiler/src/injectable_compiler_2.ts b/packages/compiler/src/injectable_compiler_2.ts index 2fccf84c2b..b3b0a2221b 100644 --- a/packages/compiler/src/injectable_compiler_2.ts +++ b/packages/compiler/src/injectable_compiler_2.ts @@ -9,7 +9,7 @@ import {Identifiers} from './identifiers'; import * as o from './output/output_ast'; import {R3DependencyMetadata, R3FactoryDelegateType, R3FactoryMetadata, R3FactoryTarget, compileFactoryFunction} from './render3/r3_factory'; -import {mapToMapExpression, typeWithParameters} from './render3/util'; +import {R3Reference, mapToMapExpression, typeWithParameters} from './render3/util'; export interface InjectableDef { expression: o.Expression; @@ -19,7 +19,7 @@ export interface InjectableDef { export interface R3InjectableMetadata { name: string; - type: o.Expression; + type: R3Reference; internalType: o.Expression; typeArgumentCount: number; providedIn: o.Expression; @@ -69,7 +69,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef { result = compileFactoryFunction(factoryMeta); } else { result = delegateToFactory( - meta.type as o.WrappedNodeExpr, meta.useClass as o.WrappedNodeExpr); + meta.type.value as o.WrappedNodeExpr, meta.useClass as o.WrappedNodeExpr); } } else if (meta.useFactory !== undefined) { if (meta.userDeps !== undefined) { @@ -101,7 +101,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef { }); } else { result = delegateToFactory( - meta.type as o.WrappedNodeExpr, meta.internalType as o.WrappedNodeExpr); + meta.type.value as o.WrappedNodeExpr, meta.internalType as o.WrappedNodeExpr); } const token = meta.internalType; @@ -116,7 +116,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef { const expression = o.importExpr(Identifiers.ɵɵdefineInjectable).callFn([mapToMapExpression(injectableProps)]); const type = new o.ExpressionType(o.importExpr( - Identifiers.InjectableDef, [typeWithParameters(meta.type, meta.typeArgumentCount)])); + Identifiers.InjectableDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount)])); return { expression, diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index acd7502e9b..b1095f801d 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -39,7 +39,7 @@ export class CompilerFacadeImpl implements CompilerFacade { any { const metadata: R3PipeMetadata = { name: facade.name, - type: new WrappedNodeExpr(facade.type), + type: wrapReference(facade.type), internalType: new WrappedNodeExpr(facade.type), typeArgumentCount: facade.typeArgumentCount, deps: convertR3DependencyMetadataArray(facade.deps), @@ -55,7 +55,7 @@ export class CompilerFacadeImpl implements CompilerFacade { facade: R3InjectableMetadataFacade): any { const {expression, statements} = compileInjectable({ name: facade.name, - type: new WrappedNodeExpr(facade.type), + type: wrapReference(facade.type), internalType: new WrappedNodeExpr(facade.type), typeArgumentCount: facade.typeArgumentCount, providedIn: computeProvidedIn(facade.providedIn), @@ -74,7 +74,7 @@ export class CompilerFacadeImpl implements CompilerFacade { facade: R3InjectorMetadataFacade): any { const meta: R3InjectorMetadata = { name: facade.name, - type: new WrappedNodeExpr(facade.type), + type: wrapReference(facade.type), internalType: new WrappedNodeExpr(facade.type), deps: convertR3DependencyMetadataArray(facade.deps), providers: new WrappedNodeExpr(facade.providers), @@ -88,7 +88,7 @@ export class CompilerFacadeImpl implements CompilerFacade { angularCoreEnv: CoreEnvironment, sourceMapUrl: string, facade: R3NgModuleMetadataFacade): any { const meta: R3NgModuleMetadata = { - type: new WrappedNodeExpr(facade.type), + type: wrapReference(facade.type), internalType: new WrappedNodeExpr(facade.type), adjacentType: new WrappedNodeExpr(facade.type), bootstrap: facade.bootstrap.map(wrapReference), @@ -163,7 +163,7 @@ export class CompilerFacadeImpl implements CompilerFacade { angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3FactoryDefMetadataFacade) { const factoryRes = compileFactoryFunction({ name: meta.name, - type: new WrappedNodeExpr(meta.type), + type: wrapReference(meta.type), internalType: new WrappedNodeExpr(meta.type), typeArgumentCount: meta.typeArgumentCount, deps: convertR3DependencyMetadataArray(meta.deps), @@ -252,7 +252,7 @@ function convertDirectiveFacadeToMetadata(facade: R3DirectiveMetadataFacade): R3 return { ...facade as R3DirectiveMetadataFacadeNoPropAndWhitespace, typeSourceSpan: facade.typeSourceSpan, - type: new WrappedNodeExpr(facade.type), + type: wrapReference(facade.type), internalType: new WrappedNodeExpr(facade.type), deps: convertR3DependencyMetadataArray(facade.deps), host: extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host), diff --git a/packages/compiler/src/render3/r3_factory.ts b/packages/compiler/src/render3/r3_factory.ts index 7fe5eefc48..c3ede764a5 100644 --- a/packages/compiler/src/render3/r3_factory.ts +++ b/packages/compiler/src/render3/r3_factory.ts @@ -15,7 +15,7 @@ import * as o from '../output/output_ast'; import {Identifiers as R3} from '../render3/r3_identifiers'; import {OutputContext} from '../util'; -import {typeWithParameters} from './util'; +import {R3Reference, typeWithParameters} from './util'; import {unsupported} from './view/util'; @@ -32,7 +32,7 @@ export interface R3ConstructorFactoryMetadata { /** * An expression representing the interface type being constructed. */ - type: o.Expression; + type: R3Reference; /** * An expression representing the constructor type, intended for use within a class definition @@ -270,7 +270,7 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): R3FactoryFn { `${meta.name}_Factory`), statements, type: o.expressionType( - o.importExpr(R3.FactoryDef, [typeWithParameters(meta.type, meta.typeArgumentCount)])) + o.importExpr(R3.FactoryDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount)])) }; } diff --git a/packages/compiler/src/render3/r3_module_compiler.ts b/packages/compiler/src/render3/r3_module_compiler.ts index 37bb1b5add..833a88bc53 100644 --- a/packages/compiler/src/render3/r3_module_compiler.ts +++ b/packages/compiler/src/render3/r3_module_compiler.ts @@ -29,7 +29,7 @@ export interface R3NgModuleMetadata { /** * An expression representing the module type being compiled. */ - type: o.Expression; + type: R3Reference; /** * An expression representing the module type being compiled, intended for use within a class @@ -160,7 +160,7 @@ export function compileNgModule(meta: R3NgModuleMetadata): R3NgModuleDef { const expression = o.importExpr(R3.defineNgModule).callFn([mapToMapExpression(definitionMap)]); const type = new o.ExpressionType(o.importExpr(R3.NgModuleDefWithMeta, [ - new o.ExpressionType(moduleType), tupleTypeOf(declarations), tupleTypeOf(imports), + new o.ExpressionType(moduleType.type), tupleTypeOf(declarations), tupleTypeOf(imports), tupleTypeOf(exports) ])); @@ -228,7 +228,7 @@ export interface R3InjectorDef { export interface R3InjectorMetadata { name: string; - type: o.Expression; + type: R3Reference; internalType: o.Expression; deps: R3DependencyMetadata[]|null; providers: o.Expression|null; @@ -259,7 +259,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef { const expression = o.importExpr(R3.defineInjector).callFn([mapToMapExpression(definitionMap)]); const type = - new o.ExpressionType(o.importExpr(R3.InjectorDef, [new o.ExpressionType(meta.type)])); + new o.ExpressionType(o.importExpr(R3.InjectorDef, [new o.ExpressionType(meta.type.type)])); return {expression, type, statements: result.statements}; } diff --git a/packages/compiler/src/render3/r3_pipe_compiler.ts b/packages/compiler/src/render3/r3_pipe_compiler.ts index 03bfab91e1..703a001a48 100644 --- a/packages/compiler/src/render3/r3_pipe_compiler.ts +++ b/packages/compiler/src/render3/r3_pipe_compiler.ts @@ -14,7 +14,7 @@ import {OutputContext, error} from '../util'; import {R3DependencyMetadata, R3FactoryTarget, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory'; import {Identifiers as R3} from './r3_identifiers'; -import {typeWithParameters} from './util'; +import {R3Reference, typeWithParameters, wrapReference} from './util'; export interface R3PipeMetadata { /** @@ -25,7 +25,7 @@ export interface R3PipeMetadata { /** * An expression representing a reference to the pipe itself. */ - type: o.Expression; + type: R3Reference; /** * An expression representing the pipe being compiled, intended for use within a class definition @@ -64,14 +64,14 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) { definitionMapValues.push({key: 'name', value: o.literal(metadata.pipeName), quoted: false}); // e.g. `type: MyPipe` - definitionMapValues.push({key: 'type', value: metadata.type, quoted: false}); + definitionMapValues.push({key: 'type', value: metadata.type.value, quoted: false}); // e.g. `pure: true` definitionMapValues.push({key: 'pure', value: o.literal(metadata.pure), quoted: false}); const expression = o.importExpr(R3.definePipe).callFn([o.literalMap(definitionMapValues)]); const type = new o.ExpressionType(o.importExpr(R3.PipeDefWithMeta, [ - typeWithParameters(metadata.type, metadata.typeArgumentCount), + typeWithParameters(metadata.type.type, metadata.typeArgumentCount), new o.ExpressionType(new o.LiteralExpr(metadata.pipeName)), ])); @@ -92,7 +92,7 @@ export function compilePipeFromRender2( const type = outputCtx.importExpr(pipe.type.reference); const metadata: R3PipeMetadata = { name, - type, + type: wrapReference(type), internalType: type, pipeName: pipe.name, typeArgumentCount: 0, diff --git a/packages/compiler/src/render3/util.ts b/packages/compiler/src/render3/util.ts index 1bfecc586f..5572495dcf 100644 --- a/packages/compiler/src/render3/util.ts +++ b/packages/compiler/src/render3/util.ts @@ -98,3 +98,8 @@ export function jitOnlyGuardedExpression(expr: o.Expression): o.Expression { /* sourceSpan */ undefined, true); return new o.BinaryOperatorExpr(o.BinaryOperator.And, jitFlagUndefinedOrTrue, expr); } + +export function wrapReference(value: any): R3Reference { + const wrapped = new o.WrappedNodeExpr(value); + return {value: wrapped, type: wrapped}; +} \ No newline at end of file diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index 0372ede4b5..5b38e0a6a6 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -12,6 +12,7 @@ import * as o from '../../output/output_ast'; import {ParseSourceSpan} from '../../parse_util'; import * as t from '../r3_ast'; import {R3DependencyMetadata} from '../r3_factory'; +import {R3Reference} from '../util'; /** @@ -26,7 +27,7 @@ export interface R3DirectiveMetadata { /** * An expression representing a reference to the directive itself. */ - type: o.Expression; + type: R3Reference; /** * An expression representing a reference to the directive being compiled, intended for use within diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index c4b7ca3f2a..f0fa0e4944 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -481,7 +481,7 @@ function createTypeForDef(meta: R3DirectiveMetadata, typeBase: o.ExternalReferen const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null; return o.expressionType(o.importExpr(typeBase, [ - typeWithParameters(meta.type, meta.typeArgumentCount), + typeWithParameters(meta.type.type, meta.typeArgumentCount), selectorForType !== null ? stringAsType(selectorForType) : o.NONE_TYPE, meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : o.NONE_TYPE, stringMapAsType(meta.inputs),